Source code for lago.lago_ansible

from collections import defaultdict
import functools
import logging
import tempfile
import contextlib

from . import log_utils

LOGGER = logging.getLogger(__name__)
LogTask = functools.partial(log_utils.LogTask, logger=LOGGER)


[docs]class LagoAnsible(object): """ A class for handling Ansible related tasks Attributes: prefix (lago.prefix.Prefix): The prefix that this object wraps """ def __init__(self, prefix): """ Args: prefix (lago.prefix.Prefix): A prefix to wrap """ self.prefix = prefix
[docs] def get_inventory_str(self, keys=None): """ Convert a dict generated by ansible.LagoAnsible.get_inventory to an INI-like file. Args: keys (list of str): Path to the keys that will be used to create groups. Returns: str: INI-like Ansible inventory """ inventory = self.get_inventory(keys) lines = [] for name, hosts in inventory.viewitems(): lines.append('[{name}]'.format(name=name)) for host in sorted(hosts): lines.append(host) return '\n'.join(lines)
[docs] def get_inventory(self, keys=None): """ Create an Ansible inventory based on python dicts and lists. The returned value is a dict in which every key represents a group and every value is a list of entries for that group. Args: keys (list of str): Path to the keys that will be used to create groups. Returns: dict: dict based Ansible inventory """ inventory = defaultdict(list) keys = keys or ['vm-type', 'groups', 'vm-provider'] vms = self.prefix.get_vms().values() for vm in vms: entry = self._generate_entry(vm) vm_spec = vm.spec for key in keys: value = self.get_key(key, vm_spec) if value is None: continue if isinstance(value, list): for sub_value in value: inventory['{}={}'.format(key, sub_value)].append(entry) else: inventory['{}={}'.format(key, value)].append(entry) # Adding a special case for the group key. # Most of the times the user wants that the host # will be a part of the group "group", and not a part of # "group=something" for group in vm_spec.get('groups', []): inventory[group].append(entry) return inventory
[docs] def _generate_entry(self, vm): """ Generate host entry for the given VM Args: vm (lago.plugins.vm.VMPlugin): The VM for which the entry should be created for. Returns: str: An entry for vm """ return \ '{name} ' \ 'ansible_host={ip} ' \ 'ansible_ssh_private_key_file={key}'.format( name=vm.name(), ip=vm.ip(), key=self.prefix.paths.ssh_id_rsa() )
[docs] @staticmethod def get_key(key, data_structure): """ Helper method for extracting values from a nested data structure. Args: key (str): The path to the vales (a series of keys and indexes separated by '/') data_structure (dict or list): The data structure from which the value will be extracted. Returns: str: The values associated with key """ if key == '/': return data_structure path = key.split('/') # If the path start with '/', remove the empty string from the list path[0] or path.pop(0) current_value = data_structure while path: current_key = path.pop(0) try: current_key = int(current_key) except ValueError: pass try: current_value = current_value[current_key] except (KeyError, IndexError): LOGGER.debug('failed to extract path {}'.format(key)) return None return current_value
[docs] @contextlib.contextmanager def get_inventory_temp_file(self, keys=None): """ Context manager which returns the inventory written on a tempfile. The tempfile will be deleted as soon as this context manger ends. Args: keys (list of str): Path to the keys that will be used to create groups. Yields: tempfile.NamedTemporaryFile: Temp file containing the inventory """ temp_file = tempfile.NamedTemporaryFile(mode='r+t') inventory = self.get_inventory_str(keys) LOGGER.debug( 'Writing inventory to temp file {} \n{}'.format( temp_file.name, inventory ) ) temp_file.write(inventory) temp_file.flush() temp_file.seek(0) yield temp_file temp_file.close()