Search code examples
ansibleansible-inventoryansible-factsansible-template

ansible - how to iterate children groups in ansible?


I do have an inventory file as below

[ParentGroup]
ChildrenGroup1
ChildrenGroup2

[ChildrenGroup1]
host1
host2
host3

[ChildrenGroup2]
host4
host5
host6

Now i want to iterate Children wise..

i.e. Perform my task in parallel on host1,host2, host3 i.e only on hosts exists inChildrenGroup1 and once this is success, i Need to go with ChildrenGroup2 i.e on host4, host5, host6

Points to be taken care ?

  1. if there is any failure on any one of the childrengroup hosts then we need to wait/pause before proceeding with next children group
  2. I shall have many children groups on my inventory
  3. I need to action my task only on one chidlrengroup at a time.
  4. I shall make sure all the childrengroups are addressed in one-shot too.

Can you suggest on how to take this forward ?


Solution

  • The critical limitation here is the fact that a playbook can't start another playbook. The only option is import_playbook. Imported files must be available when a playbook starts. As a result, the solution is a two-step process. Create the playbooks in the first step and then run them. For example, given the inventory

    shell> cat hosts
    [ParentGroup:children]
    ChildrenGroup1
    ChildrenGroup2
    
    [ChildrenGroup1]
    host1
    host2
    host3
    
    [ChildrenGroup2]
    host4
    host5
    host6
    

    you want to run the playbook pb.yml as described in the question. Take the playbook and create the template by putting {{ item }} to hosts:

    shell> cat pb.yml.j2
    - hosts: "{{ item }}"
      gather_facts: false
      tasks:
        - debug:
            msg: "{{ inventory_hostname }}: Playbook started."
    

    1. Create playbooks

    The playbook below creates the list of the groups my_groups in the first task. Then the template task iterates this list and creates playbooks for the groups. The next template task imports these playbooks into the playbook pb-groups.yml

    shell> cat pb-init.yml
    - hosts: localhost
      vars:
        groups_other: [ParentGroup, all, ungrouped]
      tasks:
        - set_fact:
            my_groups: "{{ groups.keys()|difference(groups_other) }}"
        - template:
            src: pb.yml.j2
            dest: "pb-{{ item }}.yml"
          loop: "{{ my_groups }}"
        - template:
            src: pb-groups.yml.j2
            dest: pb-groups.yml
    
    shell> cat pb-groups.yml.j2
    - hosts: localhost
      gather_facts: false
    
    {% for group in my_groups %}
    - import_playbook: pb-{{ group }}.yml
    {% endfor %}
    

    See created files

    shell> cat pb-ChildrenGroup1.yml 
    - hosts: "ChildrenGroup1"
      gather_facts: false
      tasks:
        - debug:
            msg: "localhost: Playbook started."
    
    shell> cat pb-ChildrenGroup2.yml 
    - hosts: "ChildrenGroup2"
      gather_facts: false
      tasks:
        - debug:
            msg: "localhost: Playbook started."
    
    shell> cat pb-groups.yml
    - hosts: localhost
      gather_facts: false
    
    - import_playbook: pb-ChildrenGroup1.yml
    - import_playbook: pb-ChildrenGroup2.yml
    

    2. Run created playbooks

    shell> ansible-playbook pb-groups.yml
    
    PLAY [localhost] ****
    
    PLAY [ChildrenGroup1] ****
    
    TASK [debug] ****
    ok: [host1] => 
      msg: 'localhost: Playbook started.'
    ok: [host2] => 
      msg: 'localhost: Playbook started.'
    ok: [host3] => 
      msg: 'localhost: Playbook started.'
    
    PLAY [ChildrenGroup2] ****
    
    TASK [debug] ****
    ok: [host4] => 
      msg: 'localhost: Playbook started.'
    ok: [host5] => 
      msg: 'localhost: Playbook started.'
    ok: [host6] => 
      msg: 'localhost: Playbook started.'
    
    PLAY RECAP ****
    
      ...
    
    

    Many children groups on my inventory

    Change the inventory. For example

    shell> cat hosts
    [ParentGroup:children]
    ChildrenGroup1
    ChildrenGroup2
    ChildrenGroup3
    
    [ChildrenGroup1]
    host1
    host2
    
    [ChildrenGroup2]
    host4
    host5
    
    [ChildrenGroup3]
    host3
    host6
    

    The commands below work as expected

    shell> ansible-playbook pb-init.yml
      ...
    shell> ansible-playbook pb-groups.yml
    
    PLAY [localhost] ****
    
    PLAY [ChildrenGroup1] ****
    
    TASK [debug] ****
    ok: [host1] => 
      msg: 'localhost: Playbook started.'
    ok: [host2] => 
      msg: 'localhost: Playbook started.'
    
    PLAY [ChildrenGroup2] ****
    
    TASK [debug] ****
    ok: [host4] => 
      msg: 'localhost: Playbook started.'
    ok: [host5] => 
      msg: 'localhost: Playbook started.'
    
    PLAY [ChildrenGroup3] ****
    
    TASK [debug] ****
    ok: [host3] => 
      msg: 'localhost: Playbook started.'
    ok: [host6] => 
      msg: 'localhost: Playbook started.'
    
    PLAY RECAP ****
    
      ...