Use of Nested Variables

Goal: When playbook / task is called… use varibles set for specific host withing a group

/hosts.yml # site wide master ansible inentory
all:
children:

Physical HyperConverge Server Devices for environment

hci_hosts: # Nodes for hosting VMs
hosts:
thor:
vars:
mgmt_nic: enp8s0f0 # Set in Kickstart OS install
storage_nic: ens15f0
ovs_nic: enp8s0f1
ovirt_disk: ata-Samsung_SSD_850_PRO_512GB_S250NXAGA15787L # ls -al /dev/disk/by-id/ |grep sdb
data00_disk: ata-WDC_WDS100T2B0B-00YS70_192490801828 # ls -al /dev/disk/by-id/ |grep sdc
data01_disk: ata-WDC_WDS100T2B0B-00YS70_19106A802926 # ls -al /dev/disk/by-id/ |grep sdd
odin:
vars:
mgmt_nic: enp8s0f0 # Set in Kickstart OS install
storage_nic: ens15f0
ovirt_disk: ata-Micron_1100_MTFDDAV512TBN_17401F699137 # ls -al /dev/disk/by-id/ |grep sdb
data00_disk: ata-WDC_WDS100T2B0B-00YS70_183533804564 # ls -al /dev/disk/by-id/ |grep sdc
data01_disk: nvme-nvme.126f-4141303030303030303030303030303032343538-53504343204d2e32205043496520535344-00000001 # ls -al /dev/disk/by-id/ |grep nvme0n1

Task: setup host networking and disk… where each host is different … so have to set individulized varibles

Any idea or help here

I see this concept is valid.https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#referencing-nested-variables

But for above example:

  • debug: # this works to set variable for storage interface https://docs.ansible.com/ansible/latest/collections/community/general/nmcli_module.html
    msg: “‘{{ inventory_hostname }}s’ this should be hostname with s added such as thors”
  • debug:
    msg: “{{ inventory_hostname }} this should be hostname response of thor”
  • debug:
    msg: “{{ inventory_hostname.storage_nic }} this should be response of ens15f0”
  • debug:
    msg: “{{ ansible_facts.storage_nic }} I guess if ansible_fact is a special ansible variable…this should be hostname response of ens15f0”

<< output>

/cluster_devops$ ansible-playbook hci_deploy.yml --limit thor

PLAY [Ansible Pinging Host which validates SSH passwordless login] *******************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************************ok: [thor]

TASK [hci_cluster : Copy a version of hosts file common for nodes to ignite cluster] *************************************************************************************ok: [thor]

TASK [hci_cluster : debug] ***********************************************************************************************************************************************ok: [thor] =>
msg: ‘’‘thors’’ this should be hostname with s added such as thors’

TASK [hci_cluster : debug] ***********************************************************************************************************************************************ok: [thor] =>
msg: thor this should be hostname response of thor

TASK [hci_cluster : debug] ***********************************************************************************************************************************************fatal: [thor]: FAILED! =>
msg: |-
The task includes an option with an undefined variable. The error was: ‘ansible.parsing.yaml.objects.AnsibleUnicode object’ has no attribute ‘storage_nic’

The error appears to be in ‘/mnt/c/GitHub/penguinpages_cluster_devops/cluster_devops/roles/task_network_hosts.yml’: line 63, column 3, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

msg: “{{ inventory_hostname }} this should be hostname response of thor”

  • debug:
    ^ here

PLAY RECAP ***************************************************************************************************************************************************************thor : ok=4 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0

Any idea or help here

I see this concept is
valid.https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#referencing-nested-variables

But for above example:

- debug: # this works to set variable for storage interface https://docs.ansible.com/ansible/latest/collections/community/general/nmcli_module.html
msg: "'{{ inventory_hostname }}s' this should be hostname with s added such as thors"
- debug:
msg: "{{ inventory_hostname }} this should be hostname response of thor"
- debug:
msg: "{{ inventory_hostname.storage_nic }} this should be response of ens15f0"
- debug:
msg: "{{ ansible_facts.storage_nic }} I guess if ansible_fact is a special ansible variable...this should be hostname response of ens15f0"

You don't show the task which uses nmlci_module and provides storage_nic information.

inventory_hostname.storage_nic is totally bogus as a string can't be a nested variable.

Regards
         Racke

Well. I was trying to keep it simple and just validate the variable call was valid before trying to use it in a task.

But task would be something along lines of:

  • name: Get server storage IP address from /etc/hosts
    command: “grep ‘{{ inventory_hostname }}s’ /etc/hosts | awk ‘{ print $1 }’”
    register: storage_ip

  • task: # Set Storage IP for host
    nmci:
    ipaddress: {{storage_ip}}
    interface: {{ inventory_hostname.storage_nic }}
    mask: 24
    mtu: 9000

That is the hope it will work.

Well. I was trying to keep it simple and just validate the variable call was valid before trying to use it in a task.

But task would be something along lines of:
- name: Get server storage IP address from /etc/hosts
command: "grep '{{ inventory_hostname }}s' /etc/hosts | awk '{ print $1 }'"
register: storage_ip

So the result of the command is stored in the variable storage_ip and the output of the command
is stored in storage_ip.stdout (as string) and storage_ip.stdout_lines (list of output lines).

To show the result:

debug:
   var: storage_ip

- task: # Set Storage IP for host
nmci:
ipaddress: {{storage_ip}}
interface: {{ inventory_hostname.storage_nic }}
mask: 24
mtu: 9000

So ipaddress might be {{ storage_ip.stdout }}

Regards
         Racke

My issue is not getting the variable set of “storage_ip”

But that I have to define variables in the global inventory file… That are unique to each host.

And when I run a playbook and it needs those variables… how do I get them.

Ex:

When I want to run a playbook for group “hci_cluster” which then runs on three hosts…

First host is “thor”
It has its 10Gb storage NIC as enp8s0f1

so when the playbook is running. use variable “hci_cluster-> thor->storage_nic” to know to bind ip to enp8s0f1

But how do I use a nested variable ?

My issue is not getting the variable set of "storage_ip"

But that I have to define variables in the global inventory file.. That are unique to each host.

And when I run a playbook and it needs those variables.. how do I get them.

Ex:

When I want to run a playbook for group "hci_cluster" which then runs on three hosts..

First host is "thor"
It has its 10Gb storage NIC as enp8s0f1

so when the playbook is running. use variable "hci_cluster-> thor->storage_nic" to know to bind ip to enp8s0f1

But how do I use a nested variable ?

You don't need it. It should be present as "storage_nic" variable given your inventory:

hosts:
  thor:
    vars:
      mgmt_nic: enp8s0f0 # Set in Kickstart OS install
      storage_nic: ens15f0
      ovs_nic: enp8s0f1

So please try to use {{ storage_nic }}.

Regards
        Racke

I 100% agree with you. If I set a host variable … that should be read and take precedence from what I am reading.

…but that in lies the issue… it does not work…

I 100% agree with you. If I set a host variable ... that should be read and take precedence from what I am reading.

....but that in lies the issue.. it does not work....

This causes the error:

- debug:
    msg: "{{ inventory_hostname.{{ storage_nic }} }} this should be NIC of thor for storage"

So you never reached:

- debug:
    msg: "{{ storage_nic }} this should be NIC of thor for storage"

You really need to try to understand what the error message clearly tells you.

Regards
        Racke

Ok… same inventory file:

one task…

  • debug:
    msg: “{{ storage_nic }} this should be NIC of thor for storage”

output

cluster_devops$ ansible-playbook hci_deploy.yml --limit thor

PLAY [Ansible Pinging Host which validates SSH passwordless login] *******************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************************ok: [thor]

TASK [hci_cluster : debug] ***********************************************************************************************************************************************fatal: [thor]: FAILED! =>
msg: |-
The task includes an option with an undefined variable. The error was: ‘storage_nic’ is undefined

The error appears to be in ‘/mnt/c/GitHub/penguinpages_cluster_devops/cluster_devops/roles/task_network_hosts.yml’: line 78, column 3, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

msg: “{{ inventory_hostname[storage_nic] }} this should be NIC of thor for storage”

  • debug:
    ^ here

PLAY RECAP ***************************************************************************************************************************************************************thor : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0

Ok.. same inventory file:

## one task..
- debug:
msg: "{{ storage_nic }} this should be NIC of thor for storage"

Please remove vars: from your inventory and run your task again.

hci_hosts: # Nodes for hosting VMs
  hosts:
    thor:
      mgmt_nic: enp8s0f0 # Set in Kickstart OS install
      storage_nic: ens15f0

Regards
       Racke

That was it!!!

Root cause:

Stanza of “var:” though valid… and used by some in examples… is NOT valid.

######Good: no “var” for hosts section but must have var for group…

all:
children:

Physical HyperConverge Server Devices for environment

hci_hosts: # Nodes for hosting VMs
hosts:
thor:
mgmt_nic: enp8s0f0 # Set in Kickstart OS install
storage_nic: ens15f0
ovs_nic: enp8s0f1
odin:
mgmt_nic: enp8s0f0 # Set in Kickstart OS install
storage_nic: enp7s0f1
vars:
ansible_ssh_pass: “{{ vault_ansible_sudo_password }}”
thor_storage_nic: ens15f0

bad use of var: under host

hci_hosts: # Nodes for hosting VMs
hosts:
thor:
var:
mgmt_nic: enp8s0f0 # Set in Kickstart OS install
storage_nic: ens15f0
ovs_nic: enp8s0f1
odin:
var:
mgmt_nic: enp8s0f0 # Set in Kickstart OS install
storage_nic: enp7s0f1
vars:
ansible_ssh_pass: “{{ vault_ansible_sudo_password }}”
thor_storage_nic: ens15f0

############### BAD removal of var: from hci_cluster group

hci_hosts: # Nodes for hosting VMs
hosts:
thor:
mgmt_nic: enp8s0f0 # Set in Kickstart OS install
storage_nic: ens15f0
ovs_nic: enp8s0f1
odin:
mgmt_nic: enp8s0f0 # Set in Kickstart OS install
storage_nic: enp7s0f1
ansible_ssh_pass: “{{ vault_ansible_sudo_password }}”
thor_storage_nic: ens15f0

Meh… it works… don’t ask me :stuck_out_tongue:

Thanks for postings.