Using Ansible to generate a CSV of host facts

Using Ansible to generate a CSV of host facts

I needed to get the name of the OS and CPU count of hosts that were running Windows Server 2012 or Windows Server 2012 R2.  Thankfully our Windows estate is already setup to allow Ansible connectivity

After a bit of searching and testing I got an Ansible playbook together that would generate a CSV of the data I was after.  But after doing that it's clear that this could be used for generating a report of any Ansible gathered fact about a host

The following is mostly gathered from this StackOverflow answer

# Ansible playbook to generate a CSV containing OS & CPU counts for 
# Windows Server 2012 & 2012 R2 hosts

- hosts: all
  gather_facts: yes

  # This is how filtering can be done
  # In this example, we'll end the play for hosts that do NOT have '2012'
  # in the ansible_os_name field.
  - meta: end_host
    when: ("2012" not in ansible_os_name)

  # Only matching hosts are left now

  # Use the template module to create a CSV file
  - template:
      src: os_cpu_count.csv.j2
      dest: 2012_os_report.csv
      _hosts: "{{ ansible_play_hosts|list }}"
    delegate_to: localhost

To filter out assest I didn't need, I used the meta: end_host syntax which 'Causes the play to end for the current host without failing it'.  In this example I end_host when the string 2012 is NOT in the OS name (i.e. end of any other OS other than a 2012 OS).  This section can be modified to filter out anything, including having multiple conditions on the when tag and/or additional meta: end_host sections could be added to perform further filtering, whichever is clearer/cleaner in your opinion.

After filtering the template: module is used.  Here I pass in a variable named _hosts with a list of the hosts still in play.  See the Ansible documentation for further reading on this special variable.

The template used looks like this:-

{% for i in _hosts %}
{{ i }},{{ hostvars[i]['ansible_facts']['os_name'] }},{{ hostvars[i]['ansible_facts']['processor_cores'] }},{{ hostvars[i]['ansible_facts']['processor_count'] }},{{ hostvars[i]['ansible_facts']['processor_threads_per_core'] }},{{ hostvars[i]['ansible_facts']['processor_vcpus'] }}
{% endfor %}

The template generates the header field on line 1, then iterates over each item i in _hosts.  As the template iterates over each host I needed to get the fact data from that specific host.  This StackOverflow answer helped me here, using the hostvars special variable.  See here for the Ansible documentation on that.

With the playbook ready I tried it out on a few servers first which worked well, so I ran it against the whole estate, and the CSV returned looked like this

I gave the report to the folks with the company credit card to allow us to pay the right amount for Extended Security Update (ESU) keys.