Ansible - print gathered facts for debugging purposes [duplicate] - ansible

This question already has answers here:
Where can I get a list of Ansible pre-defined variables?
(10 answers)
Closed 4 years ago.
Is there exists some way to print on console gathered facts ?
I mean gatering facts using setup module. I would like to print gathered facts. Is it possible ? If it is possible can someone show example?

Use setup module as ad-hoc command:
ansible myhost -m setup

You can simply dump the hostvars:
dump.yml
---
- name: Dump
hosts: "{{ target|default('localhost') }}"
tasks:
- name: Facts
setup:
- name: Dump
delegate_to: localhost
run_once: true
copy:
content: "{{ hostvars[inventory_hostname] | to_nice_json }}"
dest: /tmp/setup-dump.json
Call this playbook with ansible-playbook dump.yml -e target=hostname or simply without hostname.

Related

writing ansible facts to a file from a playbook

I know I can use the command below to save all ansible facts to a file:
ansible all -m setup --tree facts.d/
But I want to do this within a playbook. Currently I have:
- name: Collect facts
setup:
fact_path: facts.d
But nothing is collected when I run the task. Am I missing something?
- name: save all facts to host specific file
copy:
content: "{{ ansible_delegated_vars[inventory_hostname].vars | to_nice_json }}"
dest: "{{ playbook_dir }}/{{ ansible_fqdn }}"
delegate_to: localhost
This will create a file per host at playbook dir.
Reference : https://groups.google.com/g/ansible-project/c/HI65wOUIrx4?pli=1
If you just want to write a variable into a file you could use something like
- name: Copy Ansible facts to a file
copy:
content: "{{ ansible_facts }}"
dest: /tmp/ansible_facts_details.json
Thanks to
Cache Plugins, since that can be depending on the requirements already be a solution
Ansible: Facts in a single file
Ansible: Write whole facts to file

Get data from a host out of the `--limit` option

I have the following playbook (playbook.yaml)
- hosts: myfirsthost[0]
tasks:
- name: Get a token
slurp:
src: /var/mytoken
register: tokenFile
- hosts: myotherhosts
vars:
fileToken: "{{ hostvars[groups['myfirsthost'][0]]['tokenFile']['content'] | b64decode | replace('\n', '') }}"
tasks:
- debug:
msg: The token {{fileToken}}
When I run it for all hosts, it works fine.
But when I run it against a single host contained in the group myotherhosts (not in group myfirsthosts)
ansible playbook.yaml --limit thesinglehost
It doesn't play the first task, then the variable can not be initialized, and that is expected.
Do you have any idea how I can force the task "Get a token" for all hosts, even if they are not in myfirsthost?
Thanks
The problem
When you use --limit in your ansible-playbook command, you cannot play any tasks on hosts out of this limit. This includes gathering facts (i.e. play the setup module automatically or explicitly) and set_fact (i.e. create/update a fact manually for the host). With ansible default settings (memory facts cache), you will not be able to query any hostvars on those hosts inside your playbook because there are no keys for their inventory_hostname in that dict.
Facts cache to the rescue
A solution is to enable a non ephemeral facts cache in ansible.cfg. The default cache goes to memory and dies at the end of the playbook.
Enable the cache
As a start, you can enable and store the cache in json files on disk with the following settings in ansible.cfg:
[defaults]
fact_caching = jsonfile
fact_caching_connection = /path/to/cache/folder
For more info about this feature and all the possible cache backends, you can look at the comments for the relevant parameters in the default ansible.cfg file and check the cache plugin documentation
Populate the cache
Once you have a non ephemeral cache, you can gather facts and set_fact for all relevant hosts. If you only need facts queried from the host, you can easily do this with an ad-hoc command:
ansible -i your/inventory my_hosts -m setup
In your case, it is a bit more complicated, as you want to push to the cache the result of a task. You will need to create a first playbook that you will run on all hosts you need to use later. I'll call it init_facts_and_tokens.yml:
---
- name: Gather hosts facts and initialize tokens
hosts: my_hosts
# You can uncomment the line below to be explicit but this is on by default
# gather_facts: true
tasks:
- name: Slurp token file token
slurp:
src: /var/mytoken
register: token_file
- name: Register token in facts cache
set_fact:
token: "{{ token_file.content | b64decode | replace('\n', '') }}"
and your run it on all hosts with
ansible-playbook -i your/inventory init_facts_and_tokens.yml
Use the cache
Now that the cache is populated, you can play your other playbook, with a limit or not, and call hostvars for hosts out of the play/limit. If their facts have been correctly cached, you will get the values queried during the last facts gathering or set_fact
In such a scenario, you can probably disable facts gathering on all your plays to save some execution time on your final playbook. And if for any reason (e.g. changing a network interface, adding an lvm volume.....) you need to refresh the facts during the play, you can simply run the setup module. For any other fact not queried from you host, any use of set_fact for the given variable will create/refresh its value
---
- name: Do the jobs with cache facts
hosts: my_hosts
gather_facts: false
vars:
# We will use toker from first server in group,
# even if out of the limit
this_play_token: "{{ hostvars[groups['my_hosts'][0]].token }}"
tasks:
- name: Show token
debug:
msg: "The token for this play is {{ this_play_token }}"
# Examples to illustrate above explanations
- name: This task can use cache
debug:
msg: "OS of somehost.com is: {{ hostvars['somehost.com'].ansible_os_familly }}"
- name: This task would change target, possibly obsoleting gathered facts
debug:
msg: "Warning I might change system facts !"
- name: Refresh facts cache
setup:
- name: Back to normal activity
debug:
msg: "I use latest gathered facts from cache"
- name: This would refresh the cached token for current host
set_fact:
token: "Not so valid token"
You can now launch this second playbook with a limit or not. It will still be able to read facts (queried or user set) for any host even out of the play
# run on all hosts
ansible-playbook -i your/inventory final_playbook.yml
# run only on third host of my_hosts group
ansible-playbook -i your/inventory --limit my_host[2] final_playbook.yml

How to compare facts from multiple host inside ansible playbook

How do I create a playbook that compare the facts of multiple host in Ansible? I would like to be able to compare hosts against one another to discover one-offs. All my workstations should be the exact same.
- name: Gather Facts
hosts: all
- debug: var=vars
- debug: vars=hostvars[inventory_hostname]
- debug:
msg: "{{ hostvars[inventory_hostname] | difference([inventory_hostname]) }}""

Loop through hosts with ansible [duplicate]

This question already has answers here:
How to use Ansible's with_item with a variable?
(2 answers)
Closed 5 years ago.
I have a problem to find a working solution to loop over my inventory.
I start my playbook with linking a intentory file:
ansible-playbook -i inventory/dev.yml playbook.yml
My playbook looks like this:
---
- hosts: localhost
tasks:
- name: Create VM if enviro == true
include_role:
name: local_vm_creator
when: enviro == 'dev'
So when loading the playbook the variable enviro is read from host_vars and sets the when condition to dev. The inventory file dev.yml looks like this:
[local_vm]
192.168.99.100
192.168.99.101
192.168.99.102
[local_vm_manager_1]
192.168.99.103
[local_vm_manager_2]
192.168.99.104
[local-all:children]
local_vm
local_vm_manager_1
local_vm_manager_2
My main.yml in my role local_vm_creator looks like this:
---
- name: Create test host
local_action: shell docker-machine create -d virtualbox {{ item }}
with_items:
- node-1
- node-2
- node-3
- node-4
- node-5
- debug: msg="host is {{item}}"
with_items: groups['local_vm']
And the problem is that i can't get the listed servers from the dev.yml inventory file.
it just returns:
ok: [localhost] => (item=groups['local_vm']) => {
"item": "groups['local_vm']",
"msg": "host is groups['local_vm']" }
If the only problem is with_items loop, replace it with:
with_items: "{{ groups['local_vm'] }}"
and you are good to go. Bare variables are not supported in with_ any more.

ansible ec2 az variable

Folks,
In my .j2 template, I would like to use an ansible variable from each host like so
dc_suffix={{ ansible_ec2_placement }}
However, the "msg": "AnsibleUndefinedVariable: ERROR! 'ansible_ec2_placement' is undefined"} error appears.
What is the correct syntax for ansible to fetch the availability zone for a particular instance? The ec2_facts docs are scarce
I've been able to do this:
- name: Gather facts
action: ec2_facts
register: ec2_facts
Then in the termplate:
dc_suffix={{ ec2_facts.ansible_facts.ansible_ec2_placement_availability_zone }}
Anything wrong with doing this?
Thanks!
This can be simpler than #Cmag's answer, at least for ansible v 1.9:
- name: gather ec2 facts
action: ec2_facts
- name: display AZ
debug: msg="region is {{ ansible_ec2_placement_availability_zone }}"
From the shell, you can view all facts set by ec2_facts with the following:
echo "localhost ansible_connection=local" >inv
ansible -m ec2_facts localhost -i inv
which will print out a large number of variables in json format.

Resources