Ashar
Ashar

Reputation: 3245

Ansible - How to build dynamic inventory group from inventory host file

Below is sample inventory host file:

cat inventory.hosts

[dev_flipkart_app]
myhost6 ansible_user=fappuser
myhost9 ansible_user=fappuser
[dev_amazon_app]
myhost1 ansible_user=aappuser
[dev_snapdeal_app]
myhost4 ansible_user=sappuser

Below is my playbook main.yml

---
  - name: Playbook
    hosts: "{{ ENV }}_{{ appname }}_app"
    tasks:
      - name: ensure apache is at the latest version
        yum:
          name: httpd
          state: latest

This works fine when single {{ appname }} is passed, but how to i build a dynamic inventory from inventory.hosts using add_host when multiple {{ appname }} is passed?

ansible-playbook -i inventory.hosts main.yml -e ENV=dev -e appname="flipkart,amazon"

Expected dynamic host group should be as below:

myhost6 ansible_user=fappuser
myhost9 ansible_user=fappuser
myhost1 ansible_user=aappuser

Kindly suggest.

Upvotes: 1

Views: 1287

Answers (2)

Vladimir Botka
Vladimir Botka

Reputation: 68044

For example, the playbook

- hosts: "{{ [ENV]|product(appname.split(','))|product(['app'])|
                   map('flatten')|map('join', '_') }}"
  tasks:
    - debug: var=ansible_user

gives (abridged)

shell> ansible-playbook pb.yml -e ENV=dev -e appname="flipkart,amazon"

...

ok: [myhost6] => 
  ansible_user: fappuser
ok: [myhost9] => 
  ansible_user: fappuser
ok: [myhost1] => 
  ansible_user: aappuser

The next option is to compose a group. See

shell> ansible-doc -t inventory constructed

Create the inventory files

shell> cat hosts/01-hosts 
[dev_flipkart_app]
myhost6 ansible_user=fappuser
myhost9 ansible_user=fappuser
[dev_amazon_app]
myhost1 ansible_user=aappuser
[dev_snapdeal_app]
myhost4 ansible_user=sappuser
shell> cat hosts/02-constructed.yml
plugin: constructed
strict: True
use_extra_vars: True
compose:
  my_dev_regex: ENV
  my_appname_regex: appname.split(',')|join('|')
  my_groups: group_names
  my_composed_group: group_names|
                     select('search', ENV)|
                     select('search', appname.split(',')|join('|'))
groups:
  my_composed_group: my_groups|
                     select('search', my_dev_regex)|
                     select('search', my_appname_regex)|
                     length > 0

and enable the constructed plugin in the configuration. For example,

shell> grep constructed ansible.cfg
enable_plugins = ini, constructed

Test the inventory. For example,

shell> ansible-inventory -e ENV=dev -e appname="flipkart,amazon" --list --yaml
all:
  children:
    dev_amazon_app:
      hosts:
        myhost1:
          ENV: dev
          ansible_user: aappuser
          appname: flipkart,amazon
          my_appname_regex: flipkart|amazon
          my_composed_group:
          - dev_amazon_app
          my_dev_regex: dev
          my_groups:
          - dev_amazon_app
    dev_flipkart_app:
      hosts:
        myhost6:
          ENV: dev
          ansible_user: fappuser
          appname: flipkart,amazon
          my_appname_regex: flipkart|amazon
          my_composed_group:
          - dev_flipkart_app
          my_dev_regex: dev
          my_groups:
          - dev_flipkart_app
        myhost9:
          ENV: dev
          ansible_user: fappuser
          appname: flipkart,amazon
          my_appname_regex: flipkart|amazon
          my_composed_group:
          - dev_flipkart_app
          my_dev_regex: dev
          my_groups:
          - dev_flipkart_app
    dev_snapdeal_app:
      hosts:
        myhost4:
          ENV: dev
          ansible_user: sappuser
          appname: flipkart,amazon
          my_appname_regex: flipkart|amazon
          my_composed_group: []
          my_dev_regex: dev
          my_groups:
          - dev_snapdeal_app
    my_composed_group:
      hosts:
        myhost1: {}
        myhost6: {}
        myhost9: {}
    ungrouped: {}

Create a playbook and use the group my_composed_group

- hosts: my_composed_group
  tasks:
    - debug: var=ansible_user

This playbook gives the same results

shell> ansible-playbook pb.yml -e ENV=dev -e appname="flipkart,amazon"

...

ok: [myhost6] => 
  ansible_user: fappuser
ok: [myhost9] => 
  ansible_user: fappuser
ok: [myhost1] => 
  ansible_user: aappuser

Upvotes: 1

mdaniel
mdaniel

Reputation: 33203

You seem to have noticed that hosts: can be a jinja2 expression, but then stopped short of realizing that hosts: can be a jinja2 expression

- hosts: "{{ appname | split(',') | map('regex_replace', '(.+)', ENV ~ '_\\1_app') }}"
  tasks:
  - debug: var=ansible_user

when run with your cited example command line ansible-playbook -i inventory.hosts main.yml -e ENV=dev -e appname="flipkart,amazon" produces

ok: [myhost6] => {
    "ansible_user": "fappuser"
}
ok: [myhost9] => {
    "ansible_user": "fappuser"
}
ok: [myhost1] => {
    "ansible_user": "aappuser"
}

Upvotes: 2

Related Questions