Home > Enterprise >  looping through dictionary-formatted Ansible facts
looping through dictionary-formatted Ansible facts

Time:12-07

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?

CodePudding user response:

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"

CodePudding user response:

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
  • Related