O.K.
O.K.

Reputation: 95

loop with set_fact in ansible 2.13.2

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

Answers (1)

Zeitounator
Zeitounator

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

Related Questions