netv
netv

Reputation: 185

Ansible parse (debug) results while using loop

This is my ansible script:

tasks:
 - name: parse
   ansible.netcommon.cli_parse:
    command: show interface {{item.interface}}
    parser:
     name: ansible.netcommon.ntc_templates
   with_items: "{{ interfaces }}"
   when: inventory_hostname ==  'WAN-01A'
   register: int

 - debug:
     msg: "{{int.results|map(attribute='parsed')|list}}"
   when: inventory_hostname ==  'WAN-01A'

vars:

interfaces:
    - interface: Bundle-Ether1
    - interface: Bundle-Ether1.100

output of debug:

[
  {
    "interface": "Bundle-Ether1",
    "link_status": "up",
    "protocol_status": "up",
    "hardware_type": "Aggregated Ethernet interface",
    "address": "",
    "bia": "",
    "description": "SCLAB-WAN-01B",
    "ip_address": "10.210.255.4/31",
    "mtu": "",
    "duplex": "",
    "speed": "",
    "media_type": "",
    "bandwidth": "",
    "delay": "",
    "encapsulation": "",
    "last_input": "",
    "last_output": "",
    "last_output_hang": "",
    "queue_strategy": "",
    "input_rate": "2000",
    "output_rate": "2000",
    "input_packets": "",
    "output_packets": "",
    "input_errors": "0",
    "crc": "0",
    "abort": "0",
    "output_errors": ""
  },
  {
    "interface": "Bundle-Ether1.100",
    "link_status": "up",
    "protocol_status": "up",
    "hardware_type": "VLAN sub",
    "address": "",
    "bia": "",
    "description": "",
    "ip_address": "10.0.0.1/30",
    "mtu": "",
    "duplex": "",
    "speed": "",
    "media_type": "",
    "bandwidth": "",
    "delay": "",
    "encapsulation": "802.1Q Virtual LAN",
    "last_input": "",
    "last_output": "",
    "last_output_hang": "",
    "queue_strategy": "",
    "input_rate": "0",
    "output_rate": "0",
    "input_packets": "",
    "output_packets": "",
    "input_errors": "",
    "crc": "",
    "abort": "",
    "output_errors": ""
  }
]

what i want is , i need to print only specific values (don't want all info) for each interface like:

[
  {
    "interface": "Bundle-Ether1",
    "link_status": "up",
    "protocol_status": "up",
    "description": "WAN-01B",
    "ip_address": "10.210.255.4/31",
    "input_errors": "0",
    "crc": "0",
    "output_errors": ""
  },
  {
    "interface": "Bundle-Ether1.100",
    "link_status": "up",
    "protocol_status": "up",
    "address": "",
    "description": "",
    "ip_address": "10.0.0.1/30",
    "input_errors": "",
    "crc": "",
    "output_errors": ""
  }
]

how can I modify debug int.results|map(attribute='parsed')|list to get the above result?

Upvotes: 1

Views: 2466

Answers (3)

netv
netv

Reputation: 185

Thank you, Vladimir, I made a little modification, I have added item[0] rest everything is the same then it worked

{{ dict(wanted_fields|zip(wanted_fields|map('extract', item[0]))) }}

Upvotes: 1

Vladimir Botka
Vladimir Botka

Reputation: 68044

Q: "Print only specific values ... for each interface"

Given the list of wanted fields

    wanted_fields:
      - interface
      - link_status
      - protocol_status
      - address
      - description
      - ip_address
      - input_errors
      - crc
      - output_errors

A: Let Jinja create the list in the loop. For example

    - debug:
        msg: "{{ mylist|from_yaml }}"
      vars:
        parsed: "{{ int.results|map(attribute='parsed')|list }}"
        mylist: |-
          {% for item in parsed %}
          - {{ dict(wanted_fields|zip(wanted_fields|map('extract', item))) }}
          {% endfor %}

gives

  msg:
  - address: ''
    crc: '0'
    description: SCLAB-WAN-01B
    input_errors: '0'
    interface: Bundle-Ether1
    ip_address: 10.210.255.4/31
    link_status: up
    output_errors: ''
    protocol_status: up
  - address: ''
    crc: ''
    description: ''
    input_errors: ''
    interface: Bundle-Ether1.100
    ip_address: 10.0.0.1/30
    link_status: up
    output_errors: ''
    protocol_status: up

If you want to iterate the list

    - debug:
        msg: "{{ dict(wanted_fields|zip(wanted_fields|map('extract', item))) }}"
      loop: "{{ int.results|map(attribute='parsed')|list }}"
      loop_control:
        label: "{{ item.ip_address }}"

gives

ok: [localhost] => (item=10.210.255.4/31) => 
  msg:
    address: ''
    crc: '0'
    description: SCLAB-WAN-01B
    input_errors: '0'
    interface: Bundle-Ether1
    ip_address: 10.210.255.4/31
    link_status: up
    output_errors: ''
    protocol_status: up
ok: [localhost] => (item=10.0.0.1/30) => 
  msg:
    address: ''
    crc: ''
    description: ''
    input_errors: ''
    interface: Bundle-Ether1.100
    ip_address: 10.0.0.1/30
    link_status: up
    output_errors: ''
    protocol_status: up

Credit @lxop (formatted to simplify comparison). The "filters-only" option gives the same result

    - debug:
        msg: "{{ parsed|
                 map('dict2items')|
                 map('selectattr', 'key', 'in', wanted_fields)|
                 map('list')|
                 map('items2dict')|
                 list }}"
      vars:
        parsed: "{{ int.results|map(attribute='parsed')|list }}"

Upvotes: 0

lxop
lxop

Reputation: 8595

It can get a bit convoluted, but you can do this filtering with the following chain of filters:

vars:
  wanted_fields:
    - interface
    - link_status
    - protocol_status
    # etc
tasks:
  - debug:
      msg: '{{ int.results | map(attribute='parsed') | list | map("dict2items") | map("selectattr", "key", "in", wanted_fields) | map("list") | map("items2dict") | list }}'

This chain converts each dictionary in your output list into a list of little dicts that look like

{
  "key": "interface",
  "value": "Bundle-Ether1"
}

then filters those based on the value of the "key" field (does the name appear in your "wanted_fields" list), then reassembles the filtered little dicts into a single regular dict again (for each interface). Each of the filters are inside a map() filter because you need to apply the operations to each of the items in your output list, rather than just the list on its own.

Upvotes: 1

Related Questions