3
votes

I have a system with several hosts for availability. I only need to run my Ansible playbook on one host. However some of these hosts may not be reachable. Let's say I have host1, host2, host3 ... If host1 is not reachable, I want Ansible to try host2. If host2 is reachable and Ansible runs some bash scripts successfully, I want Ansible to skip the rest of hosts. Any suggestions?

2
How do you define "some" in "runs some bash scripts successfully"?techraf
And how do you define "unreachable"? Ansible automatically skips hosts unreachable by ssh.sm4rk0
@sm4rk0 I'm curious how would it influence the answer? The only determinant whether to continue trying or to stop is a successful execution (of mysterious "some" scripts). What role does the definition of "unreachable" play for the answer, in your opinion?techraf
@techraf You're right. I misunderstood the question.sm4rk0

2 Answers

2
votes

This is probably not the optimal solution, but I couldn't find a better one.

  • (Optionally) Set gather_facts to False, to entirely skip the hosts that need to be skipped (if you don't need to gather the host facts).
  • Set serial to 1, so the playbook is played entirely on one host at a time instead of the default 5 hosts in parallel.
  • Use set_fact to set a host fact (named done in example) to True at the end of a play, or use register if you need a more specific condition (a command output).
  • Use end_play meta at the start of the play that would execute when the variable is set to True (or has the expected value, if you used register) for any host. I used the Jinja2 template language to extract the value this way:
    1. for to loop over all the hostvars (Python dict containing all the variables set for all hosts in the inventory).
    2. if to check whether a host has done variable set to True and return a string True if it is.
    3. default filter to set the default value if done is not defined for a host (that would cause an error 'dict object' has no attribute 'done').

For example:

- hosts: all
  serial: 1
  gather_facts: False

  tasks:
  - meta: end_play
    when: "{% for item in hostvars.values() %}{% if item.done|default(False) %}True{% endif %}{% endfor %}"

  # The rest of the play goes here

  - set_fact:
      done: True
-1
votes

Ansible doesn't consider those hosts which are not reachable, in setup phase unreachable hosts list will be dropped.

On remaining list of hosts use 'run_once: yes' for that specific task of that bash script. It will pick first matching host from available hosts.