I've been struggling with this for a while. I have a list of dict like this which is created by parsing the Cisco CLI output with neighbors_raw.stdout[0] | ansible.netcommon.parse_cli_textfsm('templates/cisco_ios_show_cdp_neighbors.textfsm')
:
[
{
"CAPABILITY": "R S I",
"LOCAL_INTERFACE": "Ten 1/1/1",
"NEIGHBOR": "switch1.mydomain.com",
"NEIGHBOR_INTERFACE": "Ten 1/0/4",
"PLATFORM": "C9500-16X"
},
{
"CAPABILITY": "S I",
"LOCAL_INTERFACE": "Gig 1/1/2",
"NEIGHBOR": "switch2.mydomain.com",
"NEIGHBOR_INTERFACE": "Ten 1/1/1",
"PLATFORM": "C9200L-48"
}
]
I want to convert the interface names from Ten 1/1/1
to Te1/1/1
or Gig 1/1/2
to Gi1/1/2
.
I have tried the following:
- name: PARSE NEIGHBORS
debug:
msg: "{{ neighbors_raw.stdout[0] | ansible.netcommon.parse_cli_textfsm('templates/cisco_ios_show_cdp_neighbors.textfsm') |
regex_replace('Ten ', 'Te') |
regex_replace('Gig ', 'Gi') }}"
The output looks correct:
[
{
"CAPABILITY": "R S I",
"LOCAL_INTERFACE": "Te1/1/1",
"NEIGHBOR": "switch1.mydomain.com",
"NEIGHBOR_INTERFACE": "Te1/0/4",
"PLATFORM": "C9500-16X"
},
{
"CAPABILITY": "S I",
"LOCAL_INTERFACE": "Gi1/1/2",
"NEIGHBOR": "switch2.mydomain.com",
"NEIGHBOR_INTERFACE": "Te1/1/1",
"PLATFORM": "C9200L-48"
}
]
However, if I pipe this output into any other command it treats it like it is a character array:
- name: PARSE NEIGHBORS
debug:
msg: "{{ neighbors_raw.stdout[0] | ansible.netcommon.parse_cli_textfsm('templates/cisco_ios_show_cdp_neighbors.textfsm') |
regex_replace('Ten ', 'Te') |
regex_replace('Gig ', 'Gi') | list }}"
Output:
[
"[",
"{",
"'",
"N",
"E",
"I",
"G",
"H",
"B",
"O",
"R",
"'",
":",
" ",
"'",
The same weird output happens if I use zip
instead of list
.
I have also tried map('regex_replace', 'Ten (.*)', 'Te\\1')
but it only replaces one occurrence and turns each dict in to a string:
- name: PARSE NEIGHBORS
debug:
msg: "{{ neighbors_raw.stdout[0] | ansible.netcommon.parse_cli_textfsm('templates/cisco_ios_show_cdp_neighbors.textfsm') |
map('regex_replace', 'Ten (.*)', 'Te\\1') }}"
Output:
[
"{'NEIGHBOR': 'switch1.mydomain.com', 'LOCAL_INTERFACE': 'Te1/1/1', 'CAPABILITY': 'R S I', 'PLATFORM': 'C9500-16X', 'NEIGHBOR_INTERFACE': 'Ten 1/0/4'}",
"{'NEIGHBOR': 'switch2.mydomain.com', 'LOCAL_INTERFACE': 'Gig 1/1/2', 'CAPABILITY': 'S I', 'PLATFORM': 'C9200L-48', 'NEIGHBOR_INTERFACE': 'Te1/1/1'}"
]
I am also concerned about regex_replace on the entire dict treating it like a string. I really only want to apply the conversion to the specific value for LOCAL_INTERFACE
and NEIGHBOR_INTERFACE
.
How can I go about achieving this?
Given the data
neighbors:
- CAPABILITY: R S I
LOCAL_INTERFACE: Ten 1/1/1
NEIGHBOR: switch1.mydomain.com
NEIGHBOR_INTERFACE: Ten 1/0/4
PLATFORM: C9500-16X
- CAPABILITY: S I
LOCAL_INTERFACE: Gig 1/1/2
NEIGHBOR: switch2.mydomain.com
NEIGHBOR_INTERFACE: Ten 1/1/1
PLATFORM: C9200L-48
Create the lists of the updated attributes
lifc: "{{ neighbors |
map(attribute='LOCAL_INTERFACE') |
map('regex_replace', 'Ten ', 'Te') |
map('regex_replace', 'Gig ', 'Gi') |
map('community.general.dict_kv', 'LOCAL_INTERFACE') }}"
nifc: "{{ neighbors |
map(attribute='NEIGHBOR_INTERFACE') |
map('regex_replace', 'Ten ', 'Te') |
map('regex_replace', 'Gig ', 'Gi') |
map('community.general.dict_kv', 'NEIGHBOR_INTERFACE') }}"
gives
lifc:
- LOCAL_INTERFACE: Te1/1/1
- LOCAL_INTERFACE: Gi1/1/2
nifc:
- NEIGHBOR_INTERFACE: Te1/0/4
- NEIGHBOR_INTERFACE: Te1/1/1
zip the lists and combine items
update: "{{ lifc | zip(nifc) | map('combine') }}"
gives
update:
- LOCAL_INTERFACE: Te1/1/1
NEIGHBOR_INTERFACE: Te1/0/4
- LOCAL_INTERFACE: Gi1/1/2
NEIGHBOR_INTERFACE: Te1/1/1
zip the update and combine items
result: "{{ neighbors | zip(update) | map('combine') }}"
gives what you want
result:
- CAPABILITY: R S I
LOCAL_INTERFACE: Te1/1/1
NEIGHBOR: switch1.mydomain.com
NEIGHBOR_INTERFACE: Te1/0/4
PLATFORM: C9500-16X
- CAPABILITY: S I
LOCAL_INTERFACE: Gi1/1/2
NEIGHBOR: switch2.mydomain.com
NEIGHBOR_INTERFACE: Te1/1/1
PLATFORM: C9200L-48
Example of a complete playbook for testing
- hosts: localhost
vars:
neighbors:
- CAPABILITY: R S I
LOCAL_INTERFACE: Ten 1/1/1
NEIGHBOR: switch1.mydomain.com
NEIGHBOR_INTERFACE: Ten 1/0/4
PLATFORM: C9500-16X
- CAPABILITY: S I
LOCAL_INTERFACE: Gig 1/1/2
NEIGHBOR: switch2.mydomain.com
NEIGHBOR_INTERFACE: Ten 1/1/1
PLATFORM: C9200L-48
lifc: "{{ neighbors |
map(attribute='LOCAL_INTERFACE') |
map('regex_replace', 'Ten ', 'Te') |
map('regex_replace', 'Gig ', 'Gi') |
map('community.general.dict_kv', 'LOCAL_INTERFACE') }}"
nifc: "{{ neighbors |
map(attribute='NEIGHBOR_INTERFACE') |
map('regex_replace', 'Ten ', 'Te') |
map('regex_replace', 'Gig ', 'Gi') |
map('community.general.dict_kv', 'NEIGHBOR_INTERFACE') }}"
update: "{{ lifc | zip(nifc) | map('combine') }}"
result: "{{ neighbors | zip(update) | map('combine') }}"
tasks:
- debug:
var: lifc
- debug:
var: nifc
- debug:
var: update
- debug:
var: result