Compare commits

...

4 commits
main ... main

5 changed files with 618 additions and 204 deletions

View file

@ -41,7 +41,8 @@ class RisottoInventory(object):
parser.add_argument('--nocache', action='store_true') parser.add_argument('--nocache', action='store_true')
parser.add_argument('--debug', action='store_true') parser.add_argument('--debug', action='store_true')
parser.add_argument('--pretty_print', action='store_true') parser.add_argument('--pretty_print', action='store_true')
parser.add_argument('--quite', action='store_true') parser.add_argument('--quiet', action='store_true')
parser.add_argument('--server', action='store', default=None)
self.args = parser.parse_args() self.args = parser.parse_args()
if self.args.debug: if self.args.debug:
global DEBUG global DEBUG
@ -64,7 +65,10 @@ class RisottoInventory(object):
if self.args.list: if self.args.list:
return self.do_inventory(config) return self.do_inventory(config)
elif self.args.host: elif self.args.host:
return self.get_vars(config, self.args.host) return self.get_vars(config,
self.args.host,
self.args.server,
)
raise Exception('pfff') raise Exception('pfff')
def do_inventory(self, def do_inventory(self,
@ -86,6 +90,7 @@ class RisottoInventory(object):
def get_vars(self, def get_vars(self,
config: Config, config: Config,
host_name: str, host_name: str,
only_server_name: str,
) -> dict: ) -> dict:
ret = {} ret = {}
rougailconfig = RougailConfig.copy() rougailconfig = RougailConfig.copy()
@ -101,14 +106,19 @@ class RisottoInventory(object):
if module_name != 'host' and engine.rougail_variables_dict['general']['host'] != host_name: if module_name != 'host' and engine.rougail_variables_dict['general']['host'] != host_name:
continue continue
ret[server_name] = engine.rougail_variables_dict ret[server_name] = engine.rougail_variables_dict
ret['modules'] = config.information.get('modules') if only_server_name is None:
ret['delete_old_image'] = False ret['modules'] = config.information.get('modules')
ret['configure_host'] = True ret['delete_old_image'] = False
ret['only_machine'] = None ret['configure_host'] = True
ret['copy_templates'] = False ret['only_machine'] = None
ret['copy_tests'] = False ret['copy_templates'] = False
ret['host_install_dir'] = ret[host_name]['general']['host_install_dir'] ret['copy_tests'] = False
return dumps(ret, cls=RougailEncoder) ret['host_install_dir'] = ret[host_name]['general']['host_install_dir']
return dumps(ret, cls=RougailEncoder)
else:
if only_server_name not in ret:
raise Exception(f'cannot find server name "{only_server_name}" in {list(ret)}')
return dumps(ret[only_server_name], cls=RougailEncoder)
# Get the inventory. # Get the inventory.
@ -120,7 +130,7 @@ def main():
from pprint import pprint from pprint import pprint
from json import loads from json import loads
pprint(loads(values)) pprint(loads(values))
elif not inv.args.quite: elif not inv.args.quiet:
print(values) print(values)
except Exception as err: except Exception as err:
if DEBUG: if DEBUG:

View file

@ -1,14 +1,21 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from os import listdir
from os.path import isdir, join
from os import listdir, unlink
from os.path import isdir, isfile, join, abspath
from tabulate import tabulate from tabulate import tabulate
from sys import argv from sys import argv
from yaml import dump
from ruamel.yaml import YAML
from glob import glob
from rougail import RougailConfig from rougail import RougailConfig
from rougail.convert import RougailConvert from rougail.convert import RougailConvert
from rougail.objspace import RootRougailObject from rougail.objspace import RootRougailObject
from rougail.annotator.family import Mode
from risotto.utils import EXTRA_ANNOTATORS, ROUGAIL_NAMESPACE, ROUGAIL_NAMESPACE_DESCRIPTION from risotto.utils import EXTRA_ANNOTATORS, ROUGAIL_NAMESPACE, ROUGAIL_NAMESPACE_DESCRIPTION
from risotto.image import load_application_service from risotto.image import load_application_service
from risotto.rougail import func
rougailconfig = RougailConfig rougailconfig = RougailConfig
@ -16,36 +23,146 @@ rougailconfig['variable_namespace'] = ROUGAIL_NAMESPACE
rougailconfig['variable_namespace_description'] = ROUGAIL_NAMESPACE_DESCRIPTION rougailconfig['variable_namespace_description'] = ROUGAIL_NAMESPACE_DESCRIPTION
DEFAULT_TYPE = 'string'
ROUGAIL_VARIABLE_TYPE = 'https://forge.cloud.silique.fr/risotto/rougail/src/branch/main/doc/variable/README.md#le-type-de-la-variable' ROUGAIL_VARIABLE_TYPE = 'https://forge.cloud.silique.fr/risotto/rougail/src/branch/main/doc/variable/README.md#le-type-de-la-variable'
def add_title_family(elts, dico): def add_title_family(elts, dico, modes):
is_dynamic = False
for idx, elt in enumerate(elts): for idx, elt in enumerate(elts):
description = elt.doc description = elt.doc
if not idx: if not idx:
description = description.capitalize() description = description.capitalize()
space = idx + 3 space = idx + 3
title = '#' * space + f' {description} (*{elt.path}*)' title = '#' * space + f' {description}'
if title not in dico: if title not in dico:
dico[title] = {'variables': [], 'help': '', 'type': ''} if not is_dynamic and hasattr(elt, 'suffixes') and elt.suffixes:
is_dynamic = True
if is_dynamic:
title += '*suffix value*'
dico[title] = {'help': '', 'type': 'optiondescription', 'level': idx + 1}
if hasattr(elt, 'information') and hasattr(elt.information, 'help'): if hasattr(elt, 'information') and hasattr(elt.information, 'help'):
dico[title]['help'] = elt.information.help help_ = elt.information.help
if hasattr(elt, 'suffixes') and elt.suffixes: if not help_.endswith('.'):
dico[title]['type'] = 'dynamic' help_ += '.'
dico[title]['suffixes'] = elt.suffixes.path dico[title]['help'] += help_
if hasattr(elt, 'leadership') and elt.leadership: if hasattr(elt, 'suffixes') and elt.suffixes:
dico[title]['type'] = 'leadership' dico[title]['suffixes'] = elt.suffixes.path
return title if dico[title]['help']:
dico[title]['help'] += ' '
dico[title]['help'] += f'This a dynamic family generated from the variable "{elt.suffixes.path}".'
if hasattr(elt, 'leadership') and elt.leadership:
if dico[title]['help']:
dico[title]['help'] += ' '
dico[title]['help'] += f'This family is a leadership.'
add_mode(elt, dico[title], modes)
def add_parameter_variable(idx, child, is_leadership, type_, name):
if type_ == 'variable':
var_path = child.xmlfiles[-1].split('/', 2)[-1]
parameter = f'**[{name}]({var_path})**'
elif type_ == 'provider':
parameter = f'**{name}**'
subparameter = ''
if hasattr(child, 'properties') and 'mandatory' in child.properties:
subparameter = 'mandatory'
if ((idx == 0 or not is_leadership) and child.multi is True) or (idx != 0 and is_leadership and child.multi == 'submulti'):
if subparameter:
subparameter += ', '
subparameter += 'multiple'
if subparameter:
parameter += f'<br/>{subparameter}'
var_type = f'**Type:** [`{child.type}`]({ROUGAIL_VARIABLE_TYPE})'
return f'{parameter}<br/>{var_type}'
def parse(applicationservice, elts, dico, providers_suppliers, hidden, objectspace):
def add_title_variable(child, is_leadership, is_dynamic, objectspace):
description = f'{child.doc}'
if is_dynamic:
description += '*suffix value*'
if not description.endswith('.'):
description += '.'
if hasattr(child, 'information') and hasattr(child.information, 'help'):
if description:
description += '<br/>'
help_ = child.information.help
if not help_.endswith('.'):
help_ += '.'
description += help_
if hasattr(child, 'default'):
default = child.default
if isinstance(default, objectspace.value):
default = '*calculated*'
if isinstance(default, list):
default = '<ul>' + ''.join([f'<li>{val}</li>' for val in default]) + '</ul>'
elif is_leadership and hasattr(child, 'default_multi'):
default = child.default_multi
else:
default = None
if hasattr(child, 'choice'):
if description:
description += '<br/>'
description += '**Choices:**'
for choice in child.choice:
description += f'<br/>- `{choice.name}`'
if choice.name == default:
description += ' ← default'
elif default is not None:
if description:
description += '<br/>'
description += f'**Default:** {default}'
if hasattr(child, 'test'):
if description:
description += '<br/>'
description += f'**Example:** {child.test}'
return description
def add_mode(child, values, modes, parent=None, is_leadership=False):
for mode in modes:
if mode in child.properties:
break
else:
raise Exception(f'cannot find mode for {child.path}')
if is_leadership:
for leadership_mode in modes:
if leadership_mode in parent.properties:
break
else:
raise Exception(f'cannot find mode for {parent.path}')
if modes[mode] < modes[leadership_mode]:
mode = leadership_mode
values['mode'] = mode
def parse(applicationservice,
elts,
dico,
providers_suppliers,
hidden,
dynamic,
objectspace,
mandatory_values_without_values,
modes,
is_dynamic,
dynamic_path,
is_service,
suppliers_variables,
):
elt = elts[-1] elt = elts[-1]
first_variable = True
if not hidden: if not hidden:
hidden = hasattr(elt, 'properties') and ('hidden' in elt.properties or 'disabled' in elt.properties) hidden = hasattr(elt, 'properties') and ('hidden' in elt.properties or 'disabled' in elt.properties)
is_leadership = hasattr(elt, 'leadership') and elt.leadership if not dynamic:
dynamic = hasattr(elt, 'suffixes')
is_leadership = hasattr(elt, 'leadership') and elt.leadership is True
if not is_dynamic:
is_dynamic = hasattr(elt, 'suffixes') and elt.suffixes is not None
dynamic_path += elt.name
if is_dynamic:
dynamic_path += "*suffix value*"
dynamic_path += '.'
leader_is_mandatory = False
first_variable = True
for children in vars(elt).values(): for children in vars(elt).values():
if isinstance(children, dict): if isinstance(children, dict):
children = list(children.values()) children = list(children.values())
@ -56,60 +173,109 @@ def parse(applicationservice, elts, dico, providers_suppliers, hidden, objectspa
not isinstance(child, RootRougailObject): not isinstance(child, RootRougailObject):
continue continue
if isinstance(child, objectspace.variable): if isinstance(child, objectspace.variable):
if hasattr(child, 'provider') and child.provider and not child.provider.startswith('global:') and not child.provider.startswith('Host:'):
provider_prefix = child.provider
if ':' in provider_prefix:
provider_prefix = provider_prefix.split(':', 1)[0]
if provider_prefix != 'Host':
if child.doc == child.name:
description = None
else:
parameter = add_parameter_variable(idx, child, is_leadership, 'provider', child.provider)
description = add_title_variable(child, is_leadership, is_dynamic, objectspace)
suppliers_variables.setdefault(provider_prefix, {})[child.provider] = {'parameter': parameter, 'description': description}
if provider_prefix == child.provider:
doc = child.doc
if not doc.endswith('.'):
doc += '.'
suppliers_variables[provider_prefix]['doc'] = doc
if not hidden and (not hasattr(child, 'properties') or ('hidden' not in child.properties and not 'disabled' in child.properties)): if not hidden and (not hasattr(child, 'properties') or ('hidden' not in child.properties and not 'disabled' in child.properties)):
if is_service:
if hasattr(child, 'provider'):
provider = child.provider
if ':' not in provider:
providers_suppliers['providers'].setdefault(provider, []).append(applicationservice)
if hasattr(child, 'supplier') and child.supplier:
supplier = child.supplier
if ':' not in supplier:
providers_suppliers['suppliers'].setdefault(supplier, []).append(applicationservice)
if 'mandatory' in child.properties:
providers_suppliers['mandatory_suppliers'].setdefault(supplier, []).append(applicationservice)
if hasattr(child, 'supplier') and child.supplier and ':' not in child.supplier:
raise Exception(f'Main supplier variable "{child.path}" in {child.xmlfiles} must be hidden')
if hasattr(child, 'provider') and child.provider and not child.provider.startswith('Host:'):
raise Exception(f'Provider variable "{child.path}" in {child.xmlfiles} must be hidden')
if first_variable: if first_variable:
title = add_title_family(elts, dico) add_title_family(elts, dico, modes)
first_variable = False first_variable = False
var_title = child.doc sub_dynamic_path = dynamic_path + child.name
if hasattr(child, 'properties') and 'mandatory' in child.properties: if is_dynamic:
var_title = '**' + var_title + '**' sub_dynamic_path += "*suffix value*"
var_path = child.xmlfiles[-1].split('/', 2)[-1] if not idx and is_leadership and hasattr(child, 'properties') and 'mandatory' in child.properties:
if child.doc != child.name: leader_is_mandatory = True
var_title += f' (*[{child.name}]({var_path})*)' if hasattr(child, 'properties') and 'mandatory' in child.properties and \
else: mandatory_values_without_values is not None and \
var_title = f'*[{var_title}]({var_path})*' not hidden and \
if ((idx == 0 or not is_leadership) and child.multi is True) or (idx != 0 and is_leadership and child.multi == 'submulti'): not dynamic and \
var_title += ' [+]' not hasattr(child, 'default') and \
values = {'description': var_title, not hasattr(child, 'default_multi') and \
} (not is_leadership or leader_is_mandatory):
if hasattr(child, 'information') and hasattr(child.information, 'help'): if not hasattr(child, 'test'):
values['help'] = child.information.help raise Exception(f'{child.path} need test tag to document')
if child.type != DEFAULT_TYPE: value = child.test
values['type'] = child.type if ((not is_leadership or not idx) and child.multi is True) or (is_leadership and idx and child.multi == 'submulti'):
if hasattr(child, 'default'): value = [value]
default = child.default if is_leadership and idx:
if isinstance(default, objectspace.value): value = {'0': value}
default = '<calculated>' mandatory_values_without_values[child.path] = value
if isinstance(default, list): parameter = add_parameter_variable(idx, child, is_leadership, 'variable', sub_dynamic_path)
default = '<br />'.join(default) #
values['values'] = default if child.name == child.doc:
if hasattr(child, 'choice'): raise Exception(f'missing doc for variable {child.path} in {child.xmlfiles}')
values['choices'] = '<br />'.join([choice.name for choice in child.choice]) description = add_title_variable(child, is_leadership, is_dynamic, objectspace)
if hasattr(child, 'provider'): values = {'parameter': parameter,
provider = child.provider 'description': description,
values['provider'] = provider 'type': 'option'}
if ':' not in provider: if hasattr(child, 'supplier') and child.supplier:
providers_suppliers['providers'].setdefault(provider, []).append(applicationservice) values['supplier'] = child.supplier
if hasattr(child, 'supplier'): add_mode(child, values, modes, elt, is_leadership)
supplier = child.supplier dico[child.path] = values
values['supplier'] = supplier elif is_service:
if ':' not in supplier:
providers_suppliers['suppliers'].setdefault(supplier, []).append(applicationservice)
dico[title]['variables'].append(values)
else:
if hasattr(child, 'provider'): if hasattr(child, 'provider'):
provider = child.provider provider = child.provider
if ':' not in provider: if ':' not in provider:
providers_suppliers['providers'].setdefault(provider, []).append(applicationservice) providers_suppliers['providers'].setdefault(provider, []).append(applicationservice)
if hasattr(child, 'supplier'): if hasattr(child, 'supplier') and child.supplier:
supplier = child.supplier supplier = child.supplier
if ':' not in supplier: if ':' not in supplier:
providers_suppliers['suppliers'].setdefault(supplier, []).append(applicationservice) providers_suppliers['suppliers'].setdefault(supplier, []).append(applicationservice)
if 'mandatory' in child.properties:
providers_suppliers['mandatory_suppliers'].setdefault(supplier, []).append(applicationservice)
else: else:
parse(applicationservice, elts + [child], dico, providers_suppliers, hidden, objectspace) parse(applicationservice,
elts + [child],
dico,
providers_suppliers,
hidden,
dynamic,
objectspace,
mandatory_values_without_values,
modes,
is_dynamic,
dynamic_path,
is_service,
suppliers_variables,
)
return first_variable
def build_dependencies_tree(applicationservice, applicationservice_data, applicationservices_data, applicationservices_data_ext, space): def build_dependencies_tree(applicationservice,
applicationservice_data,
applicationservices_data,
applicationservices_data_ext,
space,
only_name: bool=False,
):
depends = [] depends = []
if applicationservice_data['depends']: if applicationservice_data['depends']:
if applicationservice in applicationservices_data: if applicationservice in applicationservices_data:
@ -132,17 +298,33 @@ def build_dependencies_tree(applicationservice, applicationservice_data, applica
else: else:
raise Exception(f'cannot find applicationservice "{applicationservice}"') raise Exception(f'cannot find applicationservice "{applicationservice}"')
ext = True ext = True
subdepends = build_dependencies_tree(depend, applicationservice_data, applicationservices_data, applicationservices_data_ext, space + 2) subdepends = build_dependencies_tree(depend,
if not idx or subdepends: applicationservice_data,
title = '\n' applicationservices_data,
applicationservices_data_ext,
space + 2,
only_name,
)
if only_name:
if depend not in depends:
depends.append(depend)
for dep in subdepends:
if dep not in depends:
depends.append(dep)
else: else:
title = '' if not idx or subdepends:
depend_desc = depend title = '\n'
if ext: else:
depend_desc += ' (in external dataset)' title = ''
title = ' ' * space + f'- [{depend_desc}]({url}/{depend}/README.md)' depend_desc = depend
depends.append(title) if ext:
depends.extend(subdepends) depend_desc += ' (in external dataset)'
doc = applicationservices_data[depend]["description"]
if not doc.endswith('.'):
doc += '.'
title = ' ' * space + f'- [{depend_desc}]({url}/{depend}/README.md): {doc}'
depends.append(title)
depends.extend(subdepends)
return depends return depends
@ -159,9 +341,11 @@ def load_data(url, directory, applicationservices_data, global_data={}):
continue continue
applicationservices_data[applicationservice] = {'description': applicationservice_data['description'], applicationservices_data[applicationservice] = {'description': applicationservice_data['description'],
'website': applicationservice_data.get('website'), 'website': applicationservice_data.get('website'),
'help': applicationservice_data.get('help'),
'as_dir': as_dir, 'as_dir': as_dir,
'depends': [], 'depends': [],
'used_by': [], 'used_by': [],
'service': applicationservice_data.get('service', False),
} }
if applicationservice in tmps: if applicationservice in tmps:
for app in tmps.pop(applicationservice): for app in tmps.pop(applicationservice):
@ -182,86 +366,255 @@ def load_data(url, directory, applicationservices_data, global_data={}):
global_data[depend]['used_by'].append(used_by) global_data[depend]['used_by'].append(used_by)
def write_data(applicationservices_data, applicationservices_data_ext): def display_example(as_fh,
dico = {} applicationservice,
providers_suppliers = {'providers': {}, 'suppliers': {}} provider_zone,
for applicationservice, applicationservice_data in applicationservices_data.items(): zones_name,
as_dir = applicationservice_data['as_dir'] values,
):
as_fh.write('\n## Example\n')
as_fh.write('\nZone names are provided as examples. Think about adapting with the value of provider_zone in configuration file.\n')
as_fh.write('\n```\n')
example = {applicationservice: {'applicationservice': applicationservice}}
if provider_zone:
example[applicationservice]['provider_zone'] = provider_zone
if zones_name:
example[applicationservice]['zones_name'] = zones_name
if values:
example[applicationservice]['values'] = values
# as_fh.write(dump(example, sort_keys=False))
yaml = YAML()
yaml.indent(sequence=4, offset=2)
yaml.dump(example, as_fh)
as_fh.write('```\n')
def load_dict(applicationservices,
applicationservices_data,
suppliers_variables,
dico,
providers_suppliers,
mandatory_values_without_values,
just_doc=True,
):
rougailconfig['dictionaries_dir'] = []
extra_dictionaries = {}
functions_file = [func.__file__]
for applicationservice in applicationservices:
as_dir = applicationservices_data[applicationservice]['as_dir']
dirname = join(as_dir, 'dictionaries') dirname = join(as_dir, 'dictionaries')
if isdir(dirname): if isdir(dirname):
rougailconfig['dictionaries_dir'] = [dirname] rougailconfig['dictionaries_dir'].append(dirname)
else:
rougailconfig['dictionaries_dir'] = []
dirname_extras = join(as_dir, 'extras') dirname_extras = join(as_dir, 'extras')
extra_dictionaries = {}
if isdir(dirname_extras): if isdir(dirname_extras):
for extra in listdir(dirname_extras): for extra in listdir(dirname_extras):
extra_dir = join(dirname_extras, extra) extra_dir = join(dirname_extras, extra)
if isdir(extra_dir): if isdir(extra_dir):
extra_dictionaries.setdefault(extra, []).append(extra_dir) extra_dictionaries.setdefault(extra, []).append(extra_dir)
if not isdir(dirname) and not extra_dictionaries: dirname_func = join(as_dir, 'funcs')
continue if isdir(dirname_func):
rougailconfig['extra_dictionaries'] = extra_dictionaries for f in listdir(dirname_func):
converted = RougailConvert(rougailconfig, just_doc=True) if f.startswith('__'):
converted.load_dictionaries() continue
converted.annotate() functions_file.append(abspath(join(dirname_func, f)))
objectspace = converted.rougailobjspace rougailconfig['extra_dictionaries'] = extra_dictionaries
if hasattr(objectspace.space, 'variables'): rougailconfig['functions_file'] = functions_file
dico[applicationservice] = {} rougailconfig['extra_annotators'] = EXTRA_ANNOTATORS
for name, elt in objectspace.space.variables.items(): converted = RougailConvert(rougailconfig, just_doc=just_doc)
parse(applicationservice, [elt], dico[applicationservice], providers_suppliers, False, objectspace) converted.load_dictionaries()
converted.annotate()
objectspace = converted.rougailobjspace
modes = {name: Mode(idx) for idx, name in enumerate(objectspace.rougailconfig['modes_level'])}
if hasattr(objectspace.space, 'variables'):
dico[applicationservice] = {}
if mandatory_values_without_values is not None:
mandatory_values_without_values[applicationservice] = {}
mandatory_values = mandatory_values_without_values[applicationservice]
else:
mandatory_values = None
for name, elt in objectspace.space.variables.items():
parse(applicationservice,
[elt],
dico[applicationservice],
providers_suppliers,
False,
False,
objectspace,
mandatory_values,
modes,
False,
'',
applicationservices_data[applicationservice]['service'],
suppliers_variables,
)
def write_data(applicationservices_data, applicationservices_data_ext):
dico = {}
providers_suppliers = {'providers': {}, 'suppliers': {}, 'mandatory_suppliers': {}, 'depends': {}}
mandatory_values_without_values = {}
suppliers_variables = {}
for applicationservice, applicationservice_data in applicationservices_data.items():
if applicationservice_data['service']:
depends = build_dependencies_tree(applicationservice,
applicationservice_data,
applicationservices_data,
applicationservices_data_ext,
0,
only_name=True,
)
depends.append(applicationservice)
providers_suppliers['depends'][applicationservice] = set(depends)
load_dict(['provider-systemd-machined'] + depends,
applicationservices_data,
suppliers_variables,
dico,
providers_suppliers,
mandatory_values_without_values,
just_doc=False,
)
else:
load_dict([applicationservice],
applicationservices_data,
suppliers_variables,
dico,
providers_suppliers,
None,
)
for provider in suppliers_variables:
for supplier, tdico in suppliers_variables[provider].items():
if supplier == 'doc':
continue
if not tdico['description']:
raise Exception(f'variable with provider "{supplier}" must have a description')
#
for filename in glob('seed/README.*.md'):
unlink(filename)
for provider in suppliers_variables:
with open(join(f'seed/README.{provider}.md'), 'w') as as_fh:
as_fh.write(f'---\ngitea: none\ninclude_toc: true\n---\n\n')
as_fh.write(f'\n[Return to the list of application services.](README.md)\n')
as_fh.write(f'# {provider}\n\n')
as_fh.write(f'## Synopsis\n\n')
as_fh.write(suppliers_variables[provider][provider]['description'])
as_fh.write(f'\n\n## Variables\n\n')
providers = []
for provider_name, tdico in suppliers_variables[provider].items():
if ':' in provider_name:
providers.append(list(tdico.values()))
if providers:
as_fh.write(tabulate(providers, headers=['Parameter', 'Comment'], tablefmt="github"))
as_fh.write(f'\n')
applicationservices = providers_suppliers['providers'].get(provider, [])
if applicationservices:
if len(applicationservices) == 1:
as_fh.write(f'\n## Provider\n\n')
for applicationservice in applicationservices:
doc = applicationservices_data[applicationservice]["description"]
if not doc.endswith('.'):
doc += '.'
as_fh.write(f'[{applicationservice}]({applicationservice}/README.md): {doc}\n')
else:
as_fh.write(f'\n## Providers\n\n')
for applicationservice in applicationservices:
doc = applicationservices_data[applicationservice]["description"]
if not doc.endswith('.'):
doc += '.'
as_fh.write(f'- [{applicationservice}]({applicationservice}/README.md): {doc}\n')
applicationservices = providers_suppliers['suppliers'].get(provider, [])
if applicationservices:
if len(applicationservices) == 1:
as_fh.write(f'\n## Supplier\n\n')
for applicationservice in applicationservices:
doc = applicationservices_data[applicationservice]["description"]
if not doc.endswith('.'):
doc += '.'
as_fh.write(f'[{applicationservice}]({applicationservice}/README.md): {doc}\n')
else:
as_fh.write(f'\n## Suppliers\n\n')
for applicationservice in applicationservices:
doc = applicationservices_data[applicationservice]["description"]
if not doc.endswith('.'):
doc += '.'
as_fh.write(f'- [{applicationservice}]({applicationservice}/README.md): {doc}\n')
#
for applicationservice, applicationservice_data in applicationservices_data.items(): for applicationservice, applicationservice_data in applicationservices_data.items():
as_dir = applicationservice_data['as_dir'] as_dir = applicationservice_data['as_dir']
local_dico = dico
with open(join(as_dir, 'README.md'), 'w') as as_fh: with open(join(as_dir, 'README.md'), 'w') as as_fh:
as_fh.write(f'---\ngitea: none\ninclude_toc: true\n---\n\n') as_fh.write(f'---\ngitea: none\ninclude_toc: true\n---\n\n')
as_fh.write(f'\n[Return to the list of application services.](../README.md)\n')
as_fh.write(f'# {applicationservice}\n\n') as_fh.write(f'# {applicationservice}\n\n')
as_fh.write(f'## Description\n\n') as_fh.write(f'## Synopsis\n\n')
description = applicationservice_data['description'] + '.\n' description = applicationservice_data['description'] + '.'
if applicationservice_data['website']: if applicationservice_data['website']:
description += f'\n[For more informations]({applicationservice_data["website"]})\n' description = f"\n[{description}]({applicationservice_data['website']})"
description += '\n'
if applicationservice_data['help']:
help_ = applicationservice_data['help'].strip()
if not help_.endswith('.'):
help_ += 'p.'
description += f'\n{help_}\n'
as_fh.write(description) as_fh.write(description)
# variables
if applicationservice in local_dico and local_dico[applicationservice]:
display_variables(as_dir, as_fh, applicationservice, local_dico)
if applicationservice_data['service']:
mandatory_zones_name = {}
zones_name = {}
provider_name = None
if applicationservice_data['depends']:
depends_set = providers_suppliers['depends'][applicationservice]
# providers
for provider, provider_as in providers_suppliers['providers'].items():
if not set(provider_as) & depends_set:
continue
provider_name = provider.lower()
break
#
if providers_suppliers['suppliers'] and list(providers_suppliers['suppliers']) != ['Host']:
as_fh.write('\n## Requirements services\n')
provider_hosts = []
for provider, provider_data in providers_suppliers['suppliers'].items():
if provider == 'Host':
continue
if applicationservice not in provider_data:
continue
suppliers = providers_suppliers['providers'].get(provider, [])
if len(suppliers) == 1:
if suppliers[0] in provider_hosts:
continue
provider_hosts.append(suppliers[0])
filename = f'README.{provider}.md'
if isfile(join('seed', filename)):
msg = f'[{provider}](../{filename})'
else:
msg = provider
if provider in providers_suppliers['mandatory_suppliers']:
mandatory_zones_name[provider] = msg
else:
zones_name[provider] = msg
if mandatory_zones_name:
as_fh.write('\n### Mandatories\n\n')
for provider, msg in mandatory_zones_name.items():
as_fh.write(f'- {msg}: {suppliers_variables[provider]["doc"]}\n')
if zones_name:
as_fh.write('\n### Optionals\n\n')
for provider, msg in zones_name.items():
as_fh.write(f'- {msg}: {suppliers_variables[provider]["doc"]}\n')
#
mandatory_zones_name = [provider.lower() for provider in mandatory_zones_name]
mandatory_zones_name.sort()
display_example(as_fh,
applicationservice,
provider_name,
mandatory_zones_name,
mandatory_values_without_values[applicationservice],
)
if applicationservice_data['depends']: if applicationservice_data['depends']:
as_fh.write(f'\n## Dependances\n\n') as_fh.write('\n## Dependances\n\n')
for depend in build_dependencies_tree(applicationservice, applicationservice_data, applicationservices_data, applicationservices_data_ext, 0): for depend in build_dependencies_tree(applicationservice, applicationservice_data, applicationservices_data, applicationservices_data_ext, 0):
as_fh.write(f'{depend}\n') as_fh.write(f'{depend}\n')
if applicationservice in dico and dico[applicationservice]:
as_fh.write('\n## Variables\n\n')
for title, data in dico[applicationservice].items():
as_fh.write(f'{title}\n')
if data['type'] == 'leadership':
as_fh.write('\nThis a family is a leadership.\n')
if data['type'] == 'dynamic':
as_fh.write(f'\nThis a dynamic family generated from the variable "{data["suffixes"]}".\n')
if data['help']:
as_fh.write(f'\n{data["help"]}\n')
keys = []
if data['variables']:
variables = data['variables']
for variable in variables:
for key in variable:
if key not in keys:
keys.append(key)
values = []
for variable in variables:
value = []
for key in keys:
if key in variable:
val = variable[key]
elif key == 'type':
val = DEFAULT_TYPE
else:
val = ''
if key == 'type':
val = f'[{val}]({ROUGAIL_VARIABLE_TYPE})'
value.append(val)
values.append(value)
as_fh.write('\n')
as_fh.write(tabulate(values, headers=[key.capitalize() for key in keys], tablefmt="github"))
as_fh.write('\n')
as_fh.write('\n')
# FIXME if not applicationservice_data['used_by']:
# FIXME as_fh.write('\n## Variables with dependencies\n\n')
as_fh.write('\n- [+]: variable is multiple\n- **bold**: variable is mandatory\n')
if applicationservice_data['used_by']: if applicationservice_data['used_by']:
as_fh.write('\n## Used by\n\n') as_fh.write('\n## Used by\n\n')
if len(applicationservice_data['used_by']) == 1: if len(applicationservice_data['used_by']) == 1:
@ -274,79 +627,120 @@ def write_data(applicationservices_data, applicationservices_data_ext):
for provider, provider_as in providers_suppliers['providers'].items(): for provider, provider_as in providers_suppliers['providers'].items():
if not applicationservice in provider_as: if not applicationservice in provider_as:
continue continue
for supplier in providers_suppliers['suppliers'][provider]: if provider in providers_suppliers['suppliers']:
if supplier in linked: for supplier in providers_suppliers['suppliers'][provider]:
continue if supplier in linked:
linked.append(supplier) continue
linked.append(supplier)
linked.sort() linked.sort()
if linked: if linked:
if len(linked) == 1: if len(linked) == 1:
as_fh.write('\n## Supplier\n\n') as_fh.write('\n## Useful for service\n\n')
as_fh.write(f'[{linked[0]}](../{linked[0]}/README.md)\n') description = applicationservices_data[linked[0]]["description"]
if not description.endswith('.'):
description += '.'
as_fh.write(f'[{linked[0]}](../{linked[0]}/README.md): {description}\n')
else: else:
as_fh.write('\n## Suppliers\n\n') as_fh.write('\n## Useful for services\n\n')
for supplier in linked: for supplier in linked:
as_fh.write(f'- [{supplier}](../{supplier}/README.md)\n') description = applicationservices_data[supplier]["description"]
linked = [] if not description.endswith('.'):
for supplier, supplier_as in providers_suppliers['suppliers'].items(): description += '.'
if not applicationservice in supplier_as: as_fh.write(f'- [{supplier}](../{supplier}/README.md): {description}\n')
continue
for provider in providers_suppliers['providers'][supplier]:
if provider in linked:
continue
linked.append(provider)
linked.sort()
if linked:
if len(linked) == 1:
as_fh.write('\n## Provider\n\n')
as_fh.write(f'[{linked[0]}](../{linked[0]}/README.md)\n')
else:
as_fh.write('\n## Providers\n\n')
for provider in linked:
as_fh.write(f'- [{provider}](../{provider}/README.md)\n')
as_fh.write(f'\n[All applications services for this dataset.](../README.md)\n')
with open('seed/README.md', 'w') as as_fh: with open('seed/README.md', 'w') as as_fh:
as_fh.write('# Application services\n\n') for service in [True, False]:
applicationservices = {} if service:
for applicationservice in applicationservices_data: as_fh.write('# Application services\n\n')
applicationservices.setdefault(applicationservice.split('-')[0], []).append(applicationservice)
applicationservice_categories = list(applicationservices.keys())
applicationservice_categories.sort()
for category in applicationservice_categories:
applicationservices_ = applicationservices[category]
if len(applicationservices_) == 1:
applicationservice = applicationservices_[0]
applicationservice_data = applicationservices_data[applicationservice]
as_fh.write(f'- [{applicationservice}]({applicationservice}/README.md): {applicationservice_data["description"]}\n')
else: else:
as_fh.write(f'- {category}:\n') as_fh.write('# Application dependencies\n\n')
applicationservices_.sort() applicationservices = {}
for applicationservice in applicationservices_: for applicationservice, applicationservice_data in applicationservices_data.items():
if applicationservice_data['service'] is not service:
continue
applicationservices.setdefault(applicationservice.split('-')[0], []).append(applicationservice)
applicationservice_categories = list(applicationservices.keys())
applicationservice_categories.sort()
for category in applicationservice_categories:
applicationservices_ = applicationservices[category]
if len(applicationservices_) == 1:
applicationservice = applicationservices_[0]
applicationservice_data = applicationservices_data[applicationservice] applicationservice_data = applicationservices_data[applicationservice]
as_fh.write(f' - [{applicationservice}]({applicationservice}/README.md): {applicationservice_data["description"]}\n') as_fh.write(f'- [{applicationservice}]({applicationservice}/README.md): {applicationservice_data["description"]}\n')
else:
as_fh.write(f'- {category}:\n')
applicationservices_.sort()
for applicationservice in applicationservices_:
applicationservice_data = applicationservices_data[applicationservice]
as_fh.write(f' - [{applicationservice}]({applicationservice}/README.md): {applicationservice_data["description"]}\n')
providers = list(providers_suppliers['providers'].keys()) providers = list(providers_suppliers['providers'].keys())
providers.sort() providers.sort()
if providers: if providers:
as_fh.write('\n# Providers and suppliers\n\n') as_fh.write('\n# Providers\n\n')
for provider in providers: for provider in providers:
as_fh.write(f'- {provider}:\n') if provider in suppliers_variables[provider]:
if providers_suppliers['providers'][provider]: as_fh.write(f'- [{provider}](README.{provider}.md): {suppliers_variables[provider]["doc"]}\n')
if len(providers_suppliers['providers'][provider]) == 1:
applicationservice = providers_suppliers['providers'][provider][0]
as_fh.write(f' - Provider: [{applicationservice}]({applicationservice}/README.md)\n') def display_variables(as_dir, as_fh, applicationservice, local_dico):
else: for main_title, modes in [('Basic variables', ['basic']),
as_fh.write(f' - Providers:\n') ('Variables', ['basic', 'normal']),
for applicationservice in providers_suppliers['providers'][provider]: ('Variables for expert', ['basic', 'normal', 'expert']),
as_fh.write(f' - [{applicationservice}]({applicationservice}/README.md)\n') ]:
if providers_suppliers['suppliers']: main_title_added = False
if len(providers_suppliers['suppliers'][provider]) == 1: titles = []
applicationservice = providers_suppliers['suppliers'][provider][0] variables = []
as_fh.write(f' - Supplier: [{applicationservice}]({applicationservice}/README.md)\n') parent_path = None
else: for title, data in list(local_dico[applicationservice].items()):
as_fh.write(f' - Suppliers:\n') keys = []
for applicationservice in providers_suppliers['suppliers'][provider]: if data['type'] == 'optiondescription':
as_fh.write(f' - [{applicationservice}]({applicationservice}/README.md)\n') #if data['mode'] not in modes:
# continue
if variables:
as_fh.write(tabulate(variables, headers=['Parameter', 'Comment'], tablefmt="github"))
as_fh.write('\n')
as_fh.write('\n')
variables = []
parent_path = None
title_level = data['level']
len_titles = len(titles)
if len_titles < title_level:
titles.append((None, None))
titles[title_level - 1] = (title, data)
if len_titles > title_level:
for idx in range(title_level, len_titles):
titles.pop(title_level)
else:
if data['mode'] not in modes:
continue
if not main_title_added:
as_fh.write(f'\n## {main_title}\n\n')
main_title_added = True
for idx, td in enumerate(titles):
t, d = td
if not t:
continue
as_fh.write(f'{t}\n\n')
if d['help']:
help = d['help']
if not help.endswith('.'):
help += '.'
as_fh.write(f'{help}\n\n')
titles[idx] = (None, None)
if data['mode'] != modes[-1]:
continue
new_parent_path = title.rsplit('.', 1)[0]
if variables and parent_path != new_parent_path:
as_fh.write(tabulate(variables, headers=['Parameter', 'Comments'], tablefmt="github"))
as_fh.write('\n')
as_fh.write('\n')
variables = []
parent_path = new_parent_path
variables.append([data['parameter'], data['description']])
del local_dico[applicationservice][title]
if variables:
as_fh.write(tabulate(variables, headers=['Parameter', 'Comments'], tablefmt="github"))
as_fh.write('\n')
def main(): def main():

View file

@ -539,7 +539,7 @@ def build_files(hostname: str,
if is_list_name != is_list_domain: if is_list_name != is_list_domain:
raise Exception('certificate name and domain name must be a list together') raise Exception('certificate name and domain name must be a list together')
if 'provider' not in certificate_data: if 'provider' not in certificate_data:
certificate_data['provider'] = 'autosigne' certificate_data['provider'] = 'self-signed'
if is_list_name: if is_list_name:
if len(certificate_data['name']) != len(certificate_data['domain']): if len(certificate_data['name']) != len(certificate_data['domain']):
raise Exception('certificate name and domain name must have same length') raise Exception('certificate name and domain name must have same length')

View file

@ -39,7 +39,10 @@ class Annotator(Walk):
# construct self.globals, self.suppliers and self.providers dictionnaries # construct self.globals, self.suppliers and self.providers dictionnaries
provider_prefix, provider_suffix = self._cut_out_provider_name(provider_name) provider_prefix, provider_suffix = self._cut_out_provider_name(provider_name)
dns = self.objectspace.space.variables[variable.path_prefix].doc if variable.path_prefix:
dns = self.objectspace.space.variables[variable.path_prefix].doc
else:
dns = "example.net"
if provider_prefix == 'global': if provider_prefix == 'global':
if type_ == 'supplier': if type_ == 'supplier':
raise DictConsistencyError(f'{type_} {provider_name} in {dns} not allowed', 0, variable.xmlfiles) raise DictConsistencyError(f'{type_} {provider_name} in {dns} not allowed', 0, variable.xmlfiles)
@ -78,7 +81,10 @@ class Annotator(Walk):
# it's a reverse provider! # it's a reverse provider!
continue continue
if provider_prefix != 'Host': if provider_prefix != 'Host':
provider_zone = self.objectspace.rougailconfig['risotto_globals'][provider_dns]['global:provider_zone'] if 'risotto_globals' in self.objectspace.rougailconfig:
provider_zone = self.objectspace.rougailconfig['risotto_globals'][provider_dns]['global:provider_zone']
else:
provider_zone = ['zone1']
if provider_prefix not in self.suppliers: if provider_prefix not in self.suppliers:
continue continue
for supplier_dns, suppliers_suffix in self.suppliers[provider_prefix].items(): for supplier_dns, suppliers_suffix in self.suppliers[provider_prefix].items():
@ -226,9 +232,13 @@ class Annotator(Walk):
"""Convert providers global informations to default values or fills """Convert providers global informations to default values or fills
""" """
provider_prefix = 'global' provider_prefix = 'global'
if not provider_prefix in self.globals:
return
for provider_dns, providers_suffix in self.globals[provider_prefix].items(): for provider_dns, providers_suffix in self.globals[provider_prefix].items():
for provider_suffix, variable in providers_suffix.items(): for provider_suffix, variable in providers_suffix.items():
provider_name = f'{provider_prefix}:{provider_suffix}' provider_name = f'{provider_prefix}:{provider_suffix}'
if 'risotto_globals' not in self.objectspace.rougailconfig:
continue
if provider_name not in self.objectspace.rougailconfig['risotto_globals'][provider_dns]: if provider_name not in self.objectspace.rougailconfig['risotto_globals'][provider_dns]:
raise DictConsistencyError(f'cannot find {provider_name} for variable {variable.path}, should be in {list(self.objectspace.rougailconfig["risotto_globals"][provider_dns])}', 0, variable.xmlfiles) raise DictConsistencyError(f'cannot find {provider_name} for variable {variable.path}, should be in {list(self.objectspace.rougailconfig["risotto_globals"][provider_dns])}', 0, variable.xmlfiles)
provider_values = self.objectspace.rougailconfig['risotto_globals'][provider_dns][provider_name] provider_values = self.objectspace.rougailconfig['risotto_globals'][provider_dns][provider_name]

View file

@ -11,7 +11,7 @@ from pprint import pprint
MULTI_FUNCTIONS = [] MULTI_FUNCTIONS = []
EXTRA_ANNOTATORS = ['risotto.rougail'] EXTRA_ANNOTATORS = ['risotto.rougail']
ROUGAIL_NAMESPACE = 'general' ROUGAIL_NAMESPACE = 'general'
ROUGAIL_NAMESPACE_DESCRIPTION = 'Général' ROUGAIL_NAMESPACE_DESCRIPTION = 'General'
HERE = environ['PWD'] HERE = environ['PWD']
IP_DIR = join(HERE, 'ip') IP_DIR = join(HERE, 'ip')