Ansible - Access inventory alias - ansible

Having an inventory file like:
[my_hosts]
my_host ansible_ssh_host=123.123.123.123
my_host2 ansible_ssh_host=234.234.234.234
I want to gather some debug information in my templates.
How do I acces the alias variable in a playbook/template?
I.e.:
debug: msg=Myhost is {{ ansible_host_alias }}
# Myhost is my_host
# Myhost is myhost2
I tried to gather facts using ansible -m setup my_host . The variables ansible_hostname , HOSTNAME and HOST contain the machine's hostname, i.e. echo $HOSTNAME which differs from my ansible alias.

The variable I was searching for is a built in feature: inventory_hostname
Ansible documentation about inventory_hostname and inventory_hostname_short is found from chapter Magic Variables, and How To Access Information About Other Hosts.
Original question: https://groups.google.com/forum/#!topic/ansible-project/Oa5YXjHecIw

You can use the inventory_hostname special variable.
Documentation: https://docs.ansible.com/ansible/latest/reference_appendices/special_variables.html
Alternatively,
You can just simply use {{ ansible_ssh_host }} For example:
Inventory:
[my_hosts]
my_host ansible_ssh_host=127.0.0.1 my_host_alias=my_host
Playbook:
---
- name: My Good playbook
user: ubuntu
hosts: all
tasks:
- name: My message
debug: msg="Myhost is {{ ansible_ssh_host }}"
- name: My message bogus
debug: msg="My host alias is {{ my_host_alias }}"
Execution:
$ ansible-playbook -i inventory play.yml
PLAY [My Good playbook] *******************************************************
GATHERING FACTS ***************************************************************
ok: [my_host]
TASK: [My message] ************************************************************
ok: [my_host] => {
"msg": "Myhost is 127.0.0.1"
}
TASK: [My message bogus] ******************************************************
ok: [my_host] => {
"msg": "My host alias is my_host"
}
PLAY RECAP ********************************************************************
my_host : ok=3 changed=0 unreachable=0 failed=0

Related

Ansible default variable naming seems to be inconsistent

I am learning Ansible and I am observe that the variable (fact) naming seems to be inconsistent.
For example, my Jinja2 template can run successfully.
{% for host in groups['node'] %}
{{ hostvars[host]['ansible_facts']['default_ipv4']['address'] }}
{% endfor %}
But if I run ad-hoc command setup to show all variables, the variable name will be ansible_default_ipv4. If I input the prefix ansible_ in playbooks, it then not run.
I ran then setup module to look for the variable name I need and I am so confuse about it now.
Am I doing it wrong, or have another proper way to look for variable name?
I tried looking for answer anywhere.
Thank you.
Q: "I run ad-hoc command setup to show all variables."
A: Use lookup plugins vars and varnames instead. See
shell> ansible-doc -t lookup varnames
shell> ansible-doc -t lookup vars
For example,
- hosts: localhost
gather_facts: false
vars:
my_vars: "{{ query('varnames', 'ipv4') }}"
tasks:
- setup:
gather_subset: default_ipv4
- debug:
var: my_vars
- debug:
msg: "{{ lookup('vars', item) }}"
loop: "{{ my_vars }}"
gives
PLAY [localhost] *****************************************************************************
TASK [setup] *********************************************************************************
ok: [localhost]
TASK [debug] *********************************************************************************
ok: [localhost] =>
my_vars:
- ansible_default_ipv4
- ansible_all_ipv4_addresses
TASK [debug] *********************************************************************************
ok: [localhost] => (item=ansible_default_ipv4) =>
msg:
address: 10.1.0.184
alias: eth1
broadcast: 10.1.0.255
gateway: 10.1.0.10
interface: eth1
macaddress: <sanitized>
mtu: 1500
netmask: 255.255.255.0
network: 10.1.0.0
type: ether
ok: [localhost] => (item=ansible_all_ipv4_addresses) =>
msg:
- 172.17.0.1
- 10.1.0.184
PLAY RECAP ***********************************************************************************
localhost: ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Use dynamic variable name

I'm trying to get the value of ip_address from the following yaml that I'm including as variables on ansible:
common:
ntp:
- time.google.com
node1:
default_route: 10.128.0.1
dns:
- 10.128.0.2
hostname: ip-10-128-5-17
device_interface: ens5
cluster_interface: ens5
interfaces:
ens5:
ip_address: 10.128.5.17
nat_ip_address: 18.221.63.178
netmask: 255.255.240.0
version: 2
However the network interface (ens5 here) may be named something else, such as eth0. My ansible code is this:
- hosts: all
tasks:
- name: Read configuration from the yaml file
include_vars: "{{ config_yaml }}"
- name: Dump Interface Settings
vars:
msg: node1.interfaces.{{ cvp_device_interface }}.ip_address
debug:
msg: "{{ msg }}"
tags: debug_info
Running the code like this I can get the key's name:
TASK [Dump Interface Settings] *************************************************
│ ok: [18.221.63.178] => {
│ "msg": "node1.interfaces.ens5.ip_address"
│ }
But what I actually need is the value (i.e: something like {{ vars[msg] }}, which should expand into {{ node1.interfaces.ens5.ip_address }}). How can I accomplish this?
Use sqare brackets.
Example: a minimal playbook, which defines a variable called "device". This variable is used to return the active status of the device.
- hosts: localhost
connection: local
vars:
device: enx0050b60c19af
tasks:
- debug: var=device
- debug: var=hostvars.localhost.ansible_facts[device].active
Output:
$ ansible-playbook example.yaml
[WARNING]: provided hosts list is empty, only localhost is available. Note that
the implicit localhost does not match 'all'
PLAY [localhost] *******************************************************************
TASK [Gathering Facts] *************************************************************
ok: [localhost]
TASK [debug] ***********************************************************************
ok: [localhost] => {
"device": "enx0050b60c19af"
}
TASK [debug] ***********************************************************************
ok: [localhost] => {
"hostvars.localhost.ansible_facts[device].active": true
}
PLAY RECAP *************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
see comment
- hosts: all
tasks:
- name: Read configuration from the yaml file
include_vars: "{{ config_yaml }}"
- name: Dump Interface Settings
debug:
msg: "{{ node1['interfaces'][cvp_device_interface]['ip_address'] }}"
debug:
msg: "{{ msg }}"
tags: debug_info

ansible-playbook command raising undefined variable error while variable is set in inventory file

I'm facing a mysterious ansible behaviour.
I've set groups, hosts and groups vars in my inventory file, but the ansible-playbook command is raising Undefined Variable for all my group vars, while printing them with the ansible debug module show the variable well.
Here is my inventory.ini file:
[windows]
ad_server ansible_host=mrspw00550.mydomain.com
[windows:vars]
ansible_connection=winrm
ansible_winrm_transport=ntlm
ansible_port=5985
ansible_become_method=runas
dns_zone=mydomain.com
ptr_zone=10.in-addr.arpa
dns_server=10.0.100.100
[linux]
web_server ansible_host=10.0.101.129
[linux:vars]
ansible_connection=ssh
ansible_become=yes
ansible_become_method=sudo
dns_zone=mydomain.com
ptr_zone=10.in-addr.arpa
dns_server=10.0.100.100
linux_home_dir=/home/ldaphome
the playbook file (set-hostname-and-dns.yml):
- name: Debug vars
debug: var=hostvars[inventory_hostname]['dns_zone']
delegate_to: ad_server
- name: Set hostname and make DNS registrations
block:
- name: Set hostname
hostname:
name: "web.{{ dns_zone }}"
delegate_to: web_server
- name: Create a DNS registration of type A
win_dns_record:
name: "web"
type: "A"
value: "{{ inventory_hostname }}"
zone: "{{ dns_zone }}"
computer_name: "{{ dns_server }}"
delegate_to: "{{ ad_server }}"
- name: Create a DNS registration of type PTR
win_dns_record:
name: "{{ inventory_hostname }}"
type: "PTR"
value: "web"
zone: "{{ ptr_zone }}"
computer_name: "{{ dns_server }}"
delegate_to: "{{ ad_server }}"
Running the ansible-playbook command gives :
$ ansible-playbook playbook.yml -i inventory-files/inventory.ini
PLAY [localhost] *********************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************************************************************
ok: [localhost]
TASK [create-linux-vm : Debug vars] **************************************************************************************************************************************************************************
ok: [localhost -> mrspw00550.mydomain.com] => {
"hostvars[inventory_hostname]['dns_zone']": "VARIABLE IS NOT DEFINED!"
}
TASK [create-linux-vm : Set web_server hostname] **************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dns_zone' is undefined\n\nThe error appears to be in 'set-hostname-and-dns.yml': line 14, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n block:\n - name: Set {{ vm_name }} hostname\n ^ here\nWe could be wrong, but this one looks like it might be an issue with\nmissing quotes. Always quote template expression brackets when they\nstart a value. For instance:\n\n with_items:\n - {{ foo }}\n\nShould be written as:\n\n with_items:\n - \"{{ foo }}\"\n"}
PLAY RECAP ***************************************************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Running debug module:
$ ansible -m debug -i inventory-files/inventory.ini -a "var=hostvars[inventory_hostname]['dns_zone']" all
ad_server | SUCCESS => {
"hostvars[inventory_hostname]['dns_zone']": "mydomain.com"
}
web_server | SUCCESS => {
"hostvars[inventory_hostname]['dns_zone']": "mydomain.com"
}
$
So as you can see, ansible-playbook command is unable to retrieve my host vars, while ansible debug module does.
The result is the same even if I define those variables in inventory-files/group_vars/linux.yml or inventory-files/group_vars/windows.yml, the variable is still as undefined by ansible. The problem is the same if try to access any other variable than special variables from inventory running ansible-playbook
What could be wrong there?
I tried with delegate_facts set to true, it didn't work.
Then defined a local group in the inventory containing localhost and defined my local group vars there like this :
[local]
localhost
[local:vars]
ansible_connection=local
dns_zone=mydomain.com
ptr_zone=10.in-addr.arpa
dns_server=10.0.100.100
linux_home_dir=/home/ldaphome
and remove those var from remote hosts facts, as I don't really those variables there. All my tasks are executed on the localhost and delegated to the remote hosts depending to the action.
I'd also like to precise that specifically ask for var/fact like #Zeitounator mentioned above ({{ hostvars['ad_server'].ptr_zone }}) in his comment works too.

ansible delegation to other hosts

I use ansible 2.1 and I want to run a command to a group of hosts, using delegate_to. I use localhost as the host param and I want to delegate a “touch” command to both of cls hosts
I have the following
---
- hosts: ansible
# gather_facts: yes
tasks:
- debug: var=groups.cls
- name: touch a file to running host
shell: echo {{ item }} >> /tmp/{{ inventory_hostname }}
delegate_to: "{{ item }}"
with_items: "{{ groups.cls }}"
with output:
[root#ansible control]# ansible-playbook -i inventory test.yml
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [ansible]
TASK [debug] *******************************************************************
ok: [ansible] => {
"groups.cls": [
"cls-host-1",
"cls-host-2"
]
}
TASK [touch a file to running host] ********************************************
changed: [ansible -> cls-host-1] => (item=cls-host-1)
changed: [ansible -> cls-host-2] => (item=cls-host-2)
PLAY RECAP *********************************************************************
ansible : ok=3 changed=1 unreachable=0 failed=0
but the touch is done only on the first host:
[root#cls-host-1 ~]# more /tmp/ansible
cls-host-1
cls-host-2
Is anything wrong? Can I delegate the command with any other way?
I've tested a variation of your playbook using Ansible 2.4.0.0:
#!/usr/bin/env ansible-playbook
- hosts: stretch.fritz.box
tasks:
- name: touch
shell: echo {{item}} >>/tmp/{{inventory_hostname}}
delegate_to: "{{item}}"
with_items:
- jessie.fritz.box
- short.fritz.box
This is working fine: the touch is performed on jessie and short
jessie$ cat /tmp/stretch.fritz.box
jessie.fritz.box
short$ cat /tmp/stretch.fritz.box
short.fritz.box
Perhaps this feature was introduced in Ansible between 2.1 and 2.4.

Ansible - read inventory hosts and variables to group_vars/all file

I have a dummy doubt that keeps me stuck for a long time. I have a very banal inventory file with hosts and variables:
[lb]
10.112.84.122
[tomcat]
10.112.84.124
[jboss5]
10.112.84.122
...
[tests:children]
lb
tomcat
jboss5
[default:children]
tests
[tests:vars]
data_base_user=NETWIN-4.3
data_base_password=NETWIN
data_base_encrypted_password=
data_base_host=10.112.69.48
data_base_port=1521
data_base_service=ssdenwdb
data_base_url=jdbc:oracle:thin:#10.112.69.48:1521/ssdenwdb
The problem is that I need to access all these hosts and variables, in the inventory file, from the group_vars/all file.
I've tried the following manners to access the host IP:
{{ lb }}
"{{ hostvars[lb] }}"
"{{ hostvars['lb'] }}"
{{ hostvars[lb] }}
To access a host variable I tried:
"{{ hostvars[tests].['data_base_host'] }}"
All of them are wrong!!! Can anyone help me find out the best practice to access hosts and variables, not from a playbook but from a variables file?
EDIT:
Ok. Let's clarify.
Problem: Use a host declared in the inventory file in a variable file, let's say: group_vars/all.
Example: I have a DB host with IP:10.112.83.37.
Inventory file:
[db]
10.112.83.37
In the group:vars/all file I want to use that IP to build a variable.
group_vars/all file:
data_base_url=jdbc:oracle:thin:#{{ db }}:1521/ssdenwdb
In a template I use the variable built in the group_vars/all file.
Template file:
oracle_url = {{ data_base_url }}
The problem is that the {{ db }} variable in the group_vars/all file is not replaced by the DB host IP. The user can only edit the inventory file.
- name: host
debug: msg="{{ item }}"
with_items:
- "{{ groups['tests'] }}"
This piece of code will give the message:
'10.112.84.122'
'10.112.84.124'
as groups['tests'] basically return a list of unique ip addresses ['10.112.84.122','10.112.84.124'] whereas groups['tomcat'][0] returns 10.112.84.124.
If you want to programmatically access the inventory entries to include them in a task for example. You can refer to it like this:
{{ hostvars.tomcat }}
This returns you a structure with all variables related with that host. If you want just an IP address (or hostname), you can refer to it like this:
{{ hostvars.jboss5.ansible_ssh_host }}
Here is a list of variables which you can refer to: click. Moreover, you can declare a variable and set it with for example result of some step in a playbook.
- name: Change owner and group of some file
file: path=/tmp/my-file owner=new-owner group=new-group
register: chown_result
Then if you play this step on tomcat, you can access it from jboss5 like this:
- name: Print out the result of chown
debug: msg="{{ hostvars.tomcat.chown_result }}"
Just in case if the problem is still there,
You can refer to ansible inventory through ‘hostvars’, ‘group_names’, and ‘groups’ ansible variables.
Example:
To be able to get ip addresses of all servers within group "mygroup", use the below construction:
- debug: msg="{{ hostvars[item]['ansible_eth0']['ipv4']['address'] }}"
with_items:
- "{{ groups['mygroup'] }}"
Considering your previous example:
inventory file:
[db]
10.112.83.37
group_vars/all
data_base_url=jdbc:oracle:thin:#{{ db }}:1521/ssdenwdb
template file:
oracle_url = {{ data_base_url }}
You might want to replace your group_vars/all with
data_base_url="jdbc:oracle:thin:#{{ groups['db'][0] }}:1521/ssdenwdb"
Yes the example by nixlike works very well.
Inventory:
[docker-host]
myhost1 user=barbara
myhost2 user=heather
playbook:
---
- hosts: localhost
connection: local
tasks:
- name: loop debug inventory hostnames
debug:
msg: "the docker host is {{ item }}"
with_inventory_hostnames: docker-host
- name: loop debug items
debug:
msg: "the docker host is {{ hostvars[item]['user'] }}"
with_items: "{{ groups['docker-host'] }}"
output:
ansible-playbook ansible/tests/vars-test-local.yml
PLAY [localhost]
TASK [setup]
******************************************************************* ok: [localhost]
TASK [loop debug inventory hostnames]
****************************************** ok: [localhost] => (item=myhost2) => {
"item": "myhost2",
"msg": "the docker host is myhost2" } ok: [localhost] => (item=myhost1) => {
"item": "myhost1",
"msg": "the docker host is myhost1" }
TASK [loop debug items]
******************************************************** ok: [localhost] => (item=myhost1) => {
"item": "myhost1",
"msg": "the docker host is barbara" } ok: [localhost] => (item=myhost2) => {
"item": "myhost2",
"msg": "the docker host is heather" }
PLAY RECAP
********************************************************************* localhost : ok=3 changed=0 unreachable=0
failed=0
thanks!
If you want to refer one host define under /etc/ansible/host in a task or role, the bellow link might help:
https://www.middlewareinventory.com/blog/ansible-get-ip-address/
If you want to have your vars in files under group_vars, just move them here. Vars can be in the inventory ([group:vars] section) but also (and foremost) in files under group_vars or hosts_vars.
For instance, with your example above, you can move your vars for group tests in the file group_vars/tests :
Inventory file :
[lb]
10.112.84.122
[tomcat]
10.112.84.124
[jboss5]
10.112.84.122
...
[tests:children]
lb
tomcat
jboss5
[default:children]
tests
group_vars/tests file :
data_base_user=NETWIN-4.3
data_base_password=NETWIN
data_base_encrypted_password=
data_base_host=10.112.69.48
data_base_port=1521
data_base_service=ssdenwdb
data_base_url=jdbc:oracle:thin:#10.112.69.48:1521/ssdenwdb

Resources