I have a playbook to run command on a list of servers and put the results in a file.
But, sometimes, I can't connect to those servers due to an incorrect login/password or because it is unreachable.
When it is unreachable, I have this on the console:
fatal: [fqdn]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: Could not resolve hostname fqdn: Name or service not known", "unreachable": true}
When I have an incorrect login or password, I have this:
fatal: [fqdn]: UNREACHABLE! => {"changed": false, "msg": "Invalid/incorrect password: Permission denied, please try again.", "unreachable": true}
I would like to capture this message in the output console to write in a template Jinja.
In order to have kind of a report.
I have done this in the playbook
- name: Listing des packages
hosts: all
gather_facts: false
tasks:
- name: Collect only selected facts
setup:
gather_subset: min
- name: Total number of updates
shell: yum check-update | wc -l
register: nbupdates
- name: Output to html file
template:
src: ./jinja/src/tpl_dashboard_update.j2
dest: ./jinja/dst/dashboard_update.html
force: yes
delegate_to: localhost
run_once: true
and the Jinja template
{% for host in ansible_play_hosts_all %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ host | upper }}</td>
{% if hostvars[host]['ansible_distribution'] is not defined %}
<td colspan="4">Injoignable</td>
{% else %}
<td>{{ hostvars[host]['ansible_distribution'] }} {{ hostvars[host]['ansible_distribution_version'] }}</td>
<td> {% if hostvars[host].nbupdates.stdout_lines.0 is defined %} {{ hostvars[host].nbupdates.stdout_lines.0 }} {% else %} --- {% endif %} </td>
{% endif %}
</tr>
{% endfor %}
It is not working properly, I only have the result when it is a success in the file and not the result, when it fails.
How I can "capture" the error message when it's unreachable or when I have a login/password error?
You will have to use ignore_unreachable: yes
in order to gather a result form an unreachable host.
You will also have to skip those unreachable hosts in the tasks that follows your setup
.
And, in order to overcome the possibility that all hosts are unreachable, you probably want to target localhost, all
and skip localhost when it is not needed.
Two other side notes:
shell
task to get all the available update would be better fitted in a yum
task.{% if hostvars[host].nbupdates.stdout_lines.0 is defined %}
{{ hostvars[host].nbupdates.stdout_lines.0 }}
{% else %}
---
{% endif %}
And can be easily shortened with a default
filter:
{{ hostvars[host].nbupdates.stdout_lines.0 | default('---') }}
But, this is not something we should use here since we should rely on the length of the list returned by the yum
moduleHere would be an example of a playbook with all this together:
- hosts: localhost, all
gather_facts: no
tasks:
- setup:
gather_subset: min
register: setup
ignore_unreachable: yes
when: inventory_hostname != 'localhost'
- yum:
list: updates
register: yum
when:
- setup is reachable
- inventory_hostname != 'localhost'
- template:
src: ./jinja/src/tpl_dashboard_update.j2
dest: ./jinja/dst/dashboard_update.html
force: yes
delegate_to: localhost
run_once: true
And here is the adapted template tpl_dashboard_update.j2:
<table>
{% for host in ansible_play_hosts_all if host != 'localhost' %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ host | upper }}</td>
{% if hostvars[host].setup is unreachable %}
<td>Injoignable</td>
<td>{{ hostvars[host].setup.msg }}</td>
{% else %}
<td>
{{ hostvars[host].ansible_distribution }}
{{ hostvars[host].ansible_distribution_version }}
</td>
<td>
{% if hostvars[host].yum.results is defined %}
{{ hostvars[host].yum.results | length }}
{% else %}
---
{% endif %}
</td>
{% endif %}
</tr>
{% endfor %}
</table>
This all would yield a table like (style added for readability):
table, th, td {
border: 1px solid black;
border-collapse: collapse;
padding: 4px;
}
<table>
<tr>
<td>1</td>
<td>TEST</td>
<td>Injoignable</td>
<td>Failed to connect to the host via ssh: ssh: Could not resolve hostname test: Name does not resolve</td>
</tr>
<tr>
<td>2</td>
<td>NODE1</td>
<td>
Fedora 35
</td>
<td>
29
</td>
</tr>
<tr>
<td>3</td>
<td>NODE2</td>
<td>Injoignable</td>
<td>Invalid/incorrect password: Permission denied, please try again.</td>
</tr>
</table>