All I could find was this from the docs:
Additionally, inventory_hostname is the name of the hostname as configured in Ansible’s inventory host file. This can be useful for when you don’t want to rely on the discovered hostname ansible_hostname or for other mysterious reasons. If you have a long FQDN, inventory_hostname_short also contains the part up to the first period, without the rest of the domain.
Is there any actual difference between inventory_hostname and ansible_hostname variables in Ansible? If so, then which one should I use and when?
inventory_hostname - As configured in the ansible inventory file (eg: /etc/ansible/hosts). It can be an IP address or a name that can be resolved by the DNS
ansible_hostname - As discovered by ansible. Ansible logs into the host via ssh and gathers some facts. As part of the fact, it also discovers its hostname which is stored in ansible_hostname.
Which one should you use?
hostvars is a dictionary which has an entry for each inventory host. If you want to access host information, you need to use the inventory_hostname. If you want to use/print the name of the host as configured on the host, you should use ansible_hostname since most likely the IP will be used in the inventory file.
Important: To use ansible_hostname, you need to gather facts:
gather_facts: true
Otherwise, you will get a message that ansible_hostname is not defined.
"ansible_hostname": "VARIABLE IS NOT DEFINED!"
Try this with one host to understand the differences
tasks:
- debug: var=inventory_hostname
- debug: var=ansible_hostname
- debug: var=hostvars
Related
I'm trying to create a playbook which basically consists 2 hosts init; (don't ask why)
---
- hosts: all
tasks:
- name: get the hostname of machine and save it as a variable
shell: hostname
register: host_name
when: ansible_host == "x.x.x.x" *(will be filled by my application)*
- hosts: "{{ host_name.stdout }}"
tasks:
- name: use the variable as hostname
shell: whoami
I don't have any hostname information in my application so I need to trigger my playbook with an IP address, then i should get the hostname of that machine and save it to a variable to use in my other tasks to avoid "when" command for each task.
The problem is that I'm able to use "host_name" variable in all other fields except "hosts", it gives me an Error like this when i try to run;
ERROR! The field 'hosts' has an invalid value, which includes an undefined variable. The error was: 'host_name' is undefined
Screenshot of the error
By default, Ansible itself gathers some information about a host. This happens at the beginning of a playbook's execution right after PLAY in TASK [Gathering Facts].
This automatic gathering of information about a system can be turned off via gather_facts: no, by default this is active.
This collected information is called Ansible Facts. An example of the collected facts is shown in the Ansible Docs, for your host you can print out all Ansible Facts:
either in the playbook as a task:
- name: Print all available facts
debug:
var: ansible_facts
or via CLI as an adhoc command:
ansible <hostname> -m setup
The Ansible Facts contain values like: ansible_hostname, ansible_fqdn, ansible_domain or even ansible_all_ipv4_addresses. This is the simplest way to act with the hostname of the client.
If you want to output the hostname and IP addresses that Ansible has collected, you can do it with the following tasks for example:
- name: Print hostname
debug:
var: ansible_hostname
- name: Print IP addresses
debug:
var: ansible_all_ipv4_addresses
If you start your playbook for all hosts, you can check the IP address and also stop it directly for the "wrong" clients.
---
- hosts: all
tasks:
- name: terminate execution for wrong hosts
assert:
that: '"x.x.x.x" is in ansible_all_ipv4_addresses'
fail_msg: Terminating because IP did not match
success_msg: "Host matched. Hostname: {{ ansible_hostname }}"
# your task for desired host
Running Ansible 2.9.3
Working in a large environment with hosts coming and going on a daily basis, I need to use wildcard hostnames in a host group: ie:
[excluded_hosts]
host01
host02
host03
[everyone]
host*
in my playbook I have
name: "Test working with host groups"
hosts: everyone,!excluded_hosts
connection: local
tasks:
The problem is, the task is running on hosts in the excluded group.
If I specifically list one of the excluded hosts in the everyone group, that host then gets properly excluded.
So Ansible isn't working as one might assume it would.
What's the best way to get this to work?
I tried:
hosts: "{{ ansible_hostname }}",!excluded_hosts
but it errored as invalid yaml syntax.
requirements: I can not specifically list each host, they come and go too frequently.
The playbooks are going to be automatically copied down to each host and the execution started afterwards, therefore I need to use the same ansible command line on all hosts.
I was able to come up with a solution to my problem:
---
- name: "Add host name to thishost group"
hosts: localhost
connection: local
tasks:
- name: "add host"
ini_file:
path: /opt/ansible/etc/hosts
section: thishost
option: "{{ ansible_hostname }}"
allow_no_value: yes
- meta: refresh_inventory
- name: "Do tasks on all except excluded_hosts"
hosts: thishost,!excluded_hosts
connection: local
tasks:
What this does is it adds the host's name to a group called "thishost" when the playbook runs. Then it refreshs the inventory file and runs the next play.
This avoids a having to constantly update the inventory with thousands of hosts, and avoids the use of wildcards and ranges.
Blaster,
Have you tried assigning hosts by IP address yet?
You can use wildcard patterns ... IP addresses, as long as the hosts are named in your inventory by ... IP address:
192.0.\*
\*.example.com
\*.com**
https://docs.ansible.com/ansible/latest/user_guide/intro_patterns.html
I have my hosts in an inventory file as below:
cnamgw01b ansible_ssh_host=172.17.0.26
cnamgw01a ansible_ssh_host=172.17.1.26
cnamgw02b ansible_ssh_host=172.17.0.23
cnamgw02a ansible_ssh_host=172.17.1.23
cnamgw03a ansible_ssh_host=172.17.1.13
cnamgw03b ansible_ssh_host=172.17.0.13
These are new builds and I would like to set the hostname based on the inventory file. I already have a script in place that updated the inventory file as new VM's are turned up and assigns a random hostname. I would like to take this hostname assigned and set it as the hosts hostname. How can I accomplish this? Also note that I also use folders to subdivide the hosts by region
You can use the ansible module hostname to set hostname.
https://docs.ansible.com/ansible/latest/modules/hostname_module.html
- hosts: all
tasks:
- name: Set hostname
hostname:
name: {{ inventory_hostname }}
You could run something like this to set the system hostname to the inventory hostname:
- hosts: all
tasks:
- name: set system hostname
command: hostnamectl set-hostname {{ inventory_hostname }}
That is, the variable inventory_hostname holds the name of the current host as it was named in your inventory.
This task assumes you have the hostnamectl command available. You could instead write the value of inventory_hostname to /etc/hostname and call the hostname command separately.
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: ...
I have to copy files, which are target specific files. I have stored these files in my machine as their target hostnames.
Example:
/tmp/Server1.cfg
/tmp/Server2.cfg
host file has
Server1
Server2
When my playbook runs for Server1 it should copy Server1.cfg.
When my playbook runs for Server2 it should copy Server2.cfg.
How can I achieve this ?
Thanks.
PS: Please be explicit as I am still a toddler in ansible
You may want to read some chapters at docs.ansible.com:
Additionally, inventory_hostname is the name of the hostname as configured in Ansible’s inventory host file. This can be useful for when you don’t want to rely on the discovered hostname ansible_hostname or for other mysterious reasons.
So, in your case:
- copy:
src: "{{ inventory_hostname }}"
dest: "/tmp/{{ inventory_hostname }}.cfg"