How to iterate through nested items in Ansible - arrays

I'm not sure if i'm taking the correct way but i have the next problem.
I need a simple task like:
- name: Copying files
template:
src: "{{ item[1] }}.j2"
dest: "{{ path }}/{{ item[0] }}/{{ item[1] }}"
with_nested:
- [ 'env1' , 'env2' ]
- [ 'file1' , 'file2']
Actual results:
/path/env1/file1
/path/env1/file2
/path/env2/file1
/path/env2/file2
Expected results:
/path/env1/file1
/path/env2/file2
I just need that file1 generate template in directory env1 and the file2 generate template in env2.
I can't do it with a simple 'with_items' because i hace 2 items to iterate, the name of the directory and the name of the file.
I'm sure that there is a way to do that correctly..
Thanks in advance

Use zip filter. The play below
- hosts: localhost
vars:
list1: [ 'env1' , 'env2' ]
list2: [ 'file1' , 'file2']
tasks:
- debug:
msg: "/path/{{ item.0 }}/{{ item.1 }}"
loop: "{{ list1|zip(list2)|list }}"
gives (grep msg):
"msg": "/path/env1/file1"
"msg": "/path/env2/file2"

you can try following to get expected results :
- name: Copying files
template:
src: "{{ item[1] }}.j2"
dest: "{{ path }}/{{ item[0] }}/{{ item[1] }}"
with_together:
- [ 'env1' , 'env2' ]
- [ 'file1' , 'file2']
with_together explanation

Related

Ansible: fortigate list to popolate a dictionary

remote_address_phase2:
- 192.168.88.0/24
- 192.168.1.0/24
task:
i have to create a firewall group
- name: "addrgrp"
fortios_firewall_addrgrp:
vdom: "{{ vdom }}"
state: "present"
firewall_addrgrp:
allow_routing: "disable"
#category: "default"
color: "21"
comment: "try"
exclude: "disable"
fabric_object: "disable"
member:
- name: "NET-{{ item}}"
name: "try"
type: "default"
with_items: "{{ remote_address_phase2 }}"
if i made this activity i have 2 different task but the last operation overwrite the first
any idea?
Going by the example in the documentation for the module, it seems that the member: parameter takes a list of dicts.
Example from module documentation:
member:
-
name: "default_name_7 (source firewall.address.name firewall.addrgrp.name)"
Haven't tested it, but we can create a similar structure before "addrgrp" task with set_fact and use the newly created variable.
- set_fact:
fw_members: "{{ fw_members | default([]) + [{'name': 'NET-' ~ item}] }}"
loop: "{{ remote_address_phase2 }}"
This gives:
"fw_members": [
{
"name": "NET-192.168.88.0/24"
},
{
"name": "NET-192.168.1.0/24"
}
]
It should then be possible to pass this variable as a value to the member: parameter. Example:
- set_fact:
fw_members: "{{ fw_members | default([]) + [{'name': 'NET-' ~ item}] }}"
loop: "{{ remote_address_phase2 }}"
- name: "addrgrp"
fortios_firewall_addrgrp:
vdom: "{{ vdom }}"
state: "present"
firewall_addrgrp:
allow_routing: "disable"
#category: "default"
color: "21"
comment: "try"
exclude: "disable"
fabric_object: "disable"
member: "{{ fw_members }}"
name: "try"
type: "default"

How can I build list from the values of a dictionary?

I have a list of AD users and trying to create a distinguishedName-list
vars:
admin_users: "user1;user2"
tasks:
- set_fact:
admin: "{{ admin_users.split(';') }}"
- name: Search account
community.general.ldap_search:
<...>
loop: "{{ admin }}"
register: ldap_result
- name: Build DN-array
set_fact:
group: "{{ group | default([]) }} + {{ item.value | json_query(query) }}"
with_dict: "{{ ldap_result.results }}"
when: item.key == 'results'
vars:
query: "[*].distinguishedName"
- debug:
var: "{{ group }}"
And get
"<class 'list'>": "VARIABLE IS NOT DEFINED!"
Also tried
group: "{{ group | default([]) }} + [ {{ item.value | json_query(query) }} ]"
group: "{{ group | default([]) }} + {{ [ item.value | json_query(query) ] }}"
get same message
"<class 'list'>": "VARIABLE IS NOT DEFINED!"
and
group: "{{ group | default([]) }} + [ '{{ item.value | json_query(query) }}' ]"
Then I get the error
FAILED! => {"msg": "template error while templating string: expected
token ',', got 'CN'. String: {{[] + [ '['CN=***']' ] + [ '['CN=***']' ]}}"}
Any tips?
Ok, that's right, I just needed to use a construction like this
<...>
group: "{{ group | default([]) }} + [ {{ item.value | json_query(query) }} ]"
<...>
- debug: msg="{{ group }}"
not this
- debug:
var: "{{ group_list_two }}"
correct output
ok: [localhost] => {
"msg": [
[
"CN=***"
],
[
"CN=***"
]
]
}

how can I update a dictionary in Ansible

I am creating a simple dictionary in ansible which is this one:
"types_dict": {
"name1": "Ethernet",
"name2": "Ethernet",
"name3": "Software-Pseudo",
"name4": "Ethernet",
"name5": "Software-Pseudo",
"name6": "Ethernet" }
My goal is to loop the dictionary and replace some specific values, the ones "Software-Pseudo" with "Virtual". I have tried the following:
- set_fact:
types_dict: "{{ types_dict | combine(new_item, recursive=true) }}"
vars:
new_item: "{ '{{ item.key }}': { 'type': 'Virtual' } }"
with_dict: "{{ types_dict }}"
but the problem here is that this one updates all the values in my dictionary, which is something I do not want at all. I tried also the following by adding the "when" statement, but also it is not working:
- set_fact:
types_dict: "{{ types_dict | combine(new_item, recursive=true) }}"
vars:
new_item: "{ '{{ item.key }}': { 'type': 'Virtual' } }"
when: "{{ item.value }} == Software-Pseudo"
with_dict: "{{ types_dict }}"
I also tried when: "{{ item.value }} == 'Software-Pseudo'" and many other things like this.
Any ideas on how to fix this ?
The task does the job. Items can be added to the list types_new if needed
- set_fact:
types_dict: "{{ types_dict|combine({item.0.key: item.1.replace}) }}"
with_nested:
- "{{ types_dict|dict2items }}"
- "{{ types_new }}"
when: item.0.value is search(item.1.regex)
vars:
types_new:
- {regex: 'Software-Pseudo', replace: 'Virtual'}
- debug:
var: types_dict
gives
types_dict:
name1: Ethernet
name2: Ethernet
name3: Virtual
name4: Ethernet
name5: Virtual
name6: Ethernet
Q: "I have null values like "name2": null in my dictionary, could I handle this in any way so as to replace it with sth else (another value)."
A: Add a line to the types_new. For example
vars:
types_new:
- {regex: 'Software-Pseudo', replace: 'Virtual'}
- {regex: 'None', replace: 'another_value'}
See the task below how null, None, and 'None' are treated by the search test
- debug:
msg: "{{ item.key }} {{ item.value is search('None') }}"
loop: "{{ my_vars|dict2items }}"
vars:
my_vars:
var1: abc
var2:
var3: None
var4: 'None'
gives
msg: var1 False
msg: var2 True
msg: var3 True
msg: var4 True

Back-references in Ansible loops

Is it possible to reference the "previous" value of a loop variable in an Ansible playbook?
What I would like to do is find some form of loop that effectively makes the following functional:
---
vars:
nums:
- 1
- 2
- 3
- 4
tasks:
- name: show fibonacci
command: echo {{ item }} * {{ item.prev }}
loop: nums
Use include_tasks. The play below
tasks:
- name: show fibonacci
include_tasks: fibonacci.yml
with_sequence: start=1 end=4
with include file fibonacci.yml
- debug:
msg: "{{ item|int * item_prev|default('1')|int }}"
- set_fact:
item_prev: "{{ item }}"
gives:
"msg": "1"
"msg": "2"
"msg": "6"
"msg": "12"

Ansible Parse JSON Array from Register

Related Post: ansible parse json array reply from api
I have an Ansible playlist which registers a return variable:
- name: Create Instance
ec2_instance:
aws_access_key: "{{access_key}}"
aws_secret_key: "{{secret_key}}"
key_name: ***
instance_type: t2.micro
security_group: ***
image_id: ami-39f8215b
region: ***
register: details
So the details is a JSON object like this:
{
"details": {
"changed": false,
"changes": [],
"failed": false,
"instance_ids": [
"i-1111abcde"
],
...
}
All I want to do is write a text file with each instance_id in there:
i-1111abcde
I've tried all of the following, none working:
debug:
var: item
with_items: details['instance_ids']
debug:
var: item.item
with_items: details['instance_ids']
debug:
var: details.instance_ids
with_items: details
# This works, but prints the entire JSON array...
Solution
- name: Debug Info
debug:
var: item
loop: "{{details.instance_ids}}"
- name: Write Temp File
lineinfile:
path: /tmp/temp.txt
line: "{{ item }}"
loop: "{{ details.instance_ids }}"
Note: loop is a more modern Ansible concept that with_items or with_*
Solution
- name: Debug Info
debug:
var: item
loop: "{{details.instance_ids}}"
- name: Write Temp File
lineinfile:
path: /tmp/temp.txt
line: "{{ item }}"
loop: "{{ details.instance_ids }}"
Note: loop is a more modern Ansible concept that with_items or with_*

Resources