Accessing the entire Ansible Inventory from group playbook - ansible

I am trying to get a list of the IP's of all the hosts in my inventory file from a playbook that only runs in a single group.
Assume the following inventory file:
[dbservers]
db1.example.com
db2.example.com
[webservers]
www1.example.com
www2.example.com
And the playbook:
---
- hosts: dbservers
roles:
- dosomething
And the dosomething role:
- name: print all host ips
template: src=hosts.j2 dest=/tmp/hosts.txt
And the hosts.j2 template:
{% for host in hostvars %}
{{ hostvars[host].ansible_eth0.ipv4.address }}
{% endfor %}
Problem:
When running this, I only ever get the dbserver ip's listed, not all ip's
Question:
How can I gain access to the entire inventory from within this playbook? Changing the hosts to all in the playbook works, but then the dosomething playbook also runs on all hosts, which is not what I want. I only want the list on the dbservers.

In order to gain access to all the hosts in hostvars, you first have to create a task for all hosts. I created a simple role that would simple echo something on all hosts. This role then forces gather facts on all hosts and add each to the hostvars group.
Please note that if you then run the playbook with a tag limit, the hostvars group is again effected.
I got the tip here: https://groups.google.com/forum/#!msg/Ansible-project/f90Y4T4SJfQ/L1YomumcPEQJ

The special variable groups is probably what you want to do this, in your case the value of groups will be:
"groups" : {
"dbservers": [
"db1.example.com",
"db2.example.com"
],
"webservers": [
"www1.example.com",
"www2.example.com"
]
}
which you can loop over in your jinja template.

Related

Ansible how to store output of register in list when iterated over inventory

I am running a shell command, this command runs for all hosts listed in my inventory file. I am then using register to define the variable, when i retrieve these values for debug messages i see register variable for all hosts printed for all IP in my inventory but i want to store them in a list so that i can use them in templates. How can we achieve it?
- name: Command
shell: hostname -f
register: fqdn_name
For your specific question, you are doing more work than you need to. Each time Ansible runs against a host, it collects a series of 'facts' about the host and stores them in a dictionary available during your plays. Therefore, replace your existing Command task with the following, to see what I mean:
- name: Display the Ansible FQDN fact
debug:
var: ansible_fqdn
Running ansible -m setup <hostname taken from inventory file> will show you all the variables that get collected.
The variables for all your hosts are made available through a special dictionary called 'hostvars', therefore in your template you can do something like this:
{% for host in groups.all %}
{{ hostvars[host]['ansible_fqdn'] }}
{% endfor %}
You could replace groups.all with groups.<some inventory groupname> to limit the matched hosts to a particular group.
One possible gotcha here, is that these facts will only have been collected if Ansible has already targeted a host, therefore one strategy for more complex playbooks is:
# This play simply connects to all your hosts and gathers facts
- hosts: all
gather_facts: yes
# Now all subsequent plays have access to facts for all hosts
- hosts: <all or some group>
tasks: ...

Using Host Group as Variable in Ansible Task

I'm working on putting together a playbook that will deploy local facts scripts to various groups in my Ansible inventory, and I would to be able to utilize the group name being worked on as a variable in the tasks themselves. Assume for this example that I have the traditional Ansible roles directory structure on my Ansible machine, and I have subdirectories under the "files" directory called "apache", "web", and "db". I'll now illustrate by example, ...
---
- hosts: apache:web:db
tasks:
- name: Set facts for facts directories
set_fact:
facts_dir_local: "files/{{ group_name }}"
facts_dir_remote: "/etc/ansible/facts.d"
- name: Deploy local facts
copy:
src: "{{ item }}"
dest: "{{ facts_dir_remote }}"
owner: ansible
group: ansible
mode: 0750
with_fileglob:
- "{{ facts_dir_local }}/*.fact"
The goal is to have {{ group_name }} above take on the value of "apache" for the hosts in the apache group, "web" for the hosts in the web group, and "db" for the hosts in the db group. This way I don't have to copy and paste this task and assign custom variables for each group. Any suggestions for how to accomplish this would be greatly appreciated.
While there is no group_name variable in ansible, there is a group_names (plural). That is because any host may be part of one or more groups.
It is described in the official documentation as
group_names
List of groups the current host is part of
In the most common case each host would only be part of one group and so you could simply say group_names[0] to get what you want.
TLDR;
Use group_names[0].
You can use group variables to achieve this, either specified in the inventory file or in separate group_vars/<group> files - see https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html
Note though that these group variables are squashed into host variables when you run the playbook. Hosts that are listed in multiple groups will end up with variables based on a precedence order

What is the syntax to make Host group a variable in "when inventory_hostname"?

I recently discovered how use "when inventory_hostname" to set_fact for the first host in an host group. I was wondering how to pass a variable as the host group. In my testing I use the following:
Inventory file:
---
[test]
test-001.example.com
test-002.example.com
vars file:
---
declared_hostgroup: test
playbook:
- name: set first host in group as master
set_fact:
test_order: MASTER
when: inventory_hostname == group.test[0]
That works great. But I would like to replace "test" in "group.test" with the variable "declared_hostgroup". I've tried {{ }} syntax with no success. Any suggestions would be really appreciated.
This is the correct syntax:
when: inventory_hostname == group[declared_hostgroup][0]
But keep in mind that although Ansible tries to keep order of host consistent, it can break sometime in the future (e.g. different sort order or some other quirks), so you may want to mark your host inside inventory for clarity.

How to make Ansible playbook run on first host in the group?

How can I run a playbook only on first host in the group?
I am expecting something like this:
---
- name: playbook that only run on first host in the group
hosts: "{{ groups[group_name] | first }}"
tasks:
- debug:
msg: "on {{ inventory_hostname }}"
But this doesn't work, gives error:
'groups' is undefined
How can I make it work?
You can use:
hosts: group_name[0]
Inventory hosts values (specified in the hosts directive) are processed with a custom parser, which does not allow Jinja2 expressions like the regular template engine does.
Read about Patterns.

Ansible inventory host file values in playbook

looking for ways to map replsetB to a hostname/ipaddress in the /etc/ansible/hosts inventory file? Goal is to be able to use the hosts in inventory files in playbooks as variables
Please read: How To Access Information About Other Hosts.
- debug:
msg: "This is replsetB ip {{ hostvars['replsetB'].ansible_host }}"

Resources