Search code examples
ansibleinventory

How to properly build an Ansible inventory


I want to build an Ansible inventory without making it spaghetti and I like to be DRY. I took a look at the Ansible Docs, but I can't find the information for the following:

I am currently using this format to build an inventory.

[dev-postgres]
a1-dev-01 ansible_host=vm-1.my.internal.domain.com 
a1-dev-02 ansible_host=vm-2.my.internal.domain.com 

[dev-ldap]
a1-dev-02 ansible_host=vm-2.my.internal.domain.com 
a1-dev-03 ansible_host=vm-3.my.internal.domain.com 

[dev:children]
dev-ldap
dev-postgres

[dev:vars]
env=dev

[jumphost]
a2-jump-01 ansible_host=vm-0.my.internal.domain.com 

I have three questions regarding this setup:

  • Is it possible, for each ansible_host, define 'vm-x', and configure the '.my.internal.domain.com' once, and each host will have that value appended to their ansible_host value?
  • Is it possible to define for each host the name(e.g. a6-dev-01) + ansible_host once. And then the name(e.g. a6-dev-01) could be set under multiple groups, without defining ansible_host?
  • Is it possible for the name of the group to have multiple values? E.g. [dev-postgres, another_value]?

Solution

  • Use constructed inventory plugin. See

    shell> ansible-doc -t inventory constructed
    

    For example

    shell> cat hosts-627/1-hosts
    a1_dev_01 vm_x=vm-1
    a1_dev_02 vm_x=vm-2
    a1_dev_03 vm_x=vm-3
    a2_jump_01 vm_x=vm-0
    
    [dev_postgres]
    a1_dev_01
    a1_dev_02
    
    [dev_ldap]
    a1_dev_02
    a1_dev_03
    
    [dev:children]
    dev_postgres
    dev_ldap
    
    [dev:vars]
    env=dev
    
    [jumphost]
    a2_jump_01
    
    [all:vars]
    vm_domain=my.internal.domain.com
    
    shell> cat hosts-627/2-constructed.yml 
    plugin: constructed
    strict: true
    compose:
      ansible_host: vm_x ~ '.' ~ vm_domain
    

    gives

    shell> ansible-inventory -i hosts-627 --list --yaml
    all:
      children:
        dev:
          children:
            dev_ldap:
              hosts:
                a1_dev_02:
                  ansible_host: vm-2.my.internal.domain.com
                  env: dev
                  vm_domain: my.internal.domain.com
                  vm_x: vm-2
                a1_dev_03:
                  ansible_host: vm-3.my.internal.domain.com
                  env: dev
                  vm_domain: my.internal.domain.com
                  vm_x: vm-3
            dev_postgres:
              hosts:
                a1_dev_01:
                  ansible_host: vm-1.my.internal.domain.com
                  env: dev
                  vm_domain: my.internal.domain.com
                  vm_x: vm-1
                a1_dev_02: {}
        jumphost:
          hosts:
            a2_jump_01:
              ansible_host: vm-0.my.internal.domain.com
              vm_domain: my.internal.domain.com
              vm_x: vm-0
        ungrouped: {}
    

    The next option is putting the variables into the group_vars. For example

    shell> cat hosts-628/hosts
    a1_dev_01 vm_x=vm-1
    a1_dev_02 vm_x=vm-2
    a1_dev_03 vm_x=vm-3
    a2_jump_01 vm_x=vm-0
    
    [dev_postgres]
    a1_dev_01
    a1_dev_02
    
    [dev_ldap]
    a1_dev_02
    a1_dev_03
    
    [dev:children]
    dev_postgres
    dev_ldap
    
    [jumphost]
    a2_jump_01
    
    shell> cat group_vars/all.yml 
    vm_domain: my.internal.domain.com
    ansible_host: "{{ vm_x }}.{{ vm_domain }}"
    
    shell> cat group_vars/dev.yml 
    env: dev
    

    gives

    shell> ansible-inventory -i hosts-628 --list --yaml
    all:
      children:
        dev:
          children:
            dev_ldap:
              hosts:
                a1_dev_02:
                  ansible_host: '{{ vm_x }}.{{ vm_domain }}'
                  env: dev
                  vm_domain: my.internal.domain.com
                  vm_x: vm-2
                a1_dev_03:
                  ansible_host: '{{ vm_x }}.{{ vm_domain }}'
                  env: dev
                  vm_domain: my.internal.domain.com
                  vm_x: vm-3
            dev_postgres:
              hosts:
                a1_dev_01:
                  ansible_host: '{{ vm_x }}.{{ vm_domain }}'
                  env: dev
                  vm_domain: my.internal.domain.com
                  vm_x: vm-1
                a1_dev_02: {}
        jumphost:
          hosts:
            a2_jump_01:
              ansible_host: '{{ vm_x }}.{{ vm_domain }}'
              vm_domain: my.internal.domain.com
              vm_x: vm-0
        ungrouped: {}
    

    The only difference is that the expressions will be evaluated on demand. This means that the variables vm_x and vm_domain will be subjects of the precedence. For example the playbook

    shell> cat test-628.yml
    - hosts: all
      gather_facts: false
      tasks:
        - debug:
            var: ansible_host
    

    gives (abridged)

    ok: [a2_jump_01] => 
      ansible_host: vm-0.my.internal.domain.com
    ok: [a1_dev_01] => 
      ansible_host: vm-1.my.internal.domain.com
    ok: [a1_dev_02] => 
      ansible_host: vm-2.my.internal.domain.com
    ok: [a1_dev_03] => 
      ansible_host: vm-3.my.internal.domain.com