#!/usr/bin/env python3 from asyncio import run from tabulate import tabulate from argparse import ArgumentParser from rougail.utils import normalize_family from tiramisu.error import PropertiesOptionError from risotto.machine import load, remove_cache, ROUGAIL_NAMESPACE HIDE_SECRET = True def list_to_string(lst): if isinstance(lst, list): return "\n".join([str(val) for val in lst]) return lst async def get_files_subelements(type_name, element, files_subelement, files_cols): data = {} if not await element.option('activate').value.get(): return data for subelement in files_subelement.values(): if subelement['type'] == 'subelement': try: value = list_to_string(await element.option(subelement['key']).value.get()) # FIXME except AttributeError: except Exception: value = '' elif subelement['type'] == 'information': value = await element.information.get(subelement['key'], '') elif subelement['type'] == 'none': value = subelement['value'] else: raise Exception('unknown subelement') if value != '': files_cols.add(subelement['key']) data[subelement['key']] = value if type_name == 'overrides': data['name'] = f'/systemd/system/{data["source"]}.d/rougail.conf' if not data['engine']: data['engine'] = 'none' elif not data['engine']: data['engine'] = 'cheetah' return data async def services(config, values): files_subelement = {'Source': {'key': 'source', 'type': 'information'}, 'Nom': {'key': 'name', 'type': 'subelement'}, 'Variable': {'key': 'variable', 'type': 'subelement'}, 'Propriétaire': {'key': 'owner', 'type': 'subelement'}, 'Groupe': {'key': 'group', 'type': 'subelement'}, 'Mode': {'key': 'mode', 'type': 'subelement'}, 'Moteur': {'key': 'engine', 'type': 'information'}, } disabled_services = [] for service in await config.option.list(type="all"): doc = await service.option.doc() files_lst = [] files_cols = set() if not await service.option('manage').value.get(): doc += " - unmanaged" if not await service.option('activate').value.get(): disabled_services.append([doc]) else: for type in await service.list(type="all"): type_name = await type.option.doc() if type_name in ['files', 'overrides']: for element in await type.list(type="all"): data = await get_files_subelements(type_name, element, files_subelement, files_cols) if data: files_lst.append(data) elif type_name == 'manage': pass elif type_name == 'activate': if not await type.value.get(): doc += " - unactivated" else: print("FIXME " + type_name) if files_lst: keys = [key for key, val in files_subelement.items() if val['key'] in files_cols] values[doc] = {'keys': keys, 'lst': []} for lst in files_lst: values[doc]['lst'].append([val for key, val in lst.items() if key in files_cols]) if disabled_services: values["Services désactivés"] = {'keys': ['Nom'], 'lst': disabled_services} async def table_leader(config, read_only): keys = ['Description'] if read_only: keys.append('Cachée') leadership_lst = await config.list(type="all") leader = leadership_lst.pop(0) leader_owner = await leader.owner.get() follower_names = [await follower.option.name() for follower in leadership_lst] doc = await leader.option.doc() properties = await leader.property.get() if 'mandatory' in properties: doc += '*' name = await leader.option.name() lst = [[f'{doc} ({name})']] if read_only: if 'hidden' in properties: hidden = 'oui' else: hidden = '' lst[0].append(hidden) for idx, leader_value in enumerate(await leader.value.get()): keys.append(f'Valeur {idx}') keys.append(f'Utilisateur {idx}') lst[0].append(leader_value) lst[0].append(leader_owner) for follower_idx, follower_name in enumerate(follower_names): follower_option = config.option(follower_name, idx) if idx == 0: doc = await follower_option.option.doc() properties = await follower_option.property.get() if 'mandatory' in properties: doc += '*' name = await follower_option.option.name() lst.append([f'{doc} ({name})']) if read_only: if 'hidden' in properties: hidden = 'oui' else: hidden = '' lst[-1].append(hidden) try: lst[follower_idx + 1].append(list_to_string(await follower_option.value.get())) lst[follower_idx + 1].append(await follower_option.owner.get()) except PropertiesOptionError: pass # leader = next leader_iter # if master_values is None: # master_values = await subconfig.value.get() return {'keys': keys, 'lst': lst} async def table(config, prefix_len, values, read_only): lst = [] for subconfig in await config.option.list(type="all"): # prefix = prefix_len * 2 * ' ' # if await subconfig.option.isoptiondescription(): # prefix += '=>' # else: # prefix += '-' # display_str = f'{prefix} {description}' # if name != description: # display_str = f'{display_str} ({name})' name = await subconfig.option.name() doc = await subconfig.option.doc() if prefix_len == 0 and ROUGAIL_NAMESPACE != name: doc = doc.capitalize() if prefix_len == 0 and name == 'services': values['Services'] = {} await services(subconfig, values['Services']) elif await subconfig.option.isoptiondescription(): od_name = f'{doc} ({(await subconfig.option.path()).split(".", 1)[1]})' values[od_name] = None if await subconfig.option.isleadership(): values[od_name] = await table_leader(subconfig, read_only) else: values[od_name] = await table(subconfig, prefix_len + 1, values, read_only) else: value = list_to_string(await subconfig.value.get()) doc = await subconfig.option.doc() properties = await subconfig.property.get() if 'mandatory' in properties: doc += '*' name = await subconfig.option.name() lst.append([f'{doc} ({name})', value]) if read_only: if 'hidden' in properties: hidden = 'oui' else: hidden = '' lst[-1].append(hidden) lst[-1].append(await subconfig.owner.get()) keys = ['Description', 'Valeur'] if read_only: keys.append('Cachée') keys.append('Utilisateur') return {'keys': keys, 'lst': lst} async def main(): parser = ArgumentParser() parser.add_argument('server_name') parser.add_argument('--read_only', action='store_true') parser.add_argument('--nocache', action='store_true') parser.add_argument('--debug', action='store_true') args = parser.parse_args() if args.nocache: remove_cache() values = {} server_name = args.server_name config = await load(hide_secret=HIDE_SECRET, original_display_name=True, valid_mandatories=args.read_only, ) if not args.read_only: await config.property.read_write() root_option = config.option(normalize_family(server_name)) try: await root_option.option.get() except AttributeError: exit(f'Unable to find {server_name} configuration: {[await o.option.description() for o in await config.option.list(type="optiondescription")]}') await table(root_option, 0, values, args.read_only) for title, dico in values.items(): if title == 'Services': if not dico: continue print() print(title) print('=' * len(title)) print() for subtitle, dic in dico.items(): print() print(' ' + subtitle) print(' ' + '-' * len(subtitle)) print() print(tabulate(dic['lst'], headers=dic['keys'], tablefmt="fancy_grid")) elif dico['lst']: print() print(title) print('=' * len(title)) print() print(tabulate(dico['lst'], headers=dico['keys'], tablefmt="fancy_grid")) run(main())