linuxansibleansible-facts

How to extract facts with dot in variable name ('interface.vlan_id')?


I have this sample playbook and it work fine.

- hosts: localhost
  gather_facts: true
  tasks:
    - name: Print network interface details
      debug:
        msg: "{{ ansible_ens2f0.ipv4.network }}/{{ ansible_ens2f0.ipv4.netmask }}"

If I try with VLAN tag (11)

- hosts: localhost
  gather_facts: true
  tasks:
    - name: Print network interface details
      debug:
        msg: "{{ ansible_ens2f0.11.ipv4.network }}/{{ ansible_ens2f0.11.ipv4.netmask }}"

then getting error, in short

dict object has no element 11

and full message

TASK [Print network interface details] ***************************************************************************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: dict object has no element 11\n\nThe error appears to have been in '/home/ubuntu/net.yml': line 4, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n  tasks:\n    - name: Print network interface details\n      ^ here\n"}

How do I concatenate vlan_id in variable?

EDIT:

Here is dump of

ansible localhost -m setup 
    "ansible_ens2f0.11": {
                "active": true,
                "device": "ens2f0.11",
                "features": {
                    "esp_hw_offload": "off [fixed]",
                    "esp_tx_csum_hw_offload": "off [fixed]",
                    "fcoe_mtu": "off [requested on]",
                    "generic_receive_offload": "on",
                    "generic_segmentation_offload": "on",
                    "highdma": "on",
                    "hw_tc_offload": "off [fixed]",
                    "l2_fwd_offload": "off [fixed]",
                    "large_receive_offload": "off [fixed]",
                    "loopback": "off [fixed]",
                    "netns_local": "off [fixed]",
                    "ntuple_filters": "off [fixed]",
                    "receive_hashing": "off [fixed]",
                    "rx_all": "off [fixed]",
                    "rx_checksumming": "off [fixed]",
                    "rx_fcs": "off [fixed]",
                    "rx_gro_hw": "off [fixed]",
                    "rx_udp_tunnel_port_offload": "off [fixed]",
                    "rx_vlan_filter": "off [fixed]",
                    "rx_vlan_offload": "off [fixed]",
                    "rx_vlan_stag_filter": "off [fixed]",
                    "rx_vlan_stag_hw_parse": "off [fixed]",
                    "scatter_gather": "on",
                    "tcp_segmentation_offload": "on",
                    "tls_hw_record": "off [fixed]",
                    "tls_hw_rx_offload": "off [fixed]",
                    "tls_hw_tx_offload": "off [fixed]",
                    "tx_checksum_fcoe_crc": "off [requested on]",
                    "tx_checksum_ip_generic": "on",
                    "tx_checksum_ipv4": "off [fixed]",
                    "tx_checksum_ipv6": "off [fixed]",
                    "tx_checksum_sctp": "off [requested on]",
                    "tx_checksumming": "on",
                    "tx_esp_segmentation": "off [fixed]",
                    "tx_fcoe_segmentation": "off [requested on]",
                    "tx_gre_csum_segmentation": "off [requested on]",
                    "tx_gre_segmentation": "off [requested on]",
                    "tx_gso_partial": "off [fixed]",
                    "tx_gso_robust": "off [fixed]",
                    "tx_ipxip4_segmentation": "off [requested on]",
                    "tx_ipxip6_segmentation": "off [requested on]",
                    "tx_lockless": "on [fixed]",
                    "tx_nocache_copy": "off",
                    "tx_scatter_gather": "on",
                    "tx_scatter_gather_fraglist": "off [requested on]",
                    "tx_sctp_segmentation": "on",
                    "tx_tcp6_segmentation": "on",
                    "tx_tcp_ecn_segmentation": "on",
                    "tx_tcp_mangleid_segmentation": "on",
                    "tx_tcp_segmentation": "on",
                    "tx_udp_segmentation": "off [fixed]",
                    "tx_udp_tnl_csum_segmentation": "on",
                    "tx_udp_tnl_segmentation": "on",
                    "tx_vlan_offload": "off [fixed]",
                    "tx_vlan_stag_hw_insert": "off [fixed]",
                    "udp_fragmentation_offload": "off",
                    "vlan_challenged": "off [fixed]"
                },
                "hw_timestamp_filters": [
                    "none",
                    "all"
                ],
                "ipv4": {
                    "address": "10.43.56.241",
                    "broadcast": "10.43.56.255",
                    "netmask": "255.255.255.224",
                    "network": "10.43.56.224"
                },

I want to extract facts "network": "10.43.56.224" when I am trying ansible_ens2f0.11.ipv4.network because of dot between interface and vlan_id causing issue. it think its sub element but its not.


Solution

  • In order for further working with Ansible facts a minimal example playbook based on Ansible Issue #81652

    ---
    - hosts: localhost
      become: false
      gather_facts: false
    
      vars:
    
        facts:
          ens2f0.11: {
          "active": true,
          "device": "ens2f0",
          "vlan_id": "11",
          "macaddress": "00:00:5E:00:42:11",
          "mtu": 1500,
          "promisc": false,
          "speed": 10000,
          "type": "vlan"
          }
    
        VLAN_ID: 11
    
      tasks:
    
        - debug:
            var: facts.ens2f0.11
    

    will result into an output of

    TASK [debug] ******************************
    ok: [localhost] =>
      facts.ens2f0.11: VARIABLE IS NOT DEFINED!
    

    because in this case here the variable naming in Ansible facts given by setup.py is different from documentation Creating valid variable names.

    Not all strings are valid Ansible variable names. A variable name can only include letters, numbers, and underscores. Python keywords or playbook keywords are not valid variable names. A variable name cannot begin with a number.

    In order to access the variable and data one could use

        - debug:
            var: facts['ens2f0.11']
    

    resulting into an output of

    TASK [debug] ********************
    ok: [localhost] =>
      facts['ens2f0.11']:
        active: true
        device: ens2f0
        macaddress: 00:00:5E:00:42:11
        mtu: 1500
        promisc: false
        speed: 10000
        type: vlan
        vlan_id: '11'
    

    Q: "How do I concatenate vlan_id in variable?"

    A: Since the variable naming above is done in code and static, but the vlan_id probably dynamic, one will mostly like to construct the variable name dynamic and based on other variable content, in example an given VLAN_ID. In order to do so

        - debug:
            var:  facts['ens2f0.' ~ VLAN_ID]
    
        # Or even
    
        - debug:
            msg: "{{ facts['ens2f0.' ~ VLAN_ID] }}"
    

    resulting into an output of

    TASK [debug] ********************
    ok: [localhost] =>
      facts['ens2f0.' ~ VLAN_ID]:
        active: true
        device: ens2f0
        macaddress: 00:00:5E:00:42:11
        mtu: 1500
        promisc: false
        speed: 10000
        type: vlan
        vlan_id: '11'
    

    See best practice to concatenate strings in Ansible variables and another more advanced example for your case

    ---
    - hosts: localhost
      become: false
      gather_facts: false
    
      vars:
    
        DEVICE: ens2f0
        VLAN_ID: 11
    
        facts:
          ansible_ens2f0.11: {
            "active": true,
            "device": "ens2f0.11",
            "features": {
             },
            "hw_timestamp_filters": [
              "none",
              "all"
             ],
            "ipv4": {
              "address": "10.43.56.241",
                "broadcast": "10.43.56.255",
                "netmask": "255.255.255.224",
                "network": "10.43.56.224"
               }
            }
    
      tasks:
    
        - debug:
            msg: "{{ facts['ansible_' ~ DEVICE ~ '.' ~ VLAN_ID].ipv4.network }}"```
    

    resulting into the requested output of

    TASK [debug] ******
    ok: [localhost] =>
      msg: 10.43.56.224
    

    Finally proceed further and test directly with gathered ansible_facts

    ---
    - hosts: localhost
      gather_facts: true
    
      vars:
    
        DEVICE: ens2f0
        VLAN_ID: 11
    
      tasks:
    
        - debug:
            msg: "{{ ansible_facts[DEVICE ~ '.' ~ VLAN_ID].ipv4.network }}"```