Search code examples
ansibleansible-inventory

Run ansible-playbook with multiple groups restriction


I'm trying to run a database.yaml playbook that has the databases group as hosts, which contains all the db-* hosts from the inventory.

- name: Install PostgreSQL
  hosts: databases
---
all:
  children:
    group1:
      children:
        subgroup1:
          hosts:
            db-host1:
              ansible_host: 192.168.0.1
            cache-host2:
              ansible_host: 192.168.0.2
        subgroup2:
          hosts:
            db-host3:
              ansible_host: 192.168.0.3
            cache-host4:
              ansible_host: 192.168.0.4
    group2:
      children:
        subgroup1:
          hosts:
            db-host5:
              ansible_host: 192.168.0.5
            cache-host6:
              ansible_host: 192.168.0.6
        subgroup2:
          hosts:
            db-host7:
              ansible_host: 192.168.0.7
            cache-host8:
              ansible_host: 192.168.0.8
    databases:
      hosts:
        db-host1:
        db-host3:
        db-host5:
        db-host7:
    cache:
      hosts:
        cache-host2:
        cache-host4:
        cache-host6:
        cache-host8:

But I need to run only on those hosts that are in the group “group1,subgroup1”, I can not bind to the name of the host, because in the group subgroup1 hosts db-* can be many.

At startup with limits specified:

ansible-playbook -i inventory/demo  database.yml --limit "group1,subgroup1"

The playbook runs on all hosts in the “databases” group Could you please tell me how to properly run the playbook on multiple groups?


Solution

  • Ansible inventory is flat. Given your inventory in the file hosts the below command

    shell> ansible-inventory -i hosts --list --yaml
    

    gives

    all:
      children:
        cache:
          hosts:
            cache-host2: {}
            cache-host4: {}
            cache-host6: {}
            cache-host8: {}
        databases:
          hosts:
            db-host1: {}
            db-host3: {}
            db-host5: {}
            db-host7: {}
        group1:
          children:
            subgroup1:
              hosts:
                cache-host2:
                  ansible_host: 192.168.0.2
                cache-host6:
                  ansible_host: 192.168.0.6
                db-host1:
                  ansible_host: 192.168.0.1
                db-host5:
                  ansible_host: 192.168.0.5
            subgroup2:
              hosts:
                cache-host4:
                  ansible_host: 192.168.0.4
                cache-host8:
                  ansible_host: 192.168.0.8
                db-host3:
                  ansible_host: 192.168.0.3
                db-host7:
                  ansible_host: 192.168.0.7
        group2:
          children:
            subgroup1: {}
            subgroup2: {}
    

    You can see that the content of the groups is merged. Ansible doesn't keep the structure of the subdictionaries. Instead, the content of both subgroup1 and subgroup2 are merged. Because both group1 and group2 keep subgroup1 and subgroup2 the content of group1 and group2 is equivalent. You can test it

    - hosts: all
      tasks:
        - debug:
            msg: |
              {{ groups.group1 }}
              {{ groups.group2 }}
              {{ groups.subgroup1 }}
              {{ groups.subgroup2 }}
          run_once: true
    

    gives (abridged)

    shell> ansible-playbook -i hosts pb.yml 
    
    PLAY [all] **********************************************************************************************************
    
    TASK [debug] ********************************************************************************************************
    ok: [db-host1] => 
      msg: |-
        ['db-host1', 'cache-host2', 'db-host5', 'cache-host6', 'db-host3', 'cache-host4', 'db-host7', 'cache-host8']
        ['db-host1', 'cache-host2', 'db-host5', 'cache-host6', 'db-host3', 'cache-host4', 'db-host7', 'cache-host8']
        ['db-host1', 'cache-host2', 'db-host5', 'cache-host6']
        ['db-host3', 'cache-host4', 'db-host7', 'cache-host8']
    

    Note: Look at the Common patterns. The expression group1:&subgroup1 is an intersection of groups and means:

    any hosts in group1 that are also in subgroup1

    This expression doesn't make sense in this inventory because subgroup1 is a subset of group1.


    As a result, there is no such thing as group1.subgroup1 or group2.subgroup1 in the Ansible inventory. Instead, you can create a flat structure of groups. For example,

    shell> cat hosts2
    all:
      children:
        group1_subgroup1:
          hosts:
            db-host1:
              ansible_host: 192.168.0.1
            cache-host2:
              ansible_host: 192.168.0.2
        group1_subgroup2:
          hosts:
            db-host3:
              ansible_host: 192.168.0.3
            cache-host4:
              ansible_host: 192.168.0.4
        group2_subgroup1:
          hosts:
            db-host5:
              ansible_host: 192.168.0.5
            cache-host6:
              ansible_host: 192.168.0.6
        group2_subgroup2:
          hosts:
            db-host7:
              ansible_host: 192.168.0.7
            cache-host8:
              ansible_host: 192.168.0.8
        databases:
          hosts:
            db-host1:
            db-host3:
            db-host5:
            db-host7:
        cache:
          hosts:
            cache-host2:
            cache-host4:
            cache-host6:
            cache-host8:
    

    Then, the play below

    - hosts: all
      tasks:
        - debug:
            msg: |
              {{ groups.group1_subgroup1 }}
              {{ groups.group1_subgroup2 }}
              {{ groups.group2_subgroup1 }}
              {{ groups.group2_subgroup2 }}
          run_once: true
    

    gives (abridged)

    shell> ansible-playbook -i hosts2 pb.yml 
    
    PLAY [all] **********************************************************************************************************
    
    TASK [debug] ********************************************************************************************************
    ok: [db-host1] => 
      msg: |-
        ['db-host1', 'cache-host2']
        ['db-host3', 'cache-host4']
        ['db-host5', 'cache-host6']
        ['db-host7', 'cache-host8']