Ansible: fortigate list to popolate a dictionary - loops

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"

Related

looping through dictionary-formatted Ansible facts

Considering the output of ios_facts module (or any similar gathering fact module), I wrote the following Ansible playbook:
name: checking interface status
gather_facts: no
hosts: iosxe
tasks:
name: get cisco config
cisco.ios.ios_facts:
gather_subset: all
register: cisco_output
name: task001
debug:
var: cisco_output['ansible_facts']['ansible_net_interfaces']
loop: "{{ ansible_facts['ansible_net_interfaces'] | dict2items }}"
when: item.lineprotocol == "up"
For the sake of practicing Ansible, I wanted the playbook to show list of interfaces in "up" state. The relative part in the output of the "ios_fact" shows that it is a "dictionary" not "list".
"ansible_net_interfaces": {
"GigabitEthernet1": {
"bandwidth": 1000000,
"description": null,
"duplex": "Full",
"ipv4": [
{
"address": "10.106.31.229",
"subnet": "24"
}
],
"lineprotocol": "up",
"macaddress": "000c.29c3.a8f3",
"mediatype": "Virtual",
"mtu": 1500,
"operstatus": "up",
"type": "CSR vNIC"
},
"GigabitEthernet2": {
"bandwidth": 1000000,
"description": "CSR2",
"duplex": "Full",
"ipv4": [
{
"address": "10.171.73.33",
"subnet": "27"
}
],
"lineprotocol": "up",
"macaddress": "000c.29c3.a8fd",
"mediatype": "Virtual",
"mtu": 1500,
"operstatus": "up",
"type": "CSR vNIC"
}, ...
I got several different errors and tried to workaround by changing the playbook each time as these:
loop: "{{ ansible_facts['ansible_net_interfaces'] | dict2items }}"
loop: "{{ cisco_output['ansible_facts']['ansible_net_interfaces'] }}"
loop: "{{ cisco_output['ansible_facts']['ansible_net_interfaces'] | dict2items }}"
But was unsuccessful as I got different errors again. What would be the right way of this?
The dict2items filter will convert the dict to an array of items, where the keys will be GigabitEthernet1, GigabitEthernet2, and the values of these keys will sub-dicts.
"item.key": "GigabitEthernet1"
"item.key": "GigabitEthernet2"
So, the lineprotocol key will be in the item.value, i.e. item.value.lineprotocol. A simple task such as below can demonstrate the same:
- debug:
msg: "{{ item.key }} is up"
loop: "{{ cisco_output['ansible_facts']['ansible_net_interfaces | dict2items }}"
when: item.value.lineprotocol == "up"
The attribute ipv4 is a list. Use with_subelements if you want to take into account the fact that there might be more IP addresses configured, e.g.
- debug:
msg: "{{ item.0.key }} {{ item.1.address }}"
with_subelements:
- "{{ ansible_net_interfaces|dict2items|
selectattr('value.lineprotocol', 'eq', 'up') }}"
- value.ipv4
gives
msg: GigabitEthernet1 10.106.31.229
msg: GigabitEthernet2 10.171.73.33

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

How to iterate through nested items in Ansible

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

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