Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ansible: Abort Execution if a host is unreachable

Summary: A better way for aborting ansible playbook immediately if any host is unreachable.

Is there a way to abort Ansible playbook if any one of the host is unreachable. What I find that if it cannot reach a host it will still continue on and execute all the plays/tasks in the playbook.

All my playbooks I specify the max_fail_percentage of 0, but in this case ansible does not complain since all the hosts that are reachable can execute all the plays.

Currently I have a simple but hacky solution, but seeing if there is a better answer.

My current solution:

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
like image 902
Zoro_77 Avatar asked Jul 04 '15 13:07

Zoro_77


2 Answers

alternatively, this looks simplier and more expressive

- hosts: myservers
  become: true

  pre_tasks:
    - name: Check ALL hosts are reacheable before doing the release
      assert:
        that:
          - ansible_play_hosts == groups.myservers
        fail_msg: 1 or more host is UNREACHABLE
        success_msg: ALL hosts are REACHABLE, go on
      run_once: yes

  roles:
    - deploy

https://github.com/ansible/ansible/issues/18782#issuecomment-319409529

like image 68
Julien Avatar answered Oct 13 '22 12:10

Julien


You could be a bit more explicit about the check:

- fail: Abort if hosts are unreachable
  when: "'ansible_hostname' not in hostvars[item]"
  with_items: groups['all']

I thought you could make a callback plugin to achieve this. Something like:

class CallbackModule(object):
    def runner_on_unreachable(self, host, res):
        raise Exception("Aborting due to unreachable host " + host)

Except I can't find any good way to abort the entire playbook from that callback (the exception doesn't work, return value is ignored and while you could probably abuse self.playbook to stop things, there's no public API I can see).

like image 36
Jesse Rusak Avatar answered Oct 13 '22 10:10

Jesse Rusak