Skip to content

Instantly share code, notes, and snippets.

@sferich888
Created December 31, 2019 05:40
Show Gist options
  • Save sferich888/ec5517f7b88818e84175d33a83e8b5a4 to your computer and use it in GitHub Desktop.
Save sferich888/ec5517f7b88818e84175d33a83e8b5a4 to your computer and use it in GitHub Desktop.
libvirt dynamic inventory

This asumes that your VM's in your libvirt network, have functioning DNS, using dnsmasq provided by libvirt and your host.

#!/usr/bin/env python
import libvirt, json
from sys import stderr, argv
from xml.dom import minidom
### Default (Globals)
# We want this to run on the local system only.
host_domain = 'qemu:///system'
# Initialize the dictionary. May be a horrible way to deal with it, but deal with it.
inventory = {}
inventory['_meta'] = {}
inventory['_meta']['hostvars'] = {}
inventory['all'] = {}
inventory['all']['children'] = ['active', 'inactive']
inventory['active'] = {}
inventory['inactive'] = {}
def get_doms_network(dom_list):
dom_networks = []
for dom in dom_list:
raw_xml = dom.XMLDesc(0)
xml = minidom.parseString(raw_xml)
interfaceTypes = xml.getElementsByTagName('interface')
for interfaceType in interfaceTypes:
interfaceNodes = interfaceType.childNodes
for interfaceNode in interfaceNodes:
if interfaceNode.nodeName[0:1] != "#":
try:
dom_networks.append({'domain': dom.name(),
'network': interfaceNode.attributes['network'].value})
except:
# the interfaceNode, does not have the attribute 'network'
# hasattr(interfaceNode, 'network')
# gennerally this can be ignored, thus pass.
pass
return dom_networks
def get_dom_domain(network_name):
raw_xml = virthost.networkLookupByName(network_name).XMLDesc(0)
xml = minidom.parseString(raw_xml)
return xml.getElementsByTagName('domain')[0].getAttribute('name')
def populate_inventory():
if virthost == None:
print('Failed to open connection to {}'.format(host_domain), file=stderr)
exit(1)
activedomains = virthost.listAllDomains(libvirt.VIR_CONNECT_LIST_DOMAINS_ACTIVE)
inactivedomains = virthost.listAllDomains(libvirt.VIR_CONNECT_LIST_DOMAINS_INACTIVE)
for dom_list in [(activedomains, 'active'), (inactivedomains, 'inactive')]:
host_list = []
for d in get_doms_network(dom_list[0]):
host_list.append("{}.{}".format(d['domain'], get_dom_domain(d['network'])))
if host_list:
inventory[dom_list[1]]['hosts'] = host_list
inventory[dom_list[1]]['vars'] = {}
if __name__ == '__main__':
if len(argv) == 2 and argv[1] == '--list':
virthost = libvirt.open(host_domain)
populate_inventory()
virthost.close()
print(json.dumps(inventory, indent=4, sort_keys=True))
elif len(argv) == 3 and argv[1] == '--host':
# 1: Host var's are 'empty'; from this script
# 2: We don't do anything to set these!
# TODO: Look a pulling this from domain metadata?
# - https://libvirt.org/formatdomain.html#elementsMetadata
# 3: Ansible docs say return an empty dict '{}'
# - https://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html
print(json.dumps({}))
else:
print("Need an argument, either --list or --host <host>", file=stderr)
exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment