Ansible: how to call module `add_host` for all hosts of the play

13,382

Solution 1

As you noted, there's a thing about add_host: BYPASS_HOST_LOOP = True.
So it's a kind of forced run_once.

If you don't mind running over hypervisors in sequential manner, you can simply use serial: 1:

- hosts: hypervisors
  serial: 1
  tasks:
    - shell: virsh list | awk 'NR>2' | awk '{print $2}'
      register: result_virsh
    - add_host:
        name: "{{ item }}"
        group: "guests"
      with_items: "{{ result_virsh.stdout_lines }}"

This ensures that every play batch consists of only one host, so add_host executes for every host.

Solution 2

If you don't want to run the play serially you can aggregate the results with ansible_play_hosts and map. The results can be used in the next play.

- hosts: all
  gather_facts: false
  tasks:
    - shell: virsh list | awk 'NR>2' | awk '{print $2}'
      register: result_virsh
      changed_when: false

    - add_host:
        name: "{{ item }}"
        group: guests
      changed_when: false
      loop: "{{ ansible_play_hosts | map('extract', hostvars, 'result_virsh') | map(attribute='stdout_lines') | flatten }}"

- hosts: guests
  gather_facts: false
  tasks:
    - ping:

This answer was derived from Ansible: Accumulate output across multiple hosts on task run.

Share:
13,382

Related videos on Youtube

Nelson G.
Author by

Nelson G.

Started to develop at ten with Basic. I really used the C and C++ language. Now I'm using Java/Spring/Spring-boot/Ansible

Updated on June 16, 2022

Comments

  • Nelson G.
    Nelson G. almost 2 years

    I'm creating a playbook with this play:

    On hosts hypervisors:

    • retrieve list of virtual machines from all hosts
    • use module add_host to add all of them in a new inventory group called guests

    My inventory:

    [hypervisors]
    host1
    host2
    

    My playbook:

    - hosts: hypervisors
      - shell: virsh list | awk 'NR>2' | awk '{print $2}'
        register: result_virsh
      - add_host:
          name: "{{ item }}"
          group: "guests"
        with_items: "{{ result_virsh.stdout_lines }}"
    

    Module add_host bypasses the play host loop and only runs once for all the hosts in the play.

    Then it is called once (for host1), it's a particular case of the use of this module (see link above), as if the variable run_once was implicitly fixed to true.

    How can I use it for all hosts in group hypervisors ?

    EDIT: Example to reproduce it on your computer with only localhost

    Create file /tmp/host1_test to simulate a return of guests vm1 and vm2:

    vm1
    vm2
    

    Create file /tmp/host2_test to simulate a return of guests vm3 and vm4:

    vm3
    vm4
    

    Use this inventory (test_add_host.ini) with two hosts, both with fixed IP address 127.0.0.1:

    [hypervisors]
    host1 ansible_host=127.0.0.1 test_filename=/tmp/host1_test
    host2 ansible_host=127.0.0.1 test_filename=/tmp/host2_test
    

    Use this playbook (test_add_host.yml):

    - hosts: hypervisors
      gather_facts: no
      tasks:
      - shell: "cat {{ test_filename }}"
        register: result_virsh
      - add_host:
          name: "{{ item }}"
          group: "guests"
        with_items: "{{ result_virsh.stdout_lines }}"
    
    - hosts: guests
      gather_facts: no
      tasks:
      - local_action: ping
    

    Call this playbook locally with command:

    ansible-playbook -c local -i test_add_host.ini test_add_host.yml
    
    • First play call hosts host1 and host2
    • Second play call hosts vm1 and vm2

    What should I do to call all hosts (vm1, vm2, vm3 and vm4) in second play ?

  • Nelson G.
    Nelson G. about 7 years
    Argh! I don't mind running hypervisors in serial, It was so simple in fact! THANKS!