ansible.utils.update_fact module – Update currently set facts

Note

This module is part of the ansible.utils collection (version 4.1.0).

You might already have this collection installed if you are using the ansible package. It is not included in ansible-core. To check whether it is installed, run ansible-galaxy collection list.

To install it, use: ansible-galaxy collection install ansible.utils.

To use it in a playbook, specify: ansible.utils.update_fact.

New in ansible.utils 1.0.0

Synopsis

  • This module allows updating existing variables.

  • Variables are updated on a host-by-host basis.

  • Variables are not modified in place, instead they are returned by the module.

Note

This module has a corresponding action plugin.

Parameters

Parameter

Comments

updates

list / elements=dictionary / required

A list of dictionaries, each a desired update to make.

path

string / required

The path in a currently set variable to update.

The path can be in dot or bracket notation.

It should be a valid jinja reference.

value

any / required

The value to be set at the path.

Can be a simple or complex data structure.

Examples

# Update an existing fact, dot or bracket notation
- name: Set a fact
  ansible.builtin.set_fact:
    a:
      b:
        c:
          - 1
          - 2

- name: Update the fact
  ansible.utils.update_fact:
    updates:
      - path: a.b.c.0
        value: 10
      - path: "a['b']['c'][1]"
        value: 20
  register: updated

- debug:
    var: updated.a

# updated:
#   a:
#     b:
#       c:
#       - 10
#       - 20
#   changed: true


# Lists can be appended, new keys added to dictionaries

- name: Set a fact
  ansible.builtin.set_fact:
    a:
      b:
        b1:
          - 1
          - 2

- name: Update, add to list, add new key
  ansible.utils.update_fact:
    updates:
      - path: a.b.b1.2
        value: 3
      - path: a.b.b2
        value:
          - 10
          - 20
          - 30
  register: updated

- debug:
    var: updated.a

# updated:
#   a:
#     b:
#       b1:
#       - 1
#       - 2
#       - 3
#       b2:
#       - 10
#       - 20
#       - 30
#   changed: true

#####################################################################
# Update every item in a list of dictionaries
# build the update list ahead of time using a loop
# and then apply the changes to the fact
#####################################################################

- name: Set fact
  ansible.builtin.set_fact:
    addresses:
      - raw: 10.1.1.0/255.255.255.0
        name: servers
      - raw: 192.168.1.0/255.255.255.0
        name: printers
      - raw: 8.8.8.8
        name: dns

- name: Build a list of updates
  ansible.builtin.set_fact:
    update_list: "{{ update_list + update }}"
  loop: "{{ addresses }}"
  loop_control:
    index_var: idx
  vars:
    update_list: []
    update:
      - path: addresses[{{ idx }}].network
        value: "{{ item['raw'] | ansible.netcommon.ipaddr('network') }}"
      - path: addresses[{{ idx }}].prefix
        value: "{{ item['raw'] | ansible.netcommon.ipaddr('prefix') }}"

- debug:
    var: update_list

# TASK [debug] *******************
# ok: [localhost] =>
#   update_list:
#   - path: addresses[0].network
#     value: 10.1.1.0
#   - path: addresses[0].prefix
#     value: '24'
#   - path: addresses[1].network
#     value: 192.168.1.0
#   - path: addresses[1].prefix
#     value: '24'
#   - path: addresses[2].network
#     value: 8.8.8.8
#   - path: addresses[2].prefix
#     value: '32'

- name: Make the updates
  ansible.utils.update_fact:
    updates: "{{ update_list }}"
  register: updated

- debug:
    var: updated

# TASK [debug] ***********************
# ok: [localhost] =>
#   updated:
#     addresses:
#     - name: servers
#       network: 10.1.1.0
#       prefix: '24'
#       raw: 10.1.1.0/255.255.255.0
#     - name: printers
#       network: 192.168.1.0
#       prefix: '24'
#       raw: 192.168.1.0/255.255.255.0
#     - name: dns
#       network: 8.8.8.8
#       prefix: '32'
#       raw: 8.8.8.8
#     changed: true
#     failed: false


#####################################################################
# Retrieve, update, and apply interface description change
# use index_of to locate Etherent1/1
#####################################################################

- name: Get the current interface config
  cisco.nxos.nxos_interfaces:
    state: gathered
  register: interfaces

- name: Update the description of Ethernet1/1
  ansible.utils.update_fact:
    updates:
      - path: "interfaces.gathered[{{ index }}].description"
        value: "Configured by ansible"
  vars:
    index: "{{ interfaces.gathered|ansible.utils.index_of('eq', 'Ethernet1/1', 'name') }}"
  register: updated

- name: Update the configuration
  cisco.nxos.nxos_interfaces:
    config: "{{ updated.interfaces.gathered }}"
    state: overridden
  register: result

- name: Show the commands issued
  debug:
    msg: "{{ result['commands'] }}"

# TASK [Show the commands issued] *************************************
# ok: [nxos101] => {
#     "msg": [
#         "interface Ethernet1/1",
#         "description Configured by ansible"
#     ]
# }


#####################################################################
# Retrieve, update, and apply an ipv4 ACL change
# finding the index of AFI ipv4 acls
# finding the index of the ACL named 'test1'
# finding the index of sequence 10
#####################################################################

- name: Retrieve the current acls
  arista.eos.eos_acls:
    state: gathered
  register: current

- name: Update the source of sequence 10 in the IPv4 ACL named test1
  ansible.utils.update_fact:
    updates:
      - path: current.gathered[{{ afi }}].acls[{{ acl }}].aces[{{ ace }}].source
        value:
          subnet_address: "192.168.2.0/24"
  vars:
    afi: "{{ current.gathered|ansible.utils.index_of('eq', 'ipv4', 'afi') }}"
    acl: "{{ current.gathered[afi|int].acls|ansible.utils.index_of('eq', 'test1', 'name') }}"
    ace: "{{ current.gathered[afi|int].acls[acl|int].aces|ansible.utils.index_of('eq', 10, 'sequence') }}"
  register: updated

- name: Apply the changes
  arista.eos.eos_acls:
    config: "{{ updated.current.gathered }}"
    state: overridden
  register: changes

- name: Show the commands issued
  debug:
    msg: "{{ changes['commands'] }}"

# TASK [Show the commands issued] *************************************
# ok: [eos101] => {
#     "msg": [
#         "ip access-list test1",
#         "no 10",
#         "10 permit ip 192.168.2.0/24 host 10.1.1.2"
#     ]
# }


#####################################################################
# Disable ip redirects on any layer3 interface
# find the layer 3 interfaces
# use each name to find their index in l3 interface
# build an 'update' list and apply the updates
#####################################################################

- name: Get the current interface and L3 interface configuration
  cisco.nxos.nxos_facts:
    gather_subset: min
    gather_network_resources:
      - interfaces
      - l3_interfaces

- name: Build the list of updates to make
  ansible.builtin.set_fact:
    updates: "{{ updates + [entry] }}"
  vars:
    updates: []
    entry:
      path: "ansible_network_resources.l3_interfaces[{{ item }}].redirects"
      value: false
    w_mode: "{{ ansible_network_resources.interfaces|selectattr('mode', 'defined') }}"
    m_l3: "{{ w_mode|selectattr('mode', 'eq', 'layer3') }}"
    names: "{{ m_l3|map(attribute='name')|list }}"
    l3_indicies: "{{ ansible_network_resources.l3_interfaces|ansible.utils.index_of('in', names, 'name', wantlist=True) }}"
  loop: "{{ l3_indicies }}"

# TASK [Build the list of updates to make] ****************************
# ok: [nxos101] => (item=99) => changed=false
#   ansible_facts:
#     updates:
#     - path: ansible_network_resources.l3_interfaces[99].redirects
#       value: false
#   ansible_loop_var: item
#   item: 99

- name: Update the l3 interfaces
  ansible.utils.update_fact:
    updates: "{{ updates }}"
  register: updated

# TASK [Update the l3 interfaces] *************************************
# changed: [nxos101] => changed=true
#   ansible_network_resources:
#     l3_interfaces:
#     <...>
#     - ipv4:
#       - address: 10.1.1.1/24
#       name: Ethernet1/100
#       redirects: false

- name: Apply the configuration changes
  cisco.nxos.l3_interfaces:
    config: "{{ updated.ansible_network_resources.l3_interfaces }}"
    state: overridden
  register: changes

# TASK [Apply the configuration changes] ******************************
# changed: [nxos101] => changed=true
#   commands:
#   - interface Ethernet1/100
#   - no ip redirects

Authors

  • Bradley Thornton (@cidrblock)