diff --git a/bootstrap.py b/bootstrap.py index 51313b7..4a4a9a0 100755 --- a/bootstrap.py +++ b/bootstrap.py @@ -17,7 +17,7 @@ from tiramisu.error import ValueWarning from rougail import RougailConfig, RougailConvert, RougailSystemdTemplate from rougail.utils import normalize_family -from risotto.utils import MULTI_FUNCTIONS, CONFIGS +from risotto.utils import MULTI_FUNCTIONS, CONFIGS, DOMAINS with open(environ.get('CONFIG_FILE', 'risotto.conf'), 'r') as fh: @@ -39,13 +39,14 @@ with open('servers.json', 'r') as server_fh: async def set_linked_multi_variables(value: str, linked_server: str=None, + variable_index: int=None, **kwargs: dict, ) -> None: if value is not None and linked_server is not None and 'linked_value_0' not in kwargs: kwargs['linked_value_0'] = value - elif linked_server is None: + elif not linked_server: linked_server = value - if linked_server is None: + if not linked_server: return if linked_server not in CONFIGS: warn_explicit(ValueWarning(f'cannot find linked server "{linked_server}"'), @@ -66,51 +67,76 @@ async def set_linked_multi_variables(value: str, if not path: return if index not in variables: - variables[index] = {'path': None, 'value': None} + variables[index] = {'path': None, 'value': None, 'variable_index': False} variables[index]['path'] = path elif key.startswith('linked_value_'): index = int(key[13]) if index not in variables: - variables[index] = {'path': None, 'value': None} + variables[index] = {'path': None, 'value': None, 'variable_index': False} variables[index]['value'] = value + elif key.startswith('variable_index_'): + index = int(key[15]) + if index not in variables: + variables[index] = {'path': None, 'value': None, 'variable_index': False} + variables[index]['variable_index'] = True else: raise AttributeError(f'unknown parameter {key}') - dynamic = None - slave_idx = None await config.property.read_write() - first_variable = variables[0]['value'] +# print('=====================================') +# pprint(variables) if not isinstance(variables[0]['value'], list): variables[0]['value'] = [variables[0]['value']] + dynamic = None try: - for var_index in range(len(variables[0]['value'])): - pass - for index in sorted(list(variables)): - path = variables[index]['path'] - if index == 0: - value = variables[index]['value'][var_index] - dynamic = normalize_family(value) - else: + if variables[0]['value']: + for first_idx, first_value in enumerate(variables[0]['value']): + slave_idxes = [] + dynamic = normalize_family(first_value) + for index in sorted(list(variables)): + path = variables[index]['path'] + if '{suffix}' in path: + path = path.replace('{suffix}', dynamic) + elif first_idx != 0: + continue value = variables[index]['value'] - path = path.replace('{suffix}', dynamic) - option = config.forcepermissive.option(path, slave_idx) - multi = await option.option.ismulti() - if multi and await option.option.isfollower(): - multi = await option.option.issubmulti() - if multi: - values = await option.value.get() - if value not in values: - values.append(value) - await option.value.set(values) - if await option.option.isleader(): - slave_idx = values.index(value) - else: - if isinstance(value, list): - value = value[var_index] - await option.value.set(value) + option = config.forcepermissive.option(path) + if not await option.option.isfollower(): + #print('===>', path, value, await option.option.ismulti(), await option.option.issubmulti()) + multi = await option.option.ismulti() + if multi: + isleader = await option.option.isleader() + if not isinstance(value, list): + value = [value] + # elif isleader: + # raise Exception('leader must not be a multi from now ...') + values = await option.value.get() + for val in value: + if val not in values: + if isleader: + slave_idxes.append(len(values)) + values.append(val) + elif isleader: + slave_idxes.append(values.index(val)) + await option.value.set(values) + else: + await option.value.set(value) + else: + #print('===<', path, value, await option.option.ismulti(), await option.option.issubmulti()) + if not slave_idxes: + raise Exception('please declare the leader variable before the follower') + if variables[index]['variable_index']: + value = value[variable_index] + if not isinstance(value, list): + value = [value] * len(slave_idxes) + # if isinstance(value, list) and not await option.option.issubmulti(): + for idx, val in enumerate(value): + option = config.forcepermissive.option(path, slave_idxes[idx]) + await option.value.set(val) except Exception as err: await config.property.read_only() raise err from err await config.property.read_only() + return get_ip_from_domain(linked_server) async def set_linked(linked_server: str, @@ -364,7 +390,7 @@ def build_module(module_name, datas, module_infos): for filename in listdir(manual_dir): src_file = join(manual_dir, filename) if type == 'image': - dst_file = join(install_dir, filename) + dst_file = join(install_dir, 'manual', filename) verify = False else: dst_file= join(INSTALL_DIR, filename) @@ -398,6 +424,13 @@ def build_module(module_name, datas, module_infos): calc_depends(applicationservice, added) +def get_ip_from_domain(domain): + if not domain: + return + hostname, domainname = domain.split('.', 1) + return DOMAINS[domainname][1][DOMAINS[domainname][0].index(hostname)] + + async def build(server_name, datas, module_infos): if server_name in CONFIGS: raise Exception(f'server "{server_name}" is duplicate') @@ -416,6 +449,7 @@ async def build(server_name, datas, module_infos): 'set_linked_multi_variables': set_linked_multi_variables, 'get_linked_configuration': get_linked_configuration, 'set_linked_configuration': set_linked_configuration, + 'get_ip_from_domain': get_ip_from_domain, } cfg['internal_functions'] = list(optiondescription.keys()) try: @@ -535,11 +569,14 @@ async def main(): for server_name in SERVERS: config = CONFIGS[server_name][0] await config.property.pop('mandatory') - await config.value.dict() + try: + await config.value.dict() + except Exception as err: + raise Exception(f'cannot display config for "{server_name}": {err}') await config.property.add('mandatory') for server_name in SERVERS: await valid_mandatories(server_name, CONFIGS[server_name][0]) -# print(await CONFIGS['revprox.in.gnunux.info'][0].option('nginx.reverse_proxy_for_netbox_in_gnunux_info.reverse_proxy_netbox_in_gnunux_info.revprox_url_netbox_in_gnunux_info', 0).value.get()) +# print(await CONFIGS['dovecot.in.silique.fr'][0].value.dict()) for server_name in SERVERS: await templates(server_name, *CONFIGS[server_name]) diff --git a/funcs.py b/funcs.py index 406c28c..b59c0e1 100644 --- a/funcs.py +++ b/funcs.py @@ -7,7 +7,7 @@ from secrets import token_urlsafe as _token_urlsafe from rougail.utils import normalize_family -from risotto.utils import multi_function, CONFIGS +from risotto.utils import multi_function, CONFIGS, DOMAINS from risotto.x509 import gen_cert as _x509_gen_cert, gen_ca as _x509_gen_ca, gen_pub as _x509_gen_pub, has_pub as _x509_has_pub # ============================================================= # fork of risotto-setting/src/risotto_setting/config/config.py @@ -17,7 +17,6 @@ with open('servers.json', 'r') as server_fh: ZONES = None -DOMAINS = None HERE = dirname(abspath(__file__)) @@ -49,9 +48,8 @@ def load_zones(): def load_domains(): load_zones() global DOMAINS - if DOMAINS is not None: + if DOMAINS: return - DOMAINS = {} for zone_name, zone in ZONES_SERVER['zones'].items(): if 'domain_name' in zone: hosts = [] diff --git a/src/risotto/utils.py b/src/risotto/utils.py index 326d925..0e76159 100644 --- a/src/risotto/utils.py +++ b/src/risotto/utils.py @@ -1,5 +1,6 @@ MULTI_FUNCTIONS = [] CONFIGS = {} +DOMAINS = {} def _(s):