Get Ansible Localhost Ipv4.address - ansible

I'm trying to get ipv4 address of localhost,
Tried to tested before I use it as a variable is my j2 template
ansible localhost -m setup -a 'filter=ansible_default_ipv4.address'
Output of this command is
localhost | SUCCESS => {
"ansible_facts": {},
"changed": false
}
So it is empty.
Why? Is it some bug?

A fact (the value to use in the filter argument) is ansible_default_ipv4. It is a dictionary and contains a key address.
There is no way to filter on values, so you need to use:
ansible localhost -m setup -a 'filter=ansible_default_ipv4'

Try this adhoc ansible setup module filter for me it's working.
$ ansible dev -m setup -a 'filter=ansible_all_ipv4_addresses'
node1.example.com | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"10.160.12.13"
],
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}

Related

Variable is undefined when running Ansible 'debug' ad-hoc

Could you explain why following behaviour happens. When I try to print remote Ansible IP with following playbook everything works as expected:
---
- hosts: centos1
tasks:
- name: Print ip address
debug:
msg: "ip: {{ansible_all_ipv4_addresses[0]}}"
when I try ad-hoc command it doesn't work:
ansible -i hosts centos1 -m debug -a 'msg={{ansible_all_ipv4_addresses[0]}}'
Here is the ad-hoc error:
centos1 | FAILED! => {
"msg": "The task includes an option with an undefined variable. The error was: 'ansible_all_ipv4_addresses' is undefined.
'ansible_all_ipv4_addresses' is undefined" }
I don't find any difference in both approaches that is why I was expecting both to work and print the remote IP address.
I don't find any difference in both approaches that is why I was expecting both to work and print the remote IP address.
This is because no facts were gathered. Whereby via ansible-playbook and depending on the configuration Ansible facts become gathered automatically, via ansible only and ad-hoc command not.
To do so you would need to execute the setup module instead. See Introduction to ad hoc commands - Gathering facts.
Further Q&A
How Ansible sets variables?
Why does Ansible ad-hoc debug module not print variable?
Please take note of the variable names according
Conflict of variable name packages with ansible_facts.packages
Could you please give some example on How to output "Your IP address is "{{ ansible_all_ipv4_addresses[0] }}"? using ad-hoc approach with setup module?
Example
ansible test.example.com -m setup -a 'filter=ansible_all_ipv4_addresses'
test.example.com | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"192.0.2.1"
]
},
"changed": false
}
or
ansible test.example.com -m setup -a 'filter=ansible_default_ipv4'
test.example.com | SUCCESS => {
"ansible_facts": {
"ansible_default_ipv4": {
"address": "192.0.2.1",
"alias": "eth0",
"broadcast": "192.0.2.255",
"gateway": "192.0.2.0",
"interface": "eth0",
"macaddress": "00:00:5e:12:34:56",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "192.0.2.0",
"type": "ether"
}
},
"changed": false
}
It is also recommend to have a look into the full output without the filter argument to get familiar with the result set and data structure.
Documentation
setup module - Examples

Troubleshooting fetch_module executed from Ansible Tower (awx)

I'm trying to do a very simple fetch file from remote host. Somehow I've never gotten this to work.
Fetching from a remote Linux box to the Ansible Tower (awx) host which is also a Linux box.
Here's the Ansible code:
---
- name: get new private key for user
hosts: tag_Name_ansible_kali
become: yes
gather_facts: no
- name: fetch file
fetch:
src: /tmp/key
dest: /tmp/received/
flat: yes
Here's the result which makes it appear like the fetch worked:
{
"changed": true,
"md5sum": "42abaa3160ba875051f2cb20be0233ba",
"dest": "/tmp/received/key",
"remote_md5sum": null,
"checksum": "9416f6f64b94c331cab569035fb6bb825053bc15",
"remote_checksum": "9416f6f64b94c331cab569035fb6bb825053bc15",
"_ansible_no_log": false
}
However, going to the /tmp/received directory and ls -lah shows...
[root#ansibleserver received]# ls -lah
total 4.0K
drwxr-xr-x. 2 awx awx 6 Mar 12 15:48 .
drwxrwxrwt. 10 root root 4.0K Mar 12 15:49 ..
I've tested and if I choose a target src file that doesn't exist it won't work, so it's clearly connecting to the remote host. The problem is no matter where I point dest on the Ansible server the file doesn't actually write there. Not even sure how it can have a checksum of a file that doesn't exist. I've searched the entire drive and that file does not exist. Is there another log somewhere I can look at where it's actually writing the file? It's not on the remote host either.
Any advice would be appreciated. Seriously scratching my head here.
On a RHEL 7.9.9 system with Ansible 2.9.25, Python 2.7.5, Ansible Tower 3.7.x the output from an ad-hoc fetch task on CLI for a user on the Tower Server looks like
ansible test --user ${USER} --ask-pass --module-name fetch --args "src=/home/{{ ansible_user }}/test.txt dest=/tmp/ flat=yes"
SSH password:
test1.example.com | CHANGED => {
"changed": true,
"checksum": "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83",
"dest": "/tmp/test.txt",
"md5sum": "d8e8fca2dc0f896fd7cb4cb0031ba249",
"remote_checksum": "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83",
"remote_md5sum": null
}
test2.example.com | FAILED! => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"msg": "file not found: /home/user/test.txt"
}
and the file was left there. But the command was initiated and executed under user.
The same executed from Ansible Tower as ad-hoc command with arguments src=/home/user/test.txt dest=/tmp/ flat=yes reported
test2.example.com | FAILED! => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"msg": "file not found: /home/user/test.txt"
}
test1.example..com | CHANGED => {
"changed": true,
"checksum": "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83",
"dest": "/tmp/test.txt",
"md5sum": "d8e8fca2dc0f896fd7cb4cb0031ba249",
"remote_checksum": "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83",
"remote_md5sum": null
}
And your observation was right, there was no file on the Ansible Tower (awx) server. Changing the destination directory to the user reported, if there is an file already
}
test1.example.com | FAILED! => {
"changed": false,
"checksum": null,
"dest": "/home/user/test.txt",
"file": "/home/user/test.txt",
"md5sum": null,
"msg": "checksum mismatch",
"remote_checksum": "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83",
"remote_md5sum": null
}
that there is an file already. However, it failed also if there was no file.
After changing the destination directory to the user under the Ansible Tower is running (awx) via arguments src=/home/user/test.txt dest=/home/awx/ flat=yes
test1.example.com | CHANGED => {
"changed": true,
"checksum": "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83",
"dest": "/home/awx/test.txt",
"md5sum": "d8e8fca2dc0f896fd7cb4cb0031ba249",
"remote_checksum": "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83",
"remote_md5sum": null
}
the file was left there correctly
ls -al /home/awx/
-rw-r--r--. 1 awx awx 5 Nov 6 10:42 test.txt
Regarding
The problem is no matter where I point dest on the Ansible server the file doesn't actually write there. ... Any advice would be appreciated. ...
it looks like it is caused by the user context and missing access/write rights and maybe other observations like "It turns out that Ansible Tower doesn't actually fetch the files to itself, but just copies them to a temporary directory on the remote server".
you can try
validate_checksum: no

Why does the ansible option "--private-key" works on one host but not on another?

I installed ansible 2.8.0 on VM-1 without modifying any other default configs in ansible.cfg except the "host_key_checking = false".
Then I ran ansible all -i "<IP of VM-3>," --private-key <key of VM-3> -u root -m ping with OK on VM-3, but ran ansible all -i "<IP of VM-2>," --private-key <key of VM-2> -u root -m ping with ERROR on VM-2.
I generated a pair of ssh-key on VM-2 (user is root) and copy its private key (id_rsa) content to VM-1. I save it in a file named 'key', and set this file's mode to be '700'. Finally, I ran the command below:
ansible all -i "<ip of VM-2>," --private-key key -u root -m ping
It works wrong. The error info is:
/opt # ansible --version
ansible 2.8.0
config file = /opt/ansible.cfg
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.6/site-packages/ansible
executable location = /usr/bin/ansible
python version = 3.6.8 (default, Apr 8 2019, 18:17:52) [GCC 8.3.0]
/opt # ls
ansible.cfg key
/opt # ansible all -i "192.168.100.100," --private-key key -u root -m ping
192.168.100.100 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: root#192.168.100.100: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).",
"unreachable": true
}
Then I turned to use option "-k" instead, and it works.
/opt # ansible all -i "192.168.100.100," -k -u root -m ping
SSH password:
192.168.100.100 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
Then I tried again on VM-3 with the same steps of VM-2. The command using "--private-key" works. The environment of VM-2 and VM-3 are very similar.
I didn't find any difference between VM-2 and VM-3's sshd configure at all.
So I got very confused with these above.
In addition, the "--private-key" command will be OK after the "-k" command was run, because there is a ansible process living on the background, like this:
/opt # ansible all -i "192.168.100.100," -k -u root -m ping
SSH password:
192.168.100.100 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
/opt # ps -ef |grep ansible
126 root 0:00 ssh: /root/.ansible/cp/e42d5dc861 [mux]
/opt # ansible all -i "192.168.100.100," --private-key key -u root -m ping
192.168.100.100 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
I want to know how to use "--private-key" correctly in ansible command line.

Ansible Dynamic Inventory with Openstack

I am deploying several Linux hosts to an openstack environment and attempting to configure them with ansible. I'm having some difficulty with the stock dynamic inventory script from https://github.com/ansible/ansible/blob/devel/contrib/inventory/openstack.py
If I run ansible with a static hosts file, everything works fine
# inventory/static-hosts
localhost ansible_connection=local
linweb01 ansible_host=10.1.1.101
% ansible linweb01 -m ping -i ./inventory/static-hosts \
--extra-vars="ansible_user=setup ansible_ssh_private_key_file=/home/ian/keys/setup.key"
linweb01 | SUCCESS => {
"changed": false,
"ping": "pong"
}
But if I use the dynamic inventory, the host isn't found
% ansible linweb01 -m ping -i ./inventory/openstack.py \
--extra-vars="ansible_user=setup ansible_ssh_private_key_file=/home/ian/keys/setup.key"
linweb01 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: ssh: Could not resolve hostname linweb01: Name or service not known\r\n",
"unreachable": true
}
When I run the inventory script manually, the host is found and the address returned is correct
% ./inventory/openstack.py --host linweb01
[...]
"name": "linweb01",
"networks": {},
"os-extended-volumes:volumes_attached": [],
"power_state": 1,
"private_v4": "10.1.1.101",
[...]
My guess is that the inventory script doesn't know to use the "private_v4" value for the IP address, although I can't seem to find a reference for this.
How do I get ansible to use the "private_v4" value returned by the inventory script as the "ansible_host" value for the host?
Quick look into the code suggests that ip address is expected to be in interface_ip key:
hostvars[key] = dict(
ansible_ssh_host=server['interface_ip'],
ansible_host=server['interface_ip'],
openstack=server)
If you need a workaround, you can try to add this to you group_vars/all.yml:
ansible_host: "{{ private_v4 }}"

Ansible: Can I execute role from command line?

Suppose I have a role called "apache"
Now I want to execute that role on host 192.168.0.10 from the command line from Ansible host
ansible-playbook -i "192.168.0.10" --role "path to role"
Is there a way to do that?
With ansible 2.7 you can do this:
$ ansible localhost --module-name include_role --args name=<role_name>
localhost | SUCCESS => {
"changed": false,
"include_variables": {
"name": "<role_name>"
}
}
localhost | SUCCESS => {
"msg": "<role_name>"
}
This will run role from /path/to/ansible/roles or configured role path.
Read more here:
https://github.com/ansible/ansible/pull/43131
I am not aware of this feature, but you can use tags to just run one role from your playbook.
roles:
- {role: 'mysql', tags: 'mysql'}
- {role: 'apache', tags: 'apache'}
ansible-playbook webserver.yml --tags "apache"
There is no such thing in Ansible, but if this is an often use case for you, try this script.
Put it somewhere within your searchable PATH under name ansible-role:
#!/bin/bash
if [[ $# < 2 ]]; then
cat <<HELP
Wrapper script for ansible-playbook to apply single role.
Usage: $0 <host-pattern> <role-name> [ansible-playbook options]
Examples:
$0 dest_host my_role
$0 custom_host my_role -i 'custom_host,' -vv --check
HELP
exit
fi
HOST_PATTERN=$1
shift
ROLE=$1
shift
echo "Trying to apply role \"$ROLE\" to host/group \"$HOST_PATTERN\"..."
export ANSIBLE_ROLES_PATH="$(pwd)/roles"
export ANSIBLE_RETRY_FILES_ENABLED="False"
ansible-playbook "$#" /dev/stdin <<END
---
- hosts: $HOST_PATTERN
roles:
- $ROLE
END
You could also check ansible-toolbox repository. It will allow you to use something like
ansible-role --host 192.168.0.10 --gather --user centos --become my-role
I have written a small Ansible plugin, called auto_tags, that dynamically generates for each role in your playbook a tag of the same name. You can find it here.
After installing it (instructions are in the gist above) you could then execute a specific role with:
ansible-playbook -i "192.168.0.10" --tags "name_of_role"
Have you tried that? it's super cool. I'm using 'update-os' instead of 'apache' role to give a more meaningful example. I have a role called let's say ./roles/update-os/ in my ./ I add a file called ./role-update-os.yml which looks like:
#!/usr/bin/ansible-playbook
---
- hosts: all
gather_facts: yes
become: yes
roles:
- update-os
Make this file executable (chmod +x role-update-os.yml). Now you can run and limit to whatever you have in your inventory ./update-os.yml -i inventory-dev --limit 192.168.0.10 the limit you can pass the group names as well.
--limit web,db > web and db is the group defined in your inventory
--limit 192.168.0.10,192.168.0.201
$ cat inventory-dev
[web]
192.168.0.10
[db]
192.168.0.201
Note that you can configure ssh-keys and sudoers policy to be able to execute without having to type password - ideal for automation, there are security implications with this. therefore you have to analyze your environment to see whether it's suitable.
Since in ansible 2.4 two options are available: import_role and include_role.
wohlgemuth#leela:~/workspace/rtmtb-ansible/kvm-cluster$ ansible localhost -m import_role -a name=rtmtb
[WARNING]: No inventory was parsed, only implicit localhost is available
localhost | CHANGED => {
"changed": true,
"checksum": "d31b41e68997e1c7f182bb56286edf993146dba1",
"dest": "/root/.ssh/id_rsa.github",
"gid": 0,
"group": "root",
"md5sum": "b7831c4c72f3f62207b2b96d3d7ed9b3",
"mode": "0600",
"owner": "root",
"size": 3389,
"src": "/home/wohlgemuth/.ansible/tmp/ansible-tmp-1561491049.46-139127672211209/source",
"state": "file",
"uid": 0
}
localhost | CHANGED => {
"changed": true,
"checksum": "1972ebcd25363f8e45adc91d38405dfc0386b5f0",
"dest": "/root/.ssh/config",
"gid": 0,
"group": "root",
"md5sum": "f82552a9494e40403da4a80e4c528781",
"mode": "0644",
"owner": "root",
"size": 147,
"src": "/home/wohlgemuth/.ansible/tmp/ansible-tmp-1561491049.99-214274671218454/source",
"state": "file",
"uid": 0
}
ansible.builtin.import_role – Import a role into a play
ansible.builtin.include_role – Load and execute a role
Yes, import_role is an ansible module and as such it may be invoked through ansible command. The following executes role pki on my_server
ansible my_server -m import_role \
-a "name=pki tasks_from=gencert" \
-e cn=etcdctl \
-e extended_key_usage=clientAuth
You can create the playbook files from the command line:
Install the role (if not already installed)
ansible-galaxy install git+https://github.com/user/apache-role.git
Create playbook and hosts files
cat >> playbook.yml <<EOL
---
- name: Run apache
hosts: all
roles:
- apache-role
EOL
cat >> hosts <<EOL
192.168.0.10
EOL
Run ansible
ansible-playbook playbook.yml -i hosts
Delete the files
rm playbook.yml hosts

Resources