Access required ansible facts regardless of the target limits on a particular run.
The inventory
Create an inventory file. I will use database
group in the following examples.
$ cat hosts.yml
--- database: hosts: beaver: ansible_host: 172.16.40.11 wombat: ansible_host: 172.16.40.12 rabbit: ansible_host: 172.16.40.13
Create playbook
Create standard_playbook.yml
that will be used to illustrate the issue.
$ cat standard_playbook.yml
--- - hosts: all tasks: - name: "List default IPv4 address" debug: msg: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}" - name: "List default IPv4 addresses in database group" debug: msg: "{% for host in groups['database'] %}{{ hostvars[host]['ansible_eth0']['ipv4']['address'] | d() }}{% if not loop.last and hostvars[host]['ansible_eth0']['ipv4']['address'] is defined %}, {% endif %}{% endfor %}"
Display default IPv4 addresses.
$ ansible-playbook -i hosts.yml standard_playbook.yml
PLAY [all] ************************************************************************************************************************************************************************************************************************************************************************* TASK [Gathering Facts] ************************************************************************************************************************************************************************************************************************************************************* ok: [beaver] ok: [rabbit] ok: [wombat] TASK [List default IPv4 address] *************************************************************************************************************************************************************************************************************************************************** ok: [beaver] => { "msg": "172.16.40.11" } ok: [wombat] => { "msg": "172.16.40.12" } ok: [rabbit] => { "msg": "172.16.40.13" } TASK [List default IPv4 addresses in database group] ******************************************************************************************************************************************************************************************************************************* ok: [beaver] => { "msg": "172.16.40.11, 172.16.40.12, 172.16.40.13" } ok: [wombat] => { "msg": "172.16.40.11, 172.16.40.12, 172.16.40.13" } ok: [rabbit] => { "msg": "172.16.40.11, 172.16.40.12, 172.16.40.13" } PLAY RECAP ************************************************************************************************************************************************************************************************************************************************************************* beaver : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 rabbit : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 wombat : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
It works as expected in this simple case.
The issue
Define target limits to see the issue as the service will be accidentally reconfigured.
$ ansible-playbook -i hosts.yml standard_playbook.yml --limit beaver,rabbit
PLAY [all] ************************************************************************************************************************************************************************************************************************************************************************* TASK [Gathering Facts] ************************************************************************************************************************************************************************************************************************************************************* ok: [beaver] ok: [rabbit] TASK [List default IPv4 address] *************************************************************************************************************************************************************************************************************************************************** ok: [beaver] => { "msg": "172.16.40.11" } ok: [rabbit] => { "msg": "172.16.40.13" } TASK [List default IPv4 addresses in database group] ******************************************************************************************************************************************************************************************************************************* ok: [beaver] => { "msg": "172.16.40.11, 172.16.40.13" } ok: [rabbit] => { "msg": "172.16.40.11, 172.16.40.13" } PLAY RECAP ************************************************************************************************************************************************************************************************************************************************************************* beaver : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 rabbit : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The list of default IPv4 addresses in the database group does not include wombat
hostname as facts were not collected for it due to limits imposed on the inventory.
The solution
Define yaml
as facts caching plugin and yaml_fact_cache
caching directory. yaml
will use YAML format, specify jsonfile
to use JSON format.
$ cat ansible.cfg
[defaults] fact_caching = yaml fact_caching_connection = yaml_fact_cache
Define an empty playbook to simply gather facts.
$ cat gather_facts.yml
--- - hosts: all tasks: []
Update playbook to skip facts gathering.
$ cat updated_playbook.yml
--- - hosts: all gather_facts: no tasks: - name: "List default IPv4 address" debug: msg: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}" - name: "List default IPv4 addresses in database group" debug: msg: "{% for host in groups['database'] %}{{ hostvars[host]['ansible_eth0']['ipv4']['address'] | d() }}{% if not loop.last and hostvars[host]['ansible_eth0 ']['ipv4']['address'] is defined %}, {% endif %}{% endfor %}"
Skip this step for now, but delete gathered facts in subsequent runs.
$ find yaml_fact_cache -type f -delete
Gather facts.
$ ansible-playbook -i hosts.yml gather_facts.yml
PLAY [all] ************************************************************************************************************************************************************************************************************************************************************************* TASK [Gathering Facts] ************************************************************************************************************************************************************************************************************************************************************* ok: [beaver] ok: [rabbit] ok: [wombat] PLAY RECAP ************************************************************************************************************************************************************************************************************************************************************************* beaver : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 rabbit : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 wombat : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Run playbook using gathered facts.
$ ansible-playbook -i hosts.yml updated_playbook.yml
PLAY [all] ************************************************************************************************************************************************************************************************************************************************************************* TASK [List default IPv4 address] *************************************************************************************************************************************************************************************************************************************************** ok: [beaver] => { "msg": "172.16.40.11" } ok: [wombat] => { "msg": "172.16.40.12" } ok: [rabbit] => { "msg": "172.16.40.13" } TASK [List default IPv4 addresses in database group] ******************************************************************************************************************************************************************************************************************************* ok: [beaver] => { "msg": "172.16.40.11, 172.16.40.12, 172.16.40.13" } ok: [wombat] => { "msg": "172.16.40.11, 172.16.40.12, 172.16.40.13" } ok: [rabbit] => { "msg": "172.16.40.11, 172.16.40.12, 172.16.40.13" } PLAY RECAP ************************************************************************************************************************************************************************************************************************************************************************* beaver : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 rabbit : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 wombat : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Run playbook with target limits using gathered facts.
$ ansible-playbook -i hosts.yml updated_playbook.yml --limit beaver,rabbit
PLAY [all] ************************************************************************************************************************************************************************************************************************************************************************* TASK [List default IPv4 address] *************************************************************************************************************************************************************************************************************************************************** ok: [beaver] => { "msg": "172.16.40.11" } ok: [rabbit] => { "msg": "172.16.40.13" } TASK [List default IPv4 addresses in database group] ******************************************************************************************************************************************************************************************************************************* ok: [beaver] => { "msg": "172.16.40.11, 172.16.40.12, 172.16.40.13" } ok: [rabbit] => { "msg": "172.16.40.11, 172.16.40.12, 172.16.40.13" } PLAY RECAP ************************************************************************************************************************************************************************************************************************************************************************* beaver : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 rabbit : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The list of default IPv4 addresses in the database group is created correctly as facts were gathered for every host in this group.
Additional notes
List available fact cache plugins.
$ ansible-doc -t cache -l
jsonfile JSON formatted files memcached Use memcached DB for cache memory RAM backed, non persistent mongodb Use MongoDB for caching pickle Pickle formatted files redis Use Redis DB for cache yaml YAML formatted files
Read more about cache plugins.
I will anticipate your question about using a single playbook to perform both actions. The answer is that you can put everything in a single playbook. Play with it and have fun!