Host inventory overview using Ansible’s Facts
Wednesday, January 21st, 2015
UPDATE: I’ve written a fancier version of the above script as a separate project called ansible-cmdb. It uses templates and can generate a feature-laden HTML version and text versions. It also lets you extend the information from your hosts very easily; even adding completely new hosts. Packages are available for Debian, Redhat and other operating systems.
Ansible is a multiplexing configuration orchestrator. It allows you to run commands and configure servers from a central system. For example, to run the uname -a command on servers in the group “intranet”:
[fboender@jib]~/Projects/ansible$ ansible -m shell -a "uname -a" intranet host001.example.com | success | rc=0 >> Linux host001.example.com 2.6.32-45-server #102-Ubuntu SMP Wed Jan 2 22:53:00 UTC 2013 x86_64 GNU/Linux host004.example.com | success | rc=0 >> Linux vps004c.example.com 2.6.32-55-server #117-Ubuntu SMP Tue Dec 3 17:45:11 UTC 2013 x86_64 GNU/Linux
Ansible can also gather system information using the ‘setup’ module. It returns the information as a JSON structure:
[fboender@jib]~/Projects/ansible$ ansible -m setup intranet host001.example.com | success >> { "ansible_facts": { "ansible_all_ipv4_addresses": [ "182.78.44.33", "10.0.0.1" ], "ansible_architecture": "x86_64", "ansible_bios_date": "NA", "ansible_bios_version": "NA", ... etc
We can use this to display a short tabulated overview of important system information such as the FQDN, configured IPs, Disk and memory information. I wrote a quick script to do this. The result looks like this:
[fboender@jib]~/Projects/ansible$ ./hostinfo intranet Name FQDN Datetime OS Arch Mem Disk Diskfree IPs ----------------------- ----------------------- -------------------------- ------------ ------ --------------- ------------------- ---------------- ------------------------------------------------------------------------- host001 host001.example.com 2015-01-20 14:37 CET +0100 Ubuntu 12.04 x86_64 4g (free 0.16g) 80g 40g 182.78.44.33, 10.0.0.1 host002 host002.example.com 2015-01-20 14:37 CET +0100 Ubuntu 14.04 x86_64 2g (free 1.21g) 40g 18g 182.78.44.34, 10.0.0.2 xxxxxx.xxxxxx.xx xxxxxxx.example.com 2015-01-20 13:37 CET +0000 Ubuntu 10.04 x86_64 2g (free 0.04g) 241g 20g 192.168.0.2, 10.000.0.4 xxxx.xxxxxx.xxx xxxx.otherdom.com 2015-01-20 14:37 CET +0100 Ubuntu 13.04 x86_64 8g (free 0.14g) 292g, 1877g, 1877g 237g, 583g, 785g 192.168.1.9, 192.168.1.10, 10.0.0.6 xxxxxxxx.xxxxxx.xx xxxx.otherdom.com 2015-01-20 14:36 CET +0100 Ubuntu 14.04 i386 6g (free 0.25g) 1860g, 1877g, 1877g 960g, 292g, 360g 10.0.0.5, 10.0.0.14, 192.168.1.12 xxxxx.xxxxx.xxx test.otherdom.com 2015-01-20 14:37 CET +0100 Ubuntu 9.10 x86_64 2g (free 0.28g) 40g 16g 10.0.0.15, 10.0.0.9
The script:
#!/usr/bin/python # MIT license import os import sys import shutil import json import tabulate import pprint host = sys.argv[1] tmp_dir = 'tmp_fact_col' try: shutil.rmtree(tmp_dir) except OSError: pass os.mkdir(tmp_dir) cmd = "ansible -t {} -m setup {} >/dev/null".format(tmp_dir, host) os.system(cmd) headers = [ 'Name', 'FQDN', 'Datetime', 'OS', 'Arch', 'Mem', 'Disk', 'Diskfree', 'IPs', ] d = [] for fname in os.listdir(tmp_dir): path = os.path.join(tmp_dir, fname) j = json.load(file(path, 'r')) if 'failed' in j: continue d.append( ( fname, j['ansible_facts']['ansible_fqdn'], "%s %s:%s %s %s" % ( j['ansible_facts']['ansible_date_time']['date'], j['ansible_facts']['ansible_date_time']['hour'], j['ansible_facts']['ansible_date_time']['minute'], j['ansible_facts']['ansible_date_time']['tz'], j['ansible_facts']['ansible_date_time']['tz_offset'], ), "%s %s" % ( j['ansible_facts']['ansible_distribution'], j['ansible_facts']['ansible_distribution_version'], ), j['ansible_facts']['ansible_architecture'], '%0.fg (free %0.2fg)' % ( (j['ansible_facts']['ansible_memtotal_mb'] / 1000.0), (j['ansible_facts']['ansible_memfree_mb'] / 1000.0) ), ', '.join([str(i['size_total']/1048576000) + 'g' for i in j['ansible_facts']['ansible_mounts']]), ', '.join([str(i['size_available']/1048576000) + 'g' for i in j['ansible_facts']['ansible_mounts']]), ', '.join(j['ansible_facts']['ansible_all_ipv4_addresses']), ) ) os.unlink(path) shutil.rmtree(tmp_dir) print tabulate.tabulate(d, headers=headers)
The script requires the Tabulator python library. Put the script in the directory containing your ansible hosts file, and run it.
UPDATE: I’ve written a fancier version of the above script as a separate project called ansible-cmdb. It uses templates and can generate a feature-laden HTML version and text versions. It also lets you extend the information from your hosts very easily; even adding completely new hosts. Packages are available for Debian, Redhat and other operating systems.