# Case or if/else logic in 'when'

**URL:** <https://forum.ansible.com/t/case-or-if-else-logic-in-when/8320>\
**Category:** Get Help\
**Created:** [September 7, 2024, 7:21pm UTC](https://forum.ansible.com/t/case-or-if-else-logic-in-when/8320 "2024-09-07T19:21:10Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![dulhaver](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/dulhaver/32/1061_2.png) [@dulhaver](https://forum.ansible.com/u/dulhaver)\
**Post date:** [September 7, 2024, 7:21pm UTC](https://forum.ansible.com/t/case-or-if-else-logic-in-when/8320/1 "2024-09-07T19:21:10Z")

</div>

I want to install packages on several hosts.

- [1.mydomain.org](http://1.mydomain.org)
- [2.mydomain.org](http://2.mydomain.org)
- [3.mydomain.org](http://3.mydomain.org)

now I have 3 lists in a defaults-file

```auto
packages_1:
  - vim
  - git

packages_2:
  - nano
  - less

packages_3:
  - zsh
  - go

```

my TASK would be:

```auto
- name: install packages to host 1
  package:
    name: "{{ item }}"
    state: present
  loop: "{{ packages_1}}"
  when: 1 in inventory_hostname

- name: install packages to host 2
  package:
    name: "{{ item }}"
    state: present
  loop: "{{ packages_2 }}"
  when: 2 in inventory_hostname

- name: install packages to host 3
  package:
    name: "{{ item }}"
    state: present
  loop: "{{ packages_3 }}"
  when: 3 in inventory_hostname

```

now, what I would like to achieve is to do this in a single task. This would require some sort of `if/else` or `case` logic.

Any idea, how I can achieve that?

---

<div class="post-metadata">

**Author:** ![mariolenz](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/mariolenz/32/108_2.png) [@mariolenz](https://forum.ansible.com/u/mariolenz)\
**Post date:** [September 8, 2024, 12:36pm UTC](https://forum.ansible.com/t/case-or-if-else-logic-in-when/8320/2 "2024-09-08T12:36:32Z")

</div>

Ansible isn’t very good at `if/elif/else` or `case` logic IMHO. I think this is by design, because it’s **not** a scripting language but an infrastructure-as-code tool.

That said, why do you define three lists in a defaults file? If the list of packages is unique to every host, why not have a `packages` variable [for every host in your inventory](https://docs.ansible.com/ansible/latest/inventory_guide/intro_inventory.html#assigning-a-variable-to-one-machine-host-variables)? You would only need one task then and ansible would use the correct list of packages.

This would also make it clearer that those packages are _specific_ for every host. Although it’s technically possible to do it your way, I think it’s better to have only _default_ values in a defaults file. Everything else is confusing and looks like an accident waiting to happen 😉

BTW you can have default variables and override them in several places. Although with 22 places where you can define a variable, [precedence](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#understanding-variable-precedence) is a little bit complicated. Although in practice most people probably only use 3 or 4 places (like role defaults, inventory group\_vars/all, inventory group\_vars and inventory host\_vars) where they define variables, which simplifies things.

---

<div class="post-metadata">

**Author:** ![dulhaver](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/dulhaver/32/1061_2.png) [@dulhaver](https://forum.ansible.com/u/dulhaver)\
**Post date:** [September 8, 2024, 7:18pm UTC](https://forum.ansible.com/t/case-or-if-else-logic-in-when/8320/3 "2024-09-08T19:18:54Z")

</div>

thx for the pointers

> [@mariolenz](#):
>
> why not have a `packages` variable [for every host in your inventory](https://docs.ansible.com/ansible/latest/inventory_guide/intro_inventory.html#assigning-a-variable-to-one-machine-host-variables)? You would only need one task then and ansible would use the correct list of packages.

not sure whether it makes any significant difference where to put such variants. Actually we are using a dynamic inventory, so there is no concrete way to place them where you suggest in my general setup.

I am aware of the [variable precedence list](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#understanding-variable-precedence) and the challenges, opportunities it brings. And it’s true … once you build some sort of habbit you end up only using few locations out of the (almost) countless possibilities.

good to know that probaly looking for `if/else` kind of logic is, apparently. pointless.

---

<div class="post-metadata">

**Author:** ![binbashroot](https://avatars.discourse-cdn.com/v4/letter/b/ad7895/32.png) [@binbashroot](https://forum.ansible.com/u/binbashroot)\
**Post date:** [September 8, 2024, 11:51pm UTC](https://forum.ansible.com/t/case-or-if-else-logic-in-when/8320/4 "2024-09-08T23:51:06Z")

</div>

Depending on how you’re generating your dynamic inventory you can create groups and vars. The servicenow, vmware, proxmox inventory plugins would be good examples to show you how to do this if your dynamic inventory plugin supports this. Otherwise, you could use some jinja and pare ii down to a single task. You can also add a hosts\_vars and groups\_vars in the same directory as your playbook. See: [How to build your inventory — Ansible Community Documentation](https://docs.ansible.com/ansible/latest/inventory_guide/intro_inventory.html#splitting-out-vars)  
Per the docs:  
_Ansible loads host and group variable files by searching paths relative to the inventory file or the playbook file_

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [September 9, 2024, 1:08am UTC](https://forum.ansible.com/t/case-or-if-else-logic-in-when/8320/5 "2024-09-09T01:08:52Z")

</div>

> [@mariolenz](#):
>
> Although in practice most people probably only use 3 or 4 places (like role defaults, inventory group\_vars/all, inventory group\_vars and inventory host\_vars) where they define variables, which simplifies things.

We don’t specify _any_ `group_vars` or `host_vars` in our inventories. All our `group_vars` and `host_vars` are specific to _projects_. Maybe we’re just lucky that way, or not very imaginative. But to my mind, inventories define and group hosts; variables are a different thing and should be kept separate. I’d probably make an exception for connection variables, but they are sort of part of the host definition. Fortunately, Ansible’s defaults work for all our hosts, so we’ve avoided that distinction.

---

<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:** [September 17, 2024, 12:15pm UTC](https://forum.ansible.com/t/case-or-if-else-logic-in-when/8320/6 "2024-09-17T12:15:59Z")

</div>

One option is to create a file for each list of packages in the vars-directory for the role.

```auto
$ tree vars/
vars/
├── package_1.yml
├── package_2.yml
└── package_3.yml
$ cat package_1.yml 
packages:
  - vim
  - git

```

This approach gives you the option to include the variables based on the inventory\_hostname, and results in a single “install packages” task.

```auto
- name: Include host-specific variables.
  ansible.builtin.include_vars:
    file: "{{ role_path }}/vars/package_{{ inventory_hostname | split('.') | first }}.yml"

- name: Install packages.
  ansible.builtin.package:
    name: "{{ packages }}"
    state: present

```

---

<div class="post-metadata">

**Author:** ![hugonz](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/hugonz/32/503_2.png) [@hugonz](https://forum.ansible.com/u/hugonz)\
**Post date:** [September 18, 2024, 3:43am UTC](https://forum.ansible.com/t/case-or-if-else-logic-in-when/8320/7 "2024-09-18T03:43:47Z")

</div>

When you find yourself looking for a `case` statement, the problem lends itself to an object lookup, like so:

```yaml
vars:
  host_packages:
    '1':
      - vim
      - git
    '2':
      - nano
      - less
    '3':
      - zsh
      - go

# and then
tasks:
  - name: install packages to host
    ansible.builtin.package:
      name: "{{ item }}"
      state: present
    loop: "{{ host_packages[inventory_hostname] }}"

```

Note how I’m assuming `inventory_hostname` is a string, because it always will come as a string.
