I have bit problems to understand conditions looping.
I'm getting REST API response from Ambari server.
This response contains JSON with service names on host.
I'd like to iterate over service names to do some tasks.
Here are my steps in Ansible:
## This gets http api responce.
## in components I'm getting full `json`
- name: Get Hadoop services
uri:
url: ' {{ Ambari_link }}/{{ clustername }}/hosts/{{ ansible_host }}/host_components/ '
method: GET
headers:
X-Requested-By: ambari
user: "{{ Ambari_Admin_User}}"
password: "{{ Ambari_Admin_Pass }}"
force_basic_auth: yes
register: components
Here is step that outputs service names
## Here I'm simply list all services on host in cluster.
- name: "Display all services"
debug:
msg: " {{ Ambari_link }}/{{ clustername }}/host_components/{{ item }} "
loop: "{{ components.json | json_query('items[*].HostRoles.component_name') }}"
Example output
ok: [slave] => (item=DATANODE) => {
"msg": " https://ambari-server:8443/api/v1/clusters/test_cluster/host_components/DATANODE "
}
ok: [slave] => (item=HDFS_CLIENT) => {
"msg": " https://ambari-server:8443/api/v1/clusters/test_cluster/host_components/HDFS_CLIENT "
}
ok: [slave] => (item=NODEMANAGER) => {
"msg": " https://ambari-server:8443/api/v1/clusters/test_cluster/host_components/NODEMANAGER "
}
ok: [slave] => (item=YARN_CLIENT) => {
"msg": " https://ambari-server:8443/api/v1/clusters/test_cluster/host_components/YARN_CLIENT "
}
Now part that i don't understand how to implement.
I'd like to iterate over all service names.
If service name contains _CLIENT ansible should proceed with new item.
If service name does not contains _CLIENT in should print debug message.
But this step is simply skipped
- name: Filter Clients
debug:
msg: "{{ item }}"
loop: "{{ components.json | json_query('items[*].HostRoles.component_name') }}"
when: " item.find('CLIENT') == 'CLIENT' "
I also tried to search only for DATANODE but it was also skipped step.
when: " item.find('DATANODE') == 'DATANODE' "
Can some one please explain how to search in item for _CLIENT and why it is skipped?
I have as usual over complicated simplest part.
Instead of
when: " item.find('DATANODE') == 'DATANODE' "
It is possible to use
when: not '_CLIENT' in item
=> returns DATANODE, NODEMANAGER
Or more generic
# item contains [foo,bar]
when: not 'oo' in item
=> Returns all that not contains oo
Related
Let me introduce my problem. I have some list of dictionary in my Ansible code:
my_example_list = [
{
"key1" : "value_of_first_key"
},
{
"key2": "value_of_second_key"
},
{
"key3": "value_of_third_key"
}
]
I need execute command which will iterate over this list and it should look something like:
- name: 'Example'
shell: 'Here is my {{ item.key }} and here is {{ item.value }}'
What I've do or try to do:
I was trying to do that with with_items but i'm not able to point into value of particular key.
I've also try to filter values using | first and | last but it's not worked in my case.
What I want to achieve:
Creating loop which will iterate via that list and inject separated key and value into command.
I was asked to show how I was trying to resolve my issue:
Here is some code:
# Showing last component failing
- name: "Try to show last component of my list"
debug:
msg: "{{ my_example_list[1] | last }}"
# When i'm trying to show first component of my list i get "key1"
- name: "Try to show first component of my list"
debug:
msg: "{{ my_example_list[1] | first }}"
# This shows me my list of dict
- name: "Trying use with_items"
debug:
msg: "{{ item }}"
with_items: "{{ my_example_list }}"
# But when i'm trying point to key and value for example
- name: "Trying use with_items point to key and value"
debug:
msg: "Here is my {{ item.key }} which keep {{ item.value }}"
with_items: "{{ my_example_list }}"
# It's failing.
Sorry it's not maybe solution with using loop. I'm just stack with that issue over few days... And as first step I want to know how correctly point to pair keys and values.
It also works well:
- name: Correct solution
debug:
msg: "This is my {{ item.key }} and my value {{ item.value }}"
with_dict: "{{ my_example_list }}"
Thanks #U880D for help! I'm not able to add some plus for your solution because I'm new joiner. Appreciate your answer! :)
Your data structure and naming seems to be unfavorable. There is no need to number the key name and therefore it should be avoided. Furthermore counting list elements in Python starts at 0 not 1.
The following minimal example playbook
---
- hosts: localhost
become: false
gather_facts: false
vars:
example_list: |
[
{
"key1" : "value_of_first_key"
},
{
"key2": "value_of_second_key"
},
{
"key3": "value_of_third_key"
}
]
tasks:
- name: Example loop
debug:
msg: "{{ item }} is of type {{ item | type_debug }}"
loop: "{{ example_list }}"
- name: Example loop
debug:
msg: "{{ item.values() }}"
loop: "{{ example_list }}"
will result into an output of
TASK [Example loop] ******************************************
ok: [localhost] => (item={u'key1': u'value_of_first_key'}) =>
msg: '{u''key1'': u''value_of_first_key''} is of type dict'
ok: [localhost] => (item={u'key2': u'value_of_second_key'}) =>
msg: '{u''key2'': u''value_of_second_key''} is of type dict'
ok: [localhost] => (item={u'key3': u'value_of_third_key'}) =>
msg: '{u''key3'': u''value_of_third_key''} is of type dict'
TASK [Example loop] ******************************************
ok: [localhost] => (item={u'key1': u'value_of_first_key'}) =>
msg:
- value_of_first_key
ok: [localhost] => (item={u'key2': u'value_of_second_key'}) =>
msg:
- value_of_second_key
ok: [localhost] => (item={u'key3': u'value_of_third_key'}) =>
msg:
- value_of_third_key
Further Readings
How to work with lists and dictionaries in Ansible
Extended loop variables
This has got to be a simple question but I can't seem to find the answer anywhere.
I have the following list:
yum_repo_ip_addrs: ['172.16.130.4', '172.16.130.1']
I want to dynamically create a list called yum_baseurls where I copy in these values into the list along with the rest of the url. The list should ultimately look like this when run successfully:
yum_baseurls:
- "http://172.16.130.4/repos/elrepo-8-x86_64"
- "http://172.16.130.1/repos/elrepo-8-x86_64"
Instead, I'm finding that after the first iteration of my loop it's pasting in the variables literally.
Here's my playbook:
---
- name: Print the list of baseurl IP addresses.
debug:
msg: "{{ yum_repo_ip_addrs }}"
- name: Create the list of baseurls.
set_fact:
yum_baseurls: "{{ yum_baseurls + ['http://{{ item }}/repos/elrepo-{{ ansible_distribution_major_version }}-{{ ansible_userspace_architecture }}'] }}"
with_items:
- "{{ yum_repo_ip_addrs }}"
- name: print the list of baseurls.
debug:
msg: "{{ yum_baseurls }}"
And here's the output I get when I run it:
TASK [yum : Print the list of baseurl IP addresses.] ***************************************************************************************
ok: [ansibletarget3.jnk.sys] => {
"msg": [
"172.16.130.4",
"172.16.130.1"
]
}
TASK [yum : Create the list of baseurls.] **************************************************************************************************
ok: [ansibletarget3.jnk.sys] => (item=172.16.130.4)
ok: [ansibletarget3.jnk.sys] => (item=172.16.130.1)
TASK [yum : print the list of baseurls.] ***************************************************************************************************
ok: [ansibletarget3.jnk.sys] => {
"msg": [
"http://172.16.130.1/repos/elrepo-8-x86_64",
"http://{{ item }}/repos/elrepo-{{ ansible_distribution_major_version }}-{{ ansible_userspace_architecture }}"
]
}
Is there a better way to generate my list?
I'd remove it from the code and put it somewhere into the vars, e.g.
yum_repo_ip_addrs: [172.16.130.4, 172.16.130.1]
version: 8
architecture: x86_64
yum_baseurls_str: |
{% for ip in yum_repo_ip_addrs %}
- http://{{ ip }}/repos/elrepo-{{ version }}-{{ architecture }}
{% endfor %}
yum_baseurls: "{{ yum_baseurls_str|from_yaml }}"
I have a variable that is set from a Tower survey and I am using it to retrieve an associated IP address in netbox. I am not able to get it to match when I use square brackets and when I use {{ or ' or " everything is matched and my whole IPAM database is returned.
vars:
location: "{{ LOCATION }}"
c_description: "{{CIRCUIT_DESC}}"
prefix_length: "{{PREFIX}}"
tasks:
- name: "Print IP"
debug:
msg: "{{ query('netbox.netbox.nb_lookup', 'ip-addresses', api_filter= 'description=
[c_description]', api_endpoint='http://netbox', token='', validate_certs='False') }}"
Here is my output:
TASK [Print IP] ****************************************************************
ok: [localhost] => {
"msg": []
}
Solved in another forum using a tilda:
- name: "Print IP"
debug:
msg: "{{ query('netbox.netbox.nb_lookup', 'ip-addresses', api_filter='description=' ~ c_description,
api_endpoint='http://netbox.', token='', validate_certs='False') }}"
I'm facing a strange issue while trying to search inside a dictionary. In the code above, i'm trying to define a new var "OLD_VLANID_PP", with the value of the "name" key of the dictionary "VM_NETWORK_INFOS_PP".
If the dictionary is set and not empty, I want the var to be defined, otherwise just skip the task.
In order to test if the condition was true or false, I've added a debug task which should display the content of the dictionary.
When running my playbook, the debug task does indicates that the condition is not matched, and so doesn't display my dictionary, but Ansible keep trying to define my new var as shown in the output, and so fires an error "'item' is undefined"
---
- block:
#Search VCENTER for PPROD VM (If Windows to create => Search PG / EIther search Postgre)
- name: Search for PPROD VM already created for the CLIENT {{ CLIENTNAME }} to retrieve VLANID
set_fact:
OLD_VMNAME_PP: "{{ item.guest_name }}"
with_items: "{{ VM_EXIST_PP.virtual_machines }}"
when: item.guest_name == VMNAME_PP
delegate_to: localhost
when: ENV != "PROD" and DEPLOY != "ALL" and (VM_EXIST_PP is defined) and (VM_EXIST_PP|length > 0)
#If we successfully found the previous VM for the client, then get its network info
- name: Retrieve PPROD VM {{ VMNAME_PP }} VLAN ID
community.vmware.vmware_guest_network:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
datacenter: "{{ datacenter_name }}"
validate_certs: False
name: "{{ OLD_VMNAME_PP }}"
gather_network_info: true
register: VM_NETWORK_INFOS_PP
when: (OLD_VMNAME_PP is defined) and OLD_VMNAME_PP != ""
- block:
- debug: msg={{VM_NETWORK_INFOS_PP}}
#If we successfully found the network info, set the OLD_VLANID with previous VM VLANID
- set_fact:
OLD_VLANID_PP: "{{ (item.name) | replace('(HDS : Client)','') | replace('VLAN0','') | replace('VLAN','') | replace(' ','') }}"
with_items:
- "{{ VM_NETWORK_INFOS_PP.network_info }}"
when: item.name | regex_search('VLAN') and not item.name | regex_search('PVLAN')
when: (VM_NETWORK_INFOS_PP is defined) and VM_NETWORK_INFOS_PP != ""
Debug Output (Should display the dictionary content) :
ok: [127.0.0.1] => {
"msg": {
"changed": false,
"skip_reason": "Conditional result was False",
"skipped": true
}
}
Error Output :
The error was: error while evaluating conditional (item.name | regex_search('VLAN') and not item.name | regex_search('PVLAN')): 'item' is undefined
Ansible Version : 2.10.7
Python Version : 3.7.3
Any help would be appreciated.
Thank you
Not sure if it's the right thing to do, but finally get ride of this issue using :
when: item is defined and item.name | regex_search('VLAN') and not item.name | regex_search('PVLAN')
note the item is defined before the regex search
I do have a simple json file, where i need to pull a set of value from EACH array item, but during iteration it fails.
My playbook looks like:
code:
---
- name: direct - this works like charm
set_fact:
bb: "{{ pr_json.json.issues[0].fields.customfield_11756.value }}"
- debug:
var: bb
- name: via array - this is not working since iteration is not happening
set_fact:
dd_branch: "{{ pr_json.json.issues[{{ item }}].fields.customfield_11756.value }}"
register: mass
- debug:
var: mass
Getting output as:
TASK [jira_update : direct - this works like charm] ********************************************************************************************************************
task path: /home/test/ansible_jira/roles/jira_update/tasks/call.yml:3
ok: [localhost] => {
"ansible_facts": {
"bb": "R4.19"
},
"changed": false
}
TASK [jira_update : debug] *********************************************************************************************************************************************
task path: /home/test/ansible_jira/roles/jira_update/tasks/call.yml:7
ok: [localhost] => {
"bb": "R4.19"
}
TASK [jira_update : via array - this is not working since iteratoin is not happening] **********************************************************************************
task path: /home/test/ansible_jira/roles/jira_update/tasks/call.yml:10
fatal: [localhost]: FAILED! => {
"msg": "template error while templating string: expected token ':', got '}'. String: {{ pr_json.json.issues[{{ item }}].fields.customfield_11756.value }}"
}
Please do let us know how can I iterate through an array variable value on every sequence.
tried this too, but can somebody help to iterate the array values, please.
- name: Create PR request in TEMS JIRA
jira:
uri: "{{ tems_jira }}"
username: "{{ user }}"
password: "{{ pass }}"
operation: create
project: PR
issuetype: 'PR-Form'
summary: "{{ pr_json.json| json_query('issues[].fields.summary') }}"
description: "{{ pr_json.json | json_query('issues[].fields.description') }}"
args:
fields:
customfield_10303:
value: "{{ pr_json.json | json_query('issues[].fields.customfield_11756.value') }}"
Youy need to feed your list into a with_items iterator. Thats what sets the item variable for looping purposes.
- name: via array - this is not working since iteration is not happening
set_fact:
dd_branch: "{{ pr_json.json.issues[ item ].fields.customfield_11756.value }}"
register: mass
with_items:
- 0
- 1
That will iterate through all of the list items of pr_json.json.issues which will let you dive deeper into the variable structure like you are looking for. There are a lot of other factors that you can feed into the loop that might interest you that you can find detailed here.
https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html