Search code examples
ansible

how to loop through dictionary and store certain values for later use


I have this dictionary created by output from a test device:

    "device_IPs": [
        {
            "INTERFACE": "Vlan300",
            "IP_ADDRESS": "3.3.3.1",
            "PROTO": "down",
            "STATUS": "up"
        },
        {
            "INTERFACE": "Vlan400",
            "IP_ADDRESS": "4.4.4.1",
            "PROTO": "down",
            "STATUS": "up"
        }
    ]
}

Basically i want to write a playbook that uses all of the INTERFACE values for another task - the task applies config to those vlan interfaces (derived from the INTERFACE value in the dict)

This is my playbook:


---
- name: run command and parse with textFSM
  hosts: switches
  gather_facts: no

  tasks:
  - name: show command and store in var
    cisco.ios.ios_command:
      commands: show ip interface brief | e una|Eth
    register: sh_ip_int_br_output

  - name: parse output data
    ansible.builtin.set_fact:
      device_IPs: "{{ sh_ip_int_br_output.stdout[0] | parse_cli_textfsm('testFSM_templates/ios_show_ip_int_br.textfsm') }}"


  
  - name: add ip helper to vlan 
    cisco.ios.ios_config:
      lines:
        - ip helper-address 1.1.1.1
      parents: "interface {{ each one of the INTERFACE values from dict }}"

How do I loop through each 'INTERFACE' key in the dictionary above, store the 'INTERFACE' value in a variable and loop through that later on in the last task ?

Hope that makes sense, Thanks

EDIT - this has been solved thanks to larsks & Vladimir's help

I added the following to my playbook

  - name: extract data from dictionary list
    set_fact:
      dict_interface_info: "{{ device_IPs | map (attribute='INTERFACE') }}"


  - name: add ip helper
    cisco.ios.ios_config:
      lines:
        - ip helper-address 1.1.1.1
      parents: "interface {{ item }}"
    loop: "{{ dict_interface_info }}"


Solution

  • Don't think about loops; think about filters. The map filter can be used to extract a particular attribute from a list of dictionaries, and we can use set_fact to dynamically define new variables in a playbook:

    - hosts: localhost
      gather_facts: false
      vars:
        device_IPs: [
            {
                "INTERFACE": "Vlan300",
                "IP_ADDRESS": "3.3.3.1",
                "PROTO": "down",
                "STATUS": "up"
            },
            {
                "INTERFACE": "Vlan400",
                "IP_ADDRESS": "4.4.4.1",
                "PROTO": "down",
                "STATUS": "up"
            }
          ]
      tasks:
        - set_fact:
            interfaces: "{{ device_IPs | map(attribute='INTERFACE') }}"
    
        - debug:
            var: interfaces
    

    Running this produces as output:

    TASK [debug] *********************************************************************************************************************************
    ok: [localhost] => {
        "interfaces": [
            "Vlan300",
            "Vlan400"
        ]
    }