0
votes

I'm completely new to Ansible so I'm still struggling with its way of working... I have an inventory file with several hosts sorted by environment and function:

[PRO-OSB]
host-1
host-2
[PRO-WL]
host-3
host-4
[PRO:children]
PRO-OSB
PRO-WL

But I think sometimes I might need to run playbooks specifying even more, i.e attending to the environment, its function, cluster of hosts and application running on the host. So in resume every host must have 4 "categories": environment, function, cluster and app. How could I achieve this without having to constantly repeat entries??

3

3 Answers

0
votes

How could I achieve this without having to constantly repeat entries?

You can't. You have to declare in each needed groups the machines that belong to it. So if a machine belongs to 4 distinct groups (not taking into account parent groups), you'll have to declare that host in the 4 relevant groups.

Ansible could have chosen the other way around (i.e. list for each hosts the groups it belongs to) but this is not the retained solution and it would be as verbose.

To make things easier and IMO a bit more secure, you can split your inventory in several environment inventories (prod, dev....) so that you can remove one level of complexity inside each inventory. The downside is that you cannot target all your envs at once with such a setup.

If your inventory is big and targeting some sort of cluster/cloud environment (vsphere, aws...), dynamic inventories can help.

0
votes

Q: "Every host must have 4 "categories": environment, function, cluster and app. How could I achieve this without having to constantly repeat entries?"

A: It's possible to declare default options in a [*:vars] section and override it with the host's specific options. See How variables are merged. For example the inventory

$ cat hosts
[PRO_OSB]
test_01 my_cluster='cluster_A'
test_02
[PRO_WL]
test_03 my_cluster='cluster_A'
test_04
[PRO:children]
PRO_OSB
PRO_WL
[PRO:vars]
my_environment='default_env'
my_function='default_fnc
my_cluster='default_cluster'
my_app='default_app'

with the playbook

- hosts: PRO
  gather_facts: false
  tasks:
    - debug:
        msg: "{{ inventory_hostname }}
              {{ my_environment }}
              {{ my_function }}
              {{ my_cluster }}
              {{ my_app }}"

gives (my_cluster variable of test_01 and test_03 was overridden by hosts' value)

"msg": "test_01 default_env 'default_fnc cluster_A default_app"
"msg": "test_02 default_env 'default_fnc default_cluster default_app"
"msg": "test_04 default_env 'default_fnc default_cluster default_app"
"msg": "test_03 default_env 'default_fnc cluster_A default_app"

Q: "Run playbooks specifying even more, i.e attending to the environment, its function, cluster of hosts and application."

It's possible to create dynamic groups with the module add_host and select the hosts as needed. For example create new group cluster_A in the first play and use it in the next one

- hosts: all
  tasks:
    - add_host:
        name: "{{ item }}"
        group: cluster_A
      loop: "{{ hostvars|
                dict2items|
                json_query('[?value.my_cluster == `cluster_A`].key') }}"
      delegate_to: localhost
      run_once: true

- hosts: cluster_A
  tasks:
    - debug:
        var: inventory_hostname

gives

ok: [test_01] => {
    "inventory_hostname": "test_01"
}
ok: [test_03] => {
    "inventory_hostname": "test_03"
}
0
votes

for folks who might need something like this --

I ended up using this format for my inventory file when I was trying to establish multiple variables for each host for delivering files based on role or team.

inventory/support/hosts

support:
  hosts: 
    qahost:
      host_role: 
        waiter
        dishwasher
      host_teams: 
        ops
        sales
    awshost:
      host_role:
        waiter
      host_teams:
        dev
    testhost1:
      host_role:
        dishwasher
      host_teams:
        ops
        dev
    testhost2:
      host_role:
        dishwasher
        boss
      host_teams:
        ops
        dev
        sales

and referenced them in this play:

- name: parse inventory file host variables
  debug:
    msg: |
      - "role attribute of host: {{ item }} is {{ hostvars[item]['host_role'] }}"
      - "team attribute of host: {{ item }} is {{ hostvars[item]['host_teams'] }}"
  with_items: "{{ inventory_hostname }}"
  when: hostvars[item]['host_teams'] is contains (team_name)

ansible command with custom extra_var that is passed to the playbook and matched in the inventory with the when conditional:

ansible-playbook -i inventory/support/hosts -e 'team_name="sales"' playbook.yml