Reputation: 5441
I'm creating a playbook with this play:
On hosts hypervisors
:
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
What should I do to call all hosts (vm1, vm2, vm3 and vm4) in second play ?
Upvotes: 10
Views: 18421
Reputation: 5789
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.
Upvotes: 4
Reputation: 68319
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.
Upvotes: 15
Reputation: 5441
I solved this problem (with my localhost example) with following playbook. This solution is very complex, if you have a simpler one, shared it!
I didn't want to use dynamic inventories
# Get list of virtual machines in hostvars[inventory_hostname].vms
- hosts: hypervisors
gather_facts: no
tasks:
- shell: "cat {{ test_filename }}"
register: result_virsh
- set_fact:
vms: "{{ result_virsh.stdout_lines }}"
# Remove previous vm_hosts file
- hosts: localhost
gather_facts: no
tasks:
- file:
path: /tmp/vm_hosts
state: absent
# Build file vm_hosts with list of virtual machines in serial (working in parallele with same file cause some troubles)
- hosts: hypervisors
gather_facts: no
serial: 1
tasks:
- block:
- file:
path: /tmp/vm_hosts
mode: 0644
state: touch
run_once: yes
- lineinfile:
dest: /tmp/vm_hosts
line: '{{ item }}'
with_items: "{{ hostvars[inventory_hostname].vms }}"
delegate_to: localhost
# Add list of virtual machines from file vm_hosts to in-memory inventory
- hosts: localhost
gather_facts: no
tasks:
- add_host:
name: "{{ item }}"
group: "guests"
with_lines: cat /tmp/vm_hosts
- hosts: guests
gather_facts: no
tasks:
- local_action: ping
Upvotes: 0