Reputation: 95
I have a task that I use already and works as expected in Ansible ver. 2.9.17. The same task however behaves differently in version 2.13.
I have the following list element that I loop:
vlan_list: [
"uni/tn-TST-CUSTOMER2/ap-TST-CUSTOMER2/epg-VLAN20"
"uni/tn-TST-CUSTOMER1/ap-TST-CUSTOMER1/epg-VLAN10"
"uni/tn-TST-CUSTOMER3/ap-TST-CUSTOMER3/epg-VLAN30"
]
and the task itself is as follows:
- name: gather only IDs
set_fact:
epg_list: "{{ epg_list }} + [ '{{ item.split('/')[-1] | regex_replace('epg-VLAN') }}' ]"
loop: "{{ vlan_list | flatten(levels=1) }}"
when: vlan_list|length > 0
the output of the above task in ansible v2.9 is:
ok: [my_host.com] => (item=uni/tn-TST-CUSTOMER2/ap-TST-CUSTOMER2/epg-VLAN20) => {
"ansible_facts": {
"epg_list": [
"20"
]
},
"ansible_loop_var": "item",
"changed": false,
"item": "uni/tn-TST-CUSTOMER2/ap-TST-CUSTOMER2/epg-VLAN20"
}
ok: [my_host.com] => (item=uni/tn-TST-CUSTOMER1/ap-TST-CUSTOMER1/epg-VLAN10) => {
"ansible_facts": {
"epg_list": [
"20",
"10"
]
},
"ansible_loop_var": "item",
"changed": false,
"item": "uni/tn-TST-CUSTOMER1/ap-TST-CUSTOMER1/epg-VLAN10"
}
ok: [my_host.com] => (item=uni/tn-TST-CUSTOMER3/ap-TST-CUSTOMER3/epg-VLAN30) => {
"ansible_facts": {
"epg_list": [
"20",
"10",
"30"
]
},
"ansible_loop_var": "item",
"changed": false,
"item": "uni/tn-TST-CUSTOMER3/ap-TST-CUSTOMER3/epg-VLAN30"
}
the same task gives the following in v2.13: (deducted)
.
.
.
ok: [my_host.com] => (item=uni/tn-TST-CUSTOMER3/ap-TST-CUSTOMER3/epg-VLAN30) => {
"ansible_facts": {
"epg_list": "[] + [ '20' ] + [ '10' ] + [ '30' ]"
},
"ansible_loop_var": "item",
"changed": false,
"item": "uni/tn-TST-CUSTOMER3/ap-TST-CUSTOMER3/epg-VLAN30"
.
.
.
In the second output, there is an empty list and every list is concanted with a +
So my question is, what I'm doing is the normal way, or is there a best practice way to loop over a list and extract some values from it?
Upvotes: 0
Views: 341
Reputation: 44818
The fact it was "working" in ansible 2.9 is pure coincidence. Your set_fact
task has the wrong syntax which should be (adding a bit of security when the variable is not first defined):
- name: gather only IDs
set_fact:
epg_list: "{{ epg_list | d([]) + [item.split('/')[-1] | regex_replace('epg-VLAN')] }}"
loop: "{{ vlan_list | flatten(levels=1) }}"
when: vlan_list | length > 0
Note that the flatten
filter is purely optionnal if your data always looks like the one you pasted in your question
Moreover, using a loop
(and most probably using set_fact
too) is an over-kill in this situation as you can get your result with a single jinja2 expression as demonstrated in the following playbook:
---
- hosts: localhost
gather_facts: false
vars:
# Pushing a static list for this example to work
vlan_list:
- uni/tn-TST-CUSTOMER2/ap-TST-CUSTOMER2/epg-VLAN20
- uni/tn-TST-CUSTOMER1/ap-TST-CUSTOMER1/epg-VLAN10
- uni/tn-TST-CUSTOMER3/ap-TST-CUSTOMER3/epg-VLAN30
# This will return an empty list if the above var is undefined
# This will return whatever list as long as `vlan_list`
# is defined by the time you call the var in your playbook.
# This will work with a registered var as well.
epg_list: '{{ vlan_list | d([])
| map("regex_replace", "^.*/epg-VLAN([0-9]+)$", "\g<1>")
| map("int") | sort }}'
tasks:
- debug:
var: epg_list
which gives:
TASK [debug] *********************************************************
ok: [localhost] => {
"epg_list": [
10,
20,
30
]
}
Upvotes: 1