error-handlingansibleconnection-refusedremote-connection

Ansible: continue play on a connection error to allow for different credentials


I am basically trying this inside a role:

---
- name: "Connection attempt 1"
  block:
    - name: "Credentials"
      set_fact:
        ansible_ssh_user: "{{ username_from_vault }}"
        ansible_password: "{{ password_from_vault }}"
    - name: "Try connection"
      ping:
  rescue:
    - name: "Other credentials"
      set_fact:
        ansible_ssh_user: "{{ other_username_from_vault }}"
        ansible_password: "{{ other_password_from_vault }}"
    - name: "Try connection again"
      ping:

The idea behind is a connection to machines which are either in state A or in state B. State A has a temporary user, state B the final user for ansible connections. The inventory comes from another source which must not care about additional variables entered by humans stating "well we are done with transition A->B", that is rather prone to errors.

Even with anything in the likes of failed_when: false, connections as such will always stop the play.

Is there a way to make ansible continue after a failed host connection? Or am I running in an entirely wrong direction? Mark that we want to test credentials here, so something like:

    - name: "Try connection"
      delegate_to: "localhost"
      no_log: true
      shell: "sshpass -p {{ password_from_vault }} {{ user_from_vault }}@{{ inventory_name }}"

...may do technically the trick, but will offer an additional surface with a possible leak of the password during lifetime of the play, so that would be not-so-good practice I'd rather avoid.

Any ideas?


Solution

  • The direct comment by β.εηοιτ.βε (thanks mate!) points to the Ansible documentation introducing ignore_unreachable since Ansible 2.7.

    You can then catch the unreachability from a variable like:

    - name: "Connection attempt"
      ping:
      ignore_unreachable: true
      register: "conn"
    - block:
      - name: "Change credentials"
        set_fact:
          ansible_ssh_user: "{{ whatever }}"
      - name: "Try the connection again"
        ping:
      when: "conn is mapping and conn.unreachable is defined and conn.unreachable"
    

    There is still no "rescue wasy of things" in this answer and it will increase the unreachable count in the playbooks' summaries, but it works without the delegate_to-and-sshpass stunt.

    And to use a different approach: The following "play" doesn't directly answer the initial question for unreachable events, but follows the philosophy of "try credential set #1, and on failure try credential set #2". wait_for_connection does not generate an "unreachable" event, and we can go for block-rescue again:

    - block:
      - name: "Connection attempt"
        wait_for_connection:
          timeout: 3
      rescue:
      - name: "Change credentials"
        set_fact:
          ansible_ssh_user: "{{ whatever }}"
      - name: "Connection attempt with different credentials"
        # Now truly generate "unreachable" if this fails, too
        ping: