# How to run plays with conditionals based on network os

**URL:** <https://forum.ansible.com/t/how-to-run-plays-with-conditionals-based-on-network-os/38974>\
**Category:** Get Help\
**Tags:** network\
**Created:** [December 8, 2024, 6:52am UTC](https://forum.ansible.com/t/how-to-run-plays-with-conditionals-based-on-network-os/38974 "2024-12-08T06:52:29Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![jimmychanga](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/jimmychanga/32/6921_2.png) [@jimmychanga](https://forum.ansible.com/u/jimmychanga)\
**Post date:** [December 8, 2024, 6:52am UTC](https://forum.ansible.com/t/how-to-run-plays-with-conditionals-based-on-network-os/38974/1 "2024-12-08T06:52:29Z")

</div>

Hello,

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:

```auto
- 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.

---

<div class="post-metadata">

**Author:** ![jiholland](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/jiholland/32/11273_2.png) [@jiholland](https://forum.ansible.com/u/jiholland)\
**Post date:** [December 8, 2024, 8:17pm UTC](https://forum.ansible.com/t/how-to-run-plays-with-conditionals-based-on-network-os/38974/2 "2024-12-08T20:17:24Z")

</div>

The reason this only works for the last task is because `register` still catches the status of a skipped task.

And you don’t need to register a variable as `ansible_facts` is directly accessible:

```auto
   - name: Model/Version - NXOS
      cisco.nxos.nxos_facts:
        gather_subset: all
      when:
        - ansible_network_os == "cisco.nxos.nxos"

    - name: Display results
      ansible.builtin.debug:
        msg:
          - "Device Model: {{ ansible_facts.ansible_net_model }}"
          - "Device OS Version: {{ ansible_facts.ansible_net_version }}"

```

---

<div class="post-metadata">

**Author:** ![jimmychanga](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/jimmychanga/32/6921_2.png) [@jimmychanga](https://forum.ansible.com/u/jimmychanga)\
**Post date:** [December 8, 2024, 9:12pm UTC](https://forum.ansible.com/t/how-to-run-plays-with-conditionals-based-on-network-os/38974/3 "2024-12-08T21:12:28Z")

</div>

Thanks,

Assuming I updated the playbook correctly, I now receive the following error for all the devices:

```auto
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:

```auto
- 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 }}"

```

---

<div class="post-metadata">

**Author:** ![jimmychanga](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/jimmychanga/32/6921_2.png) [@jimmychanga](https://forum.ansible.com/u/jimmychanga)\
**Post date:** [December 9, 2024, 3:54am UTC](https://forum.ansible.com/t/how-to-run-plays-with-conditionals-based-on-network-os/38974/4 "2024-12-09T03:54:32Z")

</div>

I ended up changing the “Display results” play to the following:

```auto
    - name: Display results
      ansible.builtin.debug:
        msg:
          - "Device Model: {{ ansible_facts.net_model }}"
          - "Device OS Version: {{ ansible_facts.net_version }}"

```

This worked, I’m just not sure why that worked.

---

<div class="post-metadata">

**Author:** ![jiholland](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/jiholland/32/11273_2.png) [@jiholland](https://forum.ansible.com/u/jiholland)\
**Post date:** [December 9, 2024, 8:08am UTC](https://forum.ansible.com/t/how-to-run-plays-with-conditionals-based-on-network-os/38974/5 "2024-12-09T08:08:38Z")

</div>

`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:

```yaml
- 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 }}"

```

---

<div class="post-metadata">

**Author:** ![chris](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/chris/32/293_2.png) [@chris](https://forum.ansible.com/u/chris)\
**Post date:** [December 9, 2024, 2:51pm UTC](https://forum.ansible.com/t/how-to-run-plays-with-conditionals-based-on-network-os/38974/6 "2024-12-09T14:51:41Z")

</div>

Note that you could be best off setting this in `ansible.cfg`:

```ini
[defaults]
inject_facts_as_vars = False

```

For [security and future compatibility reasons](https://docs.ansible.com/ansible/latest/porting_guides/porting_guide_2.5.html#ansible-fact-namespacing):

> 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 **not** `ansible_net_model`.

---

<div class="post-metadata">

**Author:** ![bcoca](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/bcoca/32/9269_2.png) [@bcoca](https://forum.ansible.com/u/bcoca)\
**Post date:** [December 9, 2024, 4:27pm UTC](https://forum.ansible.com/t/how-to-run-plays-with-conditionals-based-on-network-os/38974/7 "2024-12-09T16:27:44Z")

</div>

You can just use the built in [`gather_facts`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/gather_facts_module.html) (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`](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#facts-modules) at the group or host level to define which fact modules to use for that group/host.
