How to get unreachable nodes after ansible playbook execution in python?

382 Views Asked by At

After executing an ansible playbook, I need the node names that were not reached. I thought about using AnsibleRunner for running the ansible-playbook and I know of the special variables ansible_play_hosts and ansible_play_hosts_all which you can diff to get the unreachable nodes. But those special variables only exist in the context of ansible.

So how do I get the unreachable nodes from AnsibleRunner (or a similar utility), without parsing ansible's output.

On Runner Objects

Currently I am creating a runner object and evaluating its variables after execution. I see that in the events I can theoretically look for unreachable nodes, but that seems to be quite sketchy.

One might also be able to write an event handler that specifically catches those events that indicate that a node is unreachable that handles those cases differently.

I also wrote a small fact registration that registers which nodes are unreachable which will be executed as a last task, but I couldn't access it yet:

- set_fact:
    unreachable: "{{ ansible_play_hosts_all|difference(ansible_play_hosts) }}"

On ansible API

The ansible API has in its example a dictionary called host_unreachable. While that sounds very promising I have two issues with it: I) I couldn't run the example II) The API will not be downwards compatible and therefore shouldn't be used externally.

1

There are 1 best solutions below

3
Zeitounator On BEST ANSWER

What you are looking for is actually available out of the box in the Runner.stats property once your playbook has run.

Example implementation

Given:

  1. the inv.yml inventory
 ---
 local_test:
   vars:
     ansible_connection: local
     failling_hosts:
       - test2
       - test3
   hosts:
     test1:
     test2:
     test3:
     test4:
 
 unreachable:
   hosts:
     test5:
  1. the test.yml playbook
---
- hosts: all

  tasks:
    - name: dummy task for all
      debug:
        msg: task1 for all hosts

    - name: blindly fail some hosts for test
      assert:
        that: inventory_hostname not in (failling_hosts | d([]))

    - name: dummy task for survivors
      debug:
        msg: task2 for survivors
  1. the test.py python script
import ansible_runner

runner = ansible_runner.run(
    private_data_dir='.',
    inventory='inv.yml',
    playbook='test.yml',
    quiet=False if len(sys.argv) > 1 and sys.argv[1] == '-v' else True
)

overall_failed = {
    'unreachable': runner.stats['dark'].keys(),
    'failed': runner.stats['failures'].keys()
}

for elem_type, elements in overall_failed.items():
    for i, host in enumerate(elements):
        if i == 0:
            print(f'\nList of {elem_type} hosts:')
        print(f'\t{host}')

We get (run with -v if you want the playbook output too):

$ python test.py

List of unreachable hosts:
    test5

List of failed hosts:
    test2
    test3