I created a playbook that has 3 plays. I want to run the playbook against an inventory file containing a mix of EOS, IOS, and NXOS-based devices. The plays are just gathering facts for the particular OS. I’m using a debug to print the model and version. Each play has a when statement that looks at ansible_network_os. The issue is that I can only get the model and version of the very last play. The other two plays produce the following error:
FAILED! => {"msg": "The task includes an option with an undefined variable.. 'dict object' has no attribute 'ansible_facts'\n\nThe error appears to be in '/home/corpaldorf/ansible/network/playbooks/gather-os-version.yml': line 27, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: Display results\n ^ here\n"}
If I change the order of the plays, the last one always works. Here is the playbook:
- name: Model and OS Version
hosts: all
gather_facts: true
tasks:
- name: Model/Version - IOS
cisco.ios.ios_facts:
gather_subset: all
register: facts
when:
- ansible_network_os == "cisco.ios.ios"
- name: Model/Version - EOS
arista.eos.eos_facts:
gather_subset: all
register: facts
when:
- ansible_network_os == "arista.eos.eos"
- name: Model/Version - NXOS
cisco.nxos.nxos_facts:
gather_subset: all
register: facts
when:
- ansible_network_os == "cisco.nxos.nxos"
- name: Display results
ansible.builtin.debug:
msg:
- "Device Model: {{ facts.ansible_facts.ansible_net_model }}"
- "Device OS Version: {{ facts.ansible_facts.ansible_net_version }}"
What could I be doing wrong ? I’m pretty sure I’m doing something wrong
I’m just doing this as a learning exercise, so I’m 100% sure there are better ways to do this. My goal is to have this playbook dump the results into a CSV.
Assuming I updated the playbook correctly, I now receive the following error for all the devices:
fatal: [west-01-sp04]: FAILED! => {"msg": "The task includes an option with an undefined variable.. 'dict object' has no attribute 'ansible_net_model'\n\nThe error appears to be in '/home/XXXX/ansible/network/playbooks/gather-os-version.yml': line 24, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: Display results\n ^ here\n"}
Here is the complete playbook:
- name: Model and OS Version
hosts: all
gather_facts: true
tasks:
- name: Model/Version - IOS
cisco.ios.ios_facts:
gather_subset: all
when:
- ansible_network_os == "cisco.ios.ios"
- name: Model/Version - NXOS
cisco.nxos.nxos_facts:
gather_subset: all
when:
- ansible_network_os == "cisco.nxos.nxos"
- name: Model/Version - EOS
arista.eos.eos_facts:
gather_subset: all
when:
- ansible_network_os == "arista.eos.eos"
- name: Display results
ansible.builtin.debug:
msg:
- "Device Model: {{ ansible_facts.ansible_net_model }}"
- "Device OS Version: {{ ansible_facts.ansible_net_version }}"
ansible_facts is a dictionary containing all the facts gathered by ansible and this dictionary does not contain the element ansible_net_model.
The ansible_net_model variable is a shorthand for ansible_facts.net_model, so you can use whichever you prefer.
A will also suggest that you only gather the facts that you actually need, as fact gathering is resource intensive. ansible_facts.net_mode and ansible_facts.net_version are always returned, so gather_subset: min should be enough. However, in this case you can actually reduce the playbook to the following, as gather_facts: true will take care of the OS related logic:
- name: Model and OS Version
hosts: all
gather_facts: true
tasks:
- name: Display results
ansible.builtin.debug:
msg:
- "Device Model: {{ ansible_facts.net_model }}"
- "Device OS Version: {{ ansible_facts.net_version }}"
A new configuration variable, inject_facts_as_vars, has been added to ansible.cfg. Its default setting, ‘True’, keeps the 2.4 behavior of facts variables being set in the old ansible_* locations (while also writing them to the new namespace). This variable is expected to be set to ‘False’ in a future release. When inject_facts_as_vars is set to False, you must refer to ansible_facts through the new ansible_facts.* namespace.
And only using the ansible_facts.net_model variable notansible_net_model.
You can just use the built in gather_facts (which is the default fact gathering now) and avoid all these issues. It is smart by default and knows about many (but not all) network_os, in this case ios, eos and nxos are covered and it would just apply the right module for the right OS.
For those not covered in the defaults you can use ansible_facts_modules at the group or host level to define which fact modules to use for that group/host.