I'm able to list unreachable servers using the below Ansible playbook:
---
- name: "Play 1-Find the details here {{ source_host }} & {{ dest_host }}"
hosts: localhost
any_errors_fatal: True
serial: 1
vars:
source_host: "{{ hostvars[inventory_hostname]['serverlist_input'] }}"
gather_facts: no
tasks:
- add_host:
name: "{{ item | trim }}"
groups: source_node
printback_rec: "{{ hostvars[inventory_hostname]['printback_input'] }}"
with_items:
- "{{ source_host.split(',') }}"
- set_fact:
rec_group_names: 'source_node'
- name: Check unreachable hosts
hosts: "{{ hostvars['localhost']['rec_group_names'] }}"
gather_facts: true
any_errors_fatal: false
tasks:
- name: Print group names
debug:
msg: "GROUP NAME TO BE TESTED: {{ group_names }}"
- name: Perform ping in Template
ping:
- block:
- debug:
var: ansible_play_hosts_all
- debug:
var: ansible_play_hosts
- set_fact:
down: "{{ ansible_play_hosts_all|difference(ansible_play_hosts) }}"
- debug:
var: down
run_once: true
- name: "Display unreachable hosts one at a time {{ startlogstring | default('start:') }}"
debug:
msg: "Unreachable Host: {{ item }}"
loop: "{{ ansible_play_hosts_all | difference(ansible_play_hosts) }}"
run_once: true
- fail:
msg: "Exiting play if target hosts are unreachable"
when: ansible_play_hosts_all != ansible_play_hosts
run_once: true
- name: Play 2- Configure Source nodes
hosts: source_node
gather_facts: false
any_errors_fatal: false
debugger: never
ignore_unreachable: yes
vars:
ansible_ssh_common_args: '-o ConnectTimeout=2'
tasks:
# - name: Detect unreachable hosts
# import_playbook: "{{ playbook_dir }}/generictask_templates/logunreachablehost.yml"
- name: Perform ping
ping:
Desired Output:
PLAY [Play 1-Find the details here {{ source_host }} & {{ dest_host }}] ********
TASK [Reset Github logs] *******************************************************
changed: [localhost] => (item=precheck.log)
TASK [add_host] ****************************************************************
ok: [localhost] => (item=remotehost4)
ok: [localhost] => (item=remotehost3)
ok: [localhost] => (item=remotehost2)
ok: [localhost] => (item=remotehost1)
TASK [set_fact] ****************************************************************
ok: [localhost]
PLAY [Check unreachable hosts] *************************************************
TASK [Gathering Facts] *********************************************************
fatal: [remotehost1]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: Could not resolve hostname remotehost1: Name or service not known", "unreachable": true}
[WARNING]: <redacted>
ok: [remotehost3]
[WARNING]: <redacted>
ok: [remotehost4]
[WARNING]: <redacted>
ok: [remotehost2]
TASK [Print group names] *******************************************************
ok: [remotehost4] => {
"msg": "GROUP NAME TO BE TESTED: ['source_node']"
}
TASK [Perform ping in Template] ************************************************
ok: [remotehost3]
ok: [remotehost4]
ok: [remotehost2]
TASK [debug] *******************************************************************
ok: [remotehost4] => {
"ansible_play_hosts_all": [
"remotehost4",
"remotehost3",
"remotehost2",
"remotehost1"
]
}
TASK [debug] *******************************************************************
ok: [remotehost4] => {
"ansible_play_hosts": [
"remotehost4",
"remotehost3",
"remotehost2"
]
}
TASK [set_fact] ****************************************************************
ok: [remotehost4]
TASK [debug] *******************************************************************
ok: [remotehost4] => {
"down": [
"remotehost1"
]
}
TASK [Display unreachable hosts one at a time start:] ***************
ok: [remotehost4] => (item=remotehost1) => {
"msg": "Unreachable Host: remotehost1"
}
TASK [fail] ********************************************************************
fatal: [remotehost4]: FAILED! => {"changed": false, "msg": "Exiting play if target hosts are unreachable"}
NO MORE HOSTS LEFT *************************************************************
PLAY RECAP *********************************************************************
remotehost4 : ok=11 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
remotehost2 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
remotehost1 : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
remotehost3 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Here is my requirement.
I wish to create a reusable template either include_tasks or import_playbook where i can pass any <groups> to hosts: and it would help me log all unreachable servers for that group_name.
The purpose is to reuse this template / playbook in an other play to log unreachable servers.
I tried the below but it does not work and errors:
Step 1: Created reusable playbook called "{{ playbook_dir }}/templates/logunreachable.yml" and copied the same logic from the previous successful run without any changes:
cat {{ playbook_dir }}/templates/logunreachable.yml
---
- name: Check unreachable hosts
hosts: "{{ hostvars['localhost']['rec_group_names'] }}"
gather_facts: true
any_errors_fatal: false
tasks:
- name: Print group names
debug:
msg: "GROUP NAME TO BE TESTED: {{ group_names }}"
run_once: true
- name: Perform ping in Template
ping:
- block:
- debug:
var: ansible_play_hosts_all
- debug:
var: ansible_play_hosts
- set_fact:
down: "{{ ansible_play_hosts_all|difference(ansible_play_hosts) }}"
- debug:
var: down
run_once: true
- name: "Display unreachable hosts one at a time {{ startlogstring | default('are-inject-start:') }}"
debug:
msg: "Unreachable Host: {{ item }}"
loop: "{{ ansible_play_hosts_all | difference(ansible_play_hosts) }}"
run_once: true
- fail:
msg: "Exiting play if target hosts are unreachable"
when: ansible_play_hosts_all != ansible_play_hosts
run_once: true
In the main playbook I import the above playbook and expect similar output as before:
Caller playbook:
---
- name: "Play 1-Find the details here {{ source_host }} & {{ dest_host }}"
hosts: localhost
any_errors_fatal: True
serial: 1
vars:
source_host: "{{ hostvars[inventory_hostname]['serverlist_input'] }}"
gather_facts: no
tasks:
- add_host:
name: "{{ item | trim }}"
groups: source_node
printback_rec: "{{ hostvars[inventory_hostname]['printback_input'] }}"
with_items:
- "{{ source_host.split(',') }}"
- set_fact:
rec_group_names: 'source_node'
- name: Play 2- Configure Source nodes
hosts: source_node
gather_facts: false
any_errors_fatal: false
debugger: never
ignore_unreachable: yes
vars:
ansible_ssh_common_args: '-o ConnectTimeout=2'
tasks:
- name: Detect unreachable hosts
import_playbook: "{{ playbook_dir }}/generictask_templates/logunreachablehost.yml"
- name: Perform ping
ping:
However, the output is not as expected like before:
PLAY [Play 1-Find the details here {{ source_host }} & {{ dest_host }}] ********
TASK [Reset Github logs] *******************************************************
changed: [localhost] => (item=precheck.log)
TASK [add_host] ****************************************************************
ok: [localhost] => (item=remotehost4)
ok: [localhost] => (item=remotehost3)
ok: [localhost] => (item=remotehost2)
ok: [localhost] => (item=remotehost1)
TASK [set_fact] ****************************************************************
ok: [localhost]
PLAY [Play 2- Configure Source nodes] ******************************************
TASK [Detect unreachable hosts] ************************************************
fatal: [remotehost1]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: Could not resolve hostname remotehost1: Name or service not known", "skip_reason": "Host remotehost1 is unreachable", "unreachable": true}
[WARNING]: <redacted>
fatal: [remotehost3]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3.9"}, "changed": false, "module_stderr": "Shared connection to remotehost3 closed.\\r\\n", "module_stdout": "", "msg": "MODULE FAILURE\\nSee stdout/stderr for the exact error", "rc": 0}
[WARNING]: <redacted>
fatal: [remotehost2]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/local/bin/python3.9"}, "changed": false, "module_stderr": "Shared connection to remotehost2 closed.\\r\\n", "module_stdout": "", "msg": "MODULE FAILURE\\nSee stdout/stderr for the exact error", "rc": 0}
[WARNING]: <redacted>
fatal: [remotehost4]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/local/bin/python3.9"}, "changed": false, "module_stderr": "Shared connection to remotehost4 closed.\\r\\n", "module_stdout": "", "msg": "MODULE FAILURE\\nSee stdout/stderr for the exact error", "rc": 0}
TASK [Perform ping] ************************************************************
fatal: [remotehost1]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: Could not resolve hostname remotehost1: Name or service not known", "skip_reason": "Host remotehost1 is unreachable", "unreachable": true}
PLAY RECAP *********************************************************************
remotehost4 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
remotehost2 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
remotehost1 : ok=0 changed=0 unreachable=2 failed=0 skipped=2 rescued=0 ignored=0
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
remotehost3 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Can you please suggest a solution where I could pass the hosts: <groupname> and the workflow could help list all unreachable hosts for the passed ?
Ansible automatically skips the unreachable hosts and proceeds with execution without failing the play. Also, Ansible will automatically skip them in all the subsequent plays. The list of unreachable hosts will be shown in the play recap.
Consider the following minimal reproducible example:
Output (I have enabled YAML stdout callback enabled for brevity and readability):
Now, if you still want to list the unreachable hosts in a separate playbook while passing the list of hosts ad-hoc. Actually, there are three errors preventing that in your current implementation:
hostvarssimply because Ansible doesn't know what hosts should it run the play on;--extra-vars;localhost.All of them block the reusability of the playbook.
So, to solve them all, you'll need to add the hosts to the inventory in the same playbook but in a separate play on
localhost, and runpingonallhosts if that plain variable is not defined (or on that target group, if it's not empty). You don't need to add them twice, by the way, so I'm checking if they are already present in the inventory. I also added an ability to control the fact gathering and speed up the things:This playbook will work in any circumstances: with or without the extra vars, with or without the predefined inventory, with or without localhost in the inventory, with or without the target hosts in the inventory.
You can also add a
failed_whencondition, or callassertorfailmodule to stop the execution if there are any unreachable hosts but some others still work. To make the output even more clear, you can also set a fact delegating it tolocalhostand displaying it in the subsequent play. Otherwise, it will be shown for a random host, which could be confusing:To use it with any other playbook, just add it as the first play:
If you don't want to use extra vars or you don't have an inventory, you can always add
varsto that import: