I've recently implemented a variant of the answer given above by Tom Bull which works for multiple hosts, sequentially checking for access and prompting for credentials if needed, then running tasks to finish setup (e.g. adding authorised keys, or setting up a user for Ansible):
playbook.yaml
:
# Checking access to hosts must run sequentially
- hosts: all
gather_facts: no
serial: 1
tasks:
- include_tasks: check-access.yaml
# Subsequent tasks can run in parallel as usual
- hosts: all
tasks:
- include_tasks: setup-tasks.yaml
check-access.yaml
:
- name: check ansible user exists
command: ssh -o User={{ ansible_user }} -o ConnectTimeout=10 -o PreferredAuthentications=publickey -o PubkeyAuthentication=yes {{ ansible_host }} echo "Worked"
register: remote
connection: local
ignore_errors: yes
become: false
changed_when: False
- name: collect credentials
block:
- name: collect username
pause:
prompt: "Username for {{ inventory_hostname }} ({{ ansible_host }})"
echo: yes
register: username_result
- name: collect password
pause:
prompt: "Password for {{ username_result.user_input }}"
echo: no
register: password_result
- name: update ansible credentials
set_fact:
ansible_user: "{{ username_result.user_input }}"
ansible_password: "{{ password_result.user_input }}"
ansible_become_password: "{{ password_result.user_input }}"
when: remote.failed
setup-tasks.yaml
will then be run on all hosts, and can include whatever tasks are needed to ensure that the initial access check will succeed when playbook.yaml
is next run.
Whilst keeping the check-access.yaml
tasks in a separate file does make the main playbook easier to read, it may be possible to bring them into the main playbook - however I have not tried this so cannot be certain that they will run in the correct order.
Note that these tasks cannot be placed into a role, as prompt
only works within tasks