how to iterate over all specified hosts - ansible

I have a playbook that is supposed to create a config file for all specified hosts, on my monitoring_sever.
- hosts: all
gather_facts: True
hosts: monitoring_server
tasks:
- command: touch {{ hostvars[item]['ansible_fqdn'] }}
with_items: "{{ groups['all'] }}"
I execute the playbook with ansible-playbook main.yml -l "new_client, new_client2, monitoring_server"
The Resulting files on the monitoring server should look like the following:
client1.conf client2.conf
But I get an error about missing quotes, I've tried all sorts of syntax changes but I can't seem to find the problem.

Updated:
- hosts: all
gather_facts: True
tasks:
- file:
path: "{{ hostvars[item]['ansible_fqdn'] }}"
state: touch
delegate_to: host_name # Delegate task to specific host
with_items: "{{ groups['all'] }}"
You have typos in your original playbook.
with:items should be with_items
items should be item
Usage of delegate_to: http://docs.ansible.com/ansible/playbooks_delegation.html#delegation
As long as you are targeting all hosts, you don't have to make a loop as Ansible executes tasks on all targeted hosts unless excluded by condition.
On the other hand, I would suggest using file module instead of command to touch the file.
- hosts: all
tasks:
- name: Touch a file
file:
path: "{{ ansible_fqdn }}"
state: touch
PS. I assumed ansible_fqdn is a host var you defined for each host.

You need to fix:
with_items: instead of with:items:
item instead of items
a single hosts: declaration in each item on the list of plays
This should work for your case:
---
- hosts: all
gather_facts: true
- hosts: monitoring_server
tasks:
- command: touch {{ hostvars[item]['ansible_fqdn'] }}
with_items: "{{ groups['all'] }}"
Alternatively you can use delegate_to: localhost and completely drop the loop as well as the reference to hostvars:
---
- hosts: all
gather_facts: true
tasks:
- command: touch {{ ansible_fqdn }}
delegate_to: localhost

Related

Getting ansible_play_hosts from previous play?

I have an ansible playbook that interacts with the management card in a bunch of servers, and then produces a report based on that information. Structurally it looks like:
- hosts: all
tasks:
- name: do something with redfish
uri:
...
register: something
- hosts: localhost
tasks:
- name: produce report
template:
...
loop: "{{ SOME_LIST_OF_HOSTS }}"
Originally, the template task in the second was looping over groups.all, but that causes a number of complications if we limited the target hosts using -l on the command line (like ansible-playbook -l only_cluster_a ...). In that case, I would like the template task to loop over only the hosts targeted by the first play. In other words, I want to know ansible_play_hosts_all from the previous play.
This is what I've come up with:
- hosts: all
gather_facts: false
tasks:
- delegate_to: localhost
delegate_facts: true
run_once: true
set_fact:
saved_play_hosts: "{{ ansible_play_hosts_all }}"
...other tasks go here...
- hosts: localhost
gather_facts: false
tasks:
- debug:
msg:
play_hosts: "{{ saved_play_hosts }}"
Is that the best way of doing this?
you could use add_host module: at the end of first play you add a task:
- name: add variables to dummy host
add_host:
name: "variable_holder"
shared_variable: "{{ saved_play_hosts }}"
and you could trap the value in second play:
- name: second play
hosts: localhost
vars:
play_hosts: "{{ hostvars['variable_holder']['shared_variable'] }}"
tasks:
:
:

how to get inventory_hostanme and ansible_ssh_hosts info by running playbook on localhost

I want to write hostname and ssh_host under a specific group from an inventory file to a file in my localhost.
I have tried this:
my_role
set_fact:
hosts: "{{ hosts_list|default({}) | combine( {inventory_hostname: ansible_ssh_host} ) }}"
when: "'my_group' in group_names"
Playbook
become: no
gather_facts: no
roles:
- my_role
But now if i try to write this to a file in another task, it will create a file for the hosts in inventory file.
Can you please suggest if there is a better way to create a file containing dictionary with inventory_hostname and ansible_ssh_host as key and value respectively, by running playbook on localhost.
An option would be to use lineinfile and delegate_to localhost.
- hosts: test_01
tasks:
- set_fact:
my_inventory_hostname: "{{ ansible_host }}"
- tempfile:
delegate_to: localhost
register: result
- lineinfile:
path: "{{ result.path }}"
line: "inventory_hostname: {{ my_inventory_hostname }}"
delegate_to: localhost
- debug:
msg: "inventory_hostname: {{ ansible_host }}
stored in {{ result.path }}"
Note: There is no need to quote the conditions. Conditions are expanded by default.
when: my_group in group_names
Thanks a lot for your answer#Vladimir Botka
I came up with another requirement to write the hosts belonging to a certain group to a file, below code can help with that (adding to #Vladimir's solution).
- hosts: all
become: no
gather_facts: no
tasks:
- set_fact:
my_inventory_hostname: "{{ ansible_host }}"
- lineinfile:
path: temp/hosts
line: "inventory_hostname: {{ my_inventory_hostname }}"
when: inventory_hostname in groups['my_group']
delegate_to: localhost
- debug:
msg: "inventory_hostname: {{ ansible_host }}"

Run ansible-playbook from localhost, and using vars from hosts file

Let's say that I want to run something locally. but I want to use the vars from the hosts file, so basically - I want to do for each line something locally.
In this example, I want to use ec2_tag from ansible.
hosts file for ansible playbook run:
[any]
123.123.123.123 region=eu-region ec2_instance_id=x-xxxxxxxxxxxxxxxxx
123.123.123.124 region=eu-region ec2_instance_id=x-xxxxxxxxxxxxxxxxx
ansible-playbook:
- name: something
hosts: any
tasks:
- name: test
ec2_tag:
region: "{{ region }}"
resource: "{{ ec2_instance_id }}""
state: list
register: ec2_tags
- debug: msg={{ ec2_tags }}
How can i loop localy on [any] vars? let's say get region?
It's running now with local_action and taking the vars from the hosts file.
- name: something
hosts: any
tasks:
- name: test
local_action: ec2_tag region={{ region }} resource={{ ec2_instance_id }} state=list
register: ec2_tags
- debug: msg={{ ec2_tags }}

lineinfile ansible module skips a line

I have a need to know the index of host names in the inventory. I am using the below code to create a variable file that I can use in a subsequent play book
- name: Debug me
hosts: hosts
tasks:
- debug: msg="{{ inventory_hostname }}"
- debug: msg="{{ play_hosts.index(inventory_hostname) }}"
- local_action: 'lineinfile create=yes dest=/tmp/test.conf
line="host{{ play_hosts.index(inventory_hostname) }}=
{{ inventory_hostname }}"'
I have the following inventory file
[hosts]
my.host1.com
my.host2.com
Now when I run this, the test.conf that gets generated under /tmp sometimes has both hostnames like this
host1= my.host2.com
host0= my.host1.com
when I run the same playbook a few times each time emptying the test.conf before running. quite a few times the file only has one entry
host1= my.host2.com
or
host0= my.host1.com
how come the same ansible playbook behaving differently?
I believe the issue is your running two threads against different hosts, and using local_action is not thread safe.
Try using the serial keyword:
- name: Debug me
hosts: hosts
serial: 1
tasks:
- debug: msg="{{ inventory_hostname }}"
- debug: msg="{{ play_hosts.index(inventory_hostname) }}"
- local_action: 'lineinfile create=yes dest=/tmp/test.conf
line="host{{ play_hosts.index(inventory_hostname) }}=
{{ inventory_hostname }}"'
Edit: A better way to do this if just trying to operate on the list of host in inventory on the localhost, would be to avoid doing the action on the host and using local_action in the first place.
- name: Debug me
hosts: localhost
tasks:
- lineinfile:
create: yes
dest: /tmp/test.conf
line: "host{{ groups['hosts'].index(item)}}={{ item }}"
with_items: " {{ groups['hosts'] }}"
This will get you the results you desire. Then you can add another play to do operations against the hosts themselves.
The solution I am trying to avoid problems with race conditions with non-thread safe Local_action: lineinfile to write gathered data to local file. Split it across 2 different plays in the same file.
eg:
- name: gather_date
hosts: all
any_errors_fatal: false
gather_facts: no
tasks:
- name: get_Aptus_device_count_list
shell: gather_data.sh
become: true
register: Aptus_device_count_list
changed_when: false
- name: Log_gathered_date
hosts: all
any_errors_fatal: false
gather_facts: no
tasks:
- name: log_gathered_info
local_action:
module: lineinfile
dest: /home/rms-mit/MyAnsible/record_Device_count_collection.out
line: "\n--- {{ inventory_hostname }} --- \n
{{ Aptus_device_count_list.stdout }} \n.\n---\n"
changed_when: false

Ansible: register content not available for other host

Below is a part of a playbook in Ansible 2.1:
- hosts: localhost
any_errors_fatal: true
tasks:
- name: Bla Bla
file: path=/var/tmp/somedir state=directory
#ignore_errors: no
- name: Create directory for every host
file: path=/var/tmp/somedir/{{ item }} state=directory
with_items: "{{ groups['XYZ'] }}"
- name: Get File contents of NewFile
shell: cat NewFile.txt executable=/bin/bash
register: file_contents
- hosts: XYZ
#any_errors_fatal: true
vars:
num_hosts: "{{ groups['XYZ'] | length }}"
serial: num_hosts
tasks:
- name: Copy files to corresponding directories
vars:
path: /var/tmp/somedir/{{ item[0] }}
synchronize: mode=pull src={{ item[1] }} dest={{ path }}
with_nested:
- "{{ groups['XYZ'] }}"
- with_lines: cat NewFile.txt
This does not work.
Now the problem is i am not able to reference file_contents which has been registered under localhost and Ansible is not supporting to cat the NewFile from the hosts: XYZ
Is there any way to do this in some simple manner? I need to check contents of the NewFile in this playbook only and then use the same to copy files from remote to local.
As mentioned in the comments, facts (or all variables) are stored on a host basis. If you have registered a values from a task running on localhost, you can access it from any task running in context of other hosts through the global hostvars dict. All hosts and their facts are stored in there:
hostvars['localhost']['file_contents']
I am not entirely sure simply registered variables are available in the hostvars dict. If not, you have to use set_fact in the first play to store it as a fact.

Resources