Aborting ansible playbook if a host is unreachable

I was about to post a question, when I saw this one. The answer Duncan suggested does not work, atleast in my case. the host is unreachable. All my playbooks specify a max_fail_percentage of 0.

But ansible will happily execute all the tasks on the hosts that it is able to reach and perform the action. What I really wanted was if any of the host is unreachable, don’t do any of the tasks.

What I found was a simple but might be considered hacky solution, and an open for better answers.

Since the first step as part of running the playbooks, ansible gathers facts for all the hosts. And in case where a host is not reachable it will not be able to. I write a simple play at the very beginning of my playbook which will use a fact. And in case a host is unreachable that task will fail with «Undefined variable error». The task is just a dummy and will always pass if all hosts are reachable.

See below my example:

- name: Check Ansible connectivity to all hosts
  hosts: host_all
  user: "{{ remote_user }}"
  sudo: "{{ sudo_required }}"
  sudo_user: root
  connection: ssh # or paramiko
  max_fail_percentage: 0
  tasks:
    - name: check connectivity to hosts (Dummy task)
      shell: echo " {{ hostvars[item]['ansible_hostname'] }}"
      with_items: groups['host_all']
      register: cmd_output
    - name: debug ...
      debug: var=cmd_output

In case a host is unreachable you will get an error as below:

TASK: [c.. *****************************************************
fatal: [172.22.191.160] => One or more undefined variables: 'dict object'    has no attribute 'ansible_hostname'
fatal: [172.22.191.162] => One or more undefined variables: 'dict object' has no attribute 'ansible_hostname'
FATAL: all hosts have already failed -- aborting

Note: If your host group is not called host_all, you must change the dummy task to reflect that name.