ansible.utils.consolidate filter – Consolidate facts together on common attributes.

Note

This filter plugin is part of the ansible.utils collection (version 2.10.3).

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.consolidate.

New in ansible.utils 2.6.0

Synopsis

  • This plugin presents collective structured data including all supplied facts grouping on common attributes mentioned.

  • All other boolean parameter defaults to False unless parameters is explicitly mentioned.

  • Using the parameters below- data_sources|ansible.utils.consolidate(fail_missing_match_key=False))

Keyword parameters

This describes keyword parameters of the filter. These are the values key1=value1, key2=value2 and so on in the following example: input | ansible.utils.consolidate(key1=value1, key2=value2, ...).

Parameter

Comments

data_sources

list / elements=dictionary / required

This option represents a list of dictionaries to perform the operation on.

For example facts_source|ansible.utils.consolidate(fail_missing_match_key=False)), in this case facts_source represents this option.

data

any / required

Specify facts data that gets consolidated.

match_key

string / required

Specify key to match on.

name

string / required

Specify the name with which the result set be created.

fail_duplicate

boolean

Fail if the match key’s value exists more than once in a given data set.

Choices:

  • false

  • true ← (default)

fail_missing_match_key

boolean

Fail if match_key is not found in a specific data set.

Choices:

  • false

  • true ← (default)

fail_missing_match_value

boolean

Fail if the match key’s value is not found in every data source.

Choices:

  • false

  • true ← (default)

Examples

# Consolidated filter plugin example
# ----------------------------------

##play.yml
tasks:
  - name: Define some test data
    ansible.builtin.set_fact:
      values:
        - name: a
          value: 1
        - name: b
          value: 2
        - name: c
          value: 3
      colors:
        - name: a
          color: red
        - name: b
          color: green
        - name: c
          color: blue

  - name: Define some test data
    ansible.builtin.set_fact:
      base_data:
        - data: "{{ values }}"
          match_key: name
          name: values
        - data: "{{ colors }}"
          match_key: name
          name: colors

  - name: Consolidate the data source using the name key
    ansible.builtin.set_fact:
      consolidated: "{{ data_sources|ansible.utils.consolidate }}"
    vars:
      sizes:
        - name: a
          size: small
        - name: b
          size: medium
        - name: c
          size: large
      additional_data_source:
        - data: "{{ sizes }}"
          match_key: name
          name: sizes
      data_sources: "{{ base_data + additional_data_source }}"

##Output

# ok: [localhost] => {
#     "ansible_facts": {
#         "consolidated": {
#             "a": {
#                 "colors": {
#                     "color": "red",
#                     "name": "a"
#                 },
#                 "sizes": {
#                     "name": "a",
#                     "size": "small"
#                 },
#                 "values": {
#                     "name": "a",
#                     "value": 1
#                 }
#             },
#             "b": {
#                 "colors": {
#                     "color": "green",
#                     "name": "b"
#                 },
#                 "sizes": {
#                     "name": "b",
#                     "size": "medium"
#                 },
#                 "values": {
#                     "name": "b",
#                     "value": 2
#                 }
#             },
#             "c": {
#                 "colors": {
#                     "color": "blue",
#                     "name": "c"
#                 },
#                 "sizes": {
#                     "name": "c",
#                     "size": "large"
#                 },
#                 "values": {
#                     "name": "c",
#                     "value": 3
#                 }
#             }
#         }
#     },
#     "changed": false
# }

name: Consolidate the data source using different keys
ansible.builtin.set_fact:
  consolidated: "{{ data_sources|ansible.utils.consolidate }}"
vars:
  sizes:
    - title: a
      size: small
    - title: b
      size: medium
    - title: c
      size: large
  additional_data_source:
    - data: "{{ sizes }}"
      match_key: title
      name: sizes
  data_sources: "{{ base_data + additional_data_source }}"

##Output

# ok: [localhost] => {
#     "ansible_facts": {
#         "consolidated": {
#             "a": {
#                 "colors": {
#                     "color": "red",
#                     "name": "a"
#                 },
#                 "sizes": {
#                     "size": "small",
#                     "title": "a"
#                 },
#                 "values": {
#                     "name": "a",
#                     "value": 1
#                 }
#             },
#             "b": {
#                 "colors": {
#                     "color": "green",
#                     "name": "b"
#                 },
#                 "sizes": {
#                     "size": "medium",
#                     "title": "b"
#                 },
#                 "values": {
#                     "name": "b",
#                     "value": 2
#                 }
#             },
#             "c": {
#                 "colors": {
#                     "color": "blue",
#                     "name": "c"
#                 },
#                 "sizes": {
#                     "size": "large",
#                     "title": "c"
#                 },
#                 "values": {
#                     "name": "c",
#                     "value": 3
#                 }
#             }
#         }
#     },
#     "changed": false
# }

name: Consolidate the data source using the name key (fail_missing_match_key)
ansible.builtin.set_fact:
  consolidated: "{{ data_sources|ansible.utils.consolidate(fail_missing_match_key=True) }}"
ignore_errors: true
vars:
  vars:
  sizes:
    - size: small
    - size: medium
    - size: large
  additional_data_source:
    - data: "{{ sizes }}"
      match_key: name
      name: sizes
  data_sources: "{{ base_data + additional_data_source }}"

##Output

# fatal: [localhost]: FAILED! => {
#     "msg": "Error when using plugin 'consolidate': 'fail_missing_match_key'
#                   reported missing match key 'name' in data source 3 in list entry 1,
#                            missing match key 'name' in data source 3 in list entry 2,
#                            missing match key 'name' in data source 3 in list entry 3"
# }

name: Consolidate the data source using the name key (fail_missing_match_value)
ansible.builtin.set_fact:
  consolidated: "{{ data_sources|ansible.utils.consolidate(fail_missing_match_value=True) }}"
ignore_errors: true
vars:
  sizes:
    - name: a
      size: small
    - name: b
      size: medium
  additional_data_source:
    - data: "{{ sizes }}"
      match_key: name
      name: sizes
  data_sources: "{{ base_data + additional_data_source }}"

# fatal: [localhost]: FAILED! => {
#     "msg": "Error when using plugin 'consolidate': 'fail_missing_match_value'
#                   reported missing match value c in data source 3"
# }

name: Consolidate the data source using the name key (fail_duplicate)
ansible.builtin.set_fact:
  consolidated: "{{ data_sources|ansible.utils.consolidate(fail_duplicate=True) }}"
ignore_errors: true
vars:
  sizes:
    - name: a
      size: small
    - name: a
      size: small
  additional_data_source:
    - data: "{{ sizes }}"
      match_key: name
      name: sizes
  data_sources: "{{ base_data + additional_data_source }}"

# fatal: [localhost]: FAILED! => {
#     "msg": "Error when using plugin 'consolidate': 'fail_duplicate'
#                   reported duplicate values in data source 3"
# }

##facts.yml

interfaces:
  - name: GigabitEthernet0/0
    enabled: true
    duplex: auto
    speed: auto
    note:
      - Connected green wire
  - name: GigabitEthernet0/1
    description: Configured by Ansible - Interface 1
    mtu: 1500
    speed: auto
    duplex: auto
    enabled: true
    note:
      - Connected blue wire
      - Configured by Paul
    vifs:
      - vlan_id: 100
        description: Eth1 - VIF 100
        mtu: 400
        enabled: true
        comment: Needs reconfiguration
      - vlan_id: 101
        description: Eth1 - VIF 101
        enabled: true
  - name: GigabitEthernet0/2
    description: Configured by Ansible - Interface 2 (ADMIN DOWN)
    mtu: 600
    enabled: false
l2_interfaces:
  - name: GigabitEthernet0/0
  - mode: access
    name: GigabitEthernet0/1
    trunk:
      allowed_vlans:
        - "11"
        - "12"
        - "59"
        - "67"
        - "75"
        - "77"
        - "81"
        - "100"
        - 400-408
        - 411-413
        - "415"
        - "418"
        - "982"
        - "986"
        - "988"
        - "993"
  - mode: trunk
    name: GigabitEthernet0/2
    trunk:
      allowed_vlans:
        - "11"
        - "12"
        - "59"
        - "67"
        - "75"
        - "77"
        - "81"
        - "100"
        - 400-408
        - 411-413
        - "415"
        - "418"
        - "982"
        - "986"
        - "988"
        - "993"
      encapsulation: dot1q
l3_interfaces:
  - ipv4:
      - address: 192.168.0.2/24
    name: GigabitEthernet0/0
  - name: GigabitEthernet0/1
  - name: GigabitEthernet0/2
  - name: Loopback888
  - name: Loopback999

##Playbook
vars_files:
  - "facts.yml"
tasks:
  - name: Build the facts collection
    set_fact:
      data_sources:
        - data: "{{ interfaces }}"
          match_key: name
          name: interfaces
        - data: "{{ l2_interfaces }}"
          match_key: name
          name: l2_interfaces
        - data: "{{ l3_interfaces }}"
          match_key: name
          name: l3_interfaces

  - name: Combine all the facts based on match_keys
    set_fact:
      combined: "{{ data_sources|ansible.utils.consolidate(fail_missing_match_value=False) }}"

##Output
# ok: [localhost] => {
#     "ansible_facts": {
#         "data_sources": [
#             {
#                 "data": [
#                     {
#                         "duplex": "auto",
#                         "enabled": true,
#                         "name": "GigabitEthernet0/0",
#                         "note": [
#                             "Connected green wire"
#                         ],
#                         "speed": "auto"
#                     },
#                     {
#                         "description": "Configured by Ansible - Interface 1",
#                         "duplex": "auto",
#                         "enabled": true,
#                         "mtu": 1500,
#                         "name": "GigabitEthernet0/1",
#                         "note": [
#                             "Connected blue wire",
#                             "Configured by Paul"
#                         ],
#                         "speed": "auto",
#                         "vifs": [
#                             {
#                                 "comment": "Needs reconfiguration",
#                                 "description": "Eth1 - VIF 100",
#                                 "enabled": true,
#                                 "mtu": 400,
#                                 "vlan_id": 100
#                             },
#                             {
#                                 "description": "Eth1 - VIF 101",
#                                 "enabled": true,
#                                 "vlan_id": 101
#                             }
#                         ]
#                     },
#                     {
#                         "description": "Configured by Ansible - Interface 2 (ADMIN DOWN)",
#                         "enabled": false,
#                         "mtu": 600,
#                         "name": "GigabitEthernet0/2"
#                     }
#                 ],
#                 "match_key": "name",
#                 "name": "interfaces"
#             },
#             {
#                 "data": [
#                     {
#                         "name": "GigabitEthernet0/0"
#                     },
#                     {
#                         "mode": "access",
#                         "name": "GigabitEthernet0/1",
#                         "trunk": {
#                             "allowed_vlans": [
#                                 "11",
#                                 "12",
#                                 "59",
#                                 "67",
#                                 "75",
#                                 "77",
#                                 "81",
#                                 "100",
#                                 "400-408",
#                                 "411-413",
#                                 "415",
#                                 "418",
#                                 "982",
#                                 "986",
#                                 "988",
#                                 "993"
#                             ]
#                         }
#                     },
#                     {
#                         "mode": "trunk",
#                         "name": "GigabitEthernet0/2",
#                         "trunk": {
#                             "allowed_vlans": [
#                                 "11",
#                                 "12",
#                                 "59",
#                                 "67",
#                                 "75",
#                                 "77",
#                                 "81",
#                                 "100",
#                                 "400-408",
#                                 "411-413",
#                                 "415",
#                                 "418",
#                                 "982",
#                                 "986",
#                                 "988",
#                                 "993"
#                             ],
#                             "encapsulation": "dot1q"
#                         }
#                     }
#                 ],
#                 "match_key": "name",
#                 "name": "l2_interfaces"
#             },
#             {
#                 "data": [
#                     {
#                         "ipv4": [
#                             {
#                                 "address": "192.168.0.2/24"
#                             }
#                         ],
#                         "name": "GigabitEthernet0/0"
#                     },
#                     {
#                         "name": "GigabitEthernet0/1"
#                     },
#                     {
#                         "name": "GigabitEthernet0/2"
#                     },
#                     {
#                         "name": "Loopback888"
#                     },
#                     {
#                         "name": "Loopback999"
#                     }
#                 ],
#                 "match_key": "name",
#                 "name": "l3_interfaces"
#             }
#         ]
#     },
#     "changed": false
# }
# Read vars_file 'facts.yml'

# TASK [Combine all the facts based on match_keys]
# ok: [localhost] => {
#     "ansible_facts": {
#         "combined": {
#             "GigabitEthernet0/0": {
#                 "interfaces": {
#                     "duplex": "auto",
#                     "enabled": true,
#                     "name": "GigabitEthernet0/0",
#                     "note": [
#                         "Connected green wire"
#                     ],
#                     "speed": "auto"
#                 },
#                 "l2_interfaces": {
#                     "name": "GigabitEthernet0/0"
#                 },
#                 "l3_interfaces": {
#                     "ipv4": [
#                         {
#                             "address": "192.168.0.2/24"
#                         }
#                     ],
#                     "name": "GigabitEthernet0/0"
#                 }
#             },
#             "GigabitEthernet0/1": {
#                 "interfaces": {
#                     "description": "Configured by Ansible - Interface 1",
#                     "duplex": "auto",
#                     "enabled": true,
#                     "mtu": 1500,
#                     "name": "GigabitEthernet0/1",
#                     "note": [
#                         "Connected blue wire",
#                         "Configured by Paul"
#                     ],
#                     "speed": "auto",
#                     "vifs": [
#                         {
#                             "comment": "Needs reconfiguration",
#                             "description": "Eth1 - VIF 100",
#                             "enabled": true,
#                             "mtu": 400,
#                             "vlan_id": 100
#                         },
#                         {
#                             "description": "Eth1 - VIF 101",
#                             "enabled": true,
#                             "vlan_id": 101
#                         }
#                     ]
#                 },
#                 "l2_interfaces": {
#                     "mode": "access",
#                     "name": "GigabitEthernet0/1",
#                     "trunk": {
#                         "allowed_vlans": [
#                             "11",
#                             "12",
#                             "59",
#                             "67",
#                             "75",
#                             "77",
#                             "81",
#                             "100",
#                             "400-408",
#                             "411-413",
#                             "415",
#                             "418",
#                             "982",
#                             "986",
#                             "988",
#                             "993"
#                         ]
#                     }
#                 },
#                 "l3_interfaces": {
#                     "name": "GigabitEthernet0/1"
#                 }
#             },
#             "GigabitEthernet0/2": {
#                 "interfaces": {
#                     "description": "Configured by Ansible - Interface 2 (ADMIN DOWN)",
#                     "enabled": false,
#                     "mtu": 600,
#                     "name": "GigabitEthernet0/2"
#                 },
#                 "l2_interfaces": {
#                     "mode": "trunk",
#                     "name": "GigabitEthernet0/2",
#                     "trunk": {
#                         "allowed_vlans": [
#                             "11",
#                             "12",
#                             "59",
#                             "67",
#                             "75",
#                             "77",
#                             "81",
#                             "100",
#                             "400-408",
#                             "411-413",
#                             "415",
#                             "418",
#                             "982",
#                             "986",
#                             "988",
#                             "993"
#                         ],
#                         "encapsulation": "dot1q"
#                     }
#                 },
#                 "l3_interfaces": {
#                     "name": "GigabitEthernet0/2"
#                 }
#             },
#             "Loopback888": {
#                 "interfaces": {},
#                 "l2_interfaces": {},
#                 "l3_interfaces": {
#                     "name": "Loopback888"
#                 }
#             },
#             "Loopback999": {
#                 "interfaces": {},
#                 "l2_interfaces": {},
#                 "l3_interfaces": {
#                     "name": "Loopback999"
#                 }
#             }
#         }
#     },
#     "changed": false
# }

# Failing on missing match values
# -------------------------------

##facts.yaml
interfaces:
  - name: GigabitEthernet0/0
    enabled: true
    duplex: auto
    speed: auto
    note:
      - Connected green wire
  - name: GigabitEthernet0/1
    description: Configured by Ansible - Interface 1
    mtu: 1500
    speed: auto
    duplex: auto
    enabled: true
    note:
      - Connected blue wire
      - Configured by Paul
    vifs:
      - vlan_id: 100
        description: Eth1 - VIF 100
        mtu: 400
        enabled: true
        comment: Needs reconfiguration
      - vlan_id: 101
        description: Eth1 - VIF 101
        enabled: true
  - name: GigabitEthernet0/2
    description: Configured by Ansible - Interface 2 (ADMIN DOWN)
    mtu: 600
    enabled: false
l2_interfaces:
  - name: GigabitEthernet0/0
  - mode: access
    name: GigabitEthernet0/1
    trunk:
      allowed_vlans:
        - "11"
        - "12"
        - "59"
        - "67"
        - "75"
        - "77"
        - "81"
        - "100"
        - 400-408
        - 411-413
        - "415"
        - "418"
        - "982"
        - "986"
        - "988"
        - "993"
  - mode: trunk
    name: GigabitEthernet0/2
    trunk:
      allowed_vlans:
        - "11"
        - "12"
        - "59"
        - "67"
        - "75"
        - "77"
        - "81"
        - "100"
        - 400-408
        - 411-413
        - "415"
        - "418"
        - "982"
        - "986"
        - "988"
        - "993"
      encapsulation: dot1q
l3_interfaces:
  - ipv4:
      - address: 192.168.0.2/24
    name: GigabitEthernet0/0
  - name: GigabitEthernet0/1
  - name: GigabitEthernet0/2
  - name: Loopback888
  - name: Loopback999

##Playbook
vars_files:
  - "facts.yml"
tasks:
  - name: Build the facts collection
    set_fact:
      data_sources:
        - data: "{{ interfaces }}"
          match_key: name
          name: interfaces
        - data: "{{ l2_interfaces }}"
          match_key: name
          name: l2_interfaces
        - data: "{{ l3_interfaces }}"
          match_key: name
          name: l3_interfaces

  - name: Combine all the facts based on match_keys
    set_fact:
      combined: "{{ data_sources|ansible.utils.consolidate(fail_missing_match_value=True) }}"

##Output
# ok: [localhost] => {
#     "ansible_facts": {
#         "data_sources": [
#             {
#                 "data": [
#                     {
#                         "duplex": "auto",
#                         "enabled": true,
#                         "name": "GigabitEthernet0/0",
#                         "note": [
#                             "Connected green wire"
#                         ],
#                         "speed": "auto"
#                     },
#                     {
#                         "description": "Configured by Ansible - Interface 1",
#                         "duplex": "auto",
#                         "enabled": true,
#                         "mtu": 1500,
#                         "name": "GigabitEthernet0/1",
#                         "note": [
#                             "Connected blue wire",
#                             "Configured by Paul"
#                         ],
#                         "speed": "auto",
#                         "vifs": [
#                             {
#                                 "comment": "Needs reconfiguration",
#                                 "description": "Eth1 - VIF 100",
#                                 "enabled": true,
#                                 "mtu": 400,
#                                 "vlan_id": 100
#                             },
#                             {
#                                 "description": "Eth1 - VIF 101",
#                                 "enabled": true,
#                                 "vlan_id": 101
#                             }
#                         ]
#                     },
#                     {
#                         "description": "Configured by Ansible - Interface 2 (ADMIN DOWN)",
#                         "enabled": false,
#                         "mtu": 600,
#                         "name": "GigabitEthernet0/2"
#                     }
#                 ],
#                 "match_key": "name",
#                 "name": "interfaces"
#             },
#             {
#                 "data": [
#                     {
#                         "name": "GigabitEthernet0/0"
#                     },
#                     {
#                         "mode": "access",
#                         "name": "GigabitEthernet0/1",
#                         "trunk": {
#                             "allowed_vlans": [
#                                 "11",
#                                 "12",
#                                 "59",
#                                 "67",
#                                 "75",
#                                 "77",
#                                 "81",
#                                 "100",
#                                 "400-408",
#                                 "411-413",
#                                 "415",
#                                 "418",
#                                 "982",
#                                 "986",
#                                 "988",
#                                 "993"
#                             ]
#                         }
#                     },
#                     {
#                         "mode": "trunk",
#                         "name": "GigabitEthernet0/2",
#                         "trunk": {
#                             "allowed_vlans": [
#                                 "11",
#                                 "12",
#                                 "59",
#                                 "67",
#                                 "75",
#                                 "77",
#                                 "81",
#                                 "100",
#                                 "400-408",
#                                 "411-413",
#                                 "415",
#                                 "418",
#                                 "982",
#                                 "986",
#                                 "988",
#                                 "993"
#                             ],
#                             "encapsulation": "dot1q"
#                         }
#                     }
#                 ],
#                 "match_key": "name",
#                 "name": "l2_interfaces"
#             },
#             {
#                 "data": [
#                     {
#                         "ipv4": [
#                             {
#                                 "address": "192.168.0.2/24"
#                             }
#                         ],
#                         "name": "GigabitEthernet0/0"
#                     },
#                     {
#                         "name": "GigabitEthernet0/1"
#                     },
#                     {
#                         "name": "GigabitEthernet0/2"
#                     },
#                     {
#                         "name": "Loopback888"
#                     },
#                     {
#                         "name": "Loopback999"
#                     }
#                 ],
#                 "match_key": "name",
#                 "name": "l3_interfaces"
#             }
#         ]
#     },
#     "changed": false
# }
# Read vars_file 'facts.yml'

# TASK [Combine all the facts based on match_keys]
# fatal: [localhost]: FAILED! => {
#     "msg": "Error when using plugin 'consolidate': 'fail_missing_match_value' reported Missing match value Loopback999,
#     Loopback888 in data source 0, Missing match value Loopback999, Loopback888 in data source 1"
# }

# Failing on missing match keys
# -----------------------------

##facts.yaml
interfaces:
  - name: GigabitEthernet0/0
    enabled: true
    duplex: auto
    speed: auto
    note:
      - Connected green wire
  - name: GigabitEthernet0/1
    description: Configured by Ansible - Interface 1
    mtu: 1500
    speed: auto
    duplex: auto
    enabled: true
    note:
      - Connected blue wire
      - Configured by Paul
    vifs:
      - vlan_id: 100
        description: Eth1 - VIF 100
        mtu: 400
        enabled: true
        comment: Needs reconfiguration
      - vlan_id: 101
        description: Eth1 - VIF 101
        enabled: true
  - name: GigabitEthernet0/2
    description: Configured by Ansible - Interface 2 (ADMIN DOWN)
    mtu: 600
    enabled: false
l2_interfaces:
  - name: GigabitEthernet0/0
  - mode: access
    name: GigabitEthernet0/1
    trunk:
      allowed_vlans:
        - "11"
        - "12"
        - "59"
        - "67"
        - "75"
        - "77"
        - "81"
        - "100"
        - 400-408
        - 411-413
        - "415"
        - "418"
        - "982"
        - "986"
        - "988"
        - "993"
  - mode: trunk
    name: GigabitEthernet0/2
    trunk:
      allowed_vlans:
        - "11"
        - "12"
        - "59"
        - "67"
        - "75"
        - "77"
        - "81"
        - "100"
        - 400-408
        - 411-413
        - "415"
        - "418"
        - "982"
        - "986"
        - "988"
        - "993"
      encapsulation: dot1q
l3_interfaces:
  - ipv4:
      - address: 192.168.0.2/24
    inft_name: GigabitEthernet0/0
  - inft_name: GigabitEthernet0/1
  - inft_name: GigabitEthernet0/2
  - inft_name: Loopback888
  - inft_name: Loopback999

##Playbook
vars_files:
  - "facts.yml"
tasks:
  - name: Build the facts collection
    set_fact:
      data_sources:
        - data: "{{ interfaces }}"
          match_key: name
          name: interfaces
        - data: "{{ l2_interfaces }}"
          match_key: name
          name: l2_interfaces
        - data: "{{ l3_interfaces }}"
          match_key: name
          name: l3_interfaces

  - name: Combine all the facts based on match_keys
    set_fact:
      combined: "{{ data_sources|ansible.utils.consolidate(fail_missing_match_key=True) }}"

##Output
# ok: [localhost] => {
#     "ansible_facts": {
#         "data_sources": [
#             {
#                 "data": [
#                     {
#                         "duplex": "auto",
#                         "enabled": true,
#                         "name": "GigabitEthernet0/0",
#                         "note": [
#                             "Connected green wire"
#                         ],
#                         "speed": "auto"
#                     },
#                     {
#                         "description": "Configured by Ansible - Interface 1",
#                         "duplex": "auto",
#                         "enabled": true,
#                         "mtu": 1500,
#                         "name": "GigabitEthernet0/1",
#                         "note": [
#                             "Connected blue wire",
#                             "Configured by Paul"
#                         ],
#                         "speed": "auto",
#                         "vifs": [
#                             {
#                                 "comment": "Needs reconfiguration",
#                                 "description": "Eth1 - VIF 100",
#                                 "enabled": true,
#                                 "mtu": 400,
#                                 "vlan_id": 100
#                             },
#                             {
#                                 "description": "Eth1 - VIF 101",
#                                 "enabled": true,
#                                 "vlan_id": 101
#                             }
#                         ]
#                     },
#                     {
#                         "description": "Configured by Ansible - Interface 2 (ADMIN DOWN)",
#                         "enabled": false,
#                         "mtu": 600,
#                         "name": "GigabitEthernet0/2"
#                     }
#                 ],
#                 "match_key": "name",
#                 "name": "interfaces"
#             },
#             {
#                 "data": [
#                     {
#                         "name": "GigabitEthernet0/0"
#                     },
#                     {
#                         "mode": "access",
#                         "name": "GigabitEthernet0/1",
#                         "trunk": {
#                             "allowed_vlans": [
#                                 "11",
#                                 "12",
#                                 "59",
#                                 "67",
#                                 "75",
#                                 "77",
#                                 "81",
#                                 "100",
#                                 "400-408",
#                                 "411-413",
#                                 "415",
#                                 "418",
#                                 "982",
#                                 "986",
#                                 "988",
#                                 "993"
#                             ]
#                         }
#                     },
#                     {
#                         "mode": "trunk",
#                         "name": "GigabitEthernet0/2",
#                         "trunk": {
#                             "allowed_vlans": [
#                                 "11",
#                                 "12",
#                                 "59",
#                                 "67",
#                                 "75",
#                                 "77",
#                                 "81",
#                                 "100",
#                                 "400-408",
#                                 "411-413",
#                                 "415",
#                                 "418",
#                                 "982",
#                                 "986",
#                                 "988",
#                                 "993"
#                             ],
#                             "encapsulation": "dot1q"
#                         }
#                     }
#                 ],
#                 "match_key": "name",
#                 "name": "l2_interfaces"
#             },
#             {
#                 "data": [
#                     {
#                         "inft_name": "GigabitEthernet0/0",
#                         "ipv4": [
#                             {
#                                 "address": "192.168.0.2/24"
#                             }
#                         ]
#                     },
#                     {
#                         "inft_name": "GigabitEthernet0/1"
#                     },
#                     {
#                         "inft_name": "GigabitEthernet0/2"
#                     },
#                     {
#                         "inft_name": "Loopback888"
#                     },
#                     {
#                         "inft_name": "Loopback999"
#                     }
#                 ],
#                 "match_key": "name",
#                 "name": "l3_interfaces"
#             }
#         ]
#     },
#     "changed": false
# }
# Read vars_file 'facts.yml'

# TASK [Combine all the facts based on match_keys]
# fatal: [localhost]: FAILED! => {
#     "msg": "Error when using plugin 'consolidate': 'fail_missing_match_key' reported Missing match
#     key 'name' in data source 2 in list entry 0, Missing match key 'name' in data
#     source 2 in list entry 1, Missing match key 'name' in data source 2 in list
#     entry 2, Missing match key 'name' in data source 2 in list entry 3, Missing
#     match key 'name' in data source 2 in list entry 4"
# }

# Failing on duplicate values in facts
# ------------------------------------

##facts.yaml
interfaces:
  - name: GigabitEthernet0/0
    enabled: true
    duplex: auto
    speed: auto
    note:
      - Connected green wire
  - name: GigabitEthernet0/1
    description: Configured by Ansible - Interface 1
    mtu: 1500
    speed: auto
    duplex: auto
    enabled: true
    note:
      - Connected blue wire
      - Configured by Paul
    vifs:
      - vlan_id: 100
        description: Eth1 - VIF 100
        mtu: 400
        enabled: true
        comment: Needs reconfiguration
      - vlan_id: 101
        description: Eth1 - VIF 101
        enabled: true
  - name: GigabitEthernet0/2
    description: Configured by Ansible - Interface 2 (ADMIN DOWN)
    mtu: 600
    enabled: false
l2_interfaces:
  - name: GigabitEthernet0/0
  - name: GigabitEthernet0/0
  - mode: access
    name: GigabitEthernet0/1
    trunk:
      allowed_vlans:
        - "11"
        - "12"
        - "59"
        - "67"
        - "75"
        - "77"
        - "81"
        - "100"
        - 400-408
        - 411-413
        - "415"
        - "418"
        - "982"
        - "986"
        - "988"
        - "993"
  - mode: trunk
    name: GigabitEthernet0/2
    trunk:
      allowed_vlans:
        - "11"
        - "12"
        - "59"
        - "67"
        - "75"
        - "77"
        - "81"
        - "100"
        - 400-408
        - 411-413
        - "415"
        - "418"
        - "982"
        - "986"
        - "988"
        - "993"
      encapsulation: dot1q
l3_interfaces:
  - ipv4:
      - address: 192.168.0.2/24
    name: GigabitEthernet0/0
  - name: GigabitEthernet0/1
  - name: GigabitEthernet0/2
  - name: Loopback888
  - name: Loopback999

##Playbook
vars_files:
  - "facts.yml"
tasks:
  - name: Build the facts collection
    set_fact:
      data_sources:
        - data: "{{ interfaces }}"
          match_key: name
          name: interfaces
        - data: "{{ l2_interfaces }}"
          match_key: name
          name: l2_interfaces
        - data: "{{ l3_interfaces }}"
          match_key: name
          name: l3_interfaces

  - name: Combine all the facts based on match_keys
    set_fact:
      combined: "{{ data_sources|ansible.utils.consolidate(fail_duplicate=True) }}"

##Output
# ok: [localhost] => {
#     "ansible_facts": {
#         "data_sources": [
#             {
#                 "data": [
#                     {
#                         "duplex": "auto",
#                         "enabled": true,
#                         "name": "GigabitEthernet0/0",
#                         "note": [
#                             "Connected green wire"
#                         ],
#                         "speed": "auto"
#                     },
#                     {
#                         "description": "Configured by Ansible - Interface 1",
#                         "duplex": "auto",
#                         "enabled": true,
#                         "mtu": 1500,
#                         "name": "GigabitEthernet0/1",
#                         "note": [
#                             "Connected blue wire",
#                             "Configured by Paul"
#                         ],
#                         "speed": "auto",
#                         "vifs": [
#                             {
#                                 "comment": "Needs reconfiguration",
#                                 "description": "Eth1 - VIF 100",
#                                 "enabled": true,
#                                 "mtu": 400,
#                                 "vlan_id": 100
#                             },
#                             {
#                                 "description": "Eth1 - VIF 101",
#                                 "enabled": true,
#                                 "vlan_id": 101
#                             }
#                         ]
#                     },
#                     {
#                         "description": "Configured by Ansible - Interface 2 (ADMIN DOWN)",
#                         "enabled": false,
#                         "mtu": 600,
#                         "name": "GigabitEthernet0/2"
#                     }
#                 ],
#                 "match_key": "name",
#                 "name": "interfaces"
#             },
#             {
#                 "data": [
#                     {
#                         "name": "GigabitEthernet0/0"
#                     },
#                     {
#                         "name": "GigabitEthernet0/0"
#                     },
#                     {
#                         "mode": "access",
#                         "name": "GigabitEthernet0/1",
#                         "trunk": {
#                             "allowed_vlans": [
#                                 "11",
#                                 "12",
#                                 "59",
#                                 "67",
#                                 "75",
#                                 "77",
#                                 "81",
#                                 "100",
#                                 "400-408",
#                                 "411-413",
#                                 "415",
#                                 "418",
#                                 "982",
#                                 "986",
#                                 "988",
#                                 "993"
#                             ]
#                         }
#                     },
#                     {
#                         "mode": "trunk",
#                         "name": "GigabitEthernet0/2",
#                         "trunk": {
#                             "allowed_vlans": [
#                                 "11",
#                                 "12",
#                                 "59",
#                                 "67",
#                                 "75",
#                                 "77",
#                                 "81",
#                                 "100",
#                                 "400-408",
#                                 "411-413",
#                                 "415",
#                                 "418",
#                                 "982",
#                                 "986",
#                                 "988",
#                                 "993"
#                             ],
#                             "encapsulation": "dot1q"
#                         }
#                     }
#                 ],
#                 "match_key": "name",
#                 "name": "l2_interfaces"
#             },
#             {
#                 "data": [
#                     {
#                         "ipv4": [
#                             {
#                                 "address": "192.168.0.2/24"
#                             }
#                         ],
#                         "name": "GigabitEthernet0/0"
#                     },
#                     {
#                         "name": "GigabitEthernet0/1"
#                     },
#                     {
#                         "name": "GigabitEthernet0/2"
#                     },
#                     {
#                         "name": "Loopback888"
#                     },
#                     {
#                         "name": "Loopback999"
#                     }
#                 ],
#                 "match_key": "name",
#                 "name": "l3_interfaces"
#             }
#         ]
#     },
#     "changed": false
# }
# Read vars_file 'facts.yml'

# TASK [Combine all the facts based on match_keys]
# fatal: [localhost]: FAILED! => {
#     "msg": "Error when using plugin 'consolidate': 'fail_duplicate' reported Duplicate values in data source 1"
# }

Authors

  • Sagar Paul (@KB-perByte)

Hint

Configuration entries for each entry type have a low to high priority order. For example, a variable that is lower in the list will override a variable that is higher up.