#!/usr/bin/env python ''' Example custom dynamic inventory script for Ansible, in Python. ''' from argparse import ArgumentParser from json import load as json_load, dumps, JSONEncoder from os import remove from os.path import isfile from asyncio import run from traceback import print_exc from risotto.machine import load, TIRAMISU_CACHE, VALUES_CACHE, INFORMATIONS_CACHE, ROUGAIL_NAMESPACE, ROUGAIL_NAMESPACE_DESCRIPTION from tiramisu import Config from tiramisu.error import PropertiesOptionError from rougail.utils import normalize_family from rougail import RougailSystemdTemplate, RougailConfig from rougail.template.base import RougailLeader, RougailExtra DEBUG = False class RougailEncoder(JSONEncoder): def default(self, obj): if isinstance(obj, RougailLeader): return obj._follower if isinstance(obj, RougailExtra): return obj._suboption if isinstance(obj, PropertiesOptionError): return 'PropertiesOptionError' return JSONEncoder.default(self, obj) class RisottoInventory(object): def __init__(self): parser = ArgumentParser() parser.add_argument('--list', action='store_true') parser.add_argument('--host', action='store') parser.add_argument('--nocache', action='store_true') parser.add_argument('--debug', action='store_true') self.args = parser.parse_args() if self.args.debug: global DEBUG DEBUG = True async def run(self): if self.args.list and self.args.host: raise Exception('cannot have --list and --host together') if self.args.list or self.args.nocache: if isfile(TIRAMISU_CACHE): remove(TIRAMISU_CACHE) if isfile(VALUES_CACHE): remove(VALUES_CACHE) if isfile(INFORMATIONS_CACHE): remove(INFORMATIONS_CACHE) config = await load(TIRAMISU_CACHE, VALUES_CACHE, INFORMATIONS_CACHE, ) if self.args.list: return await self.do_inventory(config) elif self.args.host: return await self.get_vars(config, self.args.host) raise Exception('pfff') async def do_inventory(self, config: Config, ) -> dict: servers = [await subconfig.option.doc() for subconfig in await config.option.list('optiondescription') if await subconfig.information.get('module') == 'host'] return dumps({ 'group': { 'hosts': servers, 'vars': { # FIXME # 'ansible_ssh_host': '192.168.0.100', 'ansible_ssh_user': 'root', 'ansible_python_interpreter': '/usr/bin/python3' } } }) async def get_vars(self, config: Config, host_name: str, ) -> dict: ret = {} rougailconfig = RougailConfig.copy() rougailconfig['variable_namespace'] = ROUGAIL_NAMESPACE rougailconfig['variable_namespace_description'] = ROUGAIL_NAMESPACE_DESCRIPTION for subconfig in await config.option.list('optiondescription'): server_name = await subconfig.option.description() module_name = await subconfig.option(await subconfig.information.get('provider:global:module_name')).value.get() if module_name == 'host' and server_name != host_name: continue engine = RougailSystemdTemplate(subconfig, rougailconfig) await engine.load_variables() if module_name != 'host' and engine.rougail_variables_dict['general']['host'] != host_name: continue ret[server_name] = engine.rougail_variables_dict ret['modules'] = await config.information.get('modules') ret['delete_old_image'] = False ret['configure_host'] = True ret['only_machine'] = None ret['copy_template'] = False ret['host_install_dir'] = ret[host_name].pop('host_install_dir') return dumps(ret, cls=RougailEncoder) # Get the inventory. async def main(): try: inv = RisottoInventory() values = await inv.run() print(values) except Exception as err: if DEBUG: print_exc() exit(err) run(main())