import logging from xml.etree import ElementTree as etree import libvirt import yaml from ansible.plugins.inventory import BaseInventoryPlugin, Constructable DOCUMENTATION = r''' name: pyrocufflink extends_documentation_fragment: - constructed short_description: Pyrocufflink inventory source version_added: '' description: - Dynamic inventory for Pyrocufflink machines author: - Dustin C. Hatch options: plugin: description: Token that ensures this is a source file for the 'pyrocufflink' plugin. required: True choices: ['pyrocufflink'] ''' log = logging.getLogger('ansible.plugins.inventory.pyrocufflink') METADATA_XMLNS = 'http://du5t1n.me/xmlns/libvirt/metadata/' DOMAIN_STATES = { 0: 'no state', 1: 'the domain is running', 2: 'the domain is blocked on resource', 3: 'the domain is paused by user', 4: 'the domain is being shut down', 5: 'the domain is shut off', 6: 'the domain is crashed', 7: 'the domain is suspended by guest power management', } # Remove the default error handler, which prints to stderr libvirt.registerErrorHandler(lambda *_: None, None) class InventoryModule(BaseInventoryPlugin, Constructable): NAME = 'pyrocufflink' def parse(self, inventory, loader, path, cache=True): super().parse(inventory, loader, path, cache=cache) config_data = self._read_config_data(path) # set _options from config data self._consume_options(config_data) assert self.inventory conn = libvirt.open() for dom in conn.listAllDomains(): v = {} name = v['name'] = dom.name() try: v['title'] = dom.metadata(1, None) except libvirt.libvirtError as e: log.debug('Could not get title for domain %s: %s', name, e) inventory_hostname = name else: inventory_hostname = v['title'] self.inventory.add_host(inventory_hostname) try: v['description'] = dom.metadata(0, None) except libvirt.libvirtError as e: log.debug('Could not get description for %s: %s', name, e) try: metadata = dom.metadata(2, METADATA_XMLNS) except libvirt.libvirtError as e: log.debug( 'Could not get extended domain metadata for %s: %s', name, e, ) else: try: v['metadata'] = parse_metadata(metadata) except Exception as e: log.error('Failed to parse metadata for %s: %s', name, e) state, reason = dom.state() v['state_code'] = state v['state_reason_code'] = reason try: v['state'] = DOMAIN_STATES[state] except KeyError: pass if state == 1: try: guest_info = dom.guestInfo() except libvirt.libvirtError as e: log.error('Could not get guest info for %s: %s', name, e) else: self.inventory.set_variable(name, 'guest_info', guest_info) self.inventory.set_variable(inventory_hostname, 'libvirt', v) def parse_metadata(metadata: str): tree = etree.fromstring(metadata) return yaml.safe_load(tree.text)