On Wed, 8 Nov 2023 06:22:49 -0800 (PST)
Dimitri Yioulos <
dimitri....@gmail.com> wrote:
> ... my goal is to see if hosts are Ansible-pingable (not
> ICMP-pingable; I believe there's a difference) or not, then take
> *all* of the output, and create a report from it. Thus, i end up
> with a report of hosts that are either Ansible-pingable or not.
Dimitri, the play does what you want. The code is available also here
https://gist.github.com/vbotka/10c57962976dd1e2dd3e9411d3745c75
Let me help you to understand it step by step
>>> - hosts: test_01,test_05,test_06,test_07
>>> gather_facts: false
There are 4 hosts in the play. Setup is off, hence no connections to
the remote host up till now
>>> vars:
>>>
>>> h_unr: "{{ dict(ansible_play_hosts_all|
>>> zip(ansible_play_hosts_all|
>>> map('extract', hostvars, 'unr'))) }}"
This dictionary will be evaluated when referenced in the debug task
>>> tasks:
>>>
>>> - block:
>>> - ping:
>>> register: out
>>> - set_fact:
>>> unr: "{{ out.unreachable|d(false) }}"
>>> ignore_unreachable: true
Here come the first connections to the remote hosts. There are 2
tasks in the block. The first one is the Ansible module ping, not the
ICMP ping. (Yes, you're right. There is a difference.) The second one
is the module set_fact. Because of the ignore statement the tasks in
the block won't fail if a host is unreachable.
If a host can be reached by ping there is no attribute *unreachable*
in the registered dictionary *out*. Therefor, the value of the
variables *unr* will be the default (alias d) value *false*.
If a host can't be reached the value of the attribute *unreachable*
is *true*.
>>> - debug:
>>> var: h_unr
>>> run_once: true
>>> delegate_to: localhost
Here is the report. Let's analyse the dictionary *h_unr*. In the
above block, all hosts created the variable *unr*. When you take the
list of all hosts in the play *ansible_play_hosts_all* [1] and *map*
the function to *extract* the *hostvars* [2] variable *unr*
ansible_play_hosts_all|map('extract', hostvars, 'unr')
you get a list, for example, where only the first host was reached
[false, true, true, true]
Then, *zip* this list with *ansible_play_hosts_all*
[[test_01,false], [test_02,true], [test_03,true], [test_04,true]]
and apply the function *dict* [3]. Below is the expected result.
Enjoy!
>>> gives (abridged)
>>>
>>> ok: [test_01 -> localhost] =>
>>> h_unr:
>>> test_01: false
>>> test_05: true
>>> test_06: true
>>> test_07: true
[1]
https://docs.ansible.com/ansible/latest/reference_appendices/special_variables.html
[2]
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_filters.html#selecting-values-from-arrays-or-hashtables
[3]
https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_filters.html#combining-items-from-multiple-lists-zip-and-zip-longest
--
Vladimir Botka