I am a novice to Ansible. I am trying to print all the inventory hosts with serial number (sl.no) using a Jinja template which would be transformed to a .csv
file. I have this playbook to ping all the hosts and get the status.
- hosts: '{{ host }}'
gather_facts: true
become: true
tasks:
- name: Pinging Host {{ host }}
action: ping
register: var_ping
I want to print all hostnames and its ping status with serial order number.
How to achieve this?
Expected output: enter image description here
Use Special Variables ansible_play_hosts and ansible_play_hosts_all. Quoting:
ansible_play_hosts: List of hosts in the current play run, not limited by the serial. Failed/Unreachable hosts are excluded from this list.
ansible_play_hosts_all: List of all the hosts that were targeted by the play
For example, given the inventory
shell> cat hosts
test_11
test_12
test_13
test_14
and the abridged result of the ping module. The hosts test_12 and test_14 failed.
TASK [ping] ****************************************************************
fatal: [test_12]: FAILED! => changed=false
ok: [test_11]
ok: [test_13]
fatal: [test_14]: UNREACHABLE! => changed=false
gives
ansible_play_hosts_all: ['test_11', 'test_12', 'test_13', 'test_14']
ansible_play_hosts: ['test_11', 'test_13']
Declare the variables
failed_hosts: "{{ ansible_play_hosts_all|difference(ansible_play_hosts) }}"
failed_hosts_dict: "{{ dict(failed_hosts|product(['fail'])) }}"
passed_hosts_dict: "{{ dict(ansible_play_hosts|product(['success'])) }}"
hosts_dict: "{{ passed_hosts_dict|combine(failed_hosts_dict) }}"
gives
failed_hosts: ['test_12', 'test_14']
failed_hosts_dict: {'test_12': 'fail', 'test_14': 'fail'}
passed_hosts_dict: {'test_11': 'success', 'test_13': 'success'}
hosts_dict: {'test_11': 'success', 'test_13': 'success', 'test_12': 'fail', 'test_14': 'fail'}
Create and test a template. Fit the sorting to you needs
- debug:
msg: |
Serial Number, Hostname, Ping Status
{% for k,v in hosts_dict.items()|sort() %}
{{ loop.index }},{{ k }},{{ v }}
{% endfor %}
gives
msg: |-
Serial Number, Hostname, Ping Status
1,test_11,success
2,test_12,fail
3,test_13,success
4,test_14,fail
If this is what you want write the file
- copy:
dest: /tmp/status.csv
content: |
Serial Number, Hostname, Ping Status
{% for k,v in hosts_dict.items()|sort() %}
{{ loop.index }},{{ k }},{{ v }}
{% endfor %}
delegate_to: localhost
gives
shell> cat /tmp/status.csv
Serial Number, Hostname, Ping Status
1,test_11,success
2,test_12,fail
3,test_13,success
4,test_14,fail
Example of a complete playbook for testing
- hosts: all
gather_facts: false
vars:
failed_hosts: "{{ ansible_play_hosts_all|difference(ansible_play_hosts) }}"
failed_hosts_dict: "{{ dict(failed_hosts|product(['fail'])) }}"
passed_hosts_dict: "{{ dict(ansible_play_hosts|product(['success'])) }}"
hosts_dict: "{{ passed_hosts_dict|combine(failed_hosts_dict) }}"
tasks:
- ping:
- debug:
msg: |
ansible_play_hosts_all: {{ ansible_play_hosts_all }}
ansible_play_hosts: {{ ansible_play_hosts }}
failed_hosts: {{ failed_hosts }}
failed_hosts_dict: {{ failed_hosts_dict }}
passed_hosts_dict: {{ passed_hosts_dict }}
hosts_dict: {{ hosts_dict }}
run_once: true
- debug:
msg: |
Serial Number, Hostname, Ping Status
{% for k,v in hosts_dict.items()|sort() %}
{{ loop.index }},{{ k }},{{ v }}
{% endfor %}
run_once: true
- copy:
dest: /tmp/status.csv
content: |
Serial Number, Hostname, Ping Status
{% for k,v in hosts_dict.items()|sort() %}
{{ loop.index }},{{ k }},{{ v }}
{% endfor %}
delegate_to: localhost
run_once: true
For example, given the inventory
shell> cat hosts
test_11 sn=1
test_12 sn=2
test_13 sn=3
test_14 sn=4
Declare the variables
failed_hosts: "{{ ansible_play_hosts_all|difference(ansible_play_hosts) }}"
failed_hosts_dict: |
{% for host in failed_hosts %}
{{ host }}:
status: fail
sn: {{ hostvars[host]['sn'] }}
{% endfor %}
passed_hosts_dict: |
{% for host in ansible_play_hosts %}
{{ host }}:
status: success
sn: {{ hostvars[host]['sn'] }}
{% endfor %}
hosts_list: "{{ passed_hosts_dict|from_yaml|
combine(failed_hosts_dict|from_yaml)|
dict2items|
sort(attribute='value.sn')}}"
gives
hosts_list:
- key: test_11
value:
sn: 1
status: success
- key: test_12
value:
sn: 2
status: fail
- key: test_13
value:
sn: 3
status: success
- key: test_14
value:
sn: 4
status: fail
Write the file
- copy:
dest: /tmp/status.csv
content: |
Serial Number, Hostname, Ping Status
{% for i in hosts_list %}
{{ i.value.sn }},{{ i.key }},{{ i.value.status }}
{% endfor %}
delegate_to: localhost
run_once: true
gives the same result
shell> cat /tmp/status.csv
Serial Number, Hostname, Ping Status
1,test_11,success
2,test_12,fail
3,test_13,success
4,test_14,fail
Example of a complete playbook for testing
- hosts: all
gather_facts: false
vars:
failed_hosts: "{{ ansible_play_hosts_all|difference(ansible_play_hosts) }}"
failed_hosts_dict: |
{% for host in failed_hosts %}
{{ host }}:
status: fail
sn: {{ hostvars[host]['sn'] }}
{% endfor %}
passed_hosts_dict: |
{% for host in ansible_play_hosts %}
{{ host }}:
status: success
sn: {{ hostvars[host]['sn'] }}
{% endfor %}
hosts_list: "{{ passed_hosts_dict|from_yaml|
combine(failed_hosts_dict|from_yaml)|
dict2items|
sort(attribute='value.sn')}}"
tasks:
- ping:
- debug:
var: hosts_list
run_once: true
- debug:
msg: |
ansible_play_hosts_all: {{ ansible_play_hosts_all }}
ansible_play_hosts: {{ ansible_play_hosts }}
failed_hosts: {{ failed_hosts }}
failed_hosts_dict: {{ failed_hosts_dict|from_yaml }}
passed_hosts_dict: {{ passed_hosts_dict|from_yaml }}
hosts_list: {{ hosts_list }}
run_once: true
- debug:
msg: |
Serial Number, Hostname, Ping Status
{% for i in hosts_list %}
{{ i.value.sn }},{{ i.key }},{{ i.value.status }}
{% endfor %}
run_once: true
- copy:
dest: /tmp/status.csv
content: |
Serial Number, Hostname, Ping Status
{% for i in hosts_list %}
{{ i.value.sn }},{{ i.key }},{{ i.value.status }}
{% endfor %}
delegate_to: localhost
run_once: true