Single task launch in a group of hosts with the same server address

Viewed 30

I have an Inventory file with this format.

group_host:
  hosts:
    d1:
      ansible_host: address-server
    d2:
      ansible_host: address-server
    d3:
      ansible_host: address-server

The server address is the same for all host variables (d1, d2, d3). When I run the playbook, the task will be executed on each variable in this case three times on the same server. How can we make it a condition that the task is only executed once if the addresses-servers in the host group are the same? And how can I make the task run once for every unique server address?

1 Answers

Create a new inventory group in the first play and use it in the second.

For example, get a list of variables ansible_host

ansible_hosts: "{{ ansible_play_hosts_all|
                   map('extract', hostvars, 'ansible_host')|
                   list }}"

gives

ansible_hosts:
  - address-server
  - address-server
  - address-server

Create a dictionary

ansible_hosts_dict: "{{ dict(ansible_play_hosts_all|zip(ansible_hosts)) }}"

gives

ansible_hosts_dict:
  d1: address-server
  d2: address-server
  d3: address-server

Create a new group. Convert the dictionary to a list and iterate it using the groupby filter

    - add_host:
        groups: group_host_unique
        host: "{{ item.1.0.key }}"
        ansible_host: "{{ item.0 }}"
      loop: "{{ ansible_hosts_dict|dict2items|groupby('value') }}"

This creates the new inventory group group_host_unique with unique values of ansible_host. The first host is taken if there are more hosts with the same value of ansible_host. As a result, the tasks in the play below are executed only once for hosts with the same server address

- hosts: group_host_unique
  gather_facts: false
  tasks:
    - debug:
        var: inventory_hostname

gives

ok: [d1] => 
  inventory_hostname: d1

Example of a complete playbook

- hosts: group_host
  gather_facts: false
  vars:
    ansible_hosts: "{{ ansible_play_hosts_all|
                       map('extract', hostvars, 'ansible_host')|
                       list }}"
    ansible_hosts_dict: "{{ dict(ansible_play_hosts_all|zip(ansible_hosts)) }}"
  tasks:
    - add_host:
        groups: group_host_unique
        host: "{{ item.1.0.key }}"
        ansible_host: "{{ item.0 }}"
      loop: "{{ ansible_hosts_dict|dict2items|groupby('value') }}"
      run_once: true

- hosts: group_host_unique
  gather_facts: false
  tasks:
    - debug:
        var: inventory_hostname

Test it with various values of ansible_host. For example,

shell> cat hosts
group_host:
  hosts:
    d1:
      ansible_host: address-server1
    d2:
      ansible_host: address-server1
    d3:
      ansible_host: address-server2

gives (abridged)

ok: [d1] => 
  inventory_hostname: d1
ok: [d3] => 
  inventory_hostname: d3
Related