I am newbie to ansible and trying to write my first playbook.
- name: create volume
volume:
state: present
username: "{{ username }}"
password: "{{ password }}"
hostname: "{{ inventory_hostname }}"
vserver: "{{item[0]}}"
name: "{{item[1]}}"
aggregate_name: "{{output}}"
with_nested:
- [ 'vs10' , 'vs11' ]
- [ 'vol1' , 'vol2', 'vol3' , 'vol4' ,'vol5', ''vol6']
connection: local
Actual output:
vs10-vol1 vol2 vol3 vol4
vs11- vol1 vol2 vol3 vol4
Expected output:
vs10-vol1, vol3 vol5
vs11-vol2, vol4 vol6
This would probably work. I'm basically looping the task against volumes and calculating the vserver in the task.
- name: create volume
volume:
state: present
username: "{{ username }}"
password: "{{ password }}"
hostname: "{{ inventory_hostname }}"
# Calculate which vserver to use based on 'current volume index in the volumes list' and 'length of vservers list'.
# The logic uses modulus to try and distribute volumes across given vcenters
vserver: "{{vservers[(current_index % (vservers|length))]}}"
# Name is item itself because you are looping volumes
name: "{{item}}"
aggregate_name: "{{output}}"
# Loop the volumes
loop: [ 'vol1' , 'vol2', 'vol3' , 'vol4' ,'vol5', 'vol6']
# This is make a loop_control variable available. This will give us 'current_index'
loop_control:
index_var: current_index
# Vservers are defined here
vars:
vservers: [ 'vs10' , 'vs11' ]
Related
I am facing issue while writing nested loops in ansible, for below iteration I am getting error
ansible role I am using looks like below
The conditional check 'item[0]['value']['from'] == COMPONENT_NAME' failed. The error was: error while evaluating conditional (item[0]['value']['from'] == COMPONENT_NAME): 'item' is undefined
Role
- name: create config file
template:
src: "{{template_source}}/{{COMPONENT_NAME}}/sessions/{{ item[0]['value']['protocol']}}/{{item[0]['value']['from_template']}}"
dest: "{{dest_folder}}/{{app}}/{{instance_name}}/{{COMPONENT_NAME}}/{{VENUE}}/Config/Repo/session/{{item[0]['value']['protocol']}}/{{item[1]}}.json"
mode: 0755
vars:
dest_file_name: "{{instance_name}}_{{COMPONENT_NAME}}_{{VENUE}}_{{item[0]['key']}}"
mbFlag: "{{item[0]['value']['broker'] | default('False')}}"
when: item[0]['value']['from'] == COMPONENT_NAME
with_nested:
- "{{ connections | dict2items }}"
- "{{myFileList['from_' + COMPONENT_NAME +'_'+ VENUE +'_'+ item[0]['value']['to']].split(',') }}"
yml file having below variable and I am iterating over it.
myFileList:
{
from_et_AG_zp: DevOpsTest_et_zp_AG_zp,
from_et_AG_sSP: 'DevOpsTest_et_sSP_AG_US,DevOpsTest_et_sSP_AG_BA,DevOpsTest_et_sSP_AG_chex',
from_et_AG_esb: DevOpsTest_et_esb_AG_ABC,
from_et_BA_Y_zp: DevOpsTest_et_zp_BA_Y_zp,
from_et_BA_Y_sSP: 'DevOpsTest_et_sSP_BA_Y_US,DevOpsTest_et_sSP_BA_Y_BA,DevOpsTest_et_sSP_BA_Y_chex',
from_et_BA_Y_esb: DevOpsTest_et_esb_BA_Y_ABC,
from_et_BA_zp: DevOpsTest_et_zp_BA_zp,
from_et_BA_sSP: 'DevOpsTest_et_sSP_BA_US,DevOpsTest_et_sSP_BA_BA,DevOpsTest_et_sSP_BA_chex',
from_et_BA_esb: DevOpsTest_et_esb_BA_ABC,
from_zp_zp_esb: DevOpsTest_zp_esb_zp_ABC,
from_SP_SP_esb: DevOpsTest_SP_esb_SP_ABC,
from_SSS_SSS_esb: DevOpsTest_SSS_esb_SSS_ABC,
to_zp_zp_es: DevOpsTest_et_zp_zp_es,
to_sSP_BA_es: DevOpsTest_et_sSP_BA_es,
to_sSP_chex_es: DevOpsTest_et_sSP_chex_es,
to_sSP_US_es: DevOpsTest_et_sSP_US_es,
to_esb_ABC_es: DevOpsTest_et_esb_ABC_es,
to_esb_ABC_zp: DevOpsTest_zp_esb_ABC_zp,
to_esb_ABC_SP: DevOpsTest_SP_esb_ABC_SP,
to_esb_ABC_SSS: DevOpsTest_SSS_esb_ABC_SSS
}
connections:
et_etb:
from: et
to: etb
from_template: et_etb.json
to_template: etb_et.json
protocol: ZERO
After too many permutation and combination, I realize that we can not pass outer loop variable value from outer loop to inner loop, So as work around I write first loop in first role and second loop in another role and call second role from first by iterating over first loop that full fill my ends
---
- name: create config file
include_role:
name: patch_template
vars:
file_key: "{{ 'from_' + COMPONENT_NAME +'_'+ VENUE +'_'+ role_item.value.to }}"
myprotocol: "{{role_item.value.protocol}}"
myTemplate: "{{role_item.value.from_template}}"
subComponent: "{{VENUE}}"
when: role_item.value.from == COMPONENT_NAME
with_items: "{{ connections | dict2items }}"
loop_control:
loop_var: role_item
patch_template role file
- name: patch template
template:
src: "{{template_source}}/{{COMPONENT_NAME}}/sessions/{{myprotocol}}/{{myTemplate}}"
dest: "{{dest_folder}}/{{app}}/{{instance_name}}/{{COMPONENT_NAME}}/{{subComponent}}/Config/Repo/session/{{myprotocol}}/{{item}}.json"
mode: 0755
vars:
dest_file_name: "{{item}}"
with_items:
- "{{ myFileList[file_key].split(',') }}"
Trying to extract a key pair value from a .yaml file and populate it into a variable:
/etc/puppetlabs/puppet/csr_attributes.yaml
File Example:
extension_requests:
pp_service: 'private'
pp_instance_id: 'blah'
pp_image_name: 'RedHat 7.7 Base'
pp_project: 'TBT'
pp_application: 'xxxxx'
pp_environment: 'dev'
pp_role: 'base_stuff'
pp_software_version: '2020-04-30'
pp_provisioner: 'Ansible Tower'
pp_datacenter: 'DC2'
pp_zone: 'C6600_NPE_RS'
pp_cloudplatform: 'esx'
pp_apptier: 'dev'
pp_securitypolicy: 'Stuff'
1.3.6.1.4.1.34380.1.2.1: ''
1.3.6.1.4.1.34380.1.2.2: '8'
1.3.6.1.4.1.34380.1.2.3: '77504'
I can do it via the line number, but I need it to be more dynamic as the lines are different from server to server:
Current individual line code:
- name: cat file
shell: cat /etc/puppetlabs/puppet/csr_attributes.yaml
register: cat_content_file
- set_fact:
pp_service: "pp_service: {{ cat_content_file.stdout_lines[2].split()[1] }}"
pp_application: "pp_application: {{ cat_content_file.stdout_lines[6].split()[1] }}"
- debug:
msg:
- "{{ pp_service }}"
- "{{ pp_application }}"
I think I need to convert the output into a dict, but I'm completely stuck on how to do it.
Any advice would be appreciated.
You could use a combination of file and from_yaml:
- set_fact:
your_variable: "{{ lookup('file','/etc/puppetlabs/puppet/csr_attributes.yaml') | from_yaml }}"
- debug: var=your_variable.extension_requests.pp_service
I have the following array of record with the value:
myRecord.record.0.number = "Number 0"
myRecord.record.1.number = "Number 1"
myRecord.record.2.number = "Number 2"
myRecord.record.3.number = "Number 3"
How to create a playbook to debug the above value using loop dynamically/for every array?
for other common languange it can be done as follows:
for(int i = 0; i < myRecord.length(); i++)
{
echo myRecord.record.[i].number
}
for the repeating task of the playbook, it will looks like this:
---
- hosts: localhost
name: Array of Object
gather_facts: false
tasks:
- name: using debugMsg
debug:
msg:
- "{{ myRecord.record.0.number }}"
- "{{ myRecord.record.1.number }}"
- "{{ myRecord.record.2.number }}"
- "{{ myRecord.record.3.number }}"
I have figured out how to do this. Basically I just need to use loop_control to filter which specific value I need. Here is the playbook:
---
- hosts: localhost
name: Array of Object
gather_facts: false
tasks:
- name: using loop_control
debug:
msg: "{{ item.number }}"
with_items:
- "{{ myRecord.record }}" #this will become 'item'
loop_control:
label: "{{ item.number }}" #filter to display the value of number only
There are two methods. The first method uses the with_* keyword, and depends on the Lookup plugin. The second method uses loop keyword, which is equivalent to 'with_' + 'list lookup plugin' (so you get 'with_list').
Now, assuming your data structure looks like this:
---
# vars file for print_variable_from_list
myRecord:
record:
- number: "Number 0"
- number: "Number 1"
- number: "Number 2"
- number: "Number 3"
Every number is indexable with the "number" key.
- name: loop through myRecord
debug:
msg: "{{ item.number }}"
loop: "{{ myRecord.record }}"
Kindly refer to other posts for more complex queries.
I have the following ansible playbook. fX is for framework version 1,2 or 3. When a file has a version >= fX it should select that framework version using a last found type method, so we don't get multiple results.
file_version >= 1.2.0 should give f2 for example, and file_version >= 2.2.0 should result in f3.
- name: select version
hosts: all
connection: local
become: false
vars:
version:
f3: '2.2.0'
f2: '1.2.0'
f1: '1.0.0'
tasks:
- name: debug loop
debug:
msg: "{% for F in version %}{% if file_version | version_compare(version[F],'>=') %}{{ F }} {% endif %}{% endfor %}"
ansible-playbook case.yml -i 127.0.0.1, -vv -e file_version='1.5.0'
Ansible should decide for me, that I should be using framework version 1.2.0 or {{ f2 }}. But of course this yields two matches
f1 f2
How can I pull out the last found version? Is there a more elegant way to do this?
Try below
- name: select version
hosts: localhost
connection: local
become: false
vars:
version:
f3: '1.2.0'
f2: '2.2.0'
f1: '1.0.0'
tasks:
- name: Set found to 0
set_fact:
found: '0'
- name: Set the last value returned from the sorted dict
set_fact:
found: "{{ item.1 }}"
loop: "{{ version | dictsort(False,'value') }}"
when: "{{ file_version | version_compare(item.1,'>=') }}"
- name: debug
debug:
msg: "{{ found }}"
IMHO there is no function which returns the position of an element in a list. The play below does the job in 3 steps
- hosts: localhost
vars:
file_version: '1.5.0'
version:
f3: '2.2.0'
f2: '1.2.0'
f1: '1.0.0'
tasks:
- set_fact:
versions: "{{ version.values() + [ file_version ] }}"
- set_fact:
frameworks: "{{ frameworks|default({})|combine({item: index}) }}"
loop: "{{ versions|sort }}"
loop_control:
index_var: index
- set_fact:
framework: "f{{ frameworks[file_version] }}"
- debug:
var: framework
- debug:
msg: "{{ version[framework] }}"
gives
"framework": "f2"
"msg": "1.2.0"
With the filter_plugins/list_methods.py the simplified play
- hosts: localhost
vars:
file_version: '1.5.0'
version:
f3: '2.2.0'
f2: '1.2.0'
f1: '1.0.0'
tasks:
- set_fact:
versions: "{{ version.values() + [ file_version ] }}"
- set_fact:
index: "{{ versions|sort|list_index(file_version) }}"
- set_fact:
framework: "f{{ index }}"
- debug:
var: framework
- debug:
msg: "{{ version[framework] }}"
gives the same results.
I want to loop over the first task output in second task. In the first task getting hostname and IP in the array. In the second task loop over the array print the each item in the array in separate line.
here the code I have so for.
- name: Store known hosts of 'all' the hosts in the inventory file
hosts: localhost
connection: local
vars:
ssh_known_hosts_command: "ssh-keyscan -T 10"
ssh_known_hosts_file: "{{ lookup('env','HOME') + '/.ssh/known_hosts' }}"
ssh_known_hosts: "{{ groups['all'] }}"
tasks:
- name: For each host, find the ip
shell: 'echo -e "{{ item }}\n`dig +short {{ item }}`"'
with_items: "{{ ssh_known_hosts }}"
register: ssh_known_host_results
ignore_errors: yes
- name: print message
debug:
msg: "{{ item.stdout_lines[0] + ' test' }}"
with_items: "{{ ssh_known_host_results.results }}"
in the second task how can I loop over ssh_known_host_results.results array?
thanks
SR
I am looking for something like this:
- name: print message
debug:
msg: "{{ item+ ' test' }}"
with_items: "{{outer_item.stdout_lines "
with_items: "{{ ssh_known_host_results.results }}"
loop_control:
loop_var: outer_item
when I add to ignore localhost its not giving array item. how can it make return hostname and ip as two array elements?
- name: For each host, find the ip
shell: 'echo -e "{{ item }}\n`dig +short {{ item }}`"'
with_items: "{{ ssh_known_hosts }}"
when: not item == 'localhost'
register: ssh_known_host_results
ignore_errors: yes
- name: print message
debug:
msg: "{{ item + ' test' }}"
with_items: "{{ ssh_known_host_results.results | map(attribute='stdout_lines') | list }}"
Support for dynamic nested loops is not implemented in Ansible.
To iterate over each line, you can flatten the result:
- name: print message
debug:
msg: "{{ item + ' test' }}"
with_items: "{{ ssh_known_host_results.results | map(attribute='stdout_lines') | list }}"