I have a custom fact that is a list of dictionaries. I need to look at the value of each dictionary item and potentially change some of the values. below is an example of the fact, my loop looks at each item and queries an api for information related to bt_device and potentially change the value
[
{
"at_device": "sw",
"at_name": "GigabitEthernet0/5",
"at_type": "dcim.interface",
"bt_device": "sw2",
"bt_name": "GigabitEthernet1/0/2",
"bt_type": "dcim.interface"
},
{
"at_device": "sw",
"at_name": "GigabitEthernet0/8",
"at_type": "dcim.interface",
"bt_device": "sw3",
"bt_name": "GigabitEthernet1/0/5",
"bt_type": "dcim.interface"
}
]
so based on the query I need to change "sw3" to "fp3"
the below tasks work to show the data I want to change to on the screen, but I cannot make the leap to modifying the value in the fact as needed.
- name: load custom fact
ansible.builtin.set_fact:
custom_fact: "{{ custom_fact | default([]) + [{ 'at_device' : ansible_net_hostname, 'at_name' : item.key, 'at_type' : 'dcim.interface', 'bt_device' : item.value[0].host, 'bt_name' : item.value[0].port, 'bt_type' : 'dcim.interface'}] }}"
loop: "{{ ansible_facts | dict2items }}"
- name: modify custom fact via query
debug:
msg: "{{ query(NetBoxy stuff).device.name }}"
when: "query(NetBoxy stuff) | length > 0"
loop: "{{ custom_fact }}"
Thanks
I have attempted many things however I am new enough to have no idea how to get there.
Q: Change "sw3" to "fp3".
A: The solution depends on the structure of the data. For example, given the dictionary
update:
key: bt_device
regex: sw3
replace: fp3
the declaration below
result: "{{ devices | rejectattr(update.key, 'regex', update.regex) +
devices | selectattr(update.key, 'regex', update.regex) |
zip([{update.key: update.replace}]) |
map('combine') }}"
gives what you want
result:
- at_device: sw
at_name: GigabitEthernet0/5
at_type: dcim.interface
bt_device: sw2
bt_name: GigabitEthernet1/0/2
bt_type: dcim.interface
- at_device: sw
at_name: GigabitEthernet0/8
at_type: dcim.interface
bt_device: fp3
bt_name: GigabitEthernet1/0/5
bt_type: dcim.interface
Example of a complete playbook for testing
- hosts: localhost
vars:
devices:
- at_device: sw
at_name: GigabitEthernet0/5
at_type: dcim.interface
bt_device: sw2
bt_name: GigabitEthernet1/0/2
bt_type: dcim.interface
- at_device: sw
at_name: GigabitEthernet0/8
at_type: dcim.interface
bt_device: sw3
bt_name: GigabitEthernet1/0/5
bt_type: dcim.interface
update:
key: bt_device
regex: sw3
replace: fp3
result: "{{ devices | rejectattr(update.key, 'regex', update.regex) +
devices | selectattr(update.key, 'regex', update.regex) |
zip([{update.key: update.replace}]) |
map('combine') }}"
tasks:
- debug:
var: result
The next option is a simpler dictionary that allows updating of more keys. For example,
update:
bt_device: {regex: sw3, replace: fp3}
at_device: {regex: sw, replace: swX}
the declarations below
devices_updated: |
{% for device in devices %}
{ {% for k in device.keys()|intersect(update) %}
{% if device[k] == update[k]['regex'] %}
{{ k }}: {{ update[k]['replace'] }}, {% endif %}{% endfor %} }
{% endfor %}
result: "{{ devices |
zip(devices_updated.splitlines()|map('from_yaml')) |
map('combine') }}"
gives
result:
- at_device: swX
at_name: GigabitEthernet0/5
at_type: dcim.interface
bt_device: sw2
bt_name: GigabitEthernet1/0/2
bt_type: dcim.interface
- at_device: swX
at_name: GigabitEthernet0/8
at_type: dcim.interface
bt_device: fp3
bt_name: GigabitEthernet1/0/5
bt_type: dcim.interface
Example of a complete playbook for testing
- hosts: localhost
vars:
devices:
- at_device: sw
at_name: GigabitEthernet0/5
at_type: dcim.interface
bt_device: sw2
bt_name: GigabitEthernet1/0/2
bt_type: dcim.interface
- at_device: sw
at_name: GigabitEthernet0/8
at_type: dcim.interface
bt_device: sw3
bt_name: GigabitEthernet1/0/5
bt_type: dcim.interface
update:
bt_device: {regex: sw3, replace: fp3}
at_device: {regex: sw, replace: swX}
devices_updated: |
{% for device in devices %}
{ {% for k in device.keys()|intersect(update) %}
{% if device[k] == update[k]['regex'] %}
{{ k }}: {{ update[k]['replace'] }}, {% endif %}{% endfor %} }
{% endfor %}
result: "{{ devices |
zip(devices_updated.splitlines()|map('from_yaml')) |
map('combine') }}"
tasks:
- debug:
var: devices_updated
- debug:
var: result