Search code examples
ansibleansible-inventory

Ansible - how to launch playbook only on the first host of each inventory group


I want to launch my playbook only on the first host of each inventory group.

[ego]
server1
server2

[asp]
server1
server2

[bre]
server1
server2

I saw there is an option to specify group_name but this is just for 1 group_name

hosts: group_name[0]

This option will only run it on 1 host in general and doesn't take into account the groups.

The run_once:True

Is there a way to run the playbook or tasks over the first host of all groups without defining which groups in the playbook.

So when executing the playbook i want to be able to select different groups as a limit and only run the play against the first host of each group.


Solution

  • You can use add_host module to build a new group containing only the first host of every group in the inventory.

    - hosts: all
      gather_facts: no
      tasks:
      # groups.keys() gets all groups names. I will exclude 'all' and 'ungrouped'
      # solutions to do that in a better way are welcomed
      - set_fact:
          groups_names: "{{ groups.keys() | difference(['all'])| difference(['ungrouped']) }}"
        run_once: true
     
      # Add first host from every group to new_group
      - add_host:
          name: "{{ groups[item][0] }}"
          groups: new_group
        loop: "{{ groups_names }}"
        changed_when: false
    
      - debug:
          msg: "{{ inventory_hostname }}"
        when: inventory_hostname in groups['new_group']
    
    

    My inventory:

    [test]
    test-001
    test-002
    
    [staging]
    staging-001
    staging-002
    staging-003
    
    [prod]
    prod-001
    prod-002
    

    The output:

    PLAY [all] *************************************************
    
    TASK [set_fact] ********************************************
    ok: [test-001]
    
    TASK [add_host] ********************************************
    ok: [test-001] => (item=test)
    ok: [test-001] => (item=staging)
    ok: [test-001] => (item=prod)
    
    TASK [debug] ***********************************************
    skipping: [test-002]
    ok: [test-001] => {
        "msg": "test-001"
    }
    skipping: [staging-002]
    ok: [staging-001] => {
        "msg": "staging-001"
    }
    skipping: [staging-003]
    skipping: [prod-002]
    ok: [prod-001] => {
        "msg": "prod-001"
    }
    
    PLAY RECAP ***************************************************
    prod-001    : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    prod-002    : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
    staging-001 : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    staging-002 : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
    staging-003 : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
    test-001    : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    test-002    : ok=0    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0