commit 841643e76ef8a9d895f28475bf8c0fcbc11cf9d5 Author: Emmanuel Garette Date: Sat Nov 23 08:17:35 2019 +0100 for creole's zephir2 branch diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2fcd22b --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +# Backup and swap files +*~ +*# +*.swp diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..45fd1e6 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +################################ +# Makefile pour creole +################################ + +SOURCE=creole +EOLE_VERSION=2.7 +EOLE_RELEASE=2.7.0 + +################################ +# Début de zone à ne pas éditer +################################ + +include eole.mk +include apps.mk + +################################ +# Fin de zone à ne pas éditer +################################ + +# Makefile rules dedicated to application +# if exists +ifneq (, $(strip $(wildcard $(SOURCE).mk))) +include $(SOURCE).mk +endif diff --git a/apps.mk b/apps.mk new file mode 100644 index 0000000..1efe7df --- /dev/null +++ b/apps.mk @@ -0,0 +1,64 @@ +# +# NE PAS EDITER CE FICHIER +# +# Voir Makefile + + +########################## +# Application web envole # +########################## +ifneq (, $(filter oui web, $(PKGAPPS))) +# +# Sanity check +# +ifeq (, $(filter-out X.X, $(strip $(VERSION)))) +$(error $$(VERSION) variable has incorrect value '$(VERSION)') +endif + +# Where to store web application files +WEB_PATH := $(DESTDIR)/var/www/html + +# Envole +sharenvole_PROG_DIR := $(DESTDIR)/usr/share/envole/$(SOURCE) + +src_$(SOURCE)-$(VERSION)_REC_DIR := $(WEB_PATH)/$(SOURCE) +src_plugins-$(VERSION)_REC_DIR := $(WEB_PATH)/$(SOURCE)/plugin +src_lang-$(VERSION)_REC_DIR := $(WEB_PATH)/$(SOURCE)/lang + +endif + +########################## +# Application EOLE flask # +########################## +ifneq (, $(filter flask, $(PKGAPPS))) +# +# Sanity check +# +ifeq (, $(filter-out XXX, $(strip $(FLASK_MODULE)))) +$(error $$(FLASK_MODULE) variable has incorrect value '$(FLASK_MODULE)') +endif + +ifeq (, $(strip $(wildcard src/$(FLASK_MODULE).conf))) +$(error missing eoleflask configuration file 'src/$(FLASK_MODULE).conf') +endif + +# Everything is related to mount point +APPS_MOUNT_POINT := $(shell sed -ne 's|^"MOUNT_POINT"[[:space:]]*:[[:space:]]*"/\([^"]*\)",|\1|p' \ + src/$(FLASK_MODULE).conf) + +ifeq (, $(strip $(APPS_MOUNT_POINT))) +$(error no "MOUNT_POINT" in eoleflask configuration file 'src/$(FLASK_MODULE).conf') +endif + +# eole-flask configuration +src_DATA_DIR := $(DESTDIR)/etc/eole/flask/available + +# Where to store flask application files +FLASK_PATH := $(eole_DIR)/flask/$(APPS_MOUNT_POINT) + +# static files +src_$(FLASK_MODULE)_static_REC_DIR := $(FLASK_PATH)/static +src_$(FLASK_MODULE)_templates_REC_DIR := $(FLASK_PATH)/templates +src_$(FLASK_MODULE)_instance_REC_DIR := $(FLASK_PATH)/resources + +endif diff --git a/bin/CreoleCat b/bin/CreoleCat new file mode 100755 index 0000000..5acc618 --- /dev/null +++ b/bin/CreoleCat @@ -0,0 +1,153 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Run templatisation on a template name or file + +`CreoleCat` support two modes: + + - run on a template name with option -t: the name is looked up in + ``/usr/share/eole/creole/distrib/``. The output files are + calculated unless you explicitely specify ``-o``. + + - run on a file with options -s: this mode requires the use of + ``-o`` option. + +""" + +import sys +import os +import argparse + +from os.path import basename, join, split + +from pyeole import scriptargs +from pyeole.log import init_logging + +from creole.template import CreoleTemplateEngine +import creole.config as cfg +from creole.client import CreoleClient, CreoleClientError +from pyeole.ihm import only_root + +only_root() + +client = CreoleClient() + +def parse_cmdline(): + """Parse commande line. + """ + parser = argparse.ArgumentParser(description="Instancie un template creole", + parents=[scriptargs.container(), + scriptargs.logging()]) + parser.add_argument("-t", "--template", metavar="NAME", + help=u"nom du fichier template creole présent " + "dans /usr/share/eole/creole/distrib") + parser.add_argument("-s", "--source", metavar="PATH", + help=u"chemin d’un fichier template") + parser.add_argument("-o", "--output", metavar="OUTPUTFILE", + help=u"chemin du fichier généré") + + opts = parser.parse_args() + + if (opts.template is None and opts.source is None) \ + or (opts.template and opts.source): + parser.error("Vous devez spécifier une des options" + "'--template' ou '--source'.") + + if opts.source is not None and not os.access(opts.source, os.F_OK): + parser.error("Fichier source inexistant" + " ou illisible: {0}".format(opts.source)) + + if opts.output is None: + if opts.source is not None: + opts.output = "" + else: + if opts.template is not None \ + and opts.output == join(cfg.distrib_dir, opts.template): + parser.error("Le fichier de sortie ne peut écraser" + " le fichier template: {0}".format(opts.output) ) + if opts.source is not None and opts.output == opts.source: + parser.error("Le fichier de sortie ne peut écraser" + " le fichier source: {0}".format(opts.output) ) + + if opts.verbose: + opts.log_level = 'info' + if opts.debug: + opts.log_level = 'debug' + + return opts + + +def _find_file(name, ctx): + candidates = client.to_grouped_lists(ctx['files'], keyname='source') + for source, filevar in candidates.items(): + if name != basename(source): + continue + elif filevar[0].get('activate', False): + return filevar[0] + + +def main(): + """Setup environnment and run templatisation. + """ + + options = parse_cmdline() + try: + log = init_logging(level=options.log_level) + + engine = CreoleTemplateEngine() + + filevar = { 'source': options.source, + 'name': options.output, + 'full_name': options.output, + 'activate' : True, + 'del_comment': u'', + 'mkdir' : False, + 'rm' : False, + } + + if options.container is not None: + # force container context + groups = [client.get_container_infos(options.container)] + elif options.output is not None: + # Source without container, for root context + groups = [client.get_container_infos('root')] + else: + groups = [] + for group in client.get_groups(): + groups.append(client.get_group_infos(group)) + + instanciated_files = [] + for group in groups: + if filevar['source'] is not None: + instanciated_files.append(filevar) + engine.process(filevar, group) + elif options.template is not None: + found_file = _find_file(options.template, group) + if found_file: + instanciated_files.append(found_file) + if options.output is None: + engine._instance_file(found_file, group) + else: + # Override output + found_file['name'] = options.output + found_file['full_name'] = options.output + # Do not get through verify and + # change_properties + engine._copy_to_template_dir(found_file) + engine.process(found_file, group) + + if not instanciated_files: + # No file get instanciated + raise CreoleClientError("Fichier template inexistant:" + " {0}".format(options.template)) + + except Exception, err: + if options.debug: + log.debug(err, exc_info=True) + else: + log.error(err) + sys.exit(1) + sys.exit(0) + +if __name__ == '__main__': + main() diff --git a/bin/CreoleGet b/bin/CreoleGet new file mode 100755 index 0000000..8c1dccc --- /dev/null +++ b/bin/CreoleGet @@ -0,0 +1,130 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +"""Get a creole variable value. +""" + +import sys +import argparse + +from creole.client import CreoleClient + +from pyeole import scriptargs +from pyeole.log import init_logging +from pyeole.encode import normalize + +_RETURN_VALUES = u"""Multiple values are separated with NEWLINE character '\\n', +or SPACE character if several variables are displayed.""" + +parser = argparse.ArgumentParser(description=u"Get creole variable", + epilog=_RETURN_VALUES, + parents=[scriptargs.logging()]) + +parser.add_argument('variable', nargs='?', + help=u"Nom de variable creole") +parser.add_argument('default', nargs='?', + help=u"Valeur par défaut si la variable n’existe pas") + +incompatible_options = parser.add_mutually_exclusive_group() + +incompatible_options.add_argument('--groups', action="store_true", default=False, + help=u"Liste les groupes de conteneurs") + +incompatible_options.add_argument('--list', action="store_true", default=False, + help=u"Liste l'ensemble des variables creole") + +incompatible_options.add_argument('--reload', action="store_true", default=False, + help=u"Recharge toute la configuration creole") + +incompatible_options.add_argument('--reload-eol', action="store_true", default=False, + help=u"Recharge les valeurs de configuration creole") + +options = parser.parse_args() + +if options.verbose: + # 'info' is outputed to stdout + options.log_level = u'warning' +if options.debug: + options.log_level = u'debug' + +def output(value, strip_master=False): + """ + formatage de l'affichage + """ + if isinstance(value, list): + #FIXME: ['val1', None, 'val2'] + for val in value: + if isinstance(val, dict): + sys.stderr.write(u'{}\n'.format(val['err'])) + else: + sys.stdout.write(u'{}\n'.format(val)) + elif isinstance(value, dict): + # in case several keys/values are returned + list_keys = value.keys() + list_keys.sort() + for var in list_keys: + values = value[var] + if isinstance(values, list): + values_ = u'' + for val in values: + if val and not isinstance(val, dict): + values_ += u" {}".format(val) + values = values_ + elif values is None: + values = u'' + else: + values = u'{}'.format(values) + if strip_master: + varname = var.split('.')[-1] + else: + varname = var + sys.stdout.write(u'{}="{}"\n'.format(varname, values.strip())) + elif value is None or value == u'': + sys.stdout.write(u'\n') + else: + sys.stdout.write(u'{0}\n'.format(value)) + #return ret.rstrip('\n') + +def main(): + """Setup environnment and run templatisation. + """ + + try: + log = init_logging(level=options.log_level) + client = CreoleClient() + var = options.variable + if options.groups: + output(client.get_groups()) + elif options.list: + output(client.get_creole(), True) + elif options.reload: + client.reload_config() + elif options.reload_eol: + client.reload_eol() + elif not var: + raise Exception(u"Veuillez spécifier un nom de variable Creole") + else: + if options.default is not None: + kwargs = {'default':options.default} + else: + kwargs = {} + if '.' in var: + output(client.get(var)) + else: + output(client.get_creole(var, **kwargs)) + + except Exception, err: + if options.debug: + log.debug(normalize(err), exc_info=True) + else: + log.error(normalize(err)) + sys.exit(1) + + sys.exit(0) + +if __name__ == '__main__': + #Fix #18701 + reload(sys) + sys.setdefaultencoding('UTF8') + main() + diff --git a/bin/CreoleLint b/bin/CreoleLint new file mode 100755 index 0000000..811c7b7 --- /dev/null +++ b/bin/CreoleLint @@ -0,0 +1,68 @@ +#! /usr/bin/python + +import sys +from optparse import OptionParser + +from creole.lint.creolelint import validate +from creole.lint.ansiwriter import AnsiWriter + +def parse_cmdline(): + parser = OptionParser() + + parser.add_option("-t", "--template", dest="tmpl", + default=None, help="nom du template Creole") + parser.add_option("-l", "--level", dest="writelevel", default='warning', + help="level d'affichage des messages") + parser.add_option("-n", "--name", dest="name", + default=None, help="nom du lint a tester") + parser.add_option("-d", "--dico-only", action="store_true", + dest="only_on_dico", + default=False, help="lint uniquement sur les dicos") + return parser.parse_args() + +def main(): + options, args = parse_cmdline() + tmpl = options.tmpl + writelevel = options.writelevel + + #if options.writelevel not in errorlevel.values(): + # raise Exception('Niveau %s inconnu'% options.writelevel) + only_on_template = False + only_on_dico = options.only_on_dico + if tmpl is not None: + only_on_template = True + if options.name: + keywords = [options.name] + writelevel = 'info' + else: + keywords = [] + if not only_on_template: + # keywords.extend(['orphans_def', + # 'orphans_set', 'orphans_for', 'orphans_tmpl_files', + # 'define', 'syntax_for', 'syntax_var', 'syntax_var2', + # 'syntax_function', 'valid_client_option']) + keywords.extend(['valid_dtd', 'wrong_dicos_name', + 'tabs_in_dicos', 'hidden_if_in_dicos', + 'condition_without_target', + 'obligatoire_in_dicos', + 'valid_slave_value', + 'valid_var_label', 'valid_separator_label', + 'valid_help_label', + 'activation_var_without_help', + 'family_without_help', + 'family_without_icon', + 'old_fw_file']) + if not only_on_dico: + keywords.extend(['valid_parse_tmpl']) + keywords.append('builtins') + ansi = AnsiWriter(writelevel) + try: + for keyword in keywords: + validate(keyword, ansi, tmpl) + except Exception, err: + from traceback import print_exc + print_exc() + #print u"Erreur : {0}".format(err) + sys.exit(1) + +main() diff --git a/bin/CreoleLock b/bin/CreoleLock new file mode 100755 index 0000000..51e91ff --- /dev/null +++ b/bin/CreoleLock @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +from sys import argv +from os import getppid +from importlib import import_module +from pyeole.command_line import ArgumentParser +from pyeole.ihm import only_root + +only_root() + +allowed_functions = ('acquire', 'release', 'is_locked') +module = import_module('pyeole.lock') +module.PID = getppid() +arguments = ArgumentParser(module, allowed_functions, argv[0]) +arguments.parse_args(argv[1:]) +arguments.trigger_callback() diff --git a/bin/CreoleRun b/bin/CreoleRun new file mode 100755 index 0000000..00c920d --- /dev/null +++ b/bin/CreoleRun @@ -0,0 +1,54 @@ +#!/bin/bash + +# exécute une commande dans un conteneur + +SSHCMD="ssh -q -o LogLevel=ERROR -o StrictHostKeyChecking=no" + +commande=$1 +container=$2 +# ne lancer la commande que si dans un conteneur (ssh) +onlyifcontainer=$3 +silent=$4 +CMD='eval' + +ExecContainer() +{ + ip="$1" + cmd="$2" + tcpcheck 2 $ip:22 &>/dev/null || return 1 + $SSHCMD root@$ip "$cmd" +} + +if [[ ${container} == "all" ]] +then + if [[ $(CreoleGet mode_conteneur_actif) == "oui" ]] + then + for grp in $(CreoleGet --groups) + do + if [[ ${grp} != 'root' ]] && [[ ${grp} != 'all' ]] + then + container_ip=$(CreoleGet "container_ip_${grp}") + if [ ! "$silent" = "yes" ]; then + echo "Exécution de la commande [${commande}] dans le conteneur ${grp}" + echo + fi + ExecContainer "$container_ip" "$commande" + if [ ! "$silent" = "yes" ]; then + echo + fi + fi + done + fi +else + if [ -n "$container" ] + then + container_ip=$(CreoleGet "container_ip_$container") + fi + if [ -n "$container_ip" ] && [ ! "$container_ip" = "127.0.0.1" ] + then + ExecContainer "$container_ip" "$commande" + elif [ "$onlyifcontainer" != "yes" ] + then + eval "$commande" + fi +fi diff --git a/bin/CreoleService b/bin/CreoleService new file mode 100755 index 0000000..405a5b2 --- /dev/null +++ b/bin/CreoleService @@ -0,0 +1,71 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import sys +import argparse + +from pyeole import scriptargs +from pyeole.log import init_logging +from pyeole.service import manage_services +from creole.reconfigure import services +from pyeole.ihm import only_root + +only_root() + +def parse_cmdline(): + + service_actions=['apply', 'configure', 'enable', 'disable', 'status', + 'start', 'stop', 'restart', 'reload'] + + parser = argparse.ArgumentParser(description="Action sur les services", + parents=[scriptargs.container(), + scriptargs.logging('info')]) + parser.add_argument('service', help="Nom du service") + parser.add_argument('action', choices=service_actions, + help="Action à effectuer") + parser.add_argument("-f", "--force", action="store_true", default=False, + help="Ne pas valider l'état de service") + parser.add_argument("-s", "--silent", action="store_true", default=False, + help="Ne pas affichier sur la console") + + opts = parser.parse_args() + + if opts.verbose: + opts.log_level = 'info' + if opts.debug: + opts.log_level = 'debug' + if opts.silent: + opts.log_level = 'error' + + + return opts + +def main(): + options = parse_cmdline() + log = init_logging(level=options.log_level) + try: + display = 'console' + if options.silent: + display = 'log' + if options.service == 'all': + if options.action == 'restart': + services('stop', display_title=False, try_restart_lxc=False) + services('start', display_title=False, try_restart_lxc=False) + else: + services(options.action, display_title=False, try_restart_lxc=False) + ret = True + else: + ret = manage_services(options.action, options.service, + container=options.container, force=options.force, + display=display) + except Exception, err: + if options.debug: + log.debug(err, exc_info=True) + else: + log.error(err) + sys.exit(1) + sys.exit(ret) + +if __name__ == '__main__': + main() + diff --git a/bin/CreoleSet b/bin/CreoleSet new file mode 100755 index 0000000..b8d277a --- /dev/null +++ b/bin/CreoleSet @@ -0,0 +1,92 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import argparse +from sys import exit + +from pyeole import scriptargs +from pyeole.ansiprint import print_red +from pyeole.log import init_logging +from creole.var_loader import convert_value +from creole.loader import creole_loader, config_save_values +from tiramisu.error import PropertiesOptionError +from pyeole.ihm import only_root + +only_root() + +parser = argparse.ArgumentParser(description=u"Set Creole variable", + parents=[scriptargs.logging()]) +parser.add_argument("--default", action="store_true", default=False, + help=u"remettre à la valeur par défaut") +parser.add_argument('variable', nargs=1, + help=u"Nom de variable Creole") +parser.add_argument('value', nargs='?', + help=u"Valeur de la variable Creole") + +options = parser.parse_args() + +if options.verbose: + # 'info' is outputed to stdout + options.log_level = u'warning' +if options.debug: + options.log_level = u'debug' + +if options.default and options.value: + print_red("En cas de remise à la valeur par défaut, il ne faut pas spécifier de valeur") + exit(1) + +if not options.default and options.value is None: + print_red("Veuiller spécifier la valeur") + exit(1) + +def main(): + log = init_logging(level=options.log_level) + try: + config = creole_loader(rw=True, owner='creoleset', load_extra=True) + var = options.variable[0] + if '.' in var: + if var.startswith('.'): + var = var[1:] + namespace = var.split('.')[0] + else: + namespace = 'creole' + var = config.find_first(byname=var, type_='path', + force_permissive=True) + if options.default: + homeconfig, name = config.cfgimpl_get_home_by_path(var) + homeconfig.__delattr__(name) + else: + option = config.unwrap_from_path(var) + value = options.value + if option.impl_is_multi(): + values = [] + for val in value.split('\n'): + values.append(convert_value(option, val)) + value = values + else: + value = convert_value(option, value) + setattr(config, var, value) + config_save_values(config, namespace) + except PropertiesOptionError, err: + if options.debug: + log.debug(err, exc_info=True) + print_red(u"Erreur de propriété : {0}".format(err)) + exit(1) + except ValueError, err: + if options.debug: + log.debug(err, exc_info=True) + print_red("Valeur invalide : {0}".format(err)) + exit(1) + except AttributeError: + if options.debug: + log.debug("AttributeError", exc_info=True) + print_red("Nom de variable inconnue : {0}".format(options.variable[0])) + exit(1) + except Exception, err: + if options.debug: + log.debug(err, exc_info=True) + print_red("Erreur inconnue : {0}".format(err)) + exit(1) + +if __name__ == '__main__': + main() diff --git a/bin/Maj-Auto b/bin/Maj-Auto new file mode 100755 index 0000000..9526bd4 --- /dev/null +++ b/bin/Maj-Auto @@ -0,0 +1,454 @@ +#! /usr/bin/python +# -*- coding: utf-8 -*- +# +########################################################################## +# Maj-Auto - Manage automatique update of EOLE server +# Copyright © 2013 Pôle de compétences EOLE +# +# License CeCILL: +# * in french: http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html +# * in english http://www.cecill.info/licences/Licence_CeCILL_V2-en.html +########################################################################## + +import sys +import argparse +import atexit +import time +import locale + +from os import unlink, environ, system +from subprocess import Popen, PIPE +from os.path import basename, isfile + +from creole import reconfigure, fonctionseole +from creole.client import CreoleClient, TimeoutCreoleClientError, NotFoundError, CreoleClientError +from creole.error import UserExit, UserExitError + +from creole.eoleversion import EOLE_RELEASE, LAST_RELEASE, EOLE_VERSION + +from pyeole.lock import acquire, release, is_locked +from pyeole.log import init_logging, set_formatter +from pyeole.ihm import question_ouinon, only_root, catch_signal +from pyeole.encode import normalize + +from pyeole.pkg import EolePkg, _configure_sources_mirror, report + +from pyeole.diagnose import test_tcp +from pyeole import scriptargs + +from pyeole.i18n import i18n + +_ = i18n('creole') + +#import logging + +log = None + +only_root() + +try: + # FIXME : refactorer le système de lock de zephir-client (ref #6660) + from zephir.lib_zephir import lock, unlock + zephir_libs = True +except Exception: + zephir_libs = False + +def release_lock(): + if zephir_libs: + unlock('maj') + if is_locked('majauto', level='system'): + release('majauto', level='system') + +def user_exit(*args, **kwargs): + """ + sortie utilisateur "propre" + """ + log.warn(_(u'! Abandoning configuration !')) + log.warn(_(u'System may be in an incoherent state.\n\n')) + raise UserExitError() + + +def parse_cmdline(): + """Parse commande line. + """ + parser = argparse.ArgumentParser(prog='Maj-Auto|Query-Auto', + description=_(u"Manage EOLE server automatic update"), + parents=[scriptargs.logging('info')], + add_help=False) + + parser.add_argument('-h', '--help', + action='help', + help=_(u"show this help message and exit")) + parser.add_argument('-n', '--dry-run', + action='store_true', + help=_(u"run in dry-run mode (force to True when using Query-Auto).")) + parser.add_argument('-f', '--force', + action='store_true', + help=_(u"bypass Zephir authorizations.")) + parser.add_argument('-F', '--force-update', + action='store_true', + help=_(u"update your server without any confirmation.")) + + parser.add_argument('-s', '--simulate', + action='store_true', + help=_(u"ask apt-get to simulate packages installation")) + + # Level of upgrade + maj_level = parser.add_mutually_exclusive_group() + maj_level.add_argument('-C', '--candidat', default=False, + action='store', nargs='*', + choices=['eole', 'envole'], + help=_(u"use testing packages.")) + maj_level.add_argument('-D', '--devel', default=False, + action='store', nargs='*', + choices=['eole', 'envole'], + help=_(u"use development packages.")) + + parser.add_argument('--release', + help=argparse.SUPPRESS) + + # Action when upgrade is OK + parser.add_argument('-r', '--reconfigure', + action='store_true', + help=_(u"run reconfigure on successful upgrade.")) + + parser.add_argument('-R', '--reboot', + action='store_true', + help=_(u"run reconfigure on successful upgrade and reboot if necessary (implies -r).")) + parser.add_argument('--download', action='store_true', + help=_(u'only download packages in cache.')) + # Mirror selection + parser.add_argument('-S', '--eole-mirror', + help=_(u"EOLE repository server.")) + parser.add_argument('-U', '--ubuntu-mirror', + help=_(u"Ubuntu repository server.")) + parser.add_argument('-V', '--envole-mirror', + help=_(u"Envole repository server.")) + parser.add_argument('-c', '--cdrom', action="store_true", + help=_(u"use CDROM as source.")) + + # sortie EAD + parser.add_argument('-W', action='store_true', + help=_(u"specific output for EAD.")) + # mode sans creoled + parser.add_argument('-i', '--ignore', action='store_true', + help=_(u"ignore local configuration if creoled not responding.")) + + + opts = parser.parse_args() + + if getattr(opts, 'level', None) is None: + opts.level = u'updates' + if opts.verbose: + opts.log_level = 'info' + if opts.debug: + opts.log_level = 'debug' + + if opts.reboot: + opts.reconfigure = True + + return opts + + +def main(): + global log + opts = parse_cmdline() + if opts.W: + # variable set for pyeole.ansiprint + environ['ModeTxt'] = 'yes' + reporting = not (opts.dry_run or opts.simulate or opts.download) + if not reporting: + z_proc = 'QUERY-MAJ' + log = init_logging(name=basename(sys.argv[0]), level=opts.log_level) + pkg_log = init_logging(name='pyeole.pkg', level=opts.log_level) + diag_log = init_logging(name='pyeole.diagnose', level=opts.log_level) + else: + z_proc = 'MAJ' + report_file = '/var/lib/eole/reports/rapport-maj.log' + if isfile(report_file): + unlink(report_file) + log = init_logging(name=basename(sys.argv[0]), level=opts.log_level, + filename=report_file) + pkg_log = init_logging(name='pyeole.pkg', level=opts.log_level, + filename=report_file) + diag_log = init_logging(name='pyeole.diagnose', level=opts.log_level, + filename=report_file) + set_formatter(log, u'file', u'brief') + set_formatter(log, u'file', u'with-levelname-date') + set_formatter(pkg_log, u'file', u'with-levelname-date') + set_formatter(diag_log, u'file', u'with-levelname-date') + report(2) + locale.setlocale(locale.LC_TIME, "fr_FR.utf8") + log.info(_(u'Update at {0}').format(time.strftime("%A %d %B %Y %H:%M:%S"))) + raised_err = None + error_msg = None + try: + # gestion du ctrl+c + catch_signal(user_exit) + acquire('majauto', level='system') + atexit.register(release_lock) + client = CreoleClient() + eole_level = 'stable' + envole_level = 'stable' + try: + version = client.get_creole('eole_release') + except (TimeoutCreoleClientError, NotFoundError, CreoleClientError) as err: + if opts.ignore: + version = EOLE_RELEASE + else: + raise err + if opts.candidat is not False: + z_level = " en candidate" + # Gestion du niveau par dépôt (16110) + if len(opts.candidat) == 0: + # Si on ne précise aucun dépôt tout le monde va en candidat + eole_level = 'proposed' + envole_level = 'proposed' + else: + # Sinon on vérifie dépôt par dépôt, les dépôts non précisés restent en stable + if 'eole' in opts.candidat: + eole_level = 'proposed' + if 'envole' in opts.candidat: + envole_level = 'proposed' + elif opts.devel is not False: + z_level = " en devel" + # Gestion du niveau par dépôt (16110) + if len(opts.devel) == 0: + # Si on ne précise aucun dépôt tout le monde vas en candidat + eole_level = 'unstable' + envole_level = 'unstable' + else: + # Sinon on vérifie dépôt par dépôt, les dépôts non précisés restent en stable + if 'eole' in opts.devel: + eole_level = 'unstable' + if 'envole' in opts.devel: + envole_level = 'unstable' + else: + z_level = "" + if opts.release: + current_release = int(EOLE_RELEASE.split('.')[-1]) + new_release = opts.release.split('.') + if len(new_release) != 3 or \ + u'.'.join(new_release[0:2]) != EOLE_VERSION or \ + int(new_release[2]) not in range(current_release+1, int(LAST_RELEASE) + 1): + raise Exception(_('Unknown release number')) + z_level += " en {0}".format(opts.release) + version = opts.release + if opts.cdrom: + z_level += " via le CDROM" + #distro = 'stable' + fonctionseole.zephir("INIT", "Début{0}".format(z_level), z_proc) + if zephir_libs and not fonctionseole.init_proc('MAJ'): + if opts.force: + fonctionseole.zephir("MSG", + "Mise à jour forcée par l'utilisateur", + z_proc) + else: + log.warn(_(u"Update is locked, please contact Zéphir administrator")) + log.warn(_(u"Use -f option if you want to force execution")) + raise UserExitError() + lock('maj') + PKGMGR = EolePkg('apt', ignore=opts.ignore) + if opts.dry_run: + PKGMGR.set_option('APT::Get::Simulate', 'true') + + try: + module = client.get_creole('eole_module') + except (TimeoutCreoleClientError, NotFoundError, CreoleClientError) as err: + if opts.ignore: + module = 'module' + else: + raise err + try: + uai = client.get_creole('numero_etab') + except (TimeoutCreoleClientError, NotFoundError, CreoleClientError) as err: + if opts.ignore: + uai = None + else: + raise err + + head = "*** {0} {1}" + if uai: + head += " ({2})" + head += " ***\n" + + log.info(head.format(module, version, uai)) + + if not opts.force_update: + raising_level = u'' + if opts.release: + raising_level = _(u"(CHANGE RELEASE LEVEL)") + elif u'unstable' in [eole_level, envole_level]: + raising_level = _(u"(UNSTABLE VERSION)") + elif u'proposed' in [eole_level, envole_level]: + raising_level = _(u"(TESTING VERSION)") + + if raising_level != u'': + log.warn(_(u"{0} - Raising update level may prevent " + u"lowering back to stable version.").format(raising_level)) + try: + assert question_ouinon(_(u"Do you wish to proceed?")) == 'oui' + fonctionseole.zephir("MSG", + "Mise à jour{0} forcée par l'utilisateur".format(z_level), + z_proc) + except (AssertionError, EOFError) as err: + log.warn(_(u"Cancelling!")) + raise UserExit() + + PKGMGR.check() + + #serveurs à utiliser pour les dépôts Ubuntu et EOLE + _configure_sources_mirror(PKGMGR.pkgmgr, ubuntu=opts.ubuntu_mirror, + eole=opts.eole_mirror, envole=opts.envole_mirror, + ignore=opts.ignore, cdrom=opts.cdrom, + release=version, eole_level=eole_level, + envole_level=envole_level) + + + PKGMGR.update(silent=True) + upgrades = PKGMGR.get_upgradable_list() + + install = 0 + upgrade = 0 + delete = 0 + for container, packages in upgrades.items(): + if not packages: + continue + for name, isInstalled, candidateVersion in packages: + if isInstalled: + if candidateVersion is None: + delete += 1 + else: + upgrade += 1 + else: + install += 1 + + total_pkg = install+upgrade + + headers = [] + if total_pkg == 0: + log.info(_(u"Update successful.")) + log.info(_(u"Nothing to install.")) + fonctionseole.zephir("FIN", + "Aucun paquet à installer{0}".format(z_level), + z_proc) + if reporting: + report(3) + sys.exit(0) + + headers.append(_(u"{0} new,", u"{0} news,", install).format(install)) + headers.append(_(u"{0} upgrade,", u"{0} upgrades,", upgrade).format(upgrade)) + headers.append(_(u"{0} delete", u"{0} deletes", delete).format(delete)) + log.info(' '.join(headers)) + + for line in PKGMGR.list_upgrade(upgrades=upgrades): + log.info(line) + + if opts.dry_run: + fonctionseole.zephir("FIN", + "{0} paquets à mettre à jour{1}".format(total_pkg, z_level), + z_proc) + sys.exit(0) + + if opts.download: + for container, packages in upgrades.items(): + if not packages: + continue + pkgs = [] + for name, isInstalled, candidateVersion in packages: + pkgs.append(name) + PKGMGR.fetch_archives(container=container, packages=pkgs) + fonctionseole.zephir("FIN", + "{0} paquets téléchargés{1}".format(total_pkg, z_level), + z_proc) + + elif opts.simulate: + PKGMGR.dist_upgrade(simulate=opts.simulate) + fonctionseole.zephir("FIN", + "{0} paquets mis à jour (simulation){1}".format(total_pkg, z_level), + z_proc) + + else: + PKGMGR.download_upgrade() + PKGMGR.dist_upgrade(simulate=opts.simulate) + log.info(_(u"Update successful.")) + fonctionseole.zephir("FIN", + "{0} paquets mis à jour{1}".format(total_pkg, z_level), + z_proc) + if opts.release: + ret_code = system('/usr/share/zephir/scripts/upgrade_distrib.py --auto') + if ret_code != 0: + error_msg = str('erreur à la mise à jour vers la release {0}'.format(opts.release)) + else: + log.info(_('Upgrade post Maj-Release, please wait')) + release('majauto', level='system') + cmd = ['/usr/bin/Maj-Auto', '-F'] + process = Popen(cmd, stdin=PIPE, stderr=PIPE, stdout=PIPE, shell=False) + ret_code = process.wait() + if ret_code != 0: + error_msg = str(_('error in post maj release')) + if opts.reconfigure: + # rechargement des modules python (#7832) + # cf. http://code.activestate.com/recipes/81731-reloading-all-modules/ + if globals().has_key('init_modules'): + for m in [x for x in sys.modules.keys() if x not in init_modules]: + del(sys.modules[m]) + else: + init_modules = sys.modules.keys() + fonctionseole.zephir("MSG", + "Reconfiguration automatique", + z_proc) + elif not opts.release: + log.warn(_(u"At least one packages has been updated," + u" use command [reconfigure] to apply modifications.")) + fonctionseole.zephir("MSG", + "Reconfiguration du serveur à planifier", + z_proc) + + except (UserExit, UserExitError) as err: + if reporting: + report(1, 'Stopped by user') + fonctionseole.zephir("FIN", "Abandon par l'utilisateur", z_proc) + sys.exit(1) + + except (TimeoutCreoleClientError, NotFoundError, CreoleClientError) as err: + clue = _(". If restarting creoled service does not help, try {} command with '-i' option.") + error_msg = str(err) + clue.format('Query-Auto' if opts.dry_run else 'Maj-Auto') + raised_err = err + + except Exception as err: + error_msg = str(err) + raised_err = err + else: + if reporting: + report(0, reconf=opts.reconfigure) + + if error_msg is not None: + fonctionseole.zephir("ERR", error_msg, z_proc, console=False) + if reporting: + if raised_err is not None: + report(1, normalize(err)) + else: + report(1, error_msg) + if log is None: + # No logger defined, error in argument parsing + raise + if opts.log_level == 'debug' and raised_err is not None: + log.error(err, exc_info=True) + else: + log.error(error_msg) + sys.exit(1) + + if opts.reconfigure: + try: + reconfigure.main(force_options={'auto': opts.reboot, 'log_level': opts.log_level}, + force_args=[], need_lock=False) + except Exception as err: + fonctionseole.zephir("ERR", str(err), z_proc, console=False) + if reporting: + report(1, normalize(err)) + sys.exit(1) + + +if __name__ == '__main__': + main() diff --git a/bin/Maj-Cd b/bin/Maj-Cd new file mode 100755 index 0000000..2faff71 --- /dev/null +++ b/bin/Maj-Cd @@ -0,0 +1,3 @@ +#!/bin/bash + +Maj-Auto --cdrom $@ diff --git a/bin/Maj-Release b/bin/Maj-Release new file mode 100755 index 0000000..546831d --- /dev/null +++ b/bin/Maj-Release @@ -0,0 +1,116 @@ +#! /usr/bin/python +# -*- coding: utf-8 -*- +# +########################################################################## +# Maj-Auto - Manage automatique update of EOLE server +# Copyright © 2015 Pôle de compétences EOLE +# +# License CeCILL: +# * in french: http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html +# * in english http://www.cecill.info/licences/Licence_CeCILL_V2-en.html +########################################################################## + +from os import system +from sys import exit +import re +from creole.eoleversion import EOLE_RELEASE, LAST_RELEASE, EOLE_VERSION +from pyeole.i18n import i18n +from pyeole.ihm import print_red + +import argparse +from pyeole import scriptargs + +_ = i18n('creole') + +def parse_cmdline(): + """Parse commande line. + """ + description = _(u"This script will upgrade to a new release of this distribution") + parser = argparse.ArgumentParser(prog='Maj-Release', + description=description, + add_help=False) + + parser.add_argument('-h', '--help', + action='help', + help=_(u"show this help message and exit")) + + parser.add_argument('--release', help=_(u"Target release number")) + + parser.add_argument('-f', '--force', action='store_true', + help=_(u"Do not ask confirmation")) + + opts = parser.parse_args() + + return opts + + +def main(): + opts = parse_cmdline() + + print(_(u"This script will upgrade to a new release of this distribution")) + all_releases = [] + current_release = int(EOLE_RELEASE.split('.')[-1]) + choices = range(current_release+1, int(LAST_RELEASE)+1) + # Last is firt displayed + if choices == []: + print_red(_(u"No stable new release available")) + exit(1) + choices.reverse() + for release_suffix in choices: + all_releases.append(EOLE_VERSION + '.' + str(release_suffix)) + + while True: + if opts.release is not None: + choice = opts.release + else: + for idx, release in enumerate(all_releases): + print("{0}: {1}".format(idx+1, release)) + print(_(u"q|quit: abort")) + + try: + choice = raw_input("[1] : ") + except (KeyboardInterrupt, EOFError): + print_red(_("\nUpgrade aborted by user")) + exit(0) + + if choice == '': + # User hit enter + choice = 1 + elif choice in all_releases: + # User entrer release number + choice = all_releases.index(choice) + 1 + else: + try: + choice = int(choice) + except ValueError: + if re.match(r'^q(uit)?', choice): + print_red(_(u"Voluntary stay of proceedings")) + exit(0) + else: + print_red(_(u"Invalid response: {0}").format(choice)) + if opts.release is not None: + exit(1) + else: + continue + + if not 1 <= choice <= len(choices): + print_red(_(u"Invalid response: {0}").format(choice)) + if opts.release is not None: + exit(1) + else: + continue + else: + break + + release = all_releases[choice - 1] + if opts.force: + force = '--force-update' + else: + force = '' + + majrel = system('/usr/bin/Maj-Auto --release {0} {1}'.format(release, force)) + + exit(majrel) + +if __name__ == '__main__': + main() diff --git a/bin/Query-Auto b/bin/Query-Auto new file mode 100755 index 0000000..c8e4651 --- /dev/null +++ b/bin/Query-Auto @@ -0,0 +1,3 @@ +#!/bin/bash + +Maj-Auto --dry-run $@ diff --git a/bin/Query-Cd b/bin/Query-Cd new file mode 100755 index 0000000..1222f96 --- /dev/null +++ b/bin/Query-Cd @@ -0,0 +1,3 @@ +#!/bin/bash + +Maj-Cd --dry-run $@ diff --git a/bin/StartAll b/bin/StartAll new file mode 100755 index 0000000..c4ea7b5 --- /dev/null +++ b/bin/StartAll @@ -0,0 +1,7 @@ +#!/bin/sh + +# Stop all services +CreoleService all stop + +# Start only enabled ones +CreoleService all start diff --git a/bin/Upgrade-Auto b/bin/Upgrade-Auto new file mode 100755 index 0000000..224ea4c --- /dev/null +++ b/bin/Upgrade-Auto @@ -0,0 +1,5 @@ +#!/bin/bash + +echo "La commande Upgrade-Auto ne permet plus de changer de sous-version du serveur EOLE." +echo "Merci d'utiliser la commande Maj-Release à la place." +exit 1 diff --git a/bin/diagnose b/bin/diagnose new file mode 100755 index 0000000..1598b82 --- /dev/null +++ b/bin/diagnose @@ -0,0 +1,65 @@ +#!/bin/bash +########################################################################### +# Eole NG - 2007 +# Copyright Pole de Competence Eole (Ministere Education - Academie Dijon) +# Licence CeCill cf /root/LicenceEole.txt +# eole@ac-dijon.fr +# +# diagnose +# +# Verifie l'instanciation d'un serveur +# +########################################################################### +. /usr/lib/eole/ihm.sh +. /usr/lib/eole/utils.sh + +only_root + +CREOLE_FILE="/etc/eole/config.eol" +RELEASE_FILE="/etc/eole/release" +DIAG_DIR="/usr/share/eole/diagnose" +err_prefix="Diagnose impossible" + +TestFile $CREOLE_FILE +if [ ${?} -eq 1 ] +then + EchoRouge "${err_prefix} : le serveur n'est pas instancié" + exit 1 +fi +TestFile $RELEASE_FILE +if [ ${?} -eq 1 ] +then + EchoRouge "${err_prefix} : le serveur n'est pas instancié" + exit +fi +TestDir $DIAG_DIR +if [ ${?} -eq 1 ] +then + EchoRouge "${err_prefix} : pas script diagnose disponible" + exit 1 +fi +TestCreoled +if [ ${?} -eq 1 ] +then + EchoRouge "${err_prefix} : creoled est arrêté" + exit 1 +fi + +Opt="" +while getopts "LWT" Option +do + case $Option in + L ) export Verbose="yes";; + W ) export ModeEad="yes";; + T ) export ModeTxt="yes";; + * ) exit 1;; + esac +done + +. $RELEASE_FILE +DETAILS="$(CreoleGet nom_machine) $(CreoleGet numero_etab)" +[ -z "$EOLE_RELEASE" ] && EOLE_RELEASE=$EOLE_VERSION +EchoGras "*** Test du module $EOLE_MODULE version $EOLE_RELEASE ($DETAILS) ***" +echo +run-parts $DIAG_DIR +EchoGras "*** FIN DU DIAGNOSTIC ***" diff --git a/bin/gen_patch b/bin/gen_patch new file mode 100755 index 0000000..28ad1f8 --- /dev/null +++ b/bin/gen_patch @@ -0,0 +1,27 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from os import listdir, system, chdir +from os.path import isfile, join, basename +from creole import config + +modif_dir = basename(config.modif_dir) +distrib_dir = basename(config.distrib_dir) +patch_dir = basename(config.patch_dir) + +system('clear') + +# on travaille dans le répertoire eole +chdir(config.eoleroot) + +print "** Génération des patches à partir de %s **\n" % modif_dir +for modfile in listdir(modif_dir): + if modfile.endswith('~'): + continue + if not isfile(join(distrib_dir, modfile)): + print "ATTENTION : le fichier original %s n'existe pas !" % join(distrib_dir, modfile) + continue + print "Génération du patch %s.patch" % modfile + system("diff -uNr %s %s > %s.patch" % (join(distrib_dir,modfile), join(modif_dir,modfile), join(patch_dir,modfile))) + +print "\n** Fin de la génération des patch **\n" diff --git a/bin/gen_rpt b/bin/gen_rpt new file mode 100755 index 0000000..d10c4f9 --- /dev/null +++ b/bin/gen_rpt @@ -0,0 +1,137 @@ +#!/bin/bash +########################################################################### +# EOLE - 2010 +# Copyright Pole de Competence Eole (Ministere Education - Academie Dijon) +# Licence CeCill cf /root/LicenceEole.txt +# eole@ac-dijon.fr +# +# gen_rpt +# +# Génère un rapport d'anomalie +# +########################################################################### + +TestConf() +{ +[ -e "$1" ] && return 0 + tput setaf 3 + echo "* Erreur $0 : le fichier de configuration $1 absent" + echo "* Instanciez votre serveur" + tput sgr0 + exit 1 +} + +clear + +. /usr/lib/eole/ihm.sh +. /usr/lib/eole/utils.sh + +only_root + +numero_etab=$(CreoleGet numero_etab) +CONFIGEOL='/etc/eole/config.eol' +EOLEDIRS="/usr/share/eole/creole/dicos" +PATCHDIR="/usr/share/eole/creole/patch" +TestConf $CONFIGEOL +EOLERELEASE="/etc/eole/release" +if [ ! -e $EOLERELEASE ]; then + EchoRouge "Fichier $EOLERELEASE est introuvable" + exit 1 +fi +. $EOLERELEASE +Module="${EOLE_MODULE}-${EOLE_VERSION}" +echo "Récupération des informations ..." +RepRpt="/tmp/GenRpt" +rm -fr $RepRpt 2> /dev/null +mkdir $RepRpt +mkdir $RepRpt/log +mkdir $RepRpt/eole +mkdir $RepRpt/system +Rpt=$RepRpt"/Rpt-"$Module"-"$numero_etab +Mel="eole@ac-dijon.fr" + +# les fichiers texte +echo "Config.eol" +/bin/cp -f $CONFIGEOL $RepRpt/eole +echo "Diagnose" +/usr/bin/diagnose -LT >> $RepRpt/diagnose.txt 2>&1 +echo Pstree +pstree >> $RepRpt/system/pstree.txt 2>&1 +echo Lshw +lshw >> $RepRpt/system/lshw.txt 2>&1 +echo Lsusb +lsusb >> $RepRpt/system/lsusb.txt 2>&1 +echo Lspci +lspci >> $RepRpt/system/lspci.txt 2>&1 +echo Iptables +iptables -nvL > $RepRpt/system/iptables.txt 2>&1 +iptables -nvL -t nat >> $RepRpt/system/iptables.txt 2>&1 +echo History +grep -v "^#" /root/.bash_history > $RepRpt/system/history.txt +echo Paquets +dpkg-query -W > $RepRpt/system/packages.txt 2>&1 +# les gz +echo Syslog +for log in rsyslog su sudo kernel cron auth chpasswd exim ; do +[ -d /var/log/rsyslog/local/$log ] && gzip -rc /var/log/rsyslog/local/$log > $RepRpt/log/$log.gz +done +echo Dmesg +dmesg > $RepRpt/log/dmesg.log 2>&1 +gzip $RepRpt/log/dmesg.log +echo Creole.log +gzip -c /var/log/reconfigure.log > $RepRpt/log/reconfigure.log.gz +echo Dicos +gzip -rc $EOLEDIRS > $RepRpt/eole/dicos.gz +echo Patch +gzip -rc $PATCHDIR > $RepRpt/eole/patch.gz +echo Stats +gzip -rc /usr/share/zephir/monitor/stats > $RepRpt/stats.gz + +# spécifique Scribe +if [ -f /var/www/ead/extraction/tmp/rapport.txt ];then +echo "Rapport d'extraction" +gzip -rc /var/www/ead/extraction/tmp/rapport.txt > $RepRpt/log/extraction.log.gz +fi +if [ -f /var/log/controle-vnc/main.log ];then +echo 'Log client scribe' +gzip -rc /var/log/controle-vnc/main.log > $RepRpt/log/controle-vnc.log.gz +fi + +# spécifique Scribe/Horus/Eclair +if [ -d /var/lib/eole/reports ];then +echo "Rapport (sauvegarde/maj/...)" +gzip -rc /var/lib/eole/reports > $RepRpt/log/rapport.log.gz +fi + +# spécifique Amon +if [ -f '/usr/share/eole/test-rvp' ];then +echo 'Rvp' +/usr/sbin/ipsec status &> $RepRpt/ipsec.status 2>&1 +fi + +# Rapport debsums +if [ -x '/usr/share/eole/debsums/show-reports.py' ]; then +echo "Rapport debsums" +/usr/share/eole/debsums/show-reports.py > ${RepRpt}/log/rapport-debsums.log 2>&1 +fi + +echo +Archive=$Module-$numero_etab".tar.gz" +echo "Création de l'archive locale $Archive" +tar -C /tmp -czf $Archive GenRpt +echo + +Question_ouinon "Envoyer l'archive par email ?" +if [ $? -eq 1 ];then + exit 0 +fi + +echo "Destinataire du message : " +echo -n "[$Mel] : " +read mail +if [ "$mail" == "" ];then + mail=$Mel +fi +echo -n "Commentaire : " +read comment +echo "$comment"|mutt -a $Archive -s "Rapport $Module de $numero_etab" -c $mail -e "set copy=no" diff --git a/bin/instance b/bin/instance new file mode 100755 index 0000000..86aef70 --- /dev/null +++ b/bin/instance @@ -0,0 +1,24 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +"""Application de la configuration EOLE +""" + + +import sys +from creole.reconfigure import main +from creole.error import UserExitError, LockError, UnlockError, UserExit +from pyeole.ihm import only_root + +only_root() + +try: + # Force interactive mode + main(force_options={'interactive': True}) +except (UserExitError, LockError, UnlockError): + sys.exit(1) +except UserExit: + sys.exit(0) +except: + #FIXME: log & affichage géré au raise ? + sys.exit(1) diff --git a/bin/manage-eole b/bin/manage-eole new file mode 100755 index 0000000..665b4e9 --- /dev/null +++ b/bin/manage-eole @@ -0,0 +1,173 @@ +#!/bin/bash +########################################################## +# +# Eole NG - 2010 +# Copyright Pole de Competence Eole (Ministere Education - Academie Dijon) +# Licence CeCill http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html +# eole@ac-dijon.fr +# +# Gestion des modules en mode dialogue +# avec les comptes système eole, eole2 +# +########################################################## + +# un seul manage ? +pmanage=`pgrep manage-eole` +nbmanage=`echo $pmanage | wc -w` + +# fichiers temporaires +temp="/tmp/InBox-Eol-" +tempfile="$temp$$" + +TitreGen="Eole - Gestion du Serveur" + +########################################################## +# Fonctions reprises de FonctionsEole +########################################################## + +MenuBox() +{ +#${1="Votre Saisie"} +#${2="Saisie"} +NBlignes=${NBlignes=5} +Menu="$3" +dialog $NOMOUSE1 --backtitle "$TitreGen" \ + --aspect 45 --clear \ + --menu "$1" 16 50 $NBlignes \ + $Menu 2> $tempfile +retval=$? +case $retval in + 0) + eval $2="`cat $tempfile`";; + 1) # Cancel + eval $2="CANCEL";; + 255) # ESC + if test -s $tempfile ; + then + eval $2=`cat $tempfile` + else + eval $2="ESC" + fi + ;; +esac +} + +OkBox() +{ +dialog $NOMOUSE1 --backtitle "$TitreGen" \ + --aspect 45 --cancel-label Abandon\ + --msgbox "$1" 0 0 +} + +QuestionBox() +{ +#${1=Votre Saisie"} +#${2="Saisie"} +dialog $NOMOUSE1 --backtitle "$TitreGen" \ + --aspect 45 --clear \ + --yesno "$1" 16 50 +retval=$? +case $retval in + 0) + eval $2="OUI";; + 1) # Cancel + eval $2="NON";; + 255) # ESC + eval $2="ESC" ;; +esac +} + +Entree(){ +echo +echo "Tapez " +read Bidon +} + +CleanExit(){ +echo "Au revoir !" +rm -f $tempfile +exit $1 +} + +########################################################## +# Programme principal +########################################################## + +if [ $nbmanage -gt 1 ] +then + MenuBox "D'autres instances de manage-eole ont été détectées" Rep "1 Quitter_sans_tuer 2 Quitter_et_tuer" + rm -f "$temp*" + if [ "$Rep" == "2" ] + then + for pid in $pmanage + do + kill -9 $pid + done + fi + CleanExit 0 +fi + +OkBox "Administration EOLE\n\nPour Vous Deplacer sur l'Ecran\nUtiliser votre Souris\nOu la touche tabulation.\n\n" + +Rep="" +while [ 1 ] +do +# FIXME/TODO : ajouter des entrées de menu ! +MenuBox "Votre Choix" Rep "1 Diagnostic 2 Reconfiguration 3 Paquets_en_Maj 4 Mise_A_Jour 8 Redemarrer_Serveur 9 Arret_Serveur ! Shell_Linux Q Quitter" + +if [ "$Rep" == "CANCEL" ] +then + CleanExit 1 +fi + +case $Rep in + 1) + echo "En cours ..." + sudo /usr/bin/diagnose + Entree + ;; + 2) + sudo /usr/bin/reconfigure + Entree + ;; + 3) + sudo /usr/bin/Query-Auto + Entree + ;; + 4) + sudo /usr/bin/Maj-Auto + Entree + ;; + # TODO : pouvoir inclure des entrées venant d'ailleurs ;) + #5) + #sudo /usr/share/eole/Maj-blacklist.sh + #Entree + #;; + 8) + QuestionBox "Vous avez demandé le redémarrage du serveur\nEtes vous sur ?" Rep + if [ "$Rep" == "OUI" ] + then + sudo /sbin/reboot + sleep 1 + CleanExit 0 + fi + ;; + 9) + QuestionBox "Vous avez demandé un arret total du serveur\nEtes vous sur ?" Rep + if [ "$Rep" == "OUI" ] + then + sudo /sbin/halt -p + sleep 1 + CleanExit 0 + fi + ;; + !) + echo "\"exit\" ou \"Ctrl + d\" pour revenir au Menu" + /bin/bash + ;; + Q) + CleanExit 0 + ;; + +esac +done diff --git a/bin/reconfigure b/bin/reconfigure new file mode 100755 index 0000000..3453488 --- /dev/null +++ b/bin/reconfigure @@ -0,0 +1,22 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +"""Application de la configuration EOLE +""" + +import sys +from creole.reconfigure import main +from creole.error import UserExitError, LockError, UnlockError, UserExit +from pyeole.ihm import only_root + +only_root() + +try: + main() +except (UserExitError, LockError, UnlockError): + sys.exit(1) +except UserExit: + sys.exit(0) +except: + #FIXME: log & affichage géré au raise ? + sys.exit(1) diff --git a/creole.mk b/creole.mk new file mode 100644 index 0000000..5fdd6ec --- /dev/null +++ b/creole.mk @@ -0,0 +1,15 @@ +# creole specific rules + +schedule_PROG_DIR := $(eole_DIR)/schedule +upgrade_REC_DIR := $(eole_DIR)/upgrade +bin_PROG_DIR := $(DESTDIR)/usr/bin +sbin_PROG_DIR := $(DESTDIR)/usr/sbin +data_REC_DIR := $(DESTDIR)/usr/share/creole +fr.man8_DATA_DIR := $(DESTDIR)/usr/share/man/fr.UTF-8/man8 +en.man8_DATA_DIR := $(DESTDIR)/usr/share/man/man8 +motd_PROG_DIR := $(DESTDIR)/etc/update-motd.d +local_DATA_DIR := $(DESTDIR)/usr/share/eole/creole/dicos/local + +install-files:: + # To inform user about coding changes + $(INSTALL_DATA) deprecated/FonctionsEoleNg $(eole_DIR) diff --git a/creole/__init__.py b/creole/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/creole/annotator.py b/creole/annotator.py new file mode 100644 index 0000000..c5127ad --- /dev/null +++ b/creole/annotator.py @@ -0,0 +1,1807 @@ +# coding: utf-8 +from copy import copy + +from collections import OrderedDict +from os.path import join, basename +from ast import literal_eval +import sys +import imp + + +from .i18n import _ +from .utils import normalize_family +from .config import VIRTBASE, VIRTROOT, VIRTMASTER, templatedir +from .error import CreoleDictConsistencyError +from .xmlreflector import HIGH_COMPATIBILITY + +#mode order is important +modes_level = ('basic', 'normal', 'expert') + + +class secure_eosfunc: + def __init__(self, eosfunc): + self.eosfunc = eosfunc + + def __getattribute__(self, func_name): + if func_name == 'eosfunc': + return super().__getattribute__('eosfunc') + if func_name in self.eosfunc.func_on_zephir_context: + return getattr(self.eosfunc) + raise Exception(_('unknown or unauthorized function: {}'.format(func_name))) + + +class Mode(object): + def __init__(self, name, level): + self.name = name + self.level = level + + def __cmp__(self, other): + return cmp(self.level, other.level) + + def __eq__(self, other): + return self.level == other.level + + def __ne__(self, other): + return self.level != other.level + + def __gt__(self, other): + return other.level < self.level + + def __ge__(self, other): + return not self.level < other.level + + def __le__(self, other): + return not other.level < self.level + + +def mode_factory(): + mode_obj = {} + for idx in range(len(modes_level)): + name = modes_level[idx] + mode_obj[name] = Mode(name, idx) + return mode_obj + +modes = mode_factory() + +# a CreoleObjSpace's attribute has some annotations +# that shall not be present in the exported (flatened) XML +ERASED_ATTRIBUTES = ('redefine', 'exists', 'fallback', 'optional', 'remove_check', 'namespace', + 'remove_condition', 'path', 'instance_mode', 'index', 'is_in_master', '_real_container') + +NOT_NEED_ACTIVATE = ('package', 'disknod') + +FORCE_CHOICE = {'oui/non': ['oui', 'non'], + 'on/off': ['on', 'off'], + 'yes/no': ['yes', 'no'], + 'schedule': ['none', 'daily', 'weekly', 'monthly'], + 'schedulemod': ['pre', 'post']} + +KEY_TYPE = {'SymLinkOption': 'symlink', + 'PortOption': 'port', + 'UnicodeOption': 'string', + 'NetworkOption': 'network', + 'NetmaskOption': 'netmask', + 'URLOption': 'web_address', + 'FilenameOption': 'filename'} + +TYPE_PARAM_CHECK = ('string', 'python', 'eole') +TYPE_PARAM_CONDITION = ('string', 'python', 'number', 'eole') +TYPE_PARAM_FILL = ('string', 'eole', 'number', 'container', 'context') + +DISKNOD_KEY_TYPE = {'major': 'number', + 'minor': 'number'} + +ERASED_FAMILY_ACTION_ATTRIBUTES = ('index', 'action') + + +class ContainerAnnotator(object): + """Manage container's object + """ + def __init__(self, space, paths, objectspace): + self.space = space + self.paths = paths + self.objectspace = objectspace + self.extra_conditions = {} + var_name = 'mode_conteneur_actif' + self.containers_enabled = False + try: + family_name = self.paths.get_variable_family_name(var_name) + if (hasattr(space, 'variables') and + 'creole' in space.variables and + hasattr(space.variables['creole'], 'family') and + family_name in space.variables['creole'].family and + var_name in space.variables['creole'].family[family_name].variable and + hasattr(space.variables['creole'].family[family_name].variable[var_name], 'value')): + # assume that mode_conteneur_actif is not a multi + value = space.variables['creole'].family[family_name].variable[var_name].value[0].name + self.containers_enabled = value == 'oui' + except CreoleDictConsistencyError: + pass + + root_container = self.objectspace.container() + root_container.name = 'root' + root_container.container = 'root' + root_container.real_container = 'root' + root_container.container_group = 'root' + root_container.id = '1' + if not hasattr(self.space, 'containers'): + self.space.containers = self.objectspace.containers() + if hasattr(self.space.containers, 'container'): + old_container = list(self.space.containers.container.items()) + old_container.insert(0, ('root', root_container)) + self.space.containers.container = OrderedDict(old_container) + #self.space.containers.container['root'] = root_container + else: + self.space.containers.container = OrderedDict({'root': root_container}) + if hasattr(space, 'containers') and hasattr(space.containers, 'all'): + all_container = self.objectspace.container() + all_container.name = 'all' + all_container.container = 'all' + if self.containers_enabled: + all_container.real_container = 'all' + else: + all_container.real_container = VIRTMASTER + all_container.container_group = 'all' + old_container = list(self.space.containers.container.items()) + old_container.insert(1, ('all', all_container)) + self.space.containers.container = OrderedDict(old_container) + #self.space.containers.container['all'] = all_container + if hasattr(space, 'variables') and 'creole' in space.variables: + flattened_elts = dict() + if hasattr(space, 'files'): + for key, values in vars(self.space.files).items(): + if not isinstance(values, str) and not isinstance(values, int): + if isinstance(values, dict): + values = values.values() + for value in values: + value.container = root_container + flattened_elts.setdefault(key, []).append(value) + # Remove "all" and dispatch informations in all containers + if hasattr(space, 'containers') and hasattr(space.containers, 'all') and hasattr(space.containers, 'container'): + for type_, containers in vars(space.containers.all).items(): + if type_ == 'index': + continue + if isinstance(containers, list): + for elt in containers: + for container in space.containers.container.values(): + if container.name not in ['root', 'all']: + if not hasattr(container, type_): + setattr(container, type_, []) + new_elt = copy(elt) + new_elt.container = container + getattr(container, type_).append(new_elt) + else: + for name, elt in containers.items(): + for container in space.containers.container.values(): + if container.name not in ['root', 'all']: + if not hasattr(container, type_): + setattr(container, type_, OrderedDict()) + old_container = getattr(container, type_) + if name in old_container: + raise CreoleDictConsistencyError('{}'.format(name)) + new_elt = copy(elt) + new_elt.container = container + old_container[name] = new_elt + del space.containers.all + if hasattr(space, 'containers') and hasattr(space.containers, 'container'): + self.generate_interfaces() + groups = {} + containers = space.containers.container.values() + container_groups = {} + update_values = True + while update_values: + update_values = False + for container in containers: + if not hasattr(container, 'group'): + container.group = container.name + if not hasattr(container, 'container_group'): + container.container_group = container.group + if HIGH_COMPATIBILITY: + if self.containers_enabled: + real_container = container.group + else: + real_container = VIRTMASTER + container.real_container = real_container + if container.group in container_groups: + group = container_groups[container.group] + else: + group = container.group + if container_groups.get(container.name) != group: + container_groups[container.name] = group + container._real_container = group + if not HIGH_COMPATIBILITY and self.containers_enabled: + container.real_container = group + update_values = True + + for container in space.containers.container.values(): + if not hasattr(container, 'group'): + container.group = container.name + groupname = container.group + groups.setdefault(groupname, []).append(container) + for groupname, containers in groups.items(): + for container in containers: + if container.name == 'all': + continue + #container.container_group = groupname + if HIGH_COMPATIBILITY and hasattr(container, 'id'): + container.group_id = container.id + container.id = space.containers.container[container._real_container].id + container.container = container.name + for container in space.containers.container.values(): + container_info = self.objectspace.container() + for key, value in vars(container).items(): + if isinstance(value, str): + setattr(container_info, key, value) + for key, values in vars(container).items(): + if not isinstance(values, str) and not isinstance(values, int): + if isinstance(values, dict): + values = values.values() + for value in values: + value.container = container_info + flattened_elts.setdefault(key, []).append(value) + self.generate_containers() + if hasattr(self.space, 'files'): + del self.space.files + self.convert_containers() + + if hasattr(self.space.containers, 'family'): + raise Exception('hu?') + self.space.containers.family = OrderedDict() + self.generate_network_container() + for elttype in self.objectspace.container_elt_attr_list: + key_type_name = elttype.upper() + '_KEY_TYPE' + if key_type_name in globals(): + key_type = globals()[key_type_name] + else: + key_type = {} + elt = flattened_elts.get(elttype, {}) + families = self.make_group_from_elts(elttype, elt, key_type, + 'containers.{}s'.format(elttype), True) + if families == [] and not HIGH_COMPATIBILITY: + continue + family = self.objectspace.family() + family.name = elttype + 's' + if HIGH_COMPATIBILITY: + family.doc = '' + family.family = families + if HIGH_COMPATIBILITY: + family.mode = None + self.space.containers.family[elttype + 's'] = family + + def _generate_container_variable(self, name, description, value, family_name, frozen=False): + var_data = {'hidden': True, 'mode': 'expert', 'name': name, + 'doc': description, 'value': value, + 'type': 'string'} + variable = self.objectspace.variable() + if HIGH_COMPATIBILITY: + if frozen: + var_data['frozen'] = True + var_data['force_default_on_freeze'] = True + var_data['hidden'] = False + del var_data['mode'] + variable.mode = None + for key, value in var_data.items(): + if key == 'value': + # Value is a list of objects + val = self.objectspace.value() + val.name = value + value = [val] + setattr(variable, key, value) + self.paths.append('variable', variable.name, 'creole', family_name, variable) + return variable + + def _generate_root_container(self, family_name): + if self.containers_enabled: + ip_br0 = u'192.0.2.1' + mask_br0 = u'255.255.255.0' + network_br0 = u'192.0.2.0' + bcast_br0 = u'192.0.2.255' + else: + ip_br0 = u'127.0.0.1' + mask_br0 = u'255.0.0.0' + network_br0 = u'127.0.0.0' + bcast_br0 = u'127.255.255.255' + variables = OrderedDict() + variable = self._generate_container_variable('adresse_ip_br0', + _(u"Bridge IP address"), + ip_br0, + family_name) + variables[variable.name] = variable + variable = self._generate_container_variable('adresse_netmask_br0', + _(u"Bridge IP subnet mask"), + mask_br0, + family_name) + variables[variable.name] = variable + if HIGH_COMPATIBILITY: + msg = u"Bridge IP network_br0 address" + else: + msg = u"Bridge IP network address" + variable = self._generate_container_variable('adresse_network_br0', + _(msg), + network_br0, + family_name) + variables[variable.name] = variable + variable = self._generate_container_variable('adresse_broadcast_br0', + _(u"Bridge broadcast IP address"), + bcast_br0, + family_name) + variables[variable.name] = variable + return variables + + def _get_containers(self): + return self.space.containers.container + + def convert_containers(self): + idx = 0 + self.space.containers.containers = self.objectspace.containers() + for name, container in self.space.containers.container.items(): + variables = [] + for key, value in vars(container).items(): + if key in ['container', 'group_id'] or key in ERASED_ATTRIBUTES: + continue + if not isinstance(value, list) and not isinstance(value, OrderedDict): + variable = self.objectspace.variable() + variable.name = key + variable.mode = None + if key == 'id': + variable.type = 'number' + else: + variable.type = 'string' + if HIGH_COMPATIBILITY: + variable.doc = '' + val = self.objectspace.value() + val.name = value + variable.value = [val] + variables.append(variable) + for key in ['ip', 'path']: + var_path = self.paths.get_variable_path('container_{}_{}'.format(key, name), 'creole') + variable = self.objectspace.variable() + variable.name = key + variable.mode = None + variable.opt = var_path + variable.type = 'symlink' + variables.append(variable) + + family = self.objectspace.family() + family.name = 'container{}'.format(idx) + if HIGH_COMPATIBILITY: + family.doc = '' + family.variable = variables + if HIGH_COMPATIBILITY: + family.mode = None + setattr(self.space.containers.containers, 'container{}'.format(idx), family) + idx += 1 + del self.space.containers.container + + def generate_network_container(self): + family = self.objectspace.family() + family.name = 'network' + if HIGH_COMPATIBILITY: + family.doc = '' + family.mode = None + variables = [] + for name in ['adresse_ip_br0', 'adresse_netmask_br0', + 'adresse_network_br0', 'adresse_broadcast_br0']: + var_path = self.paths.get_variable_path(name, 'creole') + variable = self.objectspace.variable() + variable.name = name + variable.mode = 'expert' + variable.opt = var_path + variable.type = 'symlink' + variables.append(variable) + family.variable = variables + self.space.containers.family['network'] = family + + def generate_interfaces(self): + if self.containers_enabled: + for name, container in self._get_containers().items(): + if name in ['all', 'root']: + continue + interface = self.objectspace.interface() + interface.name = 'containers' + interface.container = name + interface.linkto = 'br0' + interface.method = 'bridge' + interface.ip = 'container_ip_{0}'.format(name) + interface.mask = 'adresse_netmask_br0' + interface.bcast = 'adresse_broadcast_br0' + interface.gateway = 'adresse_ip_br0' + if not hasattr(container, 'interface'): + container.interface = OrderedDict() + container.interface['containers'] = interface + else: + old = list(container.interface.items()) + old.insert(0, ('containers', interface)) + container.interface = OrderedDict(old) + + def generate_containers(self): + """generate the root's container informations + """ + family_description = 'Containers' + family_name = family_description.lower() + if family_name in self.space.variables: + raise CreoleDictConsistencyError(_('{} family already exists').format(family_name)) + variables = self._generate_root_container(family_name) + self._generate_containers(variables) + self.paths.append('family', family_name, 'creole') + family = self.objectspace.family() + family.name = family_description + family.doc = _(u'Containers informations') + family.hidden = True + if HIGH_COMPATIBILITY: + family.mode = 'normal' + family.icon = 'puzzle-piece' + family.variable = variables + # this family must be at the beginning + if hasattr(self.space.variables['creole'], 'family'): + old_families = list(self.space.variables['creole'].family.items()) + old_families.insert(0, (family_name, family)) + self.space.variables['creole'].family = OrderedDict(old_families) + + def _generate_container_path(self, container): + if container.name == 'all': + path = None + elif not self.containers_enabled or container.name == VIRTMASTER: + path = u'' + else: + group_name = container._real_container + path = join(VIRTROOT, group_name, VIRTBASE) + if sys.version_info[0] < 3: + group_name = unicode(group_name) + path = unicode(path) + return path + + def _generate_containers(self, variables): + """generate containers informations + """ + containers = self._get_containers() + family_name = 'containers' + ids = {} + for name, container in containers.items(): + if not hasattr(container, 'group'): + groupname = container.name + else: + groupname = container.group + if name == 'all': + ipaddr = None + group_name = u'all' + else: + group_name = container._real_container + if sys.version_info[0] < 3: + group_name = unicode(group_name) + if group_name not in containers: + raise CreoleDictConsistencyError(_('the container "{}" does not exist').format(group_name)) + if not hasattr(containers[group_name], 'id'): + raise CreoleDictConsistencyError(_('mandatory attribute "id" missing for container ' + '"{}"').format(group_name)) + id_value = containers[group_name].id + if id_value in ids and ids[id_value] != group_name: + raise CreoleDictConsistencyError(_('attribute "id" must be unique, but "{}" is used for containers "{}" and "{}"' + ).format(id_value, group_name, ids[id_value])) + ids[id_value] = group_name + if not self.containers_enabled or name == VIRTMASTER: + ipaddr = u'127.0.0.1' + group_name = VIRTMASTER + else: + group_id = id_value + ipaddr = u"192.0.2.{}".format(group_id) + + path = self._generate_container_path(container) + # Variable : container_path_ + path_name = 'container_path_{0}'.format(name) + variable = self._generate_container_variable(path_name, + _(u'Path of container {0}').format(name), + path, + family_name) + variables[variable.name] = variable + # Variable : container_ip_ + ip_name = 'container_ip_{0}'.format(name) + msg = u'IP address of container {0}' + variable = self._generate_container_variable(ip_name, + _(msg).format( + name), + ipaddr, + family_name) + variables[variable.name] = variable + # Variable : container_name_ + name_name = 'container_name_{0}'.format(name) + variable = self._generate_container_variable(name_name, + _(u'Group name of container {0}').format( + name), + group_name, + family_name) + variables[variable.name] = variable + # Variable : adresse_ip_ + # adresse_ip_ added for compat 2.3 (#5701, #5868) + address_name = 'adresse_ip_{0}'.format(name) + if HIGH_COMPATIBILITY: + msg = u'Path of container {0}' + else: + msg = u'IP address of container {0}' + if not self.paths.path_is_defined(address_name): + if not self.containers_enabled: + # hack to have "localhost" in non container mode #7183 + variable = self._generate_container_variable(address_name, + _(msg).format( + name), + 'localhost', + family_name, + frozen=True) + else: + self.paths.append('variable', address_name, 'creole', family_name, variable) + path = self.paths.get_variable_path(address_name, 'creole') + var_path = self.paths.get_variable_path(ip_name, 'creole') + variable = self.objectspace.variable() + variable.name = address_name + variable.path = path + variable.mode = 'expert' + variable.opt = var_path + variable.type = 'symlink' + variables[variable.name] = variable + + def _generate_element(self, eltname, name, value, type_, subpath, multi=False): + var_data = {'name': name, 'doc': '', 'value': value, + 'auto_freeze': False, 'mode': None, 'multi': multi} + values = None + if type_ == 'string': + values = self.objectspace.forced_choice_option.get(eltname, {}).get(name) + if values is not None: + type_ = 'choice' + var_data['type'] = type_ + + variable = self.objectspace.variable() + if not HIGH_COMPATIBILITY: + variable.mandatory = True + for key, value in var_data.items(): + if key == 'value': + if value is None: + continue + if type_ == 'symlink': + key = 'opt' + else: + # Value is a list of objects + if not multi: + val = self.objectspace.value() + val.name = value + value = [val] + else: + value_list = [] + for valiter in value: + val = self.objectspace.value() + val.name = valiter.name + value_list.append(val) + value = value_list + if key == 'doc' and type_ == 'symlink': + continue + setattr(variable, key, value) + if values is not None: + choices = [] + for value in values: + choice = self.objectspace.choice() + if sys.version_info[0] < 3: + choice.name = unicode(value, 'utf8') + else: + choice.name = value + choices.append(choice) + variable.choice = choices + path = '{}.{}'.format(subpath, name) + self.paths.append('variable', path, 'containers', 'containers', variable) + return variable + + def _make_disknod_auto(self, type_, index, variable): + if not hasattr(self.space.constraints, 'auto'): + self.space.constraints.auto = [] + auto = self.objectspace.auto() + self.objectspace.index += 1 + auto.index = self.objectspace.index + auto.namespace = 'containers' + param1 = self.objectspace.param() + param1.text = type_ + param2 = self.objectspace.param() + param2.text = variable.name + auto.param = [param1, param2] + auto.name = 'cdrom_minormajor' + family = 'disknod{}'.format(index) + auto.target = 'containers.disknods.{}.{}'.format(family, type_) + if not hasattr(self.space, 'constraints'): + self.space.constraints = self.objectspace.constraints() + self.space.constraints.auto.append(auto) + + def _make_disknod_type(self, index, variable): + auto = self.objectspace.auto() + self.objectspace.index += 1 + auto.index = self.objectspace.index + auto.namespace = 'containers' + param = self.objectspace.param() + param.text = variable.name + auto.param = [param] + auto.name = 'device_type' + family = 'disknod{}'.format(index) + auto.target = 'containers.disknods.{}.type'.format(family) + if not hasattr(self.space, 'constraints'): + self.space.constraints = self.objectspace.constraints() + if not hasattr(self.space.constraints, 'auto'): + self.space.constraints.auto = [] + self.space.constraints.auto.append(auto) + + + def _update_disknod(self, disknod, index): + disknod.major = None + disknod.minor = None + disknod.type = None + self._make_disknod_auto('minor', index, disknod) + self._make_disknod_auto('major', index, disknod) + self._make_disknod_type(index, disknod) + disknod.mode = u'rwm' + disknod.permission = 'allow' + + def _update_file(self, file_, index): + # take care of os.path.join and absolute part after first + # argument. + filename = file_.name + if filename[0] == '/': + filename = filename[1:] + + full_name = file_.name + container_path = self._generate_container_path(file_.container) + if container_path: + if full_name.startswith('/'): + full_name = full_name[1:] + full_name = join(container_path, full_name) + file_.full_name = full_name + + if not hasattr(file_, 'source'): + source = basename(filename) + else: + source = file_.source + source = join(templatedir, source) + file_.source = source + + def _split_elts(self, name, key, value, elt): + """for example:: + + + 123 + ntpd + + + builds a `service_access` object, but we need **two** objects `service_access`, + for example one for the port and one for the tcpwrapper + """ + for subelt in value: + new_elt = copy(elt) + for subsubelt in dir(subelt): + if subsubelt.startswith('_') or subsubelt == 'index': + continue + if hasattr(new_elt, subsubelt): + if hasattr(elt, 'name'): + name_ = elt.name + else: + name_ = elt.service + raise CreoleDictConsistencyError(_('attribute {} already exists ' + 'for {}').format(subsubelt, + name_)) + setattr(new_elt, subsubelt, getattr(subelt, subsubelt)) + if hasattr(new_elt, 'node_name') or hasattr(new_elt, 'name_type'): + raise CreoleDictConsistencyError(_('attribute node_name or name_type ' + 'already exists for {}' + '').format(name)) + if hasattr(subelt, key + '_type'): + type_ = getattr(subelt, key + '_type') + setattr(new_elt, 'name_type', type_) + setattr(new_elt, 'node_name', key) + if not hasattr(new_elt, name + 'list'): + setattr(new_elt, name + 'list', '___auto_{}'.format(elt.service)) + else: + self.extra_conditions[new_elt] = '___auto_{}'.format(elt.service) + yield new_elt + + def _reorder_elts(self, name, elts, duplicate_list): + """Reorders by index the elts (the interface, + the hosts, actions...) + """ + dict_elts = OrderedDict() + # reorder elts by index + new_elts = {} + not_indexed = [] + for elt in elts: + if not hasattr(elt, 'index'): + not_indexed.append(elt) + else: + idx = elt.index + new_elts.setdefault(idx, []).append(elt) + idxes = list(new_elts.keys()) + idxes.sort() + elts = not_indexed + for idx in idxes: + elts.extend(new_elts[idx]) + for idx, elt in enumerate(elts): + elt_added = False + for key in dir(elt): + if key.startswith('_') or key.endswith('_type') or key in ERASED_ATTRIBUTES: + continue + value = getattr(elt, key) + if isinstance(value, list) and duplicate_list: + for new_elt in self._split_elts(name, key, value, elt): + dict_elts.setdefault(new_elt.name, []).append({'elt_name': key, + 'elt': new_elt}) + elt_added = True + if not elt_added: + if hasattr(elt, 'name'): + eltname = elt.name + else: + eltname = idx + dict_elts.setdefault(eltname, []).append({'elt_name': name, 'elt': elt}) + + result_elts = [] + for elt in dict_elts.values(): + result_elts.extend(elt) + return result_elts + + + def make_group_from_elts(self, name, elts, key_type, path, duplicate_list): + """Splits each objects into a group (and `OptionDescription`, in tiramisu terms) + and build elements and its attributes (the `Options` in tiramisu terms) + """ + index = 0 + families = [] + new_elts = self._reorder_elts(name, elts, duplicate_list) + for elt_info in new_elts: + elt = elt_info['elt'] + elt_name = elt_info['elt_name'] + update_elt = '_update_' + elt_name + if hasattr(self, update_elt): + getattr(self, update_elt)(elt, index) + if hasattr(elt, 'instance_mode'): + instance_mode = elt.instance_mode + else: + instance_mode = 'always' + if ((instance_mode == 'when_container' and not self.containers_enabled) or + (instance_mode == 'when_no_container' and self.containers_enabled)): + continue + variables = [] + subpath = '{}.{}{}'.format(path, name, index) + listname = '{}list'.format(name) + if name not in NOT_NEED_ACTIVATE: + activate_path = '.'.join([subpath, 'activate']) + if elt in self.extra_conditions: + self.objectspace.list_conditions.setdefault(listname, + {}).setdefault( + self.extra_conditions[elt], + []).append(activate_path) + for key in dir(elt): + if key.startswith('_') or key.endswith('_type') or key in ERASED_ATTRIBUTES: + continue + value = getattr(elt, key) + if isinstance(value, list) and duplicate_list: + continue + if key == listname: + if name not in NOT_NEED_ACTIVATE: + self.objectspace.list_conditions.setdefault(listname, + {}).setdefault( + value, + []).append(activate_path) + if not HIGH_COMPATIBILITY: + continue + if key == 'container': + variables.append(self._generate_element(elt_name, key, value.container, + 'string', subpath)) + variables.append(self._generate_element(elt_name, 'container_group', + value.container_group, + 'string', subpath)) + if HIGH_COMPATIBILITY: + if not self.containers_enabled: + real_container = value.real_container + else: + real_container = value._real_container + variables.append(self._generate_element(elt_name, 'real_container', + real_container, + 'string', subpath)) + else: + default_type = 'string' + if key in self.objectspace.booleans_attributs: + default_type = 'boolean' + type_ = key_type.get(key, default_type) + dtd_key_type = key + '_type' + if hasattr(elt, dtd_key_type): + type_ = KEY_TYPE[getattr(elt, dtd_key_type)] + if isinstance(value, list): + variables.append(self._generate_element(elt_name, key, value, type_, + subpath, True)) + else: + variables.append(self._generate_element(elt_name, key, value, type_, + subpath, False)) + if name not in NOT_NEED_ACTIVATE: + variables.append(self._generate_element(name, 'activate', True, 'boolean', subpath)) + family = self.objectspace.family() + family.name = '{}{}'.format(name, index) + if HIGH_COMPATIBILITY: + family.doc = '' + family.variable = variables + if HIGH_COMPATIBILITY: + family.mode = None + self.paths.append('family', subpath, 'containers', creoleobj=family) + families.append(family) + index += 1 + return families + + +class ActionAnnotator(ContainerAnnotator): + + def __init__(self, space, paths, objectspace): + self.space = space + self.paths = paths + self.objectspace = objectspace + self.extra_conditions = [] + if hasattr(space, 'family_action'): + actions = self.objectspace.family() + actions.name = 'actions' + if HIGH_COMPATIBILITY: + actions.mode = None + actions.family = [] + self.space.actions = actions + namespaces = [] + for name, actions in space.family_action.items(): + subpath = 'actions.{}'.format(normalize_family(name)) + for action in actions.action: + namespace = action.namespace + if namespace in namespaces: + raise CreoleDictConsistencyError(_('only one action allow for {}' + '').format(namespace)) + namespaces.append(namespace) + action.name = action.namespace + new_actions = self.make_group_from_elts('action', actions.action, {}, subpath, False) + family = self.objectspace.family() + family.name = actions.name + family.family = new_actions + if HIGH_COMPATIBILITY: + family.mode = None + variables = [] + for key, value in vars(actions).items(): + if key not in ERASED_FAMILY_ACTION_ATTRIBUTES: + variables.append(self._generate_element('action', key, value, 'string', + subpath)) + family.variable = variables + self.space.actions.family.append(family) + del space.family_action + + +class SpaceAnnotator(object): + """Transformations applied on a CreoleObjSpace instance + """ + def __init__(self, space, paths, objectspace, eosfunc_file): + self.paths = paths + self.space = space + self.objectspace = objectspace + self.valid_enums = {} + self.force_value = {} + self.has_calc = [] + self.force_no_value = [] + self.force_not_mandatory = [] + self.eosfunc = imp.load_source('eosfunc', eosfunc_file) + if HIGH_COMPATIBILITY: + self.default_has_no_value = [] + self.has_frozen_if_in_condition = [] + try: + self.default_variable_options(space.variables) + except AttributeError: + raise CreoleDictConsistencyError(_('No configuration variables available in the configuration set')) + + for family in space.variables.values(): + if hasattr(family, 'family'): + self.change_variable_auto_freeze(family.family, family.name) + if 'group' in vars(space.constraints): + self.transform_groups(space.constraints.group, space) + if hasattr(space.constraints, 'check'): + self.filter_check(space.constraints.check) + if 'condition' in vars(space.constraints): + self.filter_condition(space.constraints.condition) + self._parse_object_space(space, None) + # valid_enums must be empty now (all information are store in objects) + if self.valid_enums: + raise CreoleDictConsistencyError(_('valid_enum sets for unknown variables {}').format(self.valid_enums.keys())) + self.filter_autofill(space) + for family in space.variables.values(): + if not HIGH_COMPATIBILITY: + self.remove_empty_family(family.family) + if hasattr(family, 'family'): + self.change_variable_mode(family.family) + if not HIGH_COMPATIBILITY: + self.change_family_mode(family.family) + if (hasattr(family, 'separators') and + hasattr(family.separators, 'separator')): + self.filter_separator(family.separators.separator) + self.absolute_path_for_symlink_in_containers(space.containers.family.values()) + if 'help' in vars(space): + self.transform_helps(space.help) + + def absolute_path_for_symlink_in_containers(self, families): + for family in families: + if hasattr(family, 'family'): + for fam in family.family: + for variable in fam.variable: + if variable.type == 'symlink' and '.' not in variable.name: + variable.opt = self.paths.get_variable_path(variable.opt, 'creole') + + def transform_helps(self, helps): + if hasattr(helps, 'variable'): + for hlp in helps.variable.values(): + hlp.name = hlp.path + if hasattr(helps, 'family'): + for hlp in helps.family.values(): + hlp.name = hlp.path + + def transform_groups(self, groups, space): # pylint: disable=C0111 + for group in groups: + master_fullname = group.master + slave_names = list(group.slave.keys()) + try: + master_family_name = self.paths.get_variable_family_name(master_fullname) + except CreoleDictConsistencyError as err: + if HIGH_COMPATIBILITY: + continue + raise err + namespace = self.paths.get_variable_namespace(master_fullname) + master_name = self.paths.get_variable_name(master_fullname) + master_family = space.variables[namespace].family[master_family_name] + master_path = namespace + '.' + master_family_name + is_master = False + for variable_name, variable in list(master_family.variable.items()): + if isinstance(variable, self.objectspace.Master): + if variable.name == master_name: + master_space = variable + is_master = True + else: + if is_master: + # slaves are multi + if variable_name in slave_names: + variable.multi = True + slave_names.remove(variable_name) + master_family.variable.pop(variable_name) + master_space.variable.append(variable) # pylint: disable=E1101 + if namespace == 'creole': + variable_fullpath = variable_name + else: + variable_fullpath = master_path + '.' + variable_name + self.paths.set_master(variable_fullpath, master_name) + if slave_names == []: + break + if is_master is False and variable_name == master_name: + master_space = self.objectspace.Master() + master_space.variable = [] + master_space.name = master_name + # manage master's variable + if variable.multi is not True: + raise CreoleDictConsistencyError(_('the variable {} in a group must be multi').format(variable.name)) + master_family.variable[master_name] = master_space + master_space.variable.append(variable) # pylint: disable=E1101 + self.paths.set_master(master_fullname, master_name) + master_space.path = master_fullname + is_master = True + else: # pragma: no cover + raise CreoleDictConsistencyError(_('cannot found a master {} ' + 'nor a slave {}').format(master_name, + slave_names)) + del space.constraints.group + + def _parse_object_space(self, space, namespace, node_name='creole', parent_path=None, ishelp=False): + space_is_help = ishelp + vars_space = dict(vars(space)) + for name, subspace in vars_space.items(): + if namespace is None and name in ['containers', 'actions']: + continue + if space_is_help is False: + ishelp = name == 'help' + self._parse_subobject_space(name, node_name, space, subspace, parent_path, namespace, ishelp) + + def _parse_subobject_space(self, name, node_name, parent, space, parent_path, namespace, ishelp): # pylint: disable=R0913 + keys = None + if isinstance(space, dict): + if namespace is None: + keys = list(space.keys()) + space = list(space.values()) + + if isinstance(space, list): + for idx, subspace in enumerate(space): + if keys is not None and namespace is None: + if subspace.__class__.__name__ == 'Variable': + current_namespace = self.paths.get_variable_namespace(keys[idx]) + elif subspace.__class__.__name__ == 'Variables': + current_namespace = keys[idx] + else: + current_namespace = self.paths.get_family_namespace(normalize_family(keys[idx], + check_name=False)) + else: + current_namespace = namespace + if hasattr(parent, 'path'): + parent_path = parent.path + else: + parent_path = None + self._parse_object_space(subspace, current_namespace, name, parent_path, ishelp) + elif isinstance(space, self.objectspace.Atom): + for subname, subspace in vars(space).items(): + self._parse_subobject_space(subname, name, space, subspace, None, namespace, ishelp) + else: + self.absolute_paths_annotation(name, node_name, parent, space, parent_path, namespace, ishelp) + self.uppercase_family_name(name, node_name, parent, space) + + def remove_empty_family(self, space): # pylint: disable=C0111,R0201 + removed_families = [] + for family_name, family in space.items(): + if not hasattr(family, 'variable') or len(family.variable) == 0: + removed_families.append(family_name) + del space[family_name] + # remove help too + if hasattr(self.space, 'help') and hasattr(self.space.help, 'family'): + for family in self.space.help.family.keys(): + if family in removed_families: + del self.space.help.family[family] + + def uppercase_family_name(self, name, node_name, parent, value): # pylint: disable=C0111,R0201 + if name == 'name' and node_name == 'family': + # let's preserve uppercase letters + # just in case where some acronyms are present, + # example : 'ARV' + if not value[0].isupper(): + if HIGH_COMPATIBILITY: + parent.name = value + else: + parent.name = value.capitalize() + + def change_family_mode(self, families): # pylint: disable=C0111 + for family in families.values(): + mode = modes_level[-1] + for variable in family.variable.values(): + if isinstance(variable, self.objectspace.Master): + variable_mode = variable.variable[0].mode + variable.mode = variable_mode + else: + variable_mode = variable.mode + if variable_mode is not None and modes[mode] > modes[variable_mode]: + mode = variable_mode + if HIGH_COMPATIBILITY and family.name == 'Containers': + family.mode = 'normal' + else: + family.mode = mode + + def _annotate_variable(self, variable, family_mode, is_slave=False): + if (HIGH_COMPATIBILITY and variable.type == 'choice' and variable.mode != modes_level[-1] and variable.mandatory is True and variable.path in self.default_has_no_value): + variable.mode = modes_level[0] + if variable.type == 'choice' and is_slave and family_mode == modes_level[0] and variable.mandatory is True: + variable.mode = modes_level[0] + # if the variable is mandatory and doesn't have any value + # then the variable's mode is set to 'basic' + has_value = hasattr(variable, 'value') + if (variable.path not in self.has_calc and variable.mandatory is True and + (not has_value or is_slave) and variable.type != 'choice'): + variable.mode = modes_level[0] + if has_value: + if not HIGH_COMPATIBILITY or (not variable.path.startswith('creole.containers.') \ + and variable.path not in self.force_no_value and variable.path not in self.force_not_mandatory): + variable.mandatory = True + if variable.hidden is True: + variable.frozen = True + if not variable.auto_save is True and 'force_default_on_freeze' not in vars(variable): + variable.force_default_on_freeze = True + if variable.name == 'frozen' and not variable.auto_save is True: + variable.force_default_on_freeze = True + if variable.mode != None and not is_slave and modes[variable.mode] < modes[family_mode]: + variable.mode = family_mode + if variable.mode != None and variable.mode != modes_level[0] and modes[variable.mode] < modes[family_mode]: + variable.mode = family_mode + if variable.name == "available_probes": + variable.force_default_on_freeze = False + + def default_variable_options(self, variables): + for families in variables.values(): + if hasattr(families, 'family'): + for family in families.family.values(): + if hasattr(family, 'variable'): + for variable in family.variable.values(): + if not hasattr(variable, 'type'): + variable.type = 'string' + if variable.type != 'symlink' and not hasattr(variable, 'description'): + variable.description = variable.name + + def change_variable_auto_freeze(self, families, namespace): # pylint: disable=C0111 + for family in families.values(): + if hasattr(family, 'variable'): + for variable in family.variable.values(): + if variable.auto_freeze: + new_condition = self.objectspace.condition() + new_condition.name = 'auto_frozen_if_in' + new_condition.namespace = namespace + new_condition.source = 'module_instancie' + new_param = self.objectspace.param() + new_param.text = 'oui' + new_condition.param = [new_param] + new_target = self.objectspace.target() + new_target.type = 'variable' + if namespace == 'creole': + path = variable.name + else: + path = namespace + '.' + family.name + '.' + variable.name + new_target.name = path + new_condition.target = [new_target] + self.space.constraints.condition.append(new_condition) + + def change_variable_mode(self, families): # pylint: disable=C0111 + for family in families.values(): + family_mode = family.mode + if hasattr(family, 'variable'): + for variable in family.variable.values(): + + if isinstance(variable, self.objectspace.Master): + mode = modes_level[-1] + for slave in variable.variable: + if slave.auto_save is True: + raise CreoleDictConsistencyError(_('master/slaves {} ' + 'could not be ' + 'auto_save').format(slave.name)) + if slave.auto_freeze is True: + raise CreoleDictConsistencyError(_('master/slaves {} ' + 'could not be ' + 'auto_freeze').format(slave.name)) + if HIGH_COMPATIBILITY and variable.name != slave.name: # and variable.variable[0].mode != modes_level[0]: + is_slave = True + else: + is_slave = False + self._annotate_variable(slave, family_mode, is_slave) + if HIGH_COMPATIBILITY: + # master's variable are right + if modes[variable.variable[0].mode] > modes[slave.mode]: + slave.mode = variable.variable[0].mode + else: + # auto_save's variable is set in 'basic' mode if its mode is 'normal' + if slave.auto_save is True and slave.mode != modes_level[-1]: + slave.mode = modes_level[0] + if modes[mode] > modes[slave.mode]: + mode = slave.mode + if not HIGH_COMPATIBILITY: + # the master's mode is the lowest + variable.variable[0].mode = mode + variable.mode = variable.variable[0].mode + else: + # auto_save's variable is set in 'basic' mode if its mode is 'normal' + if variable.auto_save is True and variable.mode != modes_level[-1]: + variable.mode = modes_level[0] + # auto_freeze's variable is set in 'basic' mode if its mode is 'normal' + if variable.auto_freeze is True and variable.mode != modes_level[-1]: + variable.mode = modes_level[0] + self._annotate_variable(variable, family_mode) + + def absolute_paths_annotation(self, name, node_name, parent, value, parent_path, namespace, ishelp): # pylint: disable=C0111,R0913 + if hasattr(parent, 'path'): + return + if name == 'name' and node_name in ['variable', 'family']: + if node_name == 'family': + family_name = normalize_family(value, check_name=False) + subpath = self.paths.get_family_path(family_name, namespace) + namespace = self.paths.get_family_namespace(family_name) + else: + if self.paths.path_is_defined(value): + value_name = value + else: + value_name = parent_path + '.' + value + if namespace is None: + namespace = self.paths.get_variable_namespace(value) + subpath = self.paths.get_variable_path(value_name, namespace) + if not ishelp and hasattr(parent, 'type') and parent.type in FORCE_CHOICE: + if subpath in self.valid_enums: + raise CreoleDictConsistencyError(_('cannot set valid enum for variable with type {}').format(parent.type)) + parent.choice = [] + for value in FORCE_CHOICE[parent.type]: + choice = self.objectspace.choice() + if sys.version_info[0] < 3: + choice.name = unicode(value, 'utf8') + else: + choice.name = str(value) + parent.choice.append(choice) + parent.type = 'choice' + if not HIGH_COMPATIBILITY: + parent.mandatory = True + if parent.choice == []: + raise CreoleDictConsistencyError(_('empty valid enum is not allowed for variable {}').format(value_name)) + if hasattr(parent, 'type') and parent.type != 'choice': + orig_type = parent.type + else: + orig_type = None + if not ishelp and subpath in self.valid_enums: + values = self.valid_enums[subpath]['values'] + if isinstance(values, list): + parent.choice = [] + choices = [] + for value in values: + choice = self.objectspace.choice() + if sys.version_info[0] < 3: + choice.name = unicode(value) + else: + choice.name = str(value) + choices.append(choice.name) + choice.type = parent.type + parent.choice.append(choice) + if hasattr(parent, 'value'): + for value in parent.value: + value.type = parent.type + if value.name not in choices: + raise CreoleDictConsistencyError(_('value "{}" of variable "{}" is not in list of all expected values ({})').format(value.name, parent.name, choices)) + if parent.choice == []: + raise CreoleDictConsistencyError(_('empty valid enum is not allowed for variable {}').format(value_name)) + else: + # probe choice + parent.choice = values + parent.type = 'choice' + del(self.valid_enums[subpath]) + if not ishelp and subpath in self.force_value: + if not hasattr(parent, 'value'): + new_value = self.objectspace.value() + new_value.name = self.force_value[subpath] + parent.value = [new_value] + self.force_no_value.append(subpath) + if not ishelp and hasattr(parent, 'type') and parent.type == 'choice': + # if choice with no value, set value with the first choice + if not hasattr(parent, 'value'): + no_value = False + if HIGH_COMPATIBILITY and parent.multi: + no_value = True + if not no_value: + new_value = self.objectspace.value() + new_value.name = parent.choice[0].name + new_value.type = orig_type + if HIGH_COMPATIBILITY: + self.default_has_no_value.append(subpath) + parent.value = [new_value] + self.force_no_value.append(subpath) + parent.path = subpath + if name == 'name' and node_name == 'separator': + pass + + def get_variable(self, name): # pylint: disable=C0111 + return self.paths.get_variable_obj(name) + + def filter_autofill(self, space): # pylint: disable=C0111 + self.filter_duplicate_autofill(space.constraints) + if 'auto' in vars(space.constraints): + self.filter_auto(space.constraints.auto, space) + if 'fill' in vars(space.constraints): + self.filter_fill(space.constraints.fill, space) + + def filter_duplicate_autofill(self, constraints): + """ Remove duplicate auto or fill for a variable + This variable must be redefined + """ + fills = {} + # sort fill/auto by index + if 'fill' in vars(constraints): + for idx, fill in enumerate(constraints.fill): + if fill.index in fills: + raise Exception('hu?') + fills[fill.index] = {'idx': idx, 'fill': fill, 'type': 'fill'} + if 'auto' in vars(constraints): + for idx, fill in enumerate(constraints.auto): + if fill.index in fills: + raise Exception('hu?') + fills[fill.index] = {'idx': idx, 'fill': fill, 'type': 'auto'} + indexes = list(fills.keys()) + indexes.sort() + targets = {} + remove_autos = [] + remove_fills = [] + for idx in indexes: + fill = fills[idx]['fill'] + if hasattr(fill, 'redefine'): + redefine = bool(fill.redefine) + else: + redefine = False + if fill.target in targets: + if redefine: + if targets[fill.target][1] == 'auto': + remove_autos.append(targets[fill.target][0]) + else: + remove_fills.append(targets[fill.target][0]) + else: + raise CreoleDictConsistencyError(_("An auto or fill already exists " + "for the target: {}").format( + fill.target)) + targets[fill.target] = (fills[idx]['idx'], fills[idx]['type']) + remove_autos.sort(reverse=True) + for idx in remove_autos: + constraints.auto.pop(idx) + remove_fills.sort(reverse=True) + for idx in remove_fills: + constraints.fill.pop(idx) + + def filter_auto(self, auto_space, space): # pylint: disable=C0111 + for auto in auto_space: + if HIGH_COMPATIBILITY and auto.target in self.has_frozen_if_in_condition: + # if a variable has a 'frozen_if_in' condition + # then we change the 'auto' variable as a 'fill' variable + continue + # an auto is a fill with "hidden" and "frozen" properties + variable = self.get_variable(auto.target) + if variable.auto_freeze: + raise CreoleDictConsistencyError(_('variable with auto value ' + 'cannot be auto_freeze').format(auto.target)) + if variable.auto_save: + raise CreoleDictConsistencyError(_('variable with auto value ' + 'cannot be auto_save').format(auto.target)) + variable.hidden = True + variable.frozen = True + variable.force_default_on_freeze = True + if 'fill' not in vars(space.constraints): + space.constraints.fill = [] + space.constraints.fill.extend(auto_space) + del space.constraints.auto + + def filter_separator(self, space): # pylint: disable=C0111,R0201 + names = [] + remove_separators = [] + for idx, separator in enumerate(space): + try: + namespace = self.paths.get_variable_namespace(separator.name) + subpath = self.paths.get_variable_path(separator.name, namespace) + separator.name = subpath + except CreoleDictConsistencyError as err: + if HIGH_COMPATIBILITY: + remove_separators.append(idx) + continue + else: + raise err + if separator.name in names: + raise CreoleDictConsistencyError(_('{} already has a separator').format(separator.name)) + names.append(separator.name) + remove_separators.sort(reverse=True) + for idx in remove_separators: + del space[idx] + + + def load_params_in_validenum(self, param, probe): + if not probe and param.type in ['string', 'python', 'number']: + if not hasattr(param, 'text') and (param.type == 'python' or param.type == 'number'): + raise CreoleDictConsistencyError(_("All '{}' variables shall be set in order to calculate {}").format(param.type, 'valid_enum')) + if param.type in ['string', 'number']: + try: + values = literal_eval(param.text) + except ValueError: + raise CreoleDictConsistencyError(_('Cannot load {}').format(param.text)) + elif param.type == 'python': + try: + values = eval(param.text, {'eosfunc': secure_eosfunc(self.eosfunc), '__builtins__': {'range': range, 'str': str}}) + #FIXME : eval('[str(i) for i in range(3, 13)]', {'eosfunc': eosfunc, '__builtins__': {'range': range, 'str': str}}) + except NameError: + raise CreoleDictConsistencyError(_('The function {} is unknown').format(param.text)) + if not isinstance(values, list): + raise CreoleDictConsistencyError(_('Function {} shall return a list').format(param.text)) + new_values = [] + for val in values: + if sys.version_info[0] < 3 and isinstance(val, str): + val = val.decode('utf-8') + new_values.append(val) + values = new_values + else: + values = param.text + return values + + def filter_check(self, space): # pylint: disable=C0111 + # valid param in check + remove_indexes = [] + for check_idx, check in enumerate(space): + namespace = check.namespace + if hasattr(check, 'param'): + param_option_indexes = [] + for idx, param in enumerate(check.param): + if param.type not in TYPE_PARAM_CHECK: + raise CreoleDictConsistencyError(_('cannot use {} type as a param in check for {}').format(param.type, check.target)) + if param.type == 'eole': + if HIGH_COMPATIBILITY and param.text.startswith('container_ip'): + if param.optional is True: + param_option_indexes.append(idx) + try: + param.text = self.paths.get_variable_path(param.text, namespace) + except CreoleDictConsistencyError as err: + if param.optional is True: + param_option_indexes.append(idx) + else: + raise err + param_option_indexes = list(set(param_option_indexes)) + param_option_indexes.sort(reverse=True) + for idx in param_option_indexes: + check.param.pop(idx) + if not HIGH_COMPATIBILITY and check.param == []: + remove_indexes.append(check_idx) + remove_indexes.sort(reverse=True) + for idx in remove_indexes: + del space[idx] + variables = {} + for index, check in enumerate(space): + namespace = check.namespace + if HIGH_COMPATIBILITY: + if not self.paths.path_is_defined(check.target): + continue + check.is_in_master = self.paths.get_master(check.target) != None + # let's replace the target by the path + check.target = self.paths.get_variable_path(check.target, namespace) + if check.target not in variables: + variables[check.target] = [] + variables[check.target].append((index, check)) + # remove check already set for a variable + remove_indexes = [] + for checks in variables.values(): + names = {} + for idx, check in checks: + if HIGH_COMPATIBILITY and check.name == 'valid_enum': + redefine = True + else: + redefine = False + #redefine = bool(check.redefine) + if redefine and check.name in names: + remove_indexes.append(names[check.name]) + del names[check.name] + names[check.name] = idx + del check.index + remove_indexes.sort(reverse=True) + for idx in remove_indexes: + del space[idx] + remove_indexes = [] + for idx, check in enumerate(space): + if not check.name in dir(self.eosfunc): + raise CreoleDictConsistencyError(_('cannot find check function {}').format(check.name)) + is_probe = not check.name in self.eosfunc.func_on_zephir_context + if is_probe: + raise CreoleDictConsistencyError(_('cannot have a check with probe function ({})').format(check.name)) + if check.name == 'valid_enum': + proposed_value_type = False + remove_params = [] + for param_idx, param in enumerate(check.param): + if hasattr(param, 'name') and param.name == 'checkval': + try: + proposed_value_type = self.objectspace._convert_boolean(param.text) == False + remove_params.append(param_idx) + except TypeError as err: + raise CreoleDictConsistencyError(_('cannot load checkval value for variable {}: {}').format(check.target, err)) + remove_params.sort(reverse=True) + for param_idx in remove_params: + del check.param[param_idx] + if len(check.param) != 1: + raise CreoleDictConsistencyError(_('cannot set more than one param ' + 'for valid_enum for variable {}' + '').format(check.target)) + param = check.param[0] + if proposed_value_type: + if param.type != 'eole': + try: + values = self.load_params_in_validenum(param, check.probe) + except NameError as err: + raise CreoleDictConsistencyError(_('cannot load value for variable {}: {}').format(check.target, err)) + add_value = True + if HIGH_COMPATIBILITY and check.is_in_master: + add_value = False + if add_value and values: + self.force_value[check.target] = values[0] + else: + if check.target in self.valid_enums: + raise CreoleDictConsistencyError(_('valid_enum already set for {}' + '').format(check.target)) + values = self.load_params_in_validenum(param, check.probe) + self.valid_enums[check.target] = {'type': param.type, + 'values': values} + remove_indexes.append(idx) + remove_indexes.sort(reverse=True) + for idx in remove_indexes: + del space[idx] + + #convert level to "warnings_only" and hidden to "transitive" + for check in space: + if check.level == 'warning': + check.warnings_only = True + else: + check.warnings_only = False + check.level = None + transitive = True + if hasattr(check, 'param'): + for param in check.param: + if not param.hidden is True: + transitive = False + param.hidden = None + check.transitive = transitive + + def filter_fill(self, fill_space, space): # pylint: disable=C0111,R0912 + fills = {} + # sort fill/auto by index + for idx, fill in enumerate(fill_space): + fills[fill.index] = {'idx': idx, 'fill': fill} + del fill.index + indexes = list(fills.keys()) + indexes.sort() + del_idx = [] + for idx in indexes: + fill = fills[idx]['fill'] + variable = self.get_variable(fill.target) + if hasattr(variable, 'value'): + del variable.value + namespace = fill.namespace + # let's replace the target by the path + fill.target = self.paths.get_variable_path(fill.target, namespace) + if not fill.name in dir(self.eosfunc): + raise CreoleDictConsistencyError(_('cannot find fill function {}').format(fill.name)) + is_probe = not fill.name in self.eosfunc.func_on_zephir_context + if hasattr(fill, 'param'): + for param in fill.param: + if param.type not in TYPE_PARAM_FILL: + raise CreoleDictConsistencyError(_('cannot use {} type as a param ' + 'in a fill/auto').format(param.type)) + param_option_indexes = [] + for fill_idx, param in enumerate(fill.param): + if not hasattr(param, 'text') and \ + (param.type == 'eole' or param.type == 'number' or \ + param.type == 'container' or param.type == 'python'): + raise CreoleDictConsistencyError(_("All '{}' variables shall be set in " + "order to calculate {}").format( + param.type, + fill.target)) + if param.type == 'container': + param.type = 'eole' + param.text = 'container_ip_{}'.format(param.text) + if param.type == 'eole': + if is_probe: + raise CreoleDictConsistencyError(_('Function {0} used to calculate {1} ' + 'is executed on remote server, ' + 'so cannot depends to an ' + 'other variable' + ).format(fill.name, fill.target)) + if HIGH_COMPATIBILITY and param.text.startswith('container_ip'): + if param.optional is True: + param_option_indexes.append(fill_idx) + try: + param.text = self.paths.get_variable_path(param.text, namespace) + except CreoleDictConsistencyError as err: + if param.optional is True: + param_option_indexes.append(fill_idx) + else: + raise err + param_option_indexes = list(set(param_option_indexes)) + param_option_indexes.sort(reverse=True) + for param_idx in param_option_indexes: + fill.param.pop(param_idx) + self.has_calc.append(fill.target) + + if is_probe: + variable.force_default_on_freeze = False + self.objectspace.probe_variables.append(fill) + del_idx.append(fills[idx]['idx']) + del_idx.sort(reverse=True) + for idx in del_idx: + space.constraints.fill.pop(idx) + + def filter_target(self, space, namespace): # pylint: disable=C0111 + del_idx = [] + for idx, target in enumerate(space.target): + if target.type == 'variable': + if (hasattr(target, 'optional') and target.optional is True and + not self.paths.path_is_defined(target.name)): + del_idx.append(idx) + continue + if space.source == target.name: + raise CreoleDictConsistencyError(_('target name and source name must be different: {}').format(space.source)) + target.name = self.paths.get_variable_path(target.name, namespace) + elif target.type == 'family': + try: + target.name = self.paths.get_family_path(target.name, namespace) + except KeyError: + raise CreoleDictConsistencyError(_('cannot found family {}').format(target.name)) + del_idx = list(set(del_idx)) + del_idx.sort(reverse=True) + for idx in del_idx: + space.target.pop(idx) + + def filter_condition(self, space): # pylint: disable=C0111 + remove_conditions = [] + fallback_variables = [] + fallback_lists = [] + # automatic generation of the service_access lists + # and the service_restriction lists from the servicelist + for condition in space: + if hasattr(condition, 'target'): + new_targets = [] + for target in condition.target: + if target.type == 'servicelist': + new_target = copy(target) + new_target.type = 'service_accesslist' + new_target.name = '___auto_{}'.format(new_target.name) + new_targets.append(new_target) + + new_target = copy(target) + new_target.type = 'service_restrictionlist' + new_target.name = '___auto_{}'.format(new_target.name) + new_targets.append(new_target) + condition.target.extend(new_targets) + + # remove condition with target + if HIGH_COMPATIBILITY: + for idx, condition in enumerate(space): + if not hasattr(condition, 'target'): + remove_conditions.append(idx) + + for idx, condition in enumerate(space): + if idx in remove_conditions: + continue + if condition.name == 'hidden_if_in': + condition.name = 'disabled_if_in' + elif condition.name == 'hidden_if_not_in': + condition.name = 'disabled_if_not_in' + # a conditon with a fallback **and** the source variable doesn't exist + if (hasattr(condition, 'fallback') and condition.fallback is True and + not self.paths.path_is_defined(condition.source)): + for target in condition.target: + if target.type in ['variable', 'family']: + name = target.name.split('.')[-1] + if target.type == 'variable': + variable = self.get_variable(name) + else: + variable = self.paths.get_family_obj(name) + if condition.name in ['disabled_if_in']: + variable.disabled = True + if condition.name in ['mandatory_if_in']: + variable.mandatory = True + if condition.name in ['disabled_if_in', 'disabled_if_not_in', + 'frozen_if_in', 'frozen_if_not_in']: + variable.hidden = False + if HIGH_COMPATIBILITY: + fallback_variables.append(name) + else: + listname = target.type + if not listname.endswith('list'): + raise Exception('not yet implemented') + listvars = self.objectspace.list_conditions.get(listname, + {}).get(target.name) + if listvars: + for listvar in listvars: + try: + variable = self.get_variable(listvar) + except CreoleDictConsistencyError: + variable = self.paths.get_family_obj(listvar) + if condition.name in ['disabled_if_in']: + variable.disabled = True + if condition.name in ['mandatory_if_in']: + variable.mandatory = True + if condition.name in ['disabled_if_in', 'disabled_if_not_in', + 'frozen_if_in', 'frozen_if_not_in']: + variable.hidden = False + fallback_lists.append(listvar) + remove_conditions.append(idx) + + for condition_idx, condition in enumerate(space): + if condition_idx in remove_conditions: + continue + namespace = condition.namespace + self.filter_target(condition, namespace) + # transform *list to variable or family + for condition_idx, condition in enumerate(space): + if condition.name in ['disabled_if_in', 'disabled_if_not_in', 'frozen_if_in', 'auto_frozen_if_in', + 'frozen_if_not_in', 'mandatory_if_in', 'mandatory_if_not_in']: + new_targets = [] + remove_targets = [] + if not hasattr(condition, 'target'): + continue + for target_idx, target in enumerate(condition.target): + if target.type not in ['variable', 'family']: + listname = target.type + if not listname.endswith('list'): + raise Exception('not yet implemented') + listvars = self.objectspace.list_conditions.get(listname, + {}).get(target.name) + if listvars: + for listvar in listvars: + if listvar in fallback_lists: + continue + try: + variable = self.get_variable(listvar) + type_ = 'variable' + except CreoleDictConsistencyError: + variable = self.paths.get_family_obj(listvar) + type_ = 'family' + new_target = self.objectspace.target() + new_target.type = type_ + new_target.name = listvar + new_target.index = target.index + new_targets.append(new_target) + remove_targets.append(target_idx) + remove_targets = list(set(remove_targets)) + remove_targets.sort(reverse=True) + for target_idx in remove_targets: + condition.target.pop(target_idx) + condition.target.extend(new_targets) + + force_remove_targets = {} + for condition_idx, condition in enumerate(space): + if condition_idx in remove_conditions: + continue + namespace = condition.namespace + src_variable = self.paths.get_variable_obj(condition.source) + condition.source = self.paths.get_variable_path(condition.source, namespace, allow_source=True) + for param in condition.param: + if param.type not in TYPE_PARAM_CONDITION: + raise CreoleDictConsistencyError(_('cannot use {} type as a param ' + 'in a condition').format(param.type)) + if condition.name in ['disabled_if_in', 'disabled_if_not_in', 'frozen_if_in', 'auto_frozen_if_in', + 'frozen_if_not_in', 'mandatory_if_in', 'mandatory_if_not_in']: + valid_enum = None + # remove condition for ChoiceOption that don't have param + if condition.source in self.valid_enums and \ + self.valid_enums[condition.source]['type'] == 'string': + valid_enum = self.valid_enums[condition.source]['values'] + if src_variable.type in FORCE_CHOICE: + valid_enum = FORCE_CHOICE[src_variable.type] + if valid_enum is not None: + remove_param = [] + for param_idx, param in enumerate(condition.param): + if param.text not in valid_enum: + remove_param.append(param_idx) + remove_param.sort(reverse=True) + for idx in remove_param: + del condition.param[idx] + if condition.param == []: + for target in condition.target: + if target.name.startswith('creole.'): + name = target.name.split('.')[-1] + else: + name = target.name + if target.type == 'variable': + variable = self.get_variable(name) + else: + variable = self.paths.get_family_obj(name) + if condition.name == 'disabled_if_not_in': + variable.disabled = True + force_remove_targets.setdefault(condition.name, + []).append(target.name) + elif condition.name == 'frozen_if_not_in': + variable.hidden = True + force_remove_targets.setdefault(condition.name, + []).append(target.name) + elif condition.name == 'mandatory_if_not_in': + variable.mandatory = True + force_remove_targets.setdefault(condition.name, + []).append(target.name) + elif HIGH_COMPATIBILITY and condition.name == 'disabled_if_in': + variable.hidden = False + remove_conditions.append(condition_idx) + remove_conditions = list(set(remove_conditions)) + remove_conditions.sort(reverse=True) + for idx in remove_conditions: + space.pop(idx) + + for condition_idx, condition in enumerate(space): + if condition.name in ['disabled_if_in', 'disabled_if_not_in', 'frozen_if_in', 'auto_frozen_if_in', + 'frozen_if_not_in', 'mandatory_if_in', 'mandatory_if_not_in']: + + remove_targets = [] + #parse each variable and family + for target_idx, target in enumerate(condition.target): + if target.name in force_remove_targets.get(condition.name, []): + remove_targets.append(target_idx) + if target.name.startswith('creole.'): + name = target.name.split('.')[-1] + else: + name = target.name + if target.type == 'variable': + variable = self.get_variable(name) + else: + variable = self.paths.get_family_obj(name) + if name in fallback_variables: + remove_targets.append(target_idx) + continue + if condition.name in ['disabled_if_in', 'disabled_if_not_in', + 'frozen_if_in', 'frozen_if_not_in']: + variable.hidden = False + if condition.name in ['mandatory_if_in', 'mandatory_if_not_in']: + variable.mandatory = False + if HIGH_COMPATIBILITY and condition.name in ['frozen_if_in', + 'frozen_if_not_in']: + self.has_frozen_if_in_condition.append(name) + if condition.name in ['mandatory_if_in', 'mandatory_if_not_in']: + self.force_not_mandatory.append(target.name) + + remove_targets = list(set(remove_targets)) + remove_targets.sort(reverse=True) + for target_idx in remove_targets: + condition.target.pop(target_idx) diff --git a/creole/cert.py b/creole/cert.py new file mode 100644 index 0000000..6726c2f --- /dev/null +++ b/creole/cert.py @@ -0,0 +1,637 @@ +# -*- coding: utf-8 -*- +########################################################################### +# +# Eole NG - 2007 +# Copyright Pole de Competence Eole (Ministere Education - Academie Dijon) +# Licence CeCill cf /root/LicenceEole.txt +# eole@ac-dijon.fr +# +# libsecure.py +# +# classes utilitaires pour lancement des services en https +# +########################################################################### +""" +points d'entrée de l'api + +- gen_certif -> génère **un** certif +- gen_certs -> génère tous les certifs + +cf creole/doc/certifs.txt + +""" +# certains imports sont utilisés dans les fragments de code installés +# dans /usr/share/eole/certs +from os.path import join, splitext, basename, dirname, isdir, isfile, islink, exists, realpath +from os import unlink, symlink, stat +import os, glob, time +from shutil import copy +from subprocess import Popen, PIPE +from OpenSSL import SSL +import re + +from .i18n import _ + +# chemin du certificat eole par défaut +from .config import cert_file, key_file, SSL_LAST_FILE +from .client import CreoleClient +from pyeole.process import system_out, system_code + +client = CreoleClient() + +global regexp_get_subject +regexp_get_subject = None + +def prep_dir() : + """ + Création de l'arborescence pour openssl + """ + #on génère le random + load_default_conf_if_needed() + rand_file = os.path.join(ssl_dir, ".rand") + if not os.path.isfile(rand_file) : + cmd_random = "/bin/dd if=/dev/urandom of=%s bs=1k count=16 >/dev/null 2>&1" % (rand_file) + cmd = Popen(cmd_random, shell=True) + res = cmd.wait() + if res != 0: + raise Exception(_(u"! Error while generating entropy file !")) + #on crée les fichiers pour gerer la pki + file_serial = os.path.join(ssl_dir, "serial") + if not os.path.isfile(file_serial) : + f = file(file_serial, "w") + f.write(str(start_index)) + f.close() + file_index = os.path.join(ssl_dir, "index.txt") + if not os.path.isfile(file_index) : + f = file(file_index, "w") + f.close() + newcerts = os.path.join(ssl_dir, "newcerts") + if not os.path.isdir(newcerts): + os.makedirs(newcerts) + if not os.path.isdir(key_dir): + os.makedirs(key_dir) + if not os.path.isdir(cert_dir): + os.makedirs(cert_dir) + if not os.path.isdir(req_dir): + os.makedirs(req_dir) + if not os.path.isdir(local_ca_dir): + os.makedirs(local_ca_dir) + ##cmd = Popen("chmod 611 %s" % (key_dir), shell=True) + dhfile = os.path.join(ssl_dir, "dh") + if not os.path.isfile(dhfile): + gen_dh = '/usr/bin/openssl dhparam -out "%s" 1024 >/dev/null 2>&1' % (dhfile) + Popen(gen_dh, shell=True) + +def sup_passwd(tmp_keyfile, keyfile) : + """ + Supression de la passphrase sur la clef privée + """ + load_default_conf_if_needed() + key_cmd = '/usr/bin/openssl rsa -in "%s" -passin pass:secret -out "%s" >/dev/null 2>&1' % (tmp_keyfile, keyfile) + cmd = Popen(key_cmd, shell=True) + res = cmd.wait() + if res != 0: + raise Exception(_(u'! Error while generating ssl key in {0} !').format(keyfile)) + +def finalise_cert (certfile, keyfile, key_user='', key_grp='', key_chmod='', + cert_user='', cert_grp='', cert_chmod=''): + """ + Finalisation du certif + """ + load_default_conf_if_needed() + if key_user != '': + try: + res = Popen("chown %s %s" % (key_user, keyfile), shell=True).wait() + assert res == 0 + except: + print _(u"\n! Rights on {0} can't be modified").format(keyfile) + return False + if key_grp != '': + try: + res=Popen("/bin/chgrp %s %s" % (key_grp, keyfile), shell=True).wait() + assert res == 0 + except: + print _(u"\n! Rights on {0} can't be modified").format(keyfile) + return False + if key_chmod != '': + try: + res = Popen("/bin/chmod %s %s" % (key_chmod, keyfile), shell=True).wait() + assert res == 0 + except: + print _(u"\n! Rights on {0} can't be modified").format(keyfile) + return False + if cert_user != '': + try: + res = Popen("/bin/chown %s %s" % (cert_user, certfile), shell=True).wait() + assert res == 0 + except: + print _(u"\n! Rights on {0} can't be modified").format(certfile) + return False + if cert_grp != '': + try: + res = Popen("/bin/chgrp %s %s" % (cert_grp, certfile), shell=True).wait() + assert res == 0 + except: + print _(u"\n! Rights on {0} can't be modified").format(certfile) + return False + if cert_chmod != '': + try: + res = Popen("/bin/chmod %s %s" % (cert_chmod, certfile), shell=True).wait() + assert res == 0 + except: + print _(u"\n! Rights on {0} can't be modified").format(certfile) + return False + return True + + +def is_simple_cert(cert_file): + """ + Teste si le fichier contient un simple certificat ou une chaîne. + :param cert_file: chemin du fichier à tester + :type cert_file: str + """ + with open(cert_file, 'r') as pem: + cert_num = len(re.findall(r'-+BEGIN CERTIFICATE-+', pem.read())) + return cert_num == 1 + +def get_certs_catalog(simple=True): + """ + Créer un dictionnaire des certificats présents + pour accélérer la reconstitution de la chaîne + de certificats intermédiaires. + :param simple: filtre sur les certificats à référencer + :type simple: booléen + """ + global certs_catalog + certs_catalog = {} + for cert_file in glob.glob(os.path.join(ssl_dir, 'certs/*')): + try: + if simple and is_simple_cert(cert_file): + certs_catalog[get_subject(certfile=cert_file)] = cert_file + elif not simple: + certs_catalog[get_subject(certfile=cert_file)] = cert_file + except: + continue + return certs_catalog + + +def get_certs_chain(certs): + """ + Récupération de la chaîne de certificats + :param certs: liste des certificats dans l'ordre de la chaîne. + :type certs: liste de chemins + """ + global certs_catalog, ca_issuer + load_default_conf_if_needed() + subject = get_subject(certfile=certs[-1]) + issuer = get_issuer_subject(certfile=certs[-1]) + if ca_issuer is None: + ca_issuer = get_issuer_subject(certfile=ca_file) + if subject == issuer: + pass + elif issuer == ca_issuer: + certs.append(ca_file) + else: + try: + if certs_catalog is None: + certs_catalog = get_certs_catalog() + certs.append(certs_catalog[issuer]) + get_certs_chain(certs) + except KeyError as e: + print _(u"Certificate chain incomplete.") + return certs + + +def get_intermediate_certs(cert): + """ + Récupération de la liste des certificats intermédiaires. + :param cert: chemin du certificat pour lequel on reconstitue la chaîne + :type cert: + """ + load_default_conf_if_needed() + try: + chain = get_certs_chain([cert,])[1:-1] + except: + chain = [] + return chain + + +def concat_fic(dst_fic, in_fics, overwrite=False, need_link=True): + """ + Concaténation d'une liste de fichiers dans un fichier de destination + (le contenu d'origine est conservé) + """ + load_default_conf_if_needed() + if need_link: + remove_link(dst_fic) + if type(in_fics) != list: + in_fics = [in_fics] + for fic in in_fics: + if not os.path.isfile(fic): + print _(u"Error: file {0} does not exist").format(fic) + data = "" + for fic_src in in_fics: + f_src = file(fic_src) + data += f_src.read().rstrip() + '\n' + f_src.close() + if overwrite: + f_dst = file(dst_fic, "w") + else: + f_dst = file(dst_fic, "a+") + f_dst.write(data) + f_dst.close() + if need_link: + build_link(dst_fic, in_fics) + +def gen_certs(regen=False, merge=True): + """ + Génère la ca puis les certificats + """ + load_default_conf_if_needed() + verif_ca() + ca_generated = gen_ca(regen) + if merge: + merge_ca() + if ca_generated: + regen = True + certif_loader(regen=regen) + +def verif_ca(): + """ + vérifie que la ca est générée correctement (serial > 0xstart_index) et cn valide + """ + load_default_conf_if_needed() + # gestion des anciennes version de ca.crt + if os.path.isfile(ca_dest_file) and not os.path.isfile(ca_file): + # on reprend le premier certificat présent dans ca.crt dans ca_local.crt + ca_certs = open(ca_dest_file).read().strip() + tag_begin = '-----BEGIN CERTIFICATE-----' + try: + ca_data = tag_begin + ca_certs.split(tag_begin)[1] + local_ca = open(ca_file, 'w') + local_ca.write(ca_data) + local_ca.close() + except IndexError: + # impossible de reprendre la ca actuelle, elle sera regénérée + pass + serial = int(eval('0x%s'%start_index)) + # vérification de la valeur actuelle du ca + # vérification du cn de la ca + if os.path.isfile(ca_file): + cmd = Popen(['/usr/bin/openssl', 'x509', '-in', ca_file, '-subject', '-noout'], stdout=PIPE) + if cmd.wait() != 0: + unlink(ca_file) + prep_dir() + if os.path.isfile(file_serial): + serial = open(file_serial).read().strip() + # conversion en hexa + serial = int(serial, 16) + if serial < min_serial: + if os.path.isfile(ca_file): + unlink(ca_file) + unlink(file_serial) + for f_index in glob.glob(os.path.join(ssl_dir, 'index*')): + unlink(f_index) + for f_cert in glob.glob(os.path.join(newcerts_dir, '*.pem')): + unlink(f_cert) + prep_dir() + +def gen_ca(regen=False, del_passwd=True, extensions="SERVEUR"): + """ + Generation ca + """ + load_default_conf_if_needed() + generated = False + prep_dir() + if not os.path.isfile(ca_conf_file): + raise Exception(_(u"Certificate configuration template can not be found:\n\t{0}\n").format(ca_conf_file)) + if regen or (not os.path.isfile(ca_keyfile)) or (not os.path.isfile(ca_file)): + print("* " + _(u"Generating CA certificate")) + remove_link(ca_file) + ## On genère le certif de l'ac + ca_gen = '/usr/bin/openssl req -x509 -config %s -newkey rsa:%s -days %s -keyout "%s" -out "%s" -extensions %s >/dev/null 2>&1' % (ca_conf_file, ssl_default_key_bits, ssl_default_cert_time, tmp_keyfile, ca_file, extensions) + cmd = Popen(ca_gen, shell=True) + if cmd.wait() != 0: + raise Exception(_(u"Error while generating CA")) + if del_passwd: + sup_passwd(tmp_keyfile, ca_keyfile) + if os.path.isfile(tmp_keyfile): + unlink(tmp_keyfile) + generated = True + ## application des droits + finalise_cert(ca_file, ca_keyfile, key_chmod='600') + build_link(ca_file) + ## génération d'une crl + if not os.path.isfile(os.path.join(ssl_dir, 'eole.crl')): + print(_(u"Generating certificate revocation list (CRL)")) + crl_gen = '/usr/bin/openssl ca -gencrl -config %s -crldays %s -out %s/eole.crl >/dev/null 2>&1' % (ca_conf_file, ssl_default_cert_time, ssl_dir) + cmd = Popen(crl_gen, shell=True) + if cmd.wait() != 0: + raise Exception(_(u"Error while generating CRL ({0}/eole.crl)").format(ssl_dir)) + return generated + +def merge_ca(): + """ + concatène toutes les ca utiles dans ca.crt + """ + load_default_conf_if_needed() + ## concaténation des certificats education + ca_list = [ca_file, os.path.join(cert_dir, 'ACInfraEducation.pem')] + ## concaténation de certificats supplémentaires si définis + for ca_perso in glob.glob(os.path.join(local_ca_dir,'*.*')): + if os.path.isfile(ca_perso): + ca_list.append(ca_perso) + concat_fic(ca_dest_file, ca_list, True, False) + +def gen_certif(certfile, keyfile=None, key_user='', key_grp='', key_chmod='', + cert_user='', cert_grp='', cert_chmod='', regen=False, copy_key=False, + del_passwd=True, signe_req=True, container=None, client_cert=False, + cert_conf_file=None): + """ + Génération des requêtes de certificats et signature par la CA + """ + if not cert_conf_file: + if client_cert: + cert_conf_file = client_conf_file + else: + cert_conf_file = conf_file + load_default_conf_if_needed() + if not os.path.isfile(cert_conf_file): + raise Exception(_(u"Certificate configuration template can not be found:\n\t{0}\n").format(cert_conf_file)) + + basefile = os.path.splitext(certfile)[0] + if keyfile is None: + keyfile = "%s.key" % (basefile) + + if container != None: + cpath = client.get_container(name=container)['path'] + certfile = cpath + certfile + keyfile = cpath + keyfile + + if regen or not os.path.isfile(certfile) or not os.path.isfile(keyfile): + + remove_link(certfile) + if not isdir(dirname(certfile)): + raise Exception(_(u"Folder {0} does not exist.").format(dirname(certfile))) + if not isdir(dirname(keyfile)): + raise Exception(_(u"Folder {0} does not exist.").format(dirname(keyfile))) + + # certificat absent ou regénération demandée + fic_p10 = os.path.join(req_dir, "%s.p10" % (os.path.basename(basefile))) + # génération de la requête de certificat x509 et d'un simili certificat auto-signé + if exists(keyfile): + gen_req = '/usr/bin/openssl req -new -key "%s" -days %s -config %s -out "%s" >/dev/null 2>&1' % ( + keyfile, ssl_default_cert_time, cert_conf_file, fic_p10) + new_key = False + else: + gen_req = '/usr/bin/openssl req -new -newkey rsa:%s -days %s -config %s -keyout "%s" -out "%s" >/dev/null 2>&1' % ( + ssl_default_key_bits, ssl_default_cert_time, cert_conf_file, tmp_keyfile, fic_p10) + new_key = True + cmd = Popen(gen_req, shell=True) + if cmd.wait() != 0: + raise Exception(_(u'! Error while generating certificate request {0} !').format(fic_p10)) + if new_key: + if del_passwd: + sup_passwd(tmp_keyfile, keyfile) + else: + copy(tmp_keyfile, keyfile) + if os.path.isfile(tmp_keyfile): + unlink(tmp_keyfile) + if signe_req: + # on signe la requête + ca_signe = '/usr/bin/openssl ca -in "%s" -config %s -out "%s" -batch -notext >/dev/null 2>&1' % (fic_p10, cert_conf_file, certfile) + cmd = Popen(ca_signe, shell=True) + if cmd.wait() != 0: + raise Exception(_(u'! Error while signing certificate request {0} !') % fic_p10) + print(_(u"* Certificate {0} successfully generated").format(certfile)) + if copy_key: + concat_fic(certfile, [keyfile], need_link=False) + finalise_cert(certfile, keyfile, key_user=key_user, + key_grp=key_grp, key_chmod=key_chmod, + cert_user=cert_user, cert_grp=cert_grp, + cert_chmod=cert_chmod) + build_link(certfile) + + +def remove_link(name, remove_broken_link=True): + load_default_conf_if_needed() + if not name.startswith(join(ssl_dir, 'certs')): + return + for cert_link in glob.glob(os.path.join(ssl_dir, 'certs/*')): + if islink(cert_link): + if remove_broken_link and not exists(cert_link): + #print 'ok lien cassé pour {} donc supprimé'.format(cert_link) + unlink(cert_link) + elif str(name) == realpath(cert_link): + #print 'ok suppression lien {} comme demandé ({})'.format(cert_link, name) + unlink(cert_link) + + +def build_link(name, concats=[]): + load_default_conf_if_needed() + if not name.startswith(join(ssl_dir, 'certs')): + return + def _check_contats_link(link): + # supprimer tous les liens vers les fichiers utilises pour la concatenation + if islink(link): + if realpath(link) in concats: + #print 'ok suppression du link {} ({} est dans {})'.format(link, realpath(link), concats) + unlink(link) + + def _check_link(fp, suffix): + # calcul du bon suffix utilise dans le nom + # si le fichier existe avec le suffix courant, ajoute 1 au numero de suffix + new_name = join(dir_name, fp) + '.' + str(suffix) + if islink(new_name): + #print 'pas de suppression du link {} ({} n\'est pas dans {})'.format(new_name, realpath(new_name), concats) + return _check_link(fp, suffix + 1) + #else: + # print "ok ce n'est pas un link {}".format(new_name) + return new_name + + def _build_link(ret): + # creer un lien a partir du hash du subject + if ret != '': + fp = ret.split('\n')[0] + if fp.isalnum(): + if concats != []: + for link in glob.glob(join(dir_name, fp) + '.*'): + _check_contats_link(link) + + new_name = _check_link(fp, 0) + #print 'ok creation du link {} vers {}'.format(new_name, name) + symlink(name, new_name) + return stat(new_name).st_mtime + return 0 + + dir_name = dirname(name) + subject_fp = ["/usr/bin/openssl", "x509", "-subject_hash", "-fingerprint", "-noout", "-in", name] + subject_fp_old = ["/usr/bin/openssl", "x509", "-subject_hash_old", "-fingerprint", "-noout", "-in", name] + new_timestamp = _build_link(system_out(subject_fp)[1]) + new_timestamp = max(_build_link(system_out(subject_fp_old)[1]), new_timestamp) + if isfile(SSL_LAST_FILE): + try: + fh = open(SSL_LAST_FILE, 'r') + timestamp = float(fh.read().strip()) + except ValueError: + timestamp = 0 + if new_timestamp > timestamp: + fh = open(SSL_LAST_FILE, 'w') + fh.write(str(new_timestamp)) + fh.close() + + +def rehash_if_needed(): + load_default_conf_if_needed() + need_rehash = False + if isfile(SSL_LAST_FILE): + try: + fh = open(SSL_LAST_FILE, 'r') + timestamp = int(float(fh.read().strip())) + for cert_link in glob.glob(os.path.join(ssl_dir, 'certs/*')): + try: + if timestamp < int(stat(cert_link).st_mtime): + need_rehash = True + break + except: + pass + except ValueError: + import traceback + traceback.print_exc() + need_rehash = True + else: + need_rehash = True + + if need_rehash: + system_code(['/usr/bin/c_rehash']) + new_timestamp = 0 + for cert_link in glob.glob(os.path.join(ssl_dir, 'certs/*')): + if isfile(cert_link): + timestamp = stat(cert_link).st_mtime + if timestamp > new_timestamp: + new_timestamp = timestamp + fh = open(SSL_LAST_FILE, 'w') + fh.write(str(new_timestamp)) + fh.close() + + +# gen_certif utils reader + +def certif_loader(regen=None): + """charge les fichiers permettant de générer les certificats + """ + load_default_conf_if_needed() + # XXX FIXME : changer le path de data vers les paquets container, + # XXX FIXME et déplacer les .gen_cert + files = glob.glob(join('/usr/share/eole/certs', '*_*.gen_cert')) + files.sort() + for fname in files: + # puts name in global namespace because we need it in execfile's + # namespace in rules_loader + name = splitext(basename(fname))[0].split('_')[1] + # exec gen_certs + execfile(fname, globals(),locals()) + +def get_subject(cert=None, certfile=None): + """ + récupère le subject d'un certificat. + spécifier obligatoirement un des deux paramètres : + - cert : contenu du certificat + - certfile : nom du fichier du certificat + """ + load_default_conf_if_needed() + global regexp_get_subject + if None not in (cert, certfile): + raise Exception(_(u'cert or certfile must be None')) + if cert == certfile: + raise Exception(_(u'cert or certfile must be set')) + if certfile != None: + cmd = ['openssl', 'x509', '-in', certfile, '-subject', '-noout'] + stdin = None + else: + cmd = ['openssl', 'x509', '-subject', '-noout'] + stdin = cert + ret = system_out(cmd=cmd, stdin=stdin) + if ret[0] != 0: + raise Exception(_(u'error in {0}: {1}').format(' '.join(cmd), str(ret[2]))) + ret = ret[1].rstrip() + if not ret.startswith("subject= "): + raise Exception(_(u'Invalid certificate subject: {0} ').format(ret)) + if regexp_get_subject is None: + regexp_get_subject = re.compile('^subject= (.*)/CN=(.*)') + return regexp_get_subject.findall(ret)[0] + +def get_issuer_subject(cert=None, certfile=None): + """ + récupère le subject de la CA d'un certificat. + spécifier obligatoirement un des deux paramètres : + - cert : contenu du certificat + - certfile : nom du fichier du certificat + """ + load_default_conf_if_needed() + if None not in (cert, certfile): + raise Exception(_(u'cert or certfile must be None')) + if cert == certfile: + raise Exception(_(u'cert or certfile must be set')) + if certfile != None: + cmd = ['openssl', 'x509', '-in', certfile, '-issuer', '-noout'] + stdin = None + else: + cmd = ['openssl', 'x509', '-issuer', '-noout'] + stdin = cert + ret = system_out(cmd=cmd, stdin=stdin) + if ret[0] != 0: + raise Exception(_(u'error in {0}: {1}').format(' '.join(cmd), str(ret[2]))) + ret = ret[1].rstrip() + if not ret.startswith("issuer= "): + raise Exception(_(u'Invalid certificate issuer: {0} ').format(ret)) + regexp = '^issuer= (.*)/CN=(.*)' + return re.findall(regexp, ret)[0] + +def load_conf(ssl_dico): + global ssl_dir, cert_dir, key_dir, tmp_keyfile, file_serial, req_dir + global local_ca_dir, newcerts_dir, ca_conf_file, conf_file, client_conf_file + global ca_file, ca_dest_file, ca_keyfile, start_index, min_serial + global ssl_default_key_bits, ssl_default_cert_time + global certs_catalog + + ssl_dir = ssl_dico.get('ssl_dir', ssl_dir) + cert_dir = ssl_dico.get('cert_dir', os.path.join(ssl_dir, "certs")) + key_dir = ssl_dico.get('key_dir', os.path.join(ssl_dir, "private")) + tmp_keyfile = ssl_dico.get('tmp_keyfile', os.path.join(key_dir, "tmpkey.key")) + file_serial = ssl_dico.get('file_serial', os.path.join(ssl_dir, "serial")) + req_dir = ssl_dico.get('req_dir', os.path.join(ssl_dir, "req")) + local_ca_dir = ssl_dico.get('local_ca_dir', os.path.join(ssl_dir, "local_ca")) + newcerts_dir = ssl_dico.get('newcerts_dir', os.path.join(ssl_dir, "newcerts")) + ca_conf_file = ssl_dico.get('ca_conf_file', ca_conf_file) + conf_file = ssl_dico.get('conf_file', conf_file) + client_conf_file = ssl_dico.get('client_conf_file', conf_file) + # chemin de la CA + ca_file = ssl_dico.get('ca_file', os.path.join(cert_dir, "ca_local.crt")) + ca_dest_file = ssl_dico.get('ca_dest_file', os.path.join(cert_dir, "ca.crt")) + ca_keyfile = ssl_dico.get('ca_keyfile', os.path.join(key_dir, "ca.key")) + # index + start_index = ssl_dico.get('start_index', hex(int(time.time()))[2:]) + min_serial = int(eval('0x30')) + ssl_default_key_bits = ssl_dico.get('ssl_default_key_bits', client.get_creole('ssl_default_key_bits', 2048)) + ssl_default_cert_time = ssl_dico.get('ssl_default_cert_time', client.get_creole('ssl_default_cert_time', 1096)) + +def load_default_conf_if_needed(): + """creoled n'est pas forcement démarré à ce moment là + ne charger la configuration par défaut qu'à l'utilisation de la lib + et non a l'importantion + #8448 + """ + global ssl_dir + if ssl_dir == None: + load_conf({'ssl_dir': '/etc/ssl', + 'ca_conf_file': '/etc/eole/ssl/ca-eole.conf', + 'conf_file': '/etc/eole/ssl/certif-eole.conf', + 'client_conf_file': '/etc/eole/ssl/client-eole.conf'}) + +ssl_dir=None +ca_conf_file=None +client_conf_file=None +conf_file=None +certs_catalog = None +ca_issuer = None diff --git a/creole/client.py b/creole/client.py new file mode 100644 index 0000000..259fa24 --- /dev/null +++ b/creole/client.py @@ -0,0 +1,838 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +########################################################################## +# creole.client - client to request creole.server through REST API +# Copyright © 2012,2013 Pôle de compétences EOLE +# +# License CeCILL: +# * in french: http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html +# * in english http://www.cecill.info/licences/Licence_CeCILL_V2-en.html +########################################################################## + +"""Request informations from :class:`creole.CreoleServer` + +Simple http :mod:`restkit.request` client to request and manipulate +informations from :class:`creole.CreoleServer`. + +""" + +from http_parser.http import NoMoreData +import restkit +import eventlet +from restkit.errors import ResourceError, RequestError, ParseException, RequestTimeout +from eventlet.timeout import Timeout as EventletTimeout + +from collections import OrderedDict + +import json +import logging +from time import sleep + +from .dtd_parser import parse_dtd +from .config import dtdfilename + +from .i18n import _ +from pyeole.encode import normalize + +import re + +# Stat filesystem +import os + +# Create instance method on the fly +import types + +log = logging.getLogger(__name__) + +_CONTAINER_COMPONENTS = ['container'] + parse_dtd(dtdfilename)['container']['options'] +"""List of components used to define an LXC container. + +They are extracted from the ``creole.dtd``. + +Each of them are use to fabric two accessor methods bound to +:class:`CreoleClient`. + +""" +LOCAL_URL = 'http://127.0.0.1:8000' +#Si on veut garder les threads, on peut désactiver les reap_connections pour éviter les tracebacks +#restkit.session.get_session('thread', reap_connections=False) + + +def _merge_entries(old, new): + """Merge component informations + + This merge keep information from :data:`old` when the :data:`new` + is ``None``. + + The boolean information are ored between :data:`old` and + :data:`new`. + + :param old: previous component informations + :type old: `dict` + :param new: new component informations + :type new: `dict` + :return: merged informations + :rtype: `dict` + + """ + for key, val in new.items(): + if val is None: + # Do not override previous value + continue + elif isinstance(val, bool): + # Switch on first True + # old[key] may not exists + old[key] = val | old.get(key, False) + else: + old[key] = val + + return old + + +def _merge_duplicates_in_components(container_info, keys_to_strip=None): + """Merge duplicates entries + + :param container_info: information on a container or group of + containers + :type container_info: `dict` + :param keys_to_strip: keys for which to remove duplicated entries + :type keys_to_strip: `list` + + """ + # Do not work in-place + info = container_info.copy() + + if keys_to_strip is None: + # Run on all keys + keys_to_strip = info.keys() + + for key in keys_to_strip: + if not isinstance(info[key], list): + # Do not work on single values + continue + + result = OrderedDict() + for entry in info[key]: + if 'name' in entry: + name = repr(entry['name']) + if name in result and not entry.get(u'activate', False): + # Duplicate found but inactive + continue + elif name in result: + # Merge old and new informations + old_entry = result[name] + # Make sure entry appears at right place + del(result[name]) + result[name] = _merge_entries(old=old_entry, + new=entry) + else: + # New entry + result[name] = entry + + if result: + # Store stripped information + info[key] = [ item for item in result.values() ] + + return info + + +def _build_component_accessors(component): + """Fabric of accessors for container components + + It build two accessors: + + - one to get all components for all containers named + ``get_s`` + + - one to get one comoponent item defined for all containers + named ``get_`` + + :param name: type of container variable + :type name: `str` + :return: component accessors + :rtype: `tuple` of `function` + + """ + def all_components(self, container=None): + """Return all components + """ + return self.get_components('{0}s'.format(component), + container=container) + + all_components.__name__ = 'get_{0}s'.format(component) + all_components.__doc__ = """Get {0}s for all containers + + :param container: limit search to a container + :type container: `str` + :returns: {0}s informations + :rtype: `list` + + """.format(component) + + def single_component(self, name, container=None): + """Return single component + """ + components = [] + ret = self.get_components('{0}s'.format(component), + container=container) + for item in ret: + if item['name'] == name: + components.append(item) + return components + single_component.__doc__ = """Get one {0} for all containers + + :param name: name of {0} to return + :type name: `str` + :param container: limit search to a container + :type container: `str` + :returns: {0} informations for all containers + :rtype: `list` + + """.format(component) + + single_component.__name__ = 'get_{0}'.format(component) + + return all_components, single_component + + +class CreoleClient(object): + """Request informations from :class:`creole.CreoleServer`. + + In addition, this class provides some utilities to manipulate + returned data. + + """ + + def __init__(self, url=None): + """Initialize client. + + :param url: HTTP URL to the :class:`creole.CreoleServer` + :type url: `str` + + """ + if url is None: + if self.is_in_lxc(): + url = 'http://192.0.2.1:8000' + else: + url = LOCAL_URL + + self.url = url + comp_list = _CONTAINER_COMPONENTS[:] + comp_list.remove('container') + # Disable logging of restkit + restkit.set_logging('critical', logging.NullHandler()) + self._is_container_actif = None + self._restkit_request = None + for component in comp_list: + get_all, get_single = _build_component_accessors(component) + setattr(self, get_all.__name__, + types.MethodType(get_all, self, CreoleClient)) + setattr(self, get_single.__name__, + types.MethodType(get_single, self, CreoleClient)) + + @staticmethod + def is_in_lxc(): + """Check if we are in LXC. + + We are under LXC if /proc/1/cgroup contains ``/lxc``. + + :return: if we are under LXC. + :rtype: `bool` + + """ + if not os.path.isdir('/proc/self'): + # when launch in chroot + return True + else: + return os.access('/dev/lxc/console', os.F_OK) + + + def close(self): + if self._restkit_request is not None: + self._restkit_request.close() + + + def _request(self, path, **kwargs): + """Send HTTP request to Creole server. + + If ConnectionError, try three time before leave. + + :param path: path to the creole resource + :type path: `str` + :return: response of the request + :rtype: :class:`restkit.wrappers.Response` + :raise CreoleClientError: on HTTP errors + + """ + timeout = 5 + max_try = 3 + tried = 0 + + method = 'GET' + if 'method' in kwargs: + method = kwargs['method'] + del(kwargs['method']) + + uri = restkit.util.make_uri(path, **kwargs) + + while tried < max_try: + tried += 1 + try: + # use eventlet backend (#13194, #21388) + with eventlet.Timeout(timeout): + self._restkit_request = restkit.request(uri, method=method, backend='eventlet') + return self._restkit_request + except (ResourceError, RequestError, ParseException, NoMoreData, RequestTimeout, EventletTimeout) as err: + log.debug(_(u"Connexion error '{0}'," + u" retry {1}/{2}").format(err, tried, max_try)) + sleep(1) + + if isinstance(err, RequestError): + msg = _(u"HTTP error: {0}\nPlease check creoled's log (/var/log/rsyslog/local/creoled/creoled.info.log)\nand restart service with command 'service creoled start'") + else: + msg = _(u"HTTP error: {0}") + if isinstance(err, RequestTimeout) or isinstance(err, EventletTimeout): + err = _(u"creoled service didn't respond in time") + + raise TimeoutCreoleClientError(msg.format(err)) + + def is_container_actif(self): + if self._is_container_actif is None: + self._is_container_actif = self.get_creole('mode_conteneur_actif', 'non') == 'oui' + return self._is_container_actif + + def request(self, command, path=None, **kwargs): + """Send HTTP request to creole server. + + :param command: action to perform for the creole resource + :type command: `str` + :param path: path to the creole resource + :type path: `str` + :return: dictionary of variable:value + :rtype: `dict` + :raise CreoleClientError: on bad response status or HTTP error + + """ + if path is not None: + path = self.validate_path(path) + ret = self._request(self.url + command + path, **kwargs) + else: + ret = self._request(self.url + command, **kwargs) + if ret.status_int != 200: + log.debug(_(u'HTML content: {0}').format(ret.body_string())) + raise CreoleClientError(_(u"HTML error {0}, please consult creoled events log (/var/log/rsyslog/local/creoled/creoled.info.log) to have more informations").format(ret.status_int)) + reply = json.loads(ret.body_string()) + + # Previous fix for NoMoreData exception #7218 : + #ret.connection.close() + + if reply['status'] != 0: + if reply['status'] == 4: + raise NotFoundError(u"{0}".format(reply['response'])) + else: + raise CreoleClientError(normalize(_("Creole error {0}: {1}")).format( + reply['status'], reply['response'])) + + return reply['response'] + + @staticmethod + def validate_path(path): + """Validate the path for http request. + + :data:`path` must use ``/`` as separator with a leading one or + use ``.`` as separator. + + :param path: path to the creole resource + :type path: `str` + :return: slash separated path to the resource + :rtype: `str` + :raise CreoleClientError: when path does not validate + + """ + ret = path + if not ret.startswith('/'): + if ret.find('.') != -1 and ret.find('/') != -1: + raise CreoleClientError(_(u"Path must not mix dotted and" + + u" slash notation: '{0}'").format(path)) + elif ret.find('.') != -1: + ret = '/{0}'.format( ret.replace('.', '/') ) + else: + raise CreoleClientError(_(u"Path must start" + + u" with '/': '{0}'").format(path)) + return ret + + def get(self, path='/creole', *args, **kwargs): + """Get the values from part of the tree. + + If :data:`path` is a variable, it returns it's value. + + If :data:`path` is a tree node, it returns the whole tree + of ``variable:value`` as flat dictionary. + + :param path: path to the creole resource + :type path: `str` + :param default: default value if any error occurs + :return: slash separated path to the resource + :rtype: `str` + + """ + # Use a dictionary to test existence + default = {} + if len(args) > 1: + raise ValueError(_("Too many positional parameters {0}.").format(args)) + + if kwargs.has_key('default'): + default['value'] = kwargs['default'] + del(kwargs['default']) + elif len(args) == 1: + default['value'] = args[0] + + try: + ret = self.request('/get', path, **kwargs) + except (NotFoundError, CreoleClientError) as err: + if default.has_key('value'): + ret = default['value'] + else: + raise err + + return ret + + def list(self, path='/creole'): + """List content of a path. + + If :data:`path` is a variable, it returns it's name. + + If :data:`path` is a tree node, it returns the list of items + under it. + + :param path: path to the creole resource + :type path: `str` + :return: items present under a path + :rtype: `list` + + """ + return self.request('/list', path) + + def get_creole(self, name=None, *args, **kwargs): + """Get variables under ``/creole``. + + The full path of variable names is stripped in key names. + + :param path: path to the creole resource + :type path: `str` + :param default: default value to return if the variable named + :data:`name` does not exist or any error occurs + :return: variables and their value + :rtype: `dict` + + """ + if name is not None: + # Tiramisu has no any meaningful message + try: + ret = self.get('/creole', *args, variable=name, **kwargs) + except NotFoundError: + msg = _(u'Unknown variable {0}') + raise NotFoundError(msg.format(name)) + else: + ret = self.strip_full_path(self.get('/creole', *args, **kwargs)) + + return ret + + def reload_config(self): + """Reload Tiramisu's config + """ + return self.request('/reload_config') + + def reload_eol(self): + """Reload Tiramisu's partial config + """ + return self.request('/reload_eol') + + def valid_mandatory(self): + return self.request('/valid_mandatory') + + def get_containers(self, group=None): + """Get basic informations of all containers + + :param group: limit search to a group of containers + :type group: `str` + :return: containers informations + :rtype: `list` + """ + mode_container = self.is_container_actif() + if group is None or (not mode_container and group == 'root'): + args = {} + else: + args = {'withoption':'group', + 'withvalue':group} + + try: + ret = self.get('/containers/containers', **args) + except NotFoundError: + # Tiramisu has no any meaningful message + if group is not None: + msg = _(u'No container found for group {0}') + else: + msg = _(u'No container found! Is that possible?') + raise NotFoundError(msg.format(group)) + + ret = self.to_list_of_dict(ret, prefix='container') + return ret + + + def get_container(self, name): + """Get informations of one container + + :param name: type of container variable + :type name: `str` + :return: component for all containers + :rtype: `list` + """ + try: + ret = self.get('/containers/containers', + withoption='name', + withvalue=name) + except NotFoundError: + # Tiramisu has no any meaningful message + raise NotFoundError(_(u'Unknown container {0}').format(name)) + + ret = self.to_list_of_dict(ret, prefix='container') + return ret[0] + + + def get_groups(self): + """Get list of container groups + + All groups are a container, but all containers are not a + group. + + :return: container groups names + :rtype: `list` + + """ + mode_container = self.is_container_actif() + containers = self.get_containers() + if not mode_container: + groups = ['root'] + else: + groups = [] + for container in containers: + if container['name'] == container['group']: + groups.append(container['name']) + if 'all' in groups: + groups.remove('all') + + return groups + + + def is_group(self, name): + """Verify is a container is a group of containers. + + :param name: name of the container + :type name: `str` + :return: is the container a group of containers? + :rtype: `bool` + + """ + mode_container = self.is_container_actif() + if not mode_container: + return name == 'root' + + container = self.get_container(name) + return name == container['group'] + + + def get_containers_components(self, containers, group=False, merge_duplicates=False): + """Get all components of a list of containers or group of containers. + + :param containers: container names + :type containers: `list` of `str` + :param group: containers are names of groups of containers + :type group: `bool` + :param merge_duplicates: merge duplicate entries + :type merge_duplicates: `bool` + :return: components of the containers + :rtype: `dict` + + """ + comp_list = [ '{0}s'.format(name) for name in _CONTAINER_COMPONENTS[:] ] + component = {} + + if not group: + if 'all' in containers: + # make sure all is first + containers.remove('all') + + # Remove duplicates + containers = list(set(containers)) + containers.insert(0, 'all') + + for comp in comp_list: + component[comp] = [] + for container in containers: + by_cont = self.get_components(None, container=container, group=group) + + for comp, items in by_cont.items(): + if comp + 's' in comp_list: + component[comp + 's'].extend(items) + + if merge_duplicates: + component = _merge_duplicates_in_components(component, comp_list) + + if 'interfaces' in component: + for interface in component['interfaces']: + if 'gateway' in interface and interface['gateway']: + component['gateway'] = {u'interface': interface['name'], + u'ip': interface['gateway']} + + return component + + + def get_container_infos(self, container): + """Get all components of a container or its group + + :param container: container name + :type container: `str` + :return: components of the container or its group + :rtype: `dict` + + """ + container_info = self.get_container(container) + group_name = container_info[u'real_container'] + container_info = self.get_group_infos(group_name) + + return container_info + + + def get_group_infos(self, group): + """Get all components of a group of container + + :param group: container group name + :type group: `str` + :return: components of the container + :rtype: `dict` + + """ + group_info = self.get_containers_components(containers=[group], + group=True, + merge_duplicates=True) + + # If we need to do thing in the name of all containers in the group + names = [] + found = False + for container in group_info['containers']: + name = container['name'] + names.append(name) + if name == group: + found = True + group_info.update(container) + if not found: + group_info.update(self.get_container(group)) + group_info['containers'] = names + + return group_info + + + def get_components(self, name, container=None, group=False): + """Get component for containers + + :param name: type of container variable + :type name: `str` + :param container: limit search to a container + :type container: `str` + :return: component for all containers + :rtype: `list` + """ + if container is not None: + if group: + option_name = 'real_container' + else: + option_name = 'container' + + args = {'withoption': option_name, + 'withvalue': container} + else: + args = {} + + ret = None + if name is None: + path = '/containers' + else: + path = '/containers/{0}'.format(name) + try: + ret = self.get(path, **args) + except NotFoundError: + # Tiramisu has no any meaningful message + msg = _(u'Unknown container components {0} for container {1}') + if container is None: + msg = _(u'Unknown container components {0}') + else: + args = {'withoption':'container_group', + 'withvalue':container} + try: + ret = self.get(path, **args) + except NotFoundError: + msg = _(u'Unknown container components {0} for container {1}') + # If not a container, maybe a container's group + if ret is None: + raise NotFoundError(msg.format(str(name), container)) + if name is None: + comp_list = _CONTAINER_COMPONENTS[:] + dico = {} + ret_comp = {} + for comp in comp_list: + dico[comp] = {} + for path, item in ret.items(): + spath = path.split('.') + #without 's' + comp = spath[0][:-1] + dico[comp]['.'.join(spath[1:])] = item + for comp in comp_list: + ret_comp[comp] = self.to_list_of_dict(dico[comp], prefix=comp) + + else: + ret_comp = self.to_list_of_dict(ret, prefix=name) + return ret_comp + + @classmethod + def to_list_of_dict(cls, flat, prefix=None): + """Convert a flat dictionary to a list of dictionaries. + + Build a list of dictionary ``:`` for each + prefix of the form ``.:`` + + If list is numerically ordered by ```` + extracted from each key accordingly to :data:`prefix`. + + If the :data:`prefix` is not specified, a random element of + :data:`flat` is extracted to compute it. + + :param flat: absolute attribute variable names and their + values + :type flat: `dict` + :param prefix: alphabetic prefix to extract integer index + :type prefix: `str` + :return: variables and their attributes values + :rtype: `list` of `dict` + + """ + reply = {} + sorted_items = [] + sort_key = None + + if prefix is None: + # Extract prefix name + random_key = flat.iterkeys().next() + indexed_prefix = random_key.split('.')[0] + re_match = re.match(r'(\D+)\d+', indexed_prefix) + prefix = re_match.group(1) + + if prefix is not None: + # check for none because maybe regexp match did not work + # Extract component index as integer for comparaison + sort_key = lambda string: int(string.split('.')[0].lstrip(prefix)) + + for key in sorted(flat.keys(), key=sort_key): + sid, sattr = cls._split_path_leaf(key) + if sid not in reply: + sorted_items.append(sid) + reply[sid] = {} + reply[sid][sattr] = flat[key] + return [ reply[item] for item in sorted_items ] + + @staticmethod + def strip_full_path(flat): + """Strip full path of flat dictionary keys. + + :param flat: absolute variable names and their value + :type flat: `dict` + :return: short variable names and their value + :rtype: `dict` + """ + ret = {} + for path in flat: + parts = path.split('.')[1:] + if len(parts) == 1: + # Single variable + ret[ parts[0] ] = flat[path] + elif len(parts) == 2 and parts[0] == parts[1]: + # Master variable + ret[ parts[0] ] = flat[path] + else: + # slave variable + ret[ '.'.join(parts) ] = flat[path] + return ret + + @staticmethod + def to_grouped_lists(dict_list, keyname, keyvalue=None): + """Convert a `list` of `dict` to a `dict` :data:`keyvalue`:`list`. + + Build dictionary of ``dictionary[:data:`keyvalue`]:`` to group all items with the same value of a key. + + :param dict_list: dictionaries + :type dict_list: `list` + :param keyname: name of the key to test + :type keyname: `str` + :param keyvalue: value to match :data:`keyname` + :return: dictionary grouped by a key value + :rtype: `dict` + + """ + reply = {} + for key in dict_list: + if keyname in key and keyvalue and keyvalue != key[keyname]: + continue + if keyname not in key: + if None not in reply: + reply[None] = [] + reply[None].append(key) + else: + if key[keyname] not in reply: + reply[ key[keyname] ] = [] + reply[ key[keyname] ].append(key) + return reply + + @staticmethod + def _split_path_leaf(path, separator='.'): + """Split path in two parts: dirname and basename. + + If :data:`path` does not contains the :data:`separator`, it's + considered as leaf and the dirname of :data:`path` is set to + `None`. + + :param path: path to the creole resource + :type path: `str` + :return: dirname and basename of :data:`path` + :rtype: `list` + + """ + if path.find(separator) == -1: + return (None, path) + + splited = path.split(separator) + return ( '.'.join(splited[:-1]), splited[-1] ) + + +class TimeoutCreoleClientError(StandardError): + pass + + +class CreoleClientError(StandardError): + """Bad use of :class:`CreoleClient` + """ + pass + + +class NotFoundError(CreoleClientError): + """Requested variable not found + """ + pass + + +if __name__ == '__main__': + try: + print(CreoleClient().get('/')) + except Exception as err: + print(_(u"Error: {0}").format(err)) diff --git a/creole/config.py b/creole/config.py new file mode 100644 index 0000000..9a13ac9 --- /dev/null +++ b/creole/config.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- +""" +fichier de configuration pour créole + +""" +from os.path import join, isfile, isdir + +eoledir = '/usr/share/eole' +LOCALKERNEL_FILE = join(eoledir, 'noyau/local') +REBOOT_FILE = '/var/run/reboot-required' + +charset = 'UTF8' + +# chemin par defaut des templates, fichier config.eol, etc +configeoldir = '/etc/eole/' +eoleroot = join(eoledir, 'creole') +vareole = '/var/lib/eole' + +bareos_restore_root = join(eoledir, 'bareos') +bareos_restore = join(bareos_restore_root, 'restore') + +configeol = join(configeoldir, 'config.eol') + +# certificats +cert_file = '/etc/ssl/certs/eole.crt' +key_file = '/etc/ssl/certs/eole.key' +# port du serveur creole_serv +port_rpc = 4333 + +# chemin du répertoire source des fichiers templates +templatedir = '/var/lib/creole' + +dicos_dir = join(eoleroot, 'dicos') +modif_dir = join(eoleroot, 'modif') +distrib_dir = join(eoleroot, 'distrib') +patch_dir = join(eoleroot, 'patch') + +# chemin pour les fichiers de données +datadir = '/usr/share/creole' +# chemin pour les modules de fonctions supplémentaires +func_dir = join(datadir,'funcs') +# repertoire du ou des dictionnaires xml creole +eoledirs = [dicos_dir, join(dicos_dir, 'variante'), join(dicos_dir, 'local')] + +# extra +eoleextradico = join(eoledir, 'creole/extra') +eoleextraconfig = join(configeoldir, 'extra') +forbiddenextra = ['containers', 'creole'] + +# repertoire de la dtd +dtddir = datadir +if isfile('data/creole.dtd'): + dtdfilename = 'data/creole.dtd' +elif isfile('../creole/data/creole.dtd'): + dtdfilename = '../creole/data/creole.dtd' +else: + dtdfilename = join(dtddir, 'creole.dtd') + +# repertoire avec le fichier lock +LOCK_PATH = '/var/lock/eole' +LOCK_SYSTEM_PATH = join(LOCK_PATH, 'eole-system') + +# Nom du serveur maitre +VIRTMASTER = 'root' +VIRTROOT = '/var/lib/lxc' +VIRTBASE = 'rootfs' + +container_instance_lockfile = '/etc/eole/.container_instance.lock' +containers_default_network = '192.0.2' +gen_conteneurs_needed = '/etc/eole/.gen_conteneurs' + +VIRTENABLED_LOCKFILE = '/etc/eole/.VirtEnabled.lock' +VIRTDISABLED_LOCKFILE = '/etc/eole/.VirtDisabled.lock' +INSTANCE_LOCKFILE = '/etc/eole/.instance' +UPGRADE_LOCKFILE = '/etc/eole/.upgrade-auto' + +SSL_LAST_FILE = '/etc/eole/ssl/lastfile.txt' + +FLATTENED_CREOLE_DIR = join(vareole, 'config') +if not isdir(FLATTENED_CREOLE_DIR): + FLATTENED_CREOLE_DIR = join('/tmp') diff --git a/creole/containers.py b/creole/containers.py new file mode 100644 index 0000000..9ee9d36 --- /dev/null +++ b/creole/containers.py @@ -0,0 +1,224 @@ +# -*- coding: utf-8 -*- +# +########################################################################## +# creole.containers - management of LXC containers +# Copyright © 2012,2013 Pôle de compétences EOLE +# +# License CeCILL: +# * in french: http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html +# * in english http://www.cecill.info/licences/Licence_CeCILL_V2-en.html +########################################################################## + +"""Manage LXC containers + +""" + +from .client import CreoleClient, _CONTAINER_COMPONENTS +from .config import VIRTENABLED_LOCKFILE, VIRTDISABLED_LOCKFILE +from .error import VirtError +from .config import templatedir, VIRTROOT +from .template import CreoleTemplateEngine +from pyeole.process import system_code, system_out, system_progress_out +from pyeole.diagnose import test_tcp +from .i18n import _ + +from distutils.spawn import find_executable +from os.path import isdir +from os.path import isfile, islink +from os.path import ismount +from os.path import join +from os.path import dirname +from os import access +from os import F_OK +from os import stat +from os import symlink +from os import makedirs +from os import mknod +from os import makedev +from os import major +from os import minor +from os import unlink +from stat import S_IFBLK +from stat import S_ISBLK +from hashlib import md5 +from glob import glob +import cjson + +import logging + +client = CreoleClient() +log = logging.getLogger(__name__) + +_LXC_MD5 = '/etc/eole/lxc.md5' +_LXC_LOG = '/var/log/isolation.log' + +_NOT_REALLY_LXC_CONTAINERS = ['root', 'all'] +"""List of container names that are not to be generated. + +""" + +_LXC_TEMPLATE = {'config': "lxc.config", + 'fstab': "lxc.fstab", + 'rootfs/etc/network/interfaces' : "lxc.interfaces", + } +"""Creole templates for LXC containers. + +""" + +def is_lxc_locked(): + """Check if the LXC virtualization is locked. + + The virtualization is locked after first ``instance`` of the + server to avoid switching between modes. + + :return: ``enable`` if LXC is enabled, ``disable`` if LXC is + disabled or ``None`` where there is no lockfile. + + """ + if isfile(VIRTENABLED_LOCKFILE) and isfile(VIRTDISABLED_LOCKFILE): + raise VirtError(_(u"Invalid LXC lock files state: both are present.")) + elif isfile(VIRTENABLED_LOCKFILE): + virtlocked = 'enable' + elif isfile(VIRTDISABLED_LOCKFILE): + virtlocked = 'disable' + else: + virtlocked = None + return virtlocked + +def is_lxc_enabled(): + """Check if LXC controller is enabled + + We do not accept to switch between enabled and disabled LXC, after + first ``instance``, a lock file is set to check at each + ``reconfigure``. + + :return: If the LXC container mode is enabled. + :rtype: `bool` + :raise VirtError: if state in inconsistent between configuration + and lock files. + + """ + containers_enabled = client.get_creole('mode_conteneur_actif', 'non') == 'oui' + if containers_enabled and not find_executable('lxc-info'): + raise VirtError(_(u'LXC is enabled but LXC commands not found in PATH.')) + + if containers_enabled and is_lxc_locked() == 'disable': + raise VirtError(_(u"Server already instantiated in no containers mode, attempt to activate containers mode aborted.")) + elif not containers_enabled and is_lxc_locked() == 'enable': + raise VirtError(_(u"Server already instantiated in containers mode, attempt to activate no containers mode aborted.")) + + return containers_enabled + +def generate_lxc_container(name, logger=None): + """Run creation of a container. + + Check if LXC is enabled and take care of ``root`` and ``all`` + containers. + + :param name: name of the LXC container + :type name: `str` + + """ + if name not in _NOT_REALLY_LXC_CONTAINERS: + if not test_tcp('localhost', client.get_creole('apt_cacher_port')): + raise Exception(_('cacher not available, please start check log in /var/log/apt-cacher-ng/ and restart it with "service apt-cacher-ng start" command')) + if isfile(_LXC_LOG): + unlink(_LXC_LOG) + cmd = ['lxc-create', '-n', name, '-t', 'eole'] + log.debug('Run: {0}'.format(' '.join(cmd))) + code, stdout, stderr = system_progress_out(cmd, _(u"Managing container {0}").format(name), logger) + fh = open(_LXC_LOG, 'w') + fh.write(stdout) + fh.write(stderr) + fh.close() + if code != 0 and stdout.find(u"'{0}' already exists'".format(name)) >= 0: + raise Exception(_('error during the process of container creation, more informations in {0}').format(_LXC_LOG)) + path_container = client.get_creole('container_path_{0}'.format(name)) + path_apt_eole_conf = join(path_container, 'etc', 'apt', 'apt-eole.conf') + path_apt_eole = join(path_container, 'usr', 'sbin', 'apt-eole') + if not isfile(path_apt_eole_conf) or not isfile(path_apt_eole): + raise Exception(_('eole-common-pkg not installed in container, something goes wrong, more informations in {0}').format(_LXC_LOG)) + + +def is_lxc_running(container): + """Check if an LXC container is running. + + This check at LXC level and check TCP on port SSH. + + :param container: the container informations + :type container: `dict` + :return: if the container is running and reachable + :rtype: `bool` + + """ + + return is_lxc_started(container) and test_tcp(container[u'ip'], 22) + + +def is_lxc_started(container): + """Check if an LXC container is started. + + This check at LXC level and check TCP on port SSH. + + :param container: the container informations + :type container: `dict` + :return: if the container is started + :rtype: `bool` + + """ + + if not is_lxc_enabled() or container.get(u'path', None) == '': + return True + + if container.get(u'name', None) is None: + raise ValueError(_(u"Container has no name")) + + if container.get(u'ip', None) is None: + raise ValueError(_(u"Container {0} has no IP").format(container[u'name'])) + + cmd = ['lxc-info', '--state', '--name', container[u'name']] + code, stdout, stderr = system_out(cmd) + + return stdout.strip().endswith('RUNNING') + + +def create_mount_point(group): + """Create mount points in LXC. + + This is required for LXC to start. + + """ + if 'fstabs' not in group: + return + for fstab in group['fstabs']: + mount_point = fstab.get('mount_point', fstab['name']) + full_path = join(group['path'], mount_point.lstrip('/')) + if not isdir(full_path): + makedirs(full_path) + + +def lxc_need_restart(): + def md5sum(file): + return md5(open(file).read()).hexdigest() + files = ['/etc/lxc/default.conf', '/etc/default/lxc-net'] + files += glob('/opt/lxc/*/config') + files += glob('/opt/lxc/*/fstab') + md5s = [] + for f in files: + md5s.append(md5sum(f)) + if not isfile(_LXC_MD5): + ret = True + else: + try: + old_md5s = cjson.decode(open(_LXC_MD5, 'r').read()) + except cjson.DecodeError: + ret = True + else: + ret = not old_md5s == md5s + + if ret: + fh = open(_LXC_MD5, 'w') + fh.write(cjson.encode(md5s)) + fh.close() + return ret + diff --git a/creole/dtd_parser.py b/creole/dtd_parser.py new file mode 100644 index 0000000..f57581b --- /dev/null +++ b/creole/dtd_parser.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- + +from .i18n import _ + +from tiramisu import option +CONVERT_VALUE = {'True': True, 'False': False, 'None': None} +forbidden_name = ('level',) + +def parse_dtd(filename): + """Parse DTD file and return a dict. + Dict structure: + + - key: name of element + - values: + + - type: if text, option type + - options: list of subelements + - needs: list of mandatory attributes with None or list of possible + value + - optionals: tuple: + - list of optional attributes with None or list of possible + value + - default value (None if no default value) + + Example: + {'container': + {'type': False, + 'options': ['service', 'interface', 'package', 'file', 'disknod'], + 'needs': {'name': {'values': None, 'type': None}, + 'optionals': {'group': {'values': None, 'default': None, + 'type': None}, + 'id': {'values': None, 'default': None, 'type': None}}} + } + """ + def parse_option(option): + option = option.replace('(', '').replace('*', '').replace(')', '') + option = option.replace('>', '').replace(' ', '').replace('+', '') + option = option.split('|') + options = [] + for opt in option: + options.extend(opt.split(',')) + if options == ['EMPTY']: + options = [] + return options + + def parse_comment(comment, options=None): + type_ = None + if comment.startswith(''): + comment = comment[4:-3] + if comment.endswith('Option'): + if comment == 'ChoiceOption': + raise ValueError(_(u'Do not write "ChoiceOption" in comments')) + try: + type_ = getattr(option, comment) + except AttributeError: + raise ValueError(_(u"Unvalid comment content: must match a valid attribute name")) + else: + #comment is the attribute name, the option type it's value + type_ = comment + return type_ + + fh = open(filename) + dtd_load = {} + for line in fh.readlines(): + sline = line.split() + if sline == []: + continue + #for element line + if sline[0] == ''): + options = ' '.join(sline[2:-1]) + else: + options = ' '.join(sline[2:]) + options = parse_option(options) + type_ = None + if '#PCDATA' in options: + options.remove('#PCDATA') + if sline[-1].startswith(''): + type_ = parse_comment(sline[-1], options) + else: + type_ = option.UnicodeOption + dtd_load[sline[1]] = {'type': type_, 'options': options, + 'needs': {}, 'optionals': {}} + #for attlist line + elif sline[0] == '', '').strip() + default = CONVERT_VALUE.get(default, default) + dtd_load[sline[1]]['optionals'][sline[2]] = {'values': values, + 'default': default, + 'type': type_} + return dtd_load diff --git a/creole/eoleversion.py b/creole/eoleversion.py new file mode 100644 index 0000000..59d28e2 --- /dev/null +++ b/creole/eoleversion.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2014 Pôle de compétences EOLE +# +# License CeCILL: +# * in french: http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html +# * in english http://www.cecill.info/licences/Licence_CeCILL_V2-en.html +########################################################################## + +"""Version variable of EOLE distribution + +""" + +UBUNTU_VERSION = u'xenial' +"""Ubuntu version used by EOLE. + +""" +EOLE_VERSION = u'2.6' +"""Current stable EOLE distribution. + +""" + +EOLE_RELEASE = u'{0}.2'.format(EOLE_VERSION) +"""Release version of the current stable EOLE distribution. + +""" + +ENVOLE_VERSION = u'6' +"""Envole version to use. + +""" + +LAST_RELEASE = u'2' +"""Last stable release for this version + +""" diff --git a/creole/error.py b/creole/error.py new file mode 100644 index 0000000..792af0d --- /dev/null +++ b/creole/error.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +""" +Erreurs Creole +""" + +class VirtError(Exception): + """incohérence concernant les conteneurs""" + pass + +#class ValueEoleError(Exception): +# """Cette valeur n'existe pas""" +# pass +# +class NoneError(Exception): + """Valeur vide""" + pass + +class OutOfRange(Exception): + pass + +class TypeEoleError(Exception): + """Erreur de type""" + pass + +class ConfigError(Exception): + pass + +class NetworkConfigError(Exception): + """ Network configuration error + """ + pass + +class FileNotFound(ConfigError): + pass + +class TemplateError(ConfigError): + pass + +class TemplateDisabled(TemplateError): + """Template is disabled. + """ + pass + +class DependencyError(ConfigError): + pass + +#class ConstraintError(ConfigError): +# pass +# + + +class LockError(Exception): + """ Add lock error + """ + pass + + +class UnlockError(Exception): + """ Remove lock error + """ + pass + + +class UserExit(Exception): + """ User exit(0) signal + """ + pass + + +class UserExitError(Exception): + """ User exit(1) signal + """ + pass + + +class CreoleOperationError(Exception): + """Type error or value Error for Creole variable's type or values + """ + + +class SpaceObjShallNotBeUpdated(Exception): + """Specific behavior in case of the presence or not + of an object in the space object + """ + + +class CreoleDictConsistencyError(Exception): + """It's not only that the Creole XML is valid against the Creole DTD + it's that it is not consistent. + """ diff --git a/creole/fonctionseole.py b/creole/fonctionseole.py new file mode 100644 index 0000000..47d39c6 --- /dev/null +++ b/creole/fonctionseole.py @@ -0,0 +1,280 @@ +# -*- coding: utf-8 -*- +""" +fonctions communes Creole +""" +import os, time, re +from os.path import join, isfile +from pyeole.process import system_out, system_code +from pyeole.ansiprint import print_orange +from pyeole.log import init_logging +from pyeole.pkg import EolePkg +from pyeole.encode import normalize +from .config import LOCALKERNEL_FILE, REBOOT_FILE + +from .i18n import _ + +#si creole client n'est pas démarré +global PkgManager +PkgManager = None + +###################### +# Gestion des noyaux # +###################### + +def split_version(version): + """ + return version as list splitting subnumbers + :param version: version number string + :type version: string + """ + version_splitted = re.split('[-\.]', version) + version_splitted = map(int, version_splitted) + return version_splitted + +def get_version_filtered_pkgs(prefix='linux-image'): + """ + return installed packages list ordered by version number + """ + vers_pkg_re = r"{0}-(?P[0-9]+(?P\.[0-9]+)*(-(?P[0-9]+))?)".format(prefix) + vers_pkg_re = re.compile(vers_pkg_re) + installed_pkgs = get_installed_kernel(prefix) + vers_pkgs = [(pkg, split_version(vers_pkg_re.search(pkg).group('vers'))) + for pkg in installed_pkgs + if vers_pkg_re.search(pkg)] + vers_pkgs = [pkg[0] for pkg in sorted(vers_pkgs, key=lambda p: p[1])] + return vers_pkgs + +def get_custom_kernel(): + """ + renvoie le nom du noyau personnalisé + ou None + """ + if isfile(LOCALKERNEL_FILE): + # noyau personnalisé détecté + kernel_file = LOCALKERNEL_FILE + return file(kernel_file).read().strip() + +def get_wanted_kernel(): + """ + renvoie le nom du noyau sur lequel on veut tourner + """ + custom_kernel = get_custom_kernel() + if custom_kernel: + ret = custom_kernel + else: + kernel_images = get_version_filtered_pkgs() + # Get last kernel version + last_ver = kernel_images[-1].split('-') + if len(last_ver) >= 4: + last_ver = "{0}-{1}-{2}".format(*last_ver[2:5]) + elif len(last_ver) == 3: + last_ver = "{0}".format(last_ver[-1]) + ret = last_ver + return ret + +def get_current_kernel(): + """ + renvoie le nom du noyau sur lequel on tourne + """ + version = system_out(['uname', '-r'])[1].strip() + return version + +def get_installed_kernel(kernel): + """ + renvoie la liste des noyaux installés + correspondant à celui demandé + """ + cmd = """COLUMNS=180 dpkg -l 2>/dev/null | awk -F " " '/^(i|h)i.*%s/ {print $2}'""" % kernel + return os.popen(cmd).read().splitlines() + +def get_package_depends(pkg): + """ + Renvois les dépendances d'un paquet + """ + try: + global PkgManager + if PkgManager is None: + PkgManager = EolePkg('apt') + res = PkgManager.get_depends(pkg) + return res + except: + return [] + +def controle_kernel(force_grub=True): + """ + Vérifie si on est sur le noyau désiré + Renvoie True si un reboot est nécessaire + """ + need_boot = False + if isfile(REBOOT_FILE): + # i.e. /var/run/reboot-required + need_boot = True + + wanted_kernel = get_wanted_kernel() + # on utilise le noyau spécifié + if wanted_kernel != get_current_kernel(): + need_boot = True + if force_grub: + # Update grub does the job since eole-kernel-version 2.3-eole37~2 + print _(u"Updating Grub configuration") + # ajout de LVM_SUPPRESS_FD_WARNINGS pour #10761 + system_code("/usr/sbin/update-grub2", env={'LVM_SUPPRESS_FD_WARNINGS': '1', "LC_ALL": 'fr_FR.UTF-8'}) + # reboot nécessaire ? + return need_boot + +def regen_initrd(): + """ + vérifie la présence de l'initrd + """ + noyau = get_wanted_kernel() + if not isfile("/boot/initrd.img-%s" % noyau): + print _(u"Initramfs missing, generating :") + cmd = ["/usr/sbin/update-initramfs", '-c', '-k', noyau] + system_code(cmd) + +def get_kernel_to_remove(): + """ + Obtenir la liste des noyaux a supprimer. Tous les noyaux sauf : + - le noyau courant + - les deux noyaux les plus récents + - l'éventuel noyau personnalisé + """ + # tous les noyaux installés + installed_kernels = get_version_filtered_pkgs() + # les deux noyaux les plus récents + to_keep = installed_kernels[-2:] + # tous les headers installés + installed_kernels.extend(get_version_filtered_pkgs(prefix='linux-headers')) + # le noyau courant + to_keep.append('linux-image-{0}'.format(get_current_kernel())) + # l'éventuel noyau personnalisé + custom_kernel = get_custom_kernel() + if custom_kernel: + to_keep.append('linux-image-{0}'.format(custom_kernel)) + # les headers correspondants aux noyaux à conserver + headers_to_keep = [k.replace('image', 'headers') for k in to_keep] + headers_to_keep.extend([h.replace('-generic', '') for h in headers_to_keep]) + to_keep.extend(headers_to_keep) + # on fait la différence + to_remove = list(set(installed_kernels) - set(to_keep)) + return to_remove + +def purge_rc(): + """ + Purge des paquets "rc" + """ + cmd = """COLUMNS=180 dpkg -l|grep "^rc"|awk -F " " '{print $2}'""" + rcs = os.popen(cmd).read().splitlines() + for pak in rcs: + os.system("dpkg -P %s >/dev/null" % pak) + +def log(etat, msg, type_proc, console=True): + """ + effectue un log local et éventuellement sur zephir + """ + msg = normalize(msg) + type_proc = normalize(type_proc) + display = False + log_func = 'info' + if etat == "ERR": + if console: + # affichage sur la console + display = True + log_func = 'error' + + try: + z_logger = init_logging(name=u'zephir', syslog=True, level=u'info', console=display) + except ValueError, err: + z_logger = init_logging(name=u'zephir', level=u'info', console=True) + z_logger.warn(_(u"Syslog logging is not working properly: {0}".format(err))) + z_logger.warn(_(u"You may need to start/restart systemd-journald")) + + getattr(z_logger, log_func)("%s => %s : %s " % (type_proc, etat, msg)) + +def zephir(etat, msg, type_proc, console=True): + """ gestion des messages Zephir """ + etat_zeph = None + if etat.upper().startswith("INIT"): + etat_zeph = -1 + elif etat.upper().startswith("FIN"): + etat_zeph = 0 + elif etat.upper().startswith('ERR'): + etat_zeph = 1 + elif etat.upper().startswith('MSG'): + etat_zeph = -2 + # log local si msg ou erreur + if (len(msg) > 0) or (etat.upper() == "ERR"): + log(etat, msg, type_proc, console) + # log sur zephir si disponible + if etat_zeph is not None: + try: + # si serveur enregistré, on envoie un log à Zéphir + from zephir.zephir_conf.zephir_conf import id_serveur + except: + pass + else: + from zephir.lib_zephir import log as zlog + zlog(type_proc, etat_zeph, msg, str(time.ctime())) + +def init_proc(type_proc): + """ + initialisation d'une procédure (log démarrage + bcage éventuel) + """ + if verify_lock(type_proc): + return True + else: + return False + +#def end_proc(etat,msg,type_proc): +# """ +# loggue la fin d'une procédure +# """ +# log(etat,msg,type_proc ) + +def verify_lock(name): + """ + vérifie le bloquage ou non d'une procédure + """ + LOCK_FILE = "/usr/share/zephir/zephir_locks" + if name == "": + return True + from zephir.lib_zephir import zephir_path + try: + from zephir.lib_zephir import config, zephir, convert + locks = convert(zephir.serveurs.get_locks(config.id_serveur)) + if locks[0] == 0: + # erreur sur zephir, on ignore cette phase + raise Exception + locks = [lock[0] for lock in locks[1]] + except Exception, mess: + # pas de message d'erreur si le serveur n'est pas enregistré + zephir_error = False + if isfile(join(zephir_path, "zephir_conf", "zephir_conf.py")): + # on ne bloque pas si l'appel à zephir échoue + print "" + print_orange(_(u"Checking permissions on Zéphir for {0} impossible.").format(name)) + print_orange(_(u"Error message: {0}").format(mess)) + zephir_error = True + # on regarde le denier état + if os.path.exists(LOCK_FILE): + if zephir_error: + print_orange(_(u"Using stored parameters")) + file_lock = file(LOCK_FILE) + locks = file_lock.read().split('\n') + file_lock.close() + # on bloque si interdit + if name in locks: + return False + else: + # mise en place du fichier de droits + content = "\n".join(locks) + try: + file_lock = file(LOCK_FILE, "w") + file_lock.write(content) + file_lock.close() + except: + print _(u"Updating {0} impossible (insufficient rights).").format(LOCK_FILE) + # retour du code + if name in locks: + return False + return True diff --git a/creole/i18n.py b/creole/i18n.py new file mode 100644 index 0000000..db1716c --- /dev/null +++ b/creole/i18n.py @@ -0,0 +1,52 @@ +# -*- coding: UTF-8 -*- +# Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors) +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +# +# The original `Config` design model is unproudly borrowed from +# the rough gus of pypy: pypy: http://codespeak.net/svn/pypy/dist/pypy/config/ +# the whole pypy projet is under MIT licence +"internationalisation utilities" +import gettext +import os +import sys +import locale + +# Application Name +APP_NAME = 'creole' + +# Traduction dir +APP_DIR = os.path.join(sys.prefix, 'share') +LOCALE_DIR = os.path.join(APP_DIR, 'locale') + +# Default Lanugage +DEFAULT_LANG = os.environ.get('LANG', '').split(':') +DEFAULT_LANG += ['en_US'] + +languages = [] +lc, encoding = locale.getdefaultlocale() +if lc: + languages = [lc] + +languages += DEFAULT_LANG +mo_location = LOCALE_DIR + +gettext.find(APP_NAME, mo_location) +gettext.textdomain(APP_NAME) +gettext.bind_textdomain_codeset(APP_NAME, "UTF-8") +gettext.translation(APP_NAME, fallback=True) + +t = gettext.translation(APP_NAME, fallback=True) + +_ = t.gettext diff --git a/creole/lint/TODO b/creole/lint/TODO new file mode 100644 index 0000000..617d411 --- /dev/null +++ b/creole/lint/TODO @@ -0,0 +1,14 @@ +XXX: Currently in progress, NOT IN WORKING STATE. + +MAJOR REASON IS : +**revamping the implementation entirely for scalability** + +AND : +NOT INTEGRATED YET +for pretty print in the console +- ansiprint.py +- terminalreport.py +- terminalwriter.py + + + diff --git a/creole/lint/__init__.py b/creole/lint/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/creole/lint/ansiwriter.py b/creole/lint/ansiwriter.py new file mode 100644 index 0000000..128061f --- /dev/null +++ b/creole/lint/ansiwriter.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +"""Simple API fro creolelint reports""" +import sys +from creole.lint.warning import Warn +from creole.lint import warnsymb + +def ansi_print(text=None, fhandle=None, newline=True, flush=False): + """normalized (ansi) print >> file handle function""" + #sys.stdout.write(self.getvalue()) + if fhandle is None: + fhandle = sys.stderr + if text != None: + #text = text.strip() + if newline: + text += '\n' + fhandle.write(text) + if flush: + fhandle.flush() +# if fhandle: +# fhandle.close() + +class AnsiWriter(object): + """Définit une interface d'écriture de warnings + """ + def __init__(self, write_level, output=sys.stdout): + self.write_level = write_level + self.output = output + + def process(self, linter): + """ + parse a result from an item.check() dictionnary + which is made of {name: TmplVar} + """ + ident=1 + itemname = linter.name + warnno = linter.warnno + warncomment = linter.warncomment + display = linter.display + name, level = warnsymb.errorcode[warnno] + if level > getattr(warnsymb, self.write_level): + print "\nLint {0} désactivé (niveau {1})".format(itemname, warnsymb.errorlevel[level]) + return '' + level = warnsymb.errorlevel[level] + if not display: + ansi_print('') + ansi_print('%s (%s:%s:%s)'%(warncomment, itemname, name, level), self.output) + checks = linter.check() + warn = Warn(self.write_level, itemname, warnno, warncomment, checks) + dico_loc = warn.to_dict() + if dico_loc != '' and dico_loc != {}: + ansi_print('') + ansi_print('%s (%s:%s:%s)'%(warncomment, itemname, name, level), self.output) + def compare(x,y): + return cmp(x[0],y[0]) + for vfile in dico_loc.keys(): + if vfile != 'dictionnaire': + ansi_print('%s\-- fichier %s' % (' '*ident, vfile), self.output, newline=False) + vlines = dico_loc[vfile] + vlines.sort(compare) + oldline=0 + for vline, var in vlines: + if hasattr(var, 'name'): + vname = '%%%%%s'%str(var.name) + else: + vname = str(var) + if vline != None: + if vline != oldline: + ansi_print('', self.output) + ansi_print('%s|-- ligne %s' % (' '*(ident+1), vline), self.output, newline=False) + pass + oldline=vline + if vfile != 'dictionnaire': + ansi_print(" %s" %vname, self.output, newline=False) + else: + ansi_print("%s\-- %s" %(' '*ident, vname), self.output) + if vfile != 'dictionnaire': + ansi_print('', self.output) + diff --git a/creole/lint/cmdexec.py b/creole/lint/cmdexec.py new file mode 100755 index 0000000..cfad6ce --- /dev/null +++ b/creole/lint/cmdexec.py @@ -0,0 +1,39 @@ +"a system command launcher" + +import os, sys +import subprocess +from subprocess import Popen, PIPE + +def cmdexec(cmd): + """ return output of executing 'cmd' in a separate process. + + raise ExecutionFailed exception if the command failed. + the exception will provide an 'err' attribute containing + the error-output from the command. + """ + process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = process.communicate() + status = process.poll() + if status: + raise ExecutionFailed(status, status, cmd, out, err) + return out + +class ExecutionFailed(Exception): + def __init__(self, status, systemstatus, cmd, out, err): + Exception.__init__(self) + self.status = status + self.systemstatus = systemstatus + self.cmd = cmd + self.err = err + self.out = out + + def __str__(self): + return "ExecutionFailed: %d %s\n%s" %(self.status, self.cmd, self.err) + +# export the exception under the name 'Error' +Error = ExecutionFailed +try: + ExecutionFailed.__module__ = 'cmdexec' + ExecutionFailed.__name__ = 'Error' +except (AttributeError, TypeError): + pass diff --git a/creole/lint/creolelint.py b/creole/lint/creolelint.py new file mode 100644 index 0000000..16ed0d5 --- /dev/null +++ b/creole/lint/creolelint.py @@ -0,0 +1,1195 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" + creole lint main module +""" +import types +import sys +import re +from glob import glob +from os.path import join, basename, isfile, abspath, normpath, isabs +from lxml.etree import parse + +from creole import config, eosfunc +from pyeole.process import system_code +from creole.lint.parsetemplate import parse_templates +from creole.lint.normalize import is_correct +from creole.var_loader import parse_dtd +from creole.lxml_parser import parse_xml_file +from creole.config import FLATTENED_CREOLE_DIR, dtdfilename +from creole.loader import PopulateTiramisuObjects + +# variables internes aux dictionnaires +DICO_TEST_VARS = ['test_', 'tmp_'] +# variables de conteneur calculées dynamiquement +CONTAINER_VARS = ['container_path_', 'container_ip_', 'container_name_', + 'adresse_ip_ftp', 'adresse_ip_mysql', 'adresse_ip_dhcp', + 'adresse_ip_internet', 'adresse_ip_interbase', + 'adresse_ip_postgresql'] + +# faux-positifs sur les variables d'activation +EXCLUDE_ACTIVATION_VARS = ['activer_cntlm_eth0', 'activer_cntlm_eth1', + 'activer_cntlm_eth2', 'activer_cntlm_eth3', + 'activer_cntlm_eth4', 'activer_supp_proxy_eth0', + 'activer_bash_completion', 'activer_log_martian', + 'activer_dns_eth0', 'activer_ctrl_alt_suppr', + 'activer_ipv6', 'activer_courier_commun', + 'activer_web_valider_ca', 'activer_admin_passfile', + 'activer_regles_filtrage_port_source', + 'activer_ftp_anonymous_access', 'activer_ftp_access', + 'activer_pydio_local', 'activer_courier_imap_sso', + 'activer_pydio_ftp', 'activer_client_ldap', + ] + +# templates à ne pas tester par défaut +EXCLUDE_TMPL = ['/usr/share/eole/creole/distrib/named.conf', + '/usr/share/eole/creole/distrib/common-squid1.conf', + '/usr/share/eole/creole/distrib/zstats.cfg', + '/usr/share/eole/creole/distrib/hosts', + '/usr/share/eole/creole/distrib/active_tags', + ] + +# dictionnaires conservés pour compatibilité 2.3 +OLD_DICOS = ['/usr/share/eole/creole/dicos/51_gepi.xml', + '/usr/share/eole/creole/dicos/51_taskfreak.xml', + '/usr/share/eole/creole/dicos/51_wordpress.xml', + '/usr/share/eole/creole/dicos/60_roundcube.xml', + '/usr/share/eole/creole/dicos/61_ajaxplorer.xml', + '/usr/share/eole/creole/dicos/61_dokuwiki.xml', + '/usr/share/eole/creole/dicos/61_fluxbb.xml', + '/usr/share/eole/creole/dicos/61_piwigo.xml', + '/usr/share/eole/creole/dicos/51_grr.xml', + '/usr/share/eole/creole/dicos/51_cdt.xml', + '/usr/share/eole/creole/dicos/51_piwik.xml', + '/usr/share/eole/creole/dicos/51_spip.xml', + ] + +starttoken = '%' +varstarttoken = '%%' +builts = [u'ArithmeticError', u'AssertionError', u'AttributeError', + u'BaseException', u'DeprecationWarning', u'EOFError', u'Ellipsis', + u'EnvironmentError', u'Exception', u'False', u'FloatingPointError', + u'FutureWarning', u'GeneratorExit', u'IOError', u'ImportError', + u'ImportWarning', u'IndentationError', u'IndexError', u'KeyError', + u'KeyboardInterrupt', u'LookupError', u'MemoryError', u'NameError', + u'None', u'NotImplemented', u'NotImplementedError', u'OSError', + u'OverflowError', u'PendingDeprecationWarning', u'ReferenceError', + u'RuntimeError', u'RuntimeWarning', u'StandardError', + u'StopIteration', u'SyntaxError', u'SyntaxWarning', u'SystemError', + u'SystemExit', u'TabError', u'True', u'TypeError', + u'UnboundLocalError', u'UnicodeDecodeError', u'UnicodeEncodeError', + u'UnicodeError', u'UnicodeTranslateError', u'UnicodeWarning', + u'UserWarning', u'ValueError', u'Warning', u'ZeroDivisionError', + u'_', u'__debug__', u'__doc__', u'__import__', u'__name__', u'abs', + u'all', u'any', u'apply', u'basestring', u'bool', u'buffer', + u'callable', u'chr', u'classmethod', u'cmp', u'coerce', u'compile', + u'complex', u'copyright', u'credits', u'delattr', u'dict', u'dir', + u'divmod', u'enumerate', u'eval', u'execfile', u'exit', u'file', + u'filter', u'float', u'frozenset', u'getattr', u'globals', + u'hasattr', u'hash', u'help', u'hex', u'id', u'input', u'int', + u'intern', u'isinstance', u'issubclass', u'iter', u'len', + u'license', u'list', u'locals', u'long', u'map', u'max', u'min', + u'object', u'oct', u'open', u'ord', u'pow', u'property', u'quit', + u'range', u'raw_input', u'reduce', u'reload', u'repr', u'reversed', + u'round', u'set', u'setattr', u'slice', u'sorted', u'staticmethod', + u'str', u'sum', u'super', u'tuple', u'type', u'unichr', u'unicode', + u'vars', u'xrange', u'zip'] +builts.append(u'is_defined') +builts.append(u'split') +builts.append(u'lower') +cmd_client = (u'creole_client', ('get', 'get_containers')) +for func in dir(eosfunc): + if not func.startswith('_'): + builts.append(unicode(func, 'utf-8')) + +# FIXME: je sais pas où la mettre +def is_container_var(varname): + """ + variables de conteneur calculées dynamiquement + """ + for var in CONTAINER_VARS: + if varname.startswith(var): + return True + return False + +class TmplVar(): + def __init__(self, name, fd, line): + self.name = name + self.location = [] + self.add_location(fd, line) + + def add_location(self, fd, line): + fd = basename(fd) + self.location.append((fd, line+1)) + + def set_location(self, location): + self.location = location + + def get_location(self): + return self.location + +class Var(): + def __init__(self, name, description, separator, help, defaultvalue, is_slave): + self.name = name + self.description = description + self.separator = separator + self.help = help + self.defaultvalue = defaultvalue + self.is_slave = is_slave + +class CreoleLinter: + """Base class for linters, collects creole vars and templates + **has to be launched once and only once** + """ + display = True + class __impl: + warnno = 1 + warncomment = "Undefined comment" + """ Implementation of the singleton interface """ + def set_config(self, tmpl_dir_or_file=None): + if tmpl_dir_or_file != None and type(tmpl_dir_or_file) != str: + raise TypeError('tmpl_dir_or_file doit être une string') + if self.tmpl_dir_or_file != None: + sys.stderr('Tentative de redefinition de tmpl_dir_or_file') + if tmpl_dir_or_file == None: + self.tmpl_dir_or_file = config.distrib_dir + else: + if not isabs(tmpl_dir_or_file): + tmpl_dir_or_file = normpath(join(config.distrib_dir, tmpl_dir_or_file)) + if not isfile(tmpl_dir_or_file): + raise Exception("template doit etre le nom d'un template valide") + self.tmpl_dir_or_file = tmpl_dir_or_file + self.eoledirs = config.eoledirs + self.dtddir = config.dtddir + self.exclude_var = [] + self.pkgname = None + + def load_dics(self): + if self.config is None: + self._collect_vars_in_dicos() + +# def load_tmpls(self): +# if self.tmplvars == None: +# self._collect_set_vars() +# self._collect_def_vars() +# self._collect_for_vars() +# self._collect_define_vars() +# self._collect_vars_in_tmplfiles() +# + def get_dicos_name(self): + if self.config is None: + raise Exception('Dictionnaire non chargé') + dic = self.variables.keys() + dic.sort() + return dic + +# def get_dicos_files(self): +# if self.creoledic == None: +# raise Exception('Dictionnaire non chargé') +# dic = [] +# for name in self.creoledic.generic['files']: +# dic.append(basename(name['source'])) +# dic.sort() +# return dic +# +# def get_tmplvars_name(self): +# if self.tmplvars == None: +# raise Exception('Template non chargé') +# tmpl = self.tmplvars.keys() +# tmpl.sort() +# return tmpl +# +# def get_defvars_name(self): +# if self.defvars == None: +# raise Exception('Template non chargé') +# defv = self.defvars.keys() +# defv.sort() +# return defv +# +# def get_setvars_name(self): +# if self.setvars == None: +# raise Exception('Fonction non chargé') +# var = self.setvars.keys() +# var.sort() +# return var +# +# def get_forvars_name(self): +# if self.forvars == None: +# raise Exception('Fonction non chargé') +# var = self.forvars.keys() +# var.sort() +# return var +# +# def get_tmplvar(self, name): +# return self.tmplvars[name] +# +# def get_separators(self): +# return self.creoledic.get_separators() +# + def get_dico_file_names(self): + if self.eoledirs == None or self.tmpl_dir_or_file == None: + raise Exception('Utiliser la methode set_config avant') + ret = [] + for eoledir in self.eoledirs: + eoledir = abspath(eoledir) + if isfile(eoledir): + ret.append(eoledir) + else: + ret.extend(glob(join(eoledir, '*.xml'))) + return ret + + def get_dtd(self): + if self.dtddir == None: + raise Exception('Utiliser la methode set_config avant') + return join(self.dtddir, 'creole.dtd') + + def _collect_vars_in_dicos(self): + if self.eoledirs == None or self.tmpl_dir_or_file == None: + raise Exception('Utiliser la methode set_config avant') + + flattened = join(FLATTENED_CREOLE_DIR, 'flattened_creole.xml') + with file(flattened, 'r') as fhd: + xmlroot = parse(fhd).getroot() + tiramisu_objects = PopulateTiramisuObjects() + tiramisu_objects.parse_dtd(dtdfilename) + tiramisu_objects.make_tiramisu_objects(xmlroot) + self.config = tiramisu_objects.build() + + self.config.read_write() + self.config.cfgimpl_get_settings().remove('hidden') + self.config.cfgimpl_get_settings().remove('validator') + self.config.cfgimpl_get_settings().remove('disabled') + for path in self.config.creole.make_dict(): + spath = path.split('.') + vname = spath[-1] + fname = spath[0] + is_slave = False + if len(spath) == 3: + master = spath[1] + if master != vname: + is_slave = True + option = self.config.unwrap_from_path('creole.' + path) + self.variables[vname] = Var(vname, option.impl_get_information('doc', None), + option.impl_get_information('separator', ''), + option.impl_get_information('help', None), + option.impl_getdefault(), + is_slave) + if fname not in self.families: + self.families.append(fname) + + def _parse_tabs_in_dicos(self): + if self.eoledirs == None or self.tmpl_dir_or_file == None: + raise Exception('Utiliser la methode set_config avant') + tabs_in_dics = [] + fnames = [] + for directory in self.eoledirs: + if isfile(directory): + fnames.append(directory) + else: + fnames.extend(glob(join(directory, "*.xml"))) + for fname in fnames: + fh = file(fname, 'r') + content = fh.read() + if '\t' in content: + tabs_in_dics.append(fname) + fh.close() + return tabs_in_dics + + def _list_tmpl_files(self): + if isfile(self.tmpl_dir_or_file): + return [self.tmpl_dir_or_file] + ret = [] + for filename in glob(join(self.tmpl_dir_or_file, '*')): + if filename.startswith('.') or filename.endswith('~'): + continue + if filename in EXCLUDE_TMPL: + print " \\-- template desactivé : {0}".format(filename) + continue + ret.append(filename) + return ret + +# def _add_collected_var(self, dvar, var, fd, linenb): +# if dvar.has_key(var): +# dvar[var].add_location(fd=fd, line=linenb) +# else: +# dvar[var] = TmplVar(name=var, fd=fd, line=linenb) +# +# def _collect_var_in(self, dvar, var, fd, linenb, exists=False): +# not_added=True +# if exists == True: +# if self.forvars.has_key(var): +# #si deja en memoire +# if (basename(fd), linenb+1) in self.forvars[var].location: +# return +# self._add_collected_var(self.forvars, var, fd, linenb) +# not_added=False +# if self.setvars.has_key(var): +# self._add_collected_var(self.setvars, var, fd, linenb) +# not_added=False +# if self.defvars.has_key(var): +# self._add_collected_var(self.defvars, var, fd, linenb) +# not_added=False +# #test les builtsin seulement si variable +# if not_added == True and unicode(var, 'utf-8') in builts: +# #self.builtsvar.append(var) +# return +# if not_added == True: +# self._add_collected_var(dvar, var, fd, linenb) +# +# def _collect_vars_in(self, expr, dvar, fd, linenb, tvarstarttoken, +# exists=False): +# if self.unknown_client == None: +# self.unknown_client = [] +# varcreole = re.compile(tvarstarttoken+'([a-zA-Z0-9_\.{}]+)') +# varcreole2 = re.compile(tvarstarttoken+'(\w+)') +# varcreolebr = re.compile(tvarstarttoken+'{(\w+)}') +# varmulti = re.compile('(\w+)\.(\w+)') +# for var in varcreole.findall(expr): +# ret = varmulti.match(var) +# if ret != None: +# if ret.group(1) == cmd_client[0]: +# if ret.group(2) not in cmd_client[1]: +# self.unknown_client.append(TmplVar(name=ret.group(2), fd=fd, line=linenb)) +# else: +# #%%var.sousvar +# self._collect_var_in(dvar, ret.group(1), fd, linenb, exists) +# self._collect_var_in(dvar, ret.group(2), fd, linenb, exists) +# else: +# #%%var +# for var2 in varcreole2.findall(tvarstarttoken+var): +# self._collect_var_in(dvar, var2, fd, linenb, exists) +# #%%{var} +# for var2 in varcreolebr.findall(tvarstarttoken+var): +# self._collect_var_in(dvar, var2, fd, linenb, exists) +# +# def _collect_vars(self, tvars, tpattern, all_char=False, with_var=False, with_vars=True, broken=None): +# """ +# collect vars in template for a specified pattern +# +# :tvars: all collected var are store in this variable +# :tpattern: re pattern +# :broken: if set, store broken variable +# """ +# if tvars == None: +# tvars = {} +# tstarttoken = '' +# tvarstarttoken = '' +# for tmplfd in self._list_tmpl_files(): +# fh = open(tmplfd, 'r') +# lines = fh.readlines() +# length = len(lines) +# settings = False +# if tstarttoken != starttoken or \ +# tvarstarttoken != varstarttoken: +# if all_char: +# char = '(.*)' +# else: +# char = '( *)' +# pattern = re.compile(char+starttoken+tpattern) +# tstarttoken = starttoken +# tvarstarttoken = varstarttoken +# for linenb in range(length): +# line = lines[linenb] +# if line.strip() == '%compiler-settings': +# settings = True +# if settings and line.strip() == \ +# '%end compiler-settings'.strip(): +# settings = False +# if not settings: +# ret = pattern.match(line.strip()) +# if ret != None: +# expr = ret.group(2).strip() +# if with_var: +# self._collect_var_in(tvars, expr, tmplfd, linenb) +# if with_vars: +# self._collect_vars_in(expr, +# tvars, tmplfd, linenb, +# tvarstarttoken) +# len_token = len(varstarttoken) +# if broken is not None and expr.strip()[:len_token] != tvarstarttoken: +# broken.append(TmplVar( +# name=line.strip(), +# fd=tmplfd, line=linenb)) +# else: +# tline = line.split('=') +# tkey = tline[0].strip() +# if tkey == 'cheetahVarStartToken': +# tvarstarttoken = tline[1].strip() +# elif tkey == 'directiveStartToken': +# tstarttoken = tline[1].strip() +# pattern = re.compile(tstarttoken+tpattern) +# fh.close() +# return tvars +# +# def _collect_for_vars(self): +# """ +# collect all vars generate in 'for' +# """ +# self.brokenfor = [] +# self.forvars = self._collect_vars(self.forvars, 'for (.+) in (.*)', broken=self.brokenfor) +# +# def _collect_def_vars(self): +# """ +# collect all vars generate in 'def' +# """ +# self.defvars = self._collect_vars(self.defvars, 'def (.*)\((.*)\)', with_var=True) +# +# def _collect_set_vars(self): +# """ +# collect all vars generate in 'set' +# """ +# self.setvars = self._collect_vars(self.setvars, 'set (.*)=.*') +# +# def _collect_define_vars(self): +# """ +# collect all vars generate in 'def' +# """ +# self.var_with_is_defined = self._collect_vars( +# self.var_with_is_defined, +# "is_defined\(\'(\w+)\'\)", +# all_char=True, +# with_var=True, with_vars=False) +# ##FIXME pas de support de cheetahVarStartToken, ... +# #if self.var_with_is_defined == None: +# # self.var_with_is_defined = {} +# # pattern = re.compile('(.*) %sis_defined\(\'(\w+)\'\)'%varstarttoken) +# # for tmplfd in self._list_tmpl_files(): +# # fh = open(tmplfd, 'r') +# # lines = fh.readlines() +# # length = len(lines) +# # for linenb in range(length): +# # line = lines[linenb] +# # ret = pattern.match(line) +# # if ret != None: +# # self._collect_var_in(self.var_with_is_defined, ret.group(2), tmplfd, linenb) +# # fh.close() +# +# def _collect_vars_in_tmplfiles(self): +# if self.eoledirs == None or self.tmpl_dir_or_file == None: +# raise Exception('Utiliser la methode set_config avant') +# # XXX ".eolvars" is a good placeholder for var names to be kept in touch +# if self.tmplvars == None: +# self.tmplvars = {} +# for tmplfd in self._list_tmpl_files(): +# fh = open(tmplfd, 'r') +# lines = fh.readlines() +# length = len(lines) +# settings = False +# tvarstarttoken = varstarttoken +# for linenb in range(length): +# line = lines[linenb] +# if line.strip() == '%compiler-settings': +# settings = True +# if settings and line.strip() == \ +# '%end compiler-settings'.strip(): +# settings = False +# if not settings: +# self._collect_vars_in(line, self.tmplvars, tmplfd, +# linenb, tvarstarttoken, True) +# else: +# tline = line.split('=') +# tkey = tline[0].strip() +# if tkey == 'cheetahVarStartToken': +# tvarstarttoken = tline[1].strip() +# +# fh.close() +# + # storage for the instance reference + __instance = None + + def __init__(self): + """ Create singleton instance """ + # Check whether we already have an instance + + if CreoleLinter.__instance is None: + # Create and remember instance + CreoleLinter.__instance = CreoleLinter.__impl() + self.tmpl_dir_or_file = None + self.eoledirs = None + self.config = None + self.variables = {} + self.families = [] + self.tmplvars = None + self.forvars = None + self.defvars = None + self.setvars = None + self.unknown_client = None + self.brokenfor = None + self.var_with_is_defined = None + self.exclude_var = None + self.skip_var = {} + self.conflevel = 'eole' + + # Store instance reference as the only member in the handle + self.__dict__['_CreoleLinter__instance'] = CreoleLinter.__instance + + def __getattr__(self, attr): + """ Delegate access to implementation """ + return getattr(self.__instance, attr) + + def __setattr__(self, attr, value): + """ Delegate access to implementation """ + return setattr(self.__instance, attr, value) + +#class SaveItem(CreoleLinter): +# """ +# eolvars not present in the dicos +# """ +# name = 'save' +# warnno = 1 +# warncomment = "Ne pas utiliser la fonction SaveItem comme un test" +# +# def process(self): +# self.load_dics() +# if self.pkgname == None: +# raise Exception('fichier creolelint.conf incomplet (name)') +# filename = join(expanduser('~/.creolelint'), self.pkgname+'.conf') +# fh = open(filename, 'w') +# fh.write('vardico = '+str(self.get_dicos_name())+'\n') +# fh.close() +# print('fichier sauvegardé') +# +# def check(self): +# return [] +# +#class OrphansInDicosItem(CreoleLinter): +# """ +# eolvars not present in the dicos +# """ +# name = 'orphans_in_dicos' +# warnno = 8 +# warncomment = "Variable dictionnaire non utilisée dans un template" +# +# def check(self): +# self.load_dics() +# self.load_tmpls() +# +# vars_name = set(self.get_dicos_name()) +# tmplvars_name = set(self.get_tmplvars_name()) +# only_in_dicos = vars_name - tmplvars_name +# ret = [] +# skip_var = self.skip_var.get(self.name, {}) +# for var in only_in_dicos: +# if skip_var.has_key(var): +# continue +# test_start = False +# for start in DICO_TEST_VARS: +# if var.startswith(start): +# test_start = True +# break +# if not test_start: +# ret.append(self.variables[var]) +# return ret +# +#class OrphansInTmplItem(CreoleLinter): +# """ +# eolvars not present in the templates +# """ +# name = 'orphans_in_tmpl' +# warnno = 8 +# warncomment = "Variable template non présente dans le dictionnaire" +# +# def check(self): +# self.load_dics() +# self.load_tmpls() +# +# vars_name = self.get_dicos_name() +# if self.exclude_var != None: +# vars_name.extend(self.exclude_var) +# vars_name=set(vars_name) +# tmplvars_name = set(self.get_tmplvars_name()) +# only_in_tmpl = tmplvars_name - vars_name +# #remove is_defined +# is_defined_name = set(self.var_with_is_defined.keys()) +# only_in_tmpl = only_in_tmpl - is_defined_name +# set_var = set(self.get_setvars_name()) +# only_in_tmpl = only_in_tmpl - set_var +# ret = [] +# for var in only_in_tmpl: +# skipped_location = [] +# for location in self.tmplvars[var].location: +# if self.skip_var.has_key(self.name) and self.skip_var[self.name].has_key(var): +# if not location in self.skip_var[self.name][var]: +# skipped_location.append(location) +# else: +# skipped_location.append(location) +# if skipped_location != []: +# tmplvar = TmplVar(var, '', 0) +# tmplvar.set_location(skipped_location) +# ret.append(tmplvar) +# #results.append(self.tmplvars[var]) +# return ret +# +#class OrphansDefItem(CreoleLinter): +# name = 'orphans_def' +# warnno = 7 +# warncomment = "Fonction définie mais non utilisée" +# +# def check(self): +# self.load_tmpls() +# results = [] +# for defvar in self.get_defvars_name(): +# defname = {} +# for filedesc, linenb in self.defvars[defvar].location: +# if not defname.has_key((defvar, filedesc)): +# defname[(defvar, filedesc)]=linenb +# else: +# defname[(defvar, filedesc)]="exists" +# for defvar, filedesc in defname.keys(): +# if defname[(defvar, filedesc)] != "exists": +# results.append(TmplVar(name=defvar, fd=filedesc, line=defname[(defvar, filedesc)])) +# +# return results +# +#class OrphansSetItem(CreoleLinter): +# name = 'orphans_set' +# warnno = 7 +# warncomment = "Variable définie dans le template mais non utilisée" +# +# def check(self): +# self.load_tmpls() +# results = [] +# tmpl_vars = set(self.get_tmplvars_name()) +# for setvar in self.get_setvars_name(): +# setname = {} +# for filedesc, linenb in self.setvars[setvar].location: +# if setname.has_key((setvar, filedesc)) == False: +# setname[(setvar, filedesc)]=linenb +# else: +# setname[(setvar, filedesc)]="exists" +# +# for setvar, filedesc in setname.keys(): +# if setname[(setvar, filedesc)] != "exists": +# results.append(TmplVar(name=setvar, fd=filedesc, line=setname[(setvar, filedesc)])) +# +# return results +# +#class OrphansForItem(CreoleLinter): +# name = 'orphans_for' +# warnno = 7 +# warncomment = "Variable définie dans une boucle mais non utilisée" +# +# def check(self): +# self.load_tmpls() +# results = [] +# for forvar in self.get_forvars_name(): +# forname = {} +# for filedesc, linenb in self.forvars[forvar].location: +# if forname.has_key((forvar, filedesc)) == False: +# forname[(forvar, filedesc)]=linenb +# else: +# forname[(forvar, filedesc)]="exists" +# +# for forvar, filedesc in forname.keys(): +# if forname[(forvar, filedesc)] != "exists": +# results.append(TmplVar(name=forvar, fd=filedesc, line=forname[(forvar, filedesc)])) +# return results +# +#class OrphansDicosFilesItem(CreoleLinter): +# """ +# """ +# name = 'orphans_dicos_files' +# warnno = 1 +# warncomment = "Template déclaré dans le dicos inexistant" +# +# def check(self): +# self.load_dics() +# +# dicos_files = [] +# for filen in self.get_dicos_files(): +# dicos_files.append(basename(filen)) +# dicos_files = set(dicos_files) +# tmpl_files = [] +# for filen in self._list_tmpl_files(): +# tmpl_files.append(unicode(basename(filen), 'utf-8')) +# tmpl_files=set(tmpl_files) +# orphans = dicos_files - tmpl_files +# ret = [] +# for var in orphans: +# if self.skip_var.has_key(self.name) and not self.skip_var[self.name].has_key(var): +# ret.append(var) +# else: +# ret.append(var) +# +# return ret +# +#class OrphansTmplFilesItem(CreoleLinter): +# """ +# """ +# name = 'orphans_tmpl_files' +# warnno = 1 +# warncomment = "Template non déclaré dans le dicos" +# +# def check(self): +# self.load_dics() +# +# dicos_files = [] +# for filen in self.get_dicos_files(): +# dicos_files.append(basename(filen)) +# dicos_files = set(dicos_files) +# tmpl_files = [] +# for filen in self._list_tmpl_files(): +# tmpl_files.append(unicode(basename(filen), 'utf-8')) +# tmpl_files=set(tmpl_files) +# return tmpl_files - dicos_files +# +class WrongDicosNameItem(CreoleLinter): + name = 'wrong_dicos_name' + warnno = 6 + warncomment = "Dictionnaire avec un nom invalide" + + def check(self): + if self.conflevel == 'common': + pattern = '(0' + elif self.conflevel == 'conf': + pattern = '(1' + elif self.conflevel == 'eole': + pattern = '(2' + else: + pattern = '([3-9]' + pattern += '[0-9]_[a-z0-9_]+)' + cpattern = re.compile(pattern) + ret = [] + for filename in self.get_dico_file_names(): + name = basename(filename) + if cpattern.match(name) == None: + ret.append(name) + return ret + +class HiddenIfInDicosItem(CreoleLinter): + name = 'hidden_if_in_dicos' + warnno = 5 + warncomment = "Dictionnaire contenant un hidden_if_*" + + def check(self): + ret = [] + dtd = parse_dtd(self.get_dtd()) + for filename in self.get_dico_file_names(): + if filename in OLD_DICOS: + continue + parse = parse_xml_file(filename, dtd, parse_all=False) + for cond in parse['conditions'].values(): + if cond[0]['name'].startswith('hidden_if_'): + ret.append(filename) + break + return ret + +class ConditionWithoutTarget(CreoleLinter): + name = 'condition_without_target' + warnno = 5 + warncomment = "Dictionnaire contenant une condition sans target" + + def check(self): + ret = [] + + dtd = parse_dtd(self.get_dtd()) + for filename in self.get_dico_file_names(): + if filename in OLD_DICOS: + continue + parse = parse_xml_file(filename, dtd, parse_all=False) + for cond in parse['conditions'].values(): + for con in cond: + if con['family'] == con['list'] == con['variable'] == []: + ret.append(filename) + break + return ret + +class ObligatoireInDicosItem(CreoleLinter): + name = 'obligatoire_in_dicos' + warnno = 5 + warncomment = "Dictionnaire contenant un check \"obligatoire\"" + + def check(self): + ret = [] + dtd = parse_dtd(self.get_dtd()) + for filename in self.get_dico_file_names(): + if filename in OLD_DICOS: + continue + parse = parse_xml_file(filename, dtd, parse_all=False) + for cond in parse['checks'].values(): + if cond[0][0] == 'obligatoire': + ret.append(filename) + break + return ret + + +class FamilyWithoutHelp(CreoleLinter): + name = 'family_without_help' + warnno = 5 + warncomment = "Famille sans balise d'aide" + + def check(self): + self.load_dics() + ret = [] + for grp in self.config.creole.iter_groups(): + doc = grp[1].cfgimpl_get_description().impl_get_information('help', None) + if doc is None: + ret.append(grp[0]) + return ret + +class FamilyWithoutIcon(CreoleLinter): + name = 'family_without_icon' + warnno = 5 + warncomment = "Famille sans icône spécifique" + + def check(self): + self.load_dics() + ret = [] + for grp in self.config.creole.iter_groups(): + if grp[1].cfgimpl_get_description().impl_get_information('icon') is None: + ret.append(grp[0]) + return ret + +#class DefineItem(CreoleLinter): +# """ +# check for syntaxes +# """ +# name = 'define' +# warnno = 4 +# warncomment = "Redéfinition d'un variable d'un dictionnaire" +# +# def check(self): +# """ +# verifie si une variable définie est une variable du dictionnaire +# """ +# self.load_dics() +# self.load_tmpls() +# dicos = set(self.get_dicos_name()) +# defv = set(self.get_defvars_name()) +# ret=[] +# for var in defv & dicos: +# ret.append(self.defvars[var]) +# return ret +# +class BuiltinsItem(CreoleLinter): + """ + verifier si une variable de dico n'est pas dans l'espace de nommage + """ + name = 'builtins' + warnno = 4 + warncomment = "Variable identitique à une fonction python" + + def check(self): + self.load_dics() +# self.load_tmpls() + ret = [] + #dans le dictionnaire + for var in set(builts) & set(self.get_dicos_name()): + ret.append(self.variables[var]) +# #dans les variables de template +# for var in set(builts) & set(self.get_tmplvars_name()): +# ret.append(self.tmplvars[var]) +# #dans les boucles for +# for var in set(builts) & set(self.get_forvars_name()): +# ret.append(self.forvars[var]) +# #dans la definition de variable dans un template +# for var in set(builts) & set(self.get_setvars_name()): +# ret.append(self.setvars[var]) +# #dans les noms de fonction +# for var in set(builts) & set(self.get_defvars_name()): +# ret.append(self.defvars[var]) + return ret + +#class SyntaxForItem(CreoleLinter): +# """ +# verifie la syntaxe de la ligne for +# """ +# name = 'syntax_for' +# warnno = 1 +# warncomment = "Syntaxe de la ligne for incorrect" +# def check(self): +# self.load_tmpls() +# return self.brokenfor +# +#class SyntaxVarItem(CreoleLinter): +# """ +# verifie les variables suivant la syntaxe de pattern +# """ +# name = 'syntax_var' +# pattern = '([a-z0-9][a-z0-9]+_[a-z0-9_]+)' +# warnno = 6 +# warncomment = "La variable ne respecte pas la regexp %s" % pattern +# +# def check(self): +# cpattern = re.compile(self.pattern) +# self.load_dics() +# self.load_tmpls() +# ret=[] +# #dans le dictionnaire +# for var in self.get_dicos_name(): +# if cpattern.match(var) == None: +# ret.append(self.variables[var]) +# #dans les variables de template +# for var in self.get_tmplvars_name(): +# if cpattern.match(var) == None: +# skipped_location = [] +# for location in self.tmplvars[var].location: +# if self.skip_var.has_key(self.name) and self.skip_var[self.name].has_key(var): +# if not location in self.skip_var[self.name][var]: +# skipped_location.append(location) +# else: +# skipped_location.append(location) +# if skipped_location != []: +# tmplvar = TmplVar(var, '', 0) +# tmplvar.set_location(skipped_location) +# ret.append(tmplvar) +# #ret.append(self.tmplvars[var]) +# #dans les boucles for +# for var in self.get_forvars_name(): +# if cpattern.match(var) == None: +# ret.append(self.forvars[var]) +# #dans la definition de variable dans un template +# for var in self.get_setvars_name(): +# if cpattern.match(var) == None: +# ret.append(self.setvars[var]) +# return ret +# +#class ForbiddenTemplateVarItem(CreoleLinter): +# """ +# vérifie la présence des noms de variable interdits dans les templates +# """ +# name = 'syntax_var2' +# warnno = 6 +# warncomment = "Nom de variable interdit dans un template" +# +# def check(self): +# #self.load_dics() +# self.load_tmpls() +# ret=[] +# #dans les variables de template +# for var in self.get_tmplvars_name(): +# for start in DICO_TEST_VARS: +# if var.startswith(start): +# ret.append(var) +# break +# return ret +# +#class SyntaxFunctionItem(CreoleLinter): +# """ +# verifie les fonctions suivant la syntaxe de pattern +# """ +# name = 'syntax_function' +# pattern = '([a-z0-9][a-z0-9]+_[a-z0-9_]+)' +# warnno = 6 +# warncomment = "La fonction ne respecte pas la regexp %s" % pattern +# +# def check(self): +# cpattern = re.compile(self.pattern) +# self.load_tmpls() +# ret=[] +# #dans les noms de fonction +# for var in self.get_defvars_name(): +# if cpattern.match(var) == None: +# ret.append(self.defvars[var]) +# return ret +# +#class OrphansVarHelpItem(CreoleLinter): +# name = 'orphans_var_help' +# warnno = 3 +# warncomment = "Aide définie dans le dictionnaire pour une variable inexistante" +# +# def check(self): +# self.load_dics() +# vars_name = set(self.get_dicos_name()) +# vars_help = set(self.creoledic.get_helps()['variables'].keys()) +# #print vars_help +# only_in_help = vars_help - vars_name +# results = [] +# for tmpl in only_in_help: +# results.append(tmpl) +# return results + +#class OrphansFamHelpItem(CreoleLinter): +# name = 'orphans_fam_help' +# warnno = 3 +# warncomment = "Aide définie dans le dictionnaire pour une famille inexistante" +# +# def check(self): +# self.load_dics() +# #FIXME +# vars_name = set(self.families) +# vars_help = set(self.creoledic.get_helps()['families'].keys()) +# only_in_help = vars_help - vars_name +# results = [] +# for tmpl in only_in_help: +# results.append(tmpl) +# return results +# +class ValidVarLabelItem(CreoleLinter): + name = 'valid_var_label' + warnno = 5 + warncomment = "Libellé de variable non valide dans un dictionnaire" + + def check(self): + self.load_dics() + ret = [] + for var in self.variables.values(): + if not is_container_var(var.name): + ret.extend(is_correct(var.description, var.name)) + return ret + +class ActivationVarWithoutHelp(CreoleLinter): + name = 'activation_var_without_help' + warnno = 5 + warncomment = "Variable d'activation sans balise d'aide" + + def check(self): + self.load_dics() + ret = [] + for var, var_obj in self.variables.items(): + if var.startswith('activer_') and var not in EXCLUDE_ACTIVATION_VARS: + if var_obj.help is None: + ret.append(var) + return ret + +class ValidSeparatorLabelItem(CreoleLinter): + name = 'valid_separator_label' + warnno = 5 + warncomment = "Libellé de séparateur non valide dans un dictionnaire" + + def check(self): + self.load_dics() + ret = [] + + for var, var_obj in self.variables.items(): + if var_obj.separator == '': + #FIXME: variables de conteneur dynamiques + continue + ret.extend(is_correct(var_obj.separator[0], var)) + return ret + +class ValidHelpLabelItem(CreoleLinter): + name = 'valid_help_label' + warnno = 5 + warncomment = "Libellé d'aide non valide dans un dictionnaire" + + def check(self): + self.load_dics() + ret = [] + for var, var_obj in self.variables.items(): + # help/variable + ret.extend(is_correct(var_obj.help, var)) + for grp in self.config.creole.iter_groups(): + # help/family + ret.extend(is_correct(grp[1].cfgimpl_get_description().impl_get_information('help', ''), + grp[0], family=True)) + return ret + +class ValidSlaveValue(CreoleLinter): + name = 'valid_slave_value' + warnno = 5 + warncomment = "Variable esclave avec une liste en valeur défaut" + + def check(self): + self.load_dics() + ret = [] + for var, var_obj in self.variables.items(): + if var_obj.is_slave: + if len(var_obj.defaultvalue) > 1: + ret.append(var) + return ret + +##class ValidCheckEnumOuiNon(CreoleLinter): +## name = 'valid_check_enum_ouinon' +## warnno = 6 +## warncomment = "Variable avec un valid_enum à oui/non au lieu du type oui/non" +## +## def check(self): +## ret = [] +## for var, content in self.creoledic.variables.items(): +## print content +## if str(type(content)) != "": +## for check in content.choices: +## if check[0] == u'valid_enum': +## for valid_enum in check[1]: +## if valid_enum['value'].startswith('['): +## eval_valid_enum = eval(valid_enum['value']) +## if set(eval_valid_enum) == set(['non', 'oui']): +## ret.append(var) +## return ret +# +##class ValidCheckEnumOnOff(CreoleLinter): +## name = 'valid_check_enum_onoff' +## warnno = 6 +## warncomment = "Variable avec un valid_enum à on/off au lieu du type on/off" +## +## def check(self): +## ret = [] +## for var, content in self.creoledic.variables.items(): +## if str(type(content)) != "": +## for check in content.checks: +## if check[0] == u'valid_enum': +## for valid_enum in check[1]: +## if valid_enum['value'].startswith('['): +## eval_valid_enum = eval(valid_enum['value']) +## if set(eval_valid_enum) == set(['on', 'off']): +## ret.append(var) +## return ret +# +class TabsInDicosItem(CreoleLinter): + name = 'tabs_in_dicos' + warnno = 5 + warncomment = "Tabulation dans le dictionnaire au lieu de 4 espaces" + + def check(self): + return self._parse_tabs_in_dicos() + +#class ValidClientOption(CreoleLinter): +# name = 'valid_client_option' +# warnno = 6 +# warncomment = "Option inconnu pour %s" % cmd_client[0] +# +# def check(self): +# self.load_tmpls() +# return self.unknown_client + +class ValidParseTmpl(CreoleLinter): + name = 'valid_parse_tmpl' + warnno = 1 + warncomment = "Template Non valide" + display = False + + def check(self): + parse_templates(self._list_tmpl_files()) + return [] + + +class ValidDTDItem(CreoleLinter): + name = 'valid_dtd' + warnno = 1 + warncomment = "DTD Non valide" + display = False + + def check(self): + dtd = self.get_dtd() + for filename in self.get_dico_file_names(): + system_code(['xmllint', '--noout', '--dtdvalid', dtd, filename]) + return [] + +class OldFwFile(CreoleLinter): + name = 'old_fw_file' + warnno = 5 + warncomment = "Ancien fichier eole-firewall présent sur le serveur" + + def check(self): + fw_templates = '/usr/share/eole/creole/distrib/*.fw' + fw_files = '/usr/share/eole/firewall/*.fw' + return glob(fw_files) + glob(fw_templates) + +def validate(keyword, ansi, tmpl): + globs = globals() + classitem = None + for cls in globs: + if cls.startswith('_') and type(globs[cls])!=types.ClassType and cls == 'CreoleLinter' and cls == 'TmplVar': + continue + if hasattr(globs[cls], 'name'): + if globs[cls].name == keyword: + classitem = globs[cls] + break + if classitem == None: + raise Exception('test %s inconnu'%keyword) + cl = classitem() + if cl.eoledirs == None: + cl.set_config(tmpl_dir_or_file=tmpl) + ansi.process(cl) + diff --git a/creole/lint/entities.py b/creole/lint/entities.py new file mode 100644 index 0000000..481c690 --- /dev/null +++ b/creole/lint/entities.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- + +modules = [ + 'Zéphir', + 'Eolebase', + 'Amon', + 'Sentinelle', + 'Sphynx', + 'Scribe', + 'Eclair', + 'Horus', + 'ZéphirLog', + 'PreludeManager', + 'AmonEcole', + 'EoleVZ', + 'Seshat', + 'ClientScribe', + 'ClientHorus'] + +projets = [ + ' EOLE', # confusion avec eole-annuaire + 'EAD', + 'ead-web', + 'ead-server', + 'frontend', + 'backend', + 'Era', + 'ESU', + 'AGRIATES', + 'RACINE-AGRIATES', + 'Samba', + 'Creole', + 'GenConfig', + 'EoleDB', + 'EoleSSO', + 'Zéphir', + "application Zéphir", + "Zéphir-web", + ] + +os_logiciels_protocoles = [ + 'Linux', + 'GNU/Linux', + 'Ubuntu', + 'Unix', + 'Windows', + 'Microsoft', +# 'ALIAS', + 'BlockInput', + 'Epreuve@SSR', + 'SSH', + 'OpenSSH', + 'DHCP', + 'DHCPd', + 'ClamAV', + 'NuFW', + 'NuWinC', + 'Nuauth', + 'DansGuardian', + 'Bacula', + 'Bareos', + 'TCP', + 'UDP', + 'ICMP', + 'IP', + ' IPsec', # confusion avec la commande ipsec + 'strongSwan', + 'DMZ', + 'FTP', + 'SMB', + 'XML', + 'XML-RPC', + ' SSO', +# 'CAS', + 'SAML', + 'Sympa', + 'MySQL', + 'SpamAssassin', + 'web', + 'phpMyAdmin', + 'Grr', + 'Gibii', + 'Gepi', + 'SPIP-EVA', + 'Envole', + 'Envole 2', + 'WebShare', + ' CSS', # confusion avec .css + 'CUPS', + 'OpenOffice.org', + 'GDM', + 'client léger', + 'client lourd', + 'OpenLDAP', + 'ProFTPD', + 'Vim', + 'Controle-vnc', + 'BE1D', + 'RVP', + 'PostgreSQL', + 'Squid', + 'NUT', + 'PPPoE', + 'VLAN', + 'SSL', + 'Nginx', + 'reverse proxy', + 'SquirrelMail', + 'LDAP', + 'FreeRADIUS', + 'LightSquid', + 'SARG', + 'iptables', + 'Netfilter', + 'POSH', + 'InterBase', + 'OCS', + ] + +divers = [ + 'Éducation nationale', + 'Internet', + 'intranet', + 'pare-feu', + 'anti-virus', + 'anti-spam', + 'USB', + 'relai', +] + +entities = modules + projets + os_logiciels_protocoles + divers + diff --git a/creole/lint/error.py b/creole/lint/error.py new file mode 100755 index 0000000..c0a4271 --- /dev/null +++ b/creole/lint/error.py @@ -0,0 +1,82 @@ +"""errno-specific classes""" + +import sys, os, errornb + +class Error(EnvironmentError): + def __repr__(self): + return "%s.%s %r: %s " %(self.__class__.__module__, + self.__class__.__name__, + self.__class__.__doc__, + " ".join(map(str, self.args)), + #repr(self.args) + ) + + def __str__(self): + s = "[%s]: %s" %(self.__class__.__doc__, + " ".join(map(str, self.args)), + ) + return s + +#FIXME set the different error better suited than errno +_winerrnomap = { + 2: errsymb.ENOENT, + 3: errsymb.ENOENT, + 17: errsymb.EEXIST, + 22: errsymb.ENOTDIR, + 267: errsymb.ENOTDIR, + 5: errsymb.EACCES, # anything better? +} + +class ErrorMaker(object): + """ lazily provides Exception classes for each possible POSIX errno + (as defined per the 'errno' module). All such instances + subclass EnvironmentError. + """ + Error = Error + _errno2class = {} + + def __getattr__(self, name): + eno = getattr(errno, name) + cls = self._geterrnoclass(eno) + setattr(self, name, cls) + return cls + + def _geterrnoclass(self, eno): + try: + return self._errno2class[eno] + except KeyError: + clsname = errno.errorcode.get(eno, "UnknownErrno%d" %(eno,)) + errorcls = type(Error)(clsname, (Error,), + {'__module__':'py.error', + '__doc__': os.strerror(eno)}) + self._errno2class[eno] = errorcls + return errorcls + + def checked_call(self, func, *args): + """ call a function and raise an errno-exception if applicable. """ + __tracebackhide__ = True + try: + return func(*args) + except self.Error: + raise + except EnvironmentError: + cls, value, tb = sys.exc_info() + if not hasattr(value, 'errno'): + raise + __tracebackhide__ = False + errno = value.errno + try: + if not isinstance(value, WindowsError): + raise NameError + except NameError: + # we are not on Windows, or we got a proper OSError + cls = self._geterrnoclass(errno) + else: + try: + cls = self._geterrnoclass(_winerrnomap[errno]) + except KeyError: + raise value + raise cls("%s%r" % (func.__name__, args)) + __tracebackhide__ = True + +error = ErrorMaker() diff --git a/creole/lint/normalize.py b/creole/lint/normalize.py new file mode 100644 index 0000000..1c694a2 --- /dev/null +++ b/creole/lint/normalize.py @@ -0,0 +1,76 @@ +# coding: utf-8 +import re +import unicodedata +from entities import entities + +# ______________________________________________________________________________ + +ENCODING = 'utf-8' + +def strip_accents(string): + return unicodedata.normalize('NFKD', unicode(string, ENCODING) + ).encode('ASCII', 'ignore') + +def normalize_entities(): + """ + enleve les accents de la liste des entites + minuscules + :return: entities normalisé + """ + norm_entities = [] + for entitie in entities: + norm_entitie = strip_accents(entitie).lower() + norm_entities.append(norm_entitie) + return norm_entities + +NORM_ENTITIES = normalize_entities() + +# ______________________________________________________________________________ + +def parse_string(text): + """ + enlève les accents d'un texte + """ +# libelle = strip_accents(text) + words = re.findall('([a-zA-Zéèàùêôëö_]+)', text) + return words + +def is_in_entities(text): + """ + donne l'index dans entities du texte + """ + norm_text = text.lower() + index = None + if norm_text in NORM_ENTITIES: + index = NORM_ENTITIES.index(norm_text) + return index + +def is_correct(libelle, name, family=False): + if libelle is not None and type(libelle) != str: + libelle = unicode.encode(libelle, ENCODING) + ret = [] + if libelle == '' or libelle is None: + return ret + if libelle[0].islower(): + #FIXME: faux positifs connus + if not libelle.startswith('ejabberd') and \ + not libelle.startswith('phpMyAdmin'): + ret.append('%%%%%s : phrase sans majuscule'%name) + for text in parse_string(libelle): + text_index = is_in_entities(text) + if not text_index == None: + if str(text) != str(entities[text_index]): + #FIXME: faux positifs connus + if 'ipsec.conf' in libelle or 'test-rvp' in libelle \ + or 'bareos-' in libelle \ + or 'bacula-' in libelle \ + or '/var/log/zephir' in libelle \ + or 'exemple : eolebase' in libelle: + continue + ent = str(unicode.encode((unicode(entities[text_index], ENCODING)), ENCODING)) + if family: + ret.append('famille [%s] : %s => %s' % (str(name), text, ent)) + else: + ret.append('%%%%%s : %s => %s' % (str(name), text, ent)) + return ret +# ______________________________________________________________________________ + diff --git a/creole/lint/parsetemplate.py b/creole/lint/parsetemplate.py new file mode 100644 index 0000000..ad8327a --- /dev/null +++ b/creole/lint/parsetemplate.py @@ -0,0 +1,660 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import sys +from os.path import basename +from creole.loader import creole_loader +from creole.client import CreoleClient +from creole.template import CreoleGet, IsDefined, CreoleTemplateEngine, CreoleMaster +from creole import eosfunc +from tiramisu.option import * +from tiramisu import Config +from tiramisu.error import ConfigError, PropertiesOptionError, \ + RequirementError, ValueWarning +from Cheetah import Parser, Compiler +from Cheetah.Template import Template +from Cheetah.NameMapper import NotFound +from pyeole.ansiprint import print_red +from creole.eosfunc import valid_regexp +from Cheetah.Unspecified import Unspecified +import warnings + + +DEBUG = False +#DEBUG = True + + +client = CreoleClient() +compilerSettings = {'directiveStartToken' : u'%', + 'cheetahVarStartToken' : u'%%', 'EOLSlurpToken' : u'%', + 'PSPStartToken' : u'µ' * 10, 'PSPEndToken' : u'µ' * 10, + 'commentStartToken' : u'µ' * 10, 'commentEndToken' : u'µ' * 10, + 'multiLineCommentStartToken' : u'µ' * 10, + 'multiLineCommentEndToken' : u'µ' * 10} + +#======================= CHEETAH ======================= +# This class is used to retrieve all template vars +#true_HighLevelParser = Parser._HighLevelParser +global cl_chunks, cl_vars +cl_chunks = set() +cl_vars = set() +class cl_Parser(Parser.Parser): + + def getCheetahVarNameChunks(self, *args, **kwargs): + global cl_chunks + chunks = super(cl_Parser, self).getCheetahVarNameChunks(*args, **kwargs) + for chunk in chunks: + #if false, it's internal variable + if chunk[1]: + name = chunk[0] + #remove master if master/slave and add force adding master + if '.' in name: + cl_chunks.add(name.split('.')[-1]) + cl_chunks.add(name.split('.')[0]) + else: + cl_chunks.add(name) + return chunks + + def getCheetahVar(self, *args, **kwargs): + global cl_vars + var = super(cl_Parser, self).getCheetahVar(*args, **kwargs) + if not var.startswith(u'VFFSL('): + cl_vars.add(var) + return var + +def getVars(): + global cl_chunks, cl_vars + #retrieve all calculated vars + ret = list(cl_chunks - cl_vars) + cl_chunks = set() + cl_vars = set() + return ret + +class CompilerGetVars(Compiler.ModuleCompiler): + parserClass = cl_Parser + + +true_compile = Template.compile +@classmethod +def cl_compile(kls, *args, **kwargs): + kwargs['compilerClass'] = CompilerGetVars + kwargs['useCache'] = False + return true_compile(*args, **kwargs) +Template.compile = cl_compile + +def CompilerGetVar(varName, default=Unspecified): + #remplace Cheetah's getVar function + #this function permite to known variable if getVar is used + if varName.startswith('%%'): + raise Exception('varname should not start with %% {0}'.format(varName)) + global extra_vars, config + config.read_only() + try: + option = config.creole.find_first(byname=varName) + path = config.cfgimpl_get_description().impl_get_path_by_opt(option) + value = getattr(config, path) + except (AttributeError, ConfigError): + try: + option = config.creole.find_first(byname=varName, check_properties=False) + path = config.cfgimpl_get_description().impl_get_path_by_opt(option) + #populate_mandatory(config, option, path, raise_propertyerror=True) + config.read_write() + populate_mandatories() + config.read_only() + value = getattr(config, path) + except (AttributeError, RequirementError), err: + config.read_only() + #support default value + if default != Unspecified: + return default + else: + raise AttributeError('option:', varName, ':', err) + except PropertiesOptionError as err: + if default != Unspecified: + return default + else: + raise err + except Exception as err: + config.read_only() + raise err + except Exception as err: + config.read_only() + raise err + lpath = '.'.join(path.split('.')[2:]) + dico = {lpath: value} + engine = CreoleTemplateEngine(force_values=dico) + name = path.split('.')[-1] + extra_vars[option] = name + if "." in lpath: + spath = lpath.split('.') + if spath[0] == spath[1]: + ret = engine.creole_variables_dict[name] + else: + ret = engine.creole_variables_dict[spath[0]].slave[spath[1]] + else: + ret = engine.creole_variables_dict[name] + return ret + +def CompilerGetattr(creolemaster, name, default=None): + if not isinstance(creolemaster, CreoleMaster): + raise Exception('creolemaster must be CreoleMaster, not {0}'.format(type(creolemaster))) + if name not in creolemaster.slave: + #FIXME assume name is slave? + value = CompilerGetVar(name, default) + if creolemaster._index is not None: + value = value[creolemaster._index] + creolemaster.add_slave(name, value) + return getattr(creolemaster, name, default) + +#======================= EOSFUNC ======================= +eos = {} +for func in dir(eosfunc): + if not func.startswith('_'): + eos[func] = getattr(eosfunc, func) + +#======================= CONFIG ======================= +def populate_mandatory(config, option, path, raise_propertyerror=False): + def _build_network(path): + for num in range(0, 4): + if path.startswith('creole.interface_{0}'.format(num)): + return num + #si il y a un test de consistence de type _cons_in_network (l'IP doit être dans un network défini) + #on utilise le réseau de ce network #10714 + if getattr(option, '_consistencies', None) is not None: + for const in option._consistencies: + if const[0] == '_cons_in_network': + try: + opt = const[1][1] + path = config.cfgimpl_get_description().impl_get_path_by_opt(opt) + val = config.getattr(path, force_permissive=True) + if isinstance(val, list): + val = val[0] + return val.split('.')[2] + except IndexError: + pass + return 5 + def _build_ip(path): + if path.endswith('_fichier_link'): + return 3 + elif path.endswith('_proxy_link'): + return 2 + else: + #ne pas retourner la même valeur si elle est censé être différente + if getattr(option, '_consistencies', None) is not None: + for const in option._consistencies: + if const[0] == '_cons_not_equal': + return 4 + + return 1 + if option.impl_getname().startswith('nom_carte_eth'): + value = unicode(option.impl_getname()) + elif isinstance(option, UnicodeOption): + value = u'value' + elif isinstance(option, IPOption): + value = u'192.168.{0}.{1}'.format(_build_network(path), _build_ip(path)) + elif isinstance(option, NetworkOption): + value = u'192.168.{0}.0'.format(_build_network(path)) + elif isinstance(option, NetmaskOption): + value = u'255.255.255.0' + elif isinstance(option, BroadcastOption): + value = u'192.168.{0}.255'.format(_build_network(path)) + elif isinstance(option, EmailOption): + value = u'foo@bar.com' + elif isinstance(option, URLOption): + value = u'http://foo.com/bar' + elif isinstance(option, DomainnameOption): + allow_without_dot = option._get_extra('_allow_without_dot') + o_type = option._get_extra('_dom_type') + if option._name == 'smb_workgroup': + value = u'othervalue' + elif o_type in ['netbios', 'hostname']: + value = u'value' + else: + value = u'value.lan' + elif isinstance(option, FilenameOption): + value = u'/tmp/foo' + elif isinstance(option, ChoiceOption): + #FIXME devrait le faire tout seul non ? + value = option.impl_get_values(config)[0] + elif isinstance(option, IntOption): + value = 1 + elif isinstance(option, PortOption): + value = 80 + elif isinstance(option, DomainnameOption): + value = 'foo.com' + elif isinstance(option, UsernameOption): + value = 'toto' + elif isinstance(option, PasswordOption): + value = 'P@ssWord' + else: + raise Exception('the Tiramisu type {0} is not supported by CreoleLint (variable : {1})'.format(type(option), path)) + validator = option.impl_get_validator() + if validator is not None and validator[0] == valid_regexp: + regexp = validator[1][''][0] + # génération d'une "value" valide + # en cas de valid_regexp sans valeur par défaut + if regexp == u'^[A-Z][0-9]$': + value = u'A1' + elif option._name == 'additional_repository_source': + # variable avec expression (très) spécifique #20291 + value = u"deb http://test dist" + elif not regexp.startswith(u'^[a-z0-9]') and regexp.startswith('^'): + value = regexp[1:] + if option.impl_is_multi(): + if option.impl_is_master_slaves('slave'): + #slave should have same length as master + masterpath = '.'.join(path.split('.')[:-1]+[path.split('.')[-2]]) + try: + len_master = len(getattr(config, masterpath)) + val = [] + for i in range(0, len_master): + val.append(value) + value = val + except: + value = [value] + else: + value = [value] + try: + config.setattr(path, value, force_permissive=True) + except ValueError, err: + msg = str('error for {0} type {1}: {2}'.format(path, type(option), err)) + raise Exception(msg) + except PropertiesOptionError, err: + if 'frozen' not in err.proptype: + if raise_propertyerror: + raise err + msg = str('error for {0} type {1}: {2}'.format(path, type(option), err)) + raise Exception(msg) + + +class Reload(Exception): + pass + + +class Check_Template: + + def __init__(self, template_name): + self.all_requires = {} + self.current_opt = {} + self.od_list = {} + global extra_vars + #reinit extra_vars + extra_vars = {} + self.old_dico = [] + self.current_var = [] + self.ori_options = [] + self.file_path = None + self.template_name = template_name + self.current_container = client.get_container_infos('mail') + self.tmpl = None + self.is_tmpl = False + self.filename_ok = False + + + def populate_requires(self, option, path, force=False): + def _parse_requires(_option): + o_requires = _option.impl_getrequires() + if o_requires is not None: + for requires in o_requires: + for require in requires: + opt_ = require[0] + path_ = config.cfgimpl_get_description().impl_get_path_by_opt(opt_) + self.populate_requires(opt_, path_, force=True) + if not force and not path.startswith('creole.'): + return + if option in self.current_opt: + return + o_requires = option.impl_getrequires() + if o_requires is not None: + for requires in o_requires: + for require in requires: + if require[0].impl_is_master_slaves('slave'): + path_ = config.cfgimpl_get_description().impl_get_path_by_opt(require[0]) + s_path = path_.split('.') + master_path = 'creole.' + s_path[1] + '.' + s_path[2] + '.' + s_path[2] + try: + opt_master = config.unwrap_from_path(master_path) + config.cfgimpl_get_settings().remove('everything_frozen') + populate_mandatory(config, opt_master, master_path) + except: + pass + self.all_requires.setdefault(option, []).append(require[0]) + if isinstance(option, OptionDescription): + self.od_list[path] = option + if force and not option._name in self.current_var: + self.current_var.append(option._name) + if option._name in self.current_var or not path.startswith('creole.'): + if not isinstance(option, OptionDescription): + if path.startswith('creole.'): + self.current_opt[option] = '.'.join(path.split('.')[1:]) + else: + self.current_opt[option] = None + _parse_requires(option) + #requires could be in parent's too + opath = '' + for parent in path.split('.')[:-1]: + opath += parent + if opath in self.od_list: + desc = self.od_list[opath] + self.current_opt[desc] = None + _parse_requires(desc) + opath += '.' + try: + if option._callback is not None: + for params in option._callback[1].values(): + for param in params: + if isinstance(param, tuple): + opt = param[0] + path = config.cfgimpl_get_description().impl_get_path_by_opt(opt) + self.populate_requires(opt, path, force=True) + except (AttributeError, KeyError): + pass + + def read_write(self): + config.read_write() + config.cfgimpl_get_settings().remove('disabled') + config.cfgimpl_get_settings().remove('hidden') + config.cfgimpl_get_settings().remove('frozen') + + def change_value(self, path, value, multi, parse_message, option): + self.read_write() + config.cfgimpl_get_settings()[option].remove('force_default_on_freeze') + if multi: + if option.impl_is_master_slaves('slave'): + s_path = path.split('.') + master_path = s_path[0] + '.' + s_path[1] + '.' + s_path[2] + '.' + s_path[2] + master_option = config.cfgimpl_get_description().impl_get_opt_by_path(master_path) + if getattr(config, master_path) == []: + populate_mandatory(config, master_option, master_path) + value = [value] + if parse_message: + print parse_message, value + setattr(config, path, value) + config.read_only() + + def template(self): + self.last_notfound = [] + def get_value(opt_, path_): + try: + return getattr(config.creole, path_) + except PropertiesOptionError, err: + if err.proptype == ['mandatory']: + self.read_write() + config.cfgimpl_get_settings().remove('mandatory') + s_path = path_.split('.') + #set value to master + if len(s_path) == 3 and s_path[1] != s_path[2]: + master_path = 'creole.' + s_path[0] + '.' + s_path[1] + '.' + s_path[1] + opt_master = config.unwrap_from_path(master_path) + populate_mandatory(config, opt_master, master_path) + populate_mandatory(config, opt_, 'creole.' + path_) + config.read_only() + config.cfgimpl_get_settings().remove('mandatory') + try: + ret = getattr(config.creole, path_) + config.cfgimpl_get_settings().append('mandatory') + return ret + except PropertiesOptionError: + pass + raise NotFound('no value') + except ConfigError: + self.read_write() + populate_mandatory(config, opt_, 'creole.' + path_) + config.read_only() + try: + return getattr(config.creole, path_) + except ConfigError, err: + raise err + except PropertiesOptionError, err: + raise NotFound('no value') + try: + is_gen_file = getattr(config, self.file_path) + except PropertiesOptionError, err: + is_gen_file = False + if not is_gen_file: + return + try: + config.read_write() + populate_mandatories() + config.read_only() + dico = {} + for opt_, path_ in self.current_opt.items(): + #path_ is None if it's an OptionDescription + if path_ is None: + continue + try: + dico[path_] = get_value(opt_, path_) + except NotFound: + pass + #FIXME revoir le strip_full_path + ndico = {} + for path_, value in dico.items(): + sdico = path_.split('.') + if len(sdico) == 2: + ndico[sdico[1]] = value + elif len(sdico) == 3: + if sdico[1] == sdico[2]: + ndico[sdico[1]] = value + else: + ndico['.'.join(sdico[1:])] = value + else: + raise Exception('chemin de longueur inconnu {}'.format(path_)) + engine = CreoleTemplateEngine(force_values=ndico) + dico = engine.creole_variables_dict + self.read_write() + except ConfigError, err: + msg = 'erreur de templating', err + raise ValueError(msg) + diff = True + for old in self.old_dico: + if dico.keys() == old.keys(): + for key in old.keys(): + if old[key] != dico[key]: + diff = False + break + if not diff: + break + if not diff: + return + try: + self.old_dico.append(dico) + searchlist = [dico, eos, {'is_defined' : IsDefined(dico), + 'creole_client' : CreoleClient(), + 'current_container': CreoleGet(self.current_container), + }] + rtmpl = self.tmpl(searchList=searchlist) + rtmpl.getVar = CompilerGetVar + rtmpl.getattr = CompilerGetattr + rtmpl = str(rtmpl) + #print rtmpl + self.is_tmpl = True + except NotFound, err: + lst = getVars() + if lst == []: + raise Exception("Il manque une option", err, 'avec le dictionnaire', dico) + for ls in lst: + try: + CompilerGetVar(ls) + except AttributeError: + self.last_notfound.append(ls) + raise Reload('') + except Exception, err: + raise Exception("Il y a une erreur", err, 'avec le dictionnaire', dico) + + def check_reload_with_extra(self): + #if extra_vars has value, check if not already in current_opt + global extra_vars + if extra_vars != {}: + oret = set(extra_vars.keys()) + opt_requires = oret & set(self.all_requires.keys()) + for opt_ in opt_requires: + oret.update(self.all_requires[opt_]) + dont_exists = set(oret) - set(self.current_opt.keys()) + ret = [] + for opt_ in dont_exists: + try: + ret.append(extra_vars[opt_]) + except KeyError: + ret.append(opt_._name) + extra_vars = {} + if ret == []: + return None + return ret + + def test_all_values_for(self, options, cpt): + option = options[0] + parse_message = None + if DEBUG: + parse_message = '*' * cpt + '>' + option._name + + if not isinstance(option, ChoiceOption): + msg = str('pas simple la... ' + option._name) + raise NotImplementedError(msg) + multi = option.impl_is_multi() + path = config.cfgimpl_get_description().impl_get_path_by_opt(option) + for value in option.impl_get_values(config): + self.change_value(path, value, multi, parse_message, option) + if options[1:] != []: + #if already value to test, restart test_all_values_for + ret = self.test_all_values_for(options[1:], cpt + 1) + if ret != None: + return ret + else: + need_reload = False + try: + self.template() + except Reload: + need_reload = True + ret = self.check_reload_with_extra() + if need_reload and ret is None: + notfound = [] + paths = config.cfgimpl_get_description()._cache_paths[1] + for ls in self.last_notfound: + #if variable is locale (means template) variable, not config's one + for path in paths: + if path.endswith('.' + ls): + notfound.append(ls) + break + if notfound != []: + raise Exception('variable not found after reload {0}'.format(notfound)) + if ret is not None: + return ret + + + def open_file(self, force_var): + # Open template and compile it + # retrieve template vars (add force_var if needed) + filecontent = open(self.template_name).read() + #try to convert content in unicode + self.tmpl = Template.compile(filecontent, compilerSettings=compilerSettings) # , + #compilerClass=CompilerGetVars) + self.current_var = getVars() + if force_var: + self.current_var.extend(force_var) + + def populate_file(self, path, option): + if path.startswith('containers.files.file'): + if path.endswith('.source') and option.impl_getdefault().endswith('/{0}'.format(self.template_name.split('/')[-1])): + self.filename_ok = True + if self.filename_ok and path.endswith('.activate'): + self.file_path = path + self.filename_ok = False + self.populate_requires(option, path, force=True) + + def test_all_values(self): + try: + options = list(set(self.all_requires.keys())&set(self.current_opt.keys())) + need_tmpl = False + if options != []: + requires_options = set() + for opt in options: + for op in self.all_requires[opt]: + if 'frozen' not in config.cfgimpl_get_settings()[op]: + requires_options.add(op) + if requires_options == set([]): + need_tmpl = True + else: + self.ori_options = requires_options + ret = self.test_all_values_for(list(requires_options), 0) + if ret is not None: + if DEBUG: + print "reload with", ret + self.check_template(ret, already_load=True) + else: + need_tmpl = True + + if need_tmpl is True: + try: + self.template() + except: + self.test_all_values() + except Exception, err: + if DEBUG: + import traceback + traceback.print_exc() + msg = self.template_name, ':', err + raise Exception(msg) + + def check_template(self, force_var=None, already_load=False): + #remove all modification (value, properties, ...) + open_error = None + try: + self.open_file(force_var) + except Exception, err: + open_error = "problème à l'ouverture du fichier {}".format(self.template_name) + + config.read_only() + for index, option in enumerate(config.cfgimpl_get_description()._cache_paths[0]): + path = config.cfgimpl_get_description()._cache_paths[1][index] + self.populate_file(path, option) + self.populate_requires(option, path) + if self.file_path is None: + if open_error is not None: + print "le fichier {0} non présent dans un dictionnaire a un problème : {1}".format(basename(self.template_name), + open_error) + else: + print " \\-- fichier non présent dans un dictionnaire {0}".format(self.template_name) + return + if open_error is not None: + raise Exception(open_error) + + if not already_load: + print " \\--", self.template_name + self.test_all_values() + if not self.is_tmpl: + print "pas de templating !" + + +def populate_mandatories(): + for path in config.cfgimpl_get_values().mandatory_warnings(config): + if path.startswith('creole.'): + option = config.cfgimpl_get_description().impl_get_opt_by_path(path) + try: + populate_mandatory(config, option, path) + except PropertiesOptionError: + pass + + +def parse_templates(templates_name): + global config, cl_chunks, cl_vars, extra_vars + config = creole_loader(load_values=False, load_extra=True) + config.read_write() + populate_mandatories() + cfg = config + for template_name in templates_name: + cl_chunks = set() + cl_vars = set() + extra_vars = {} + config = cfg.duplicate() + config.read_write() + populate_mandatories() + ctmpl = Check_Template(template_name) + try: + ctmpl.check_template() + except Exception, err: + if DEBUG: + import traceback + traceback.print_exc() + print_red(str(err)) + sys.exit(1) + diff --git a/creole/lint/terminalreport.py b/creole/lint/terminalreport.py new file mode 100755 index 0000000..cca4be6 --- /dev/null +++ b/creole/lint/terminalreport.py @@ -0,0 +1,125 @@ +""" +Implements terminal reporting of the full validation process. + +Implements the various reporting hooks. +XXX: Currently in progress, NOT IN WORKING STATE. + +""" +import sys + +def pytest_addoption(parser): + group = parser.getgroup("terminal reporting", after="general") + group._addoption('-v', '--verbose', action="count", + dest="verbose", default=0, help="increase verbosity."), + group.addoption('--report', + action="store", dest="report", default=None, metavar="opts", + help="comma separated options, valid: skipped,xfailed") + group._addoption('--fulltrace', + action="store_true", dest="fulltrace", default=False, + help="don't cut any tracebacks (default is to cut).") + + group.addoption('--traceconfig', + action="store_true", dest="traceconfig", default=False, + help="trace considerations of conftest.py files."), + +class TerminalReporter: + def __init__(self, config, file=None): + self.config = config + self.stats = {} + self.curdir = py.path.local() + if file is None: + file = sys.stdout + self._tw = TerminalWriter(file) + self.currentfspath = None + self._reportopt = getreportopt(config.getvalue('report')) + + def hasopt(self, name): + return self._reportopt.get(name, False) + + def write_fspath_result(self, fspath, res): + fspath = self.curdir.bestrelpath(fspath) + if fspath != self.currentfspath: + self._tw.line() + relpath = self.curdir.bestrelpath(fspath) + self._tw.write(relpath + " ") + self.currentfspath = fspath + self._tw.write(res) + + def write_ensure_prefix(self, prefix, extra="", **kwargs): + if self.currentfspath != prefix: + self._tw.line() + self.currentfspath = prefix + self._tw.write(prefix) + if extra: + self._tw.write(extra, **kwargs) + self.currentfspath = -2 + + def ensure_newline(self): + if self.currentfspath: + self._tw.line() + self.currentfspath = None + + def write_line(self, line, **markup): + line = str(line) + self.ensure_newline() + self._tw.line(line, **markup) + + def write_sep(self, sep, title=None, **markup): + self.ensure_newline() + self._tw.sep(sep, title, **markup) + + def getoutcomeword(self, rep): + if rep.passed: + return "PASS", dict(green=True) + elif rep.failed: + return "FAIL", dict(red=True) + elif rep.skipped: + return "SKIP" + else: + return "???", dict(red=True) + + # + # summaries for sessionfinish + # + + def summary_failures(self): + if 'failed' in self.stats and self.config.option.tbstyle != "no": + self.write_sep("=", "FAILURES") + for rep in self.stats['failed']: + msg = self._getfailureheadline(rep) + self.write_sep("_", msg) + self.write_platinfo(rep) + rep.toterminal(self._tw) + + def summary_errors(self): + if 'error' in self.stats and self.config.option.tbstyle != "no": + self.write_sep("=", "ERRORS") + for rep in self.stats['error']: + msg = self._getfailureheadline(rep) + if not hasattr(rep, 'when'): + # collect + msg = "ERROR during collection " + msg + elif rep.when == "setup": + msg = "ERROR at setup of " + msg + elif rep.when == "teardown": + msg = "ERROR at teardown of " + msg + self.write_sep("_", msg) + self.write_platinfo(rep) + rep.toterminal(self._tw) + + def summary_stats(self): + session_duration = py.std.time.time() - self._sessionstarttime + + keys = "failed passed skipped deselected".split() + for key in self.stats.keys(): + if key not in keys: + keys.append(key) + parts = [] + for key in keys: + val = self.stats.get(key, None) + if val: + parts.append("%d %s" %(len(val), key)) + line = ", ".join(parts) + # XXX coloring + self.write_sep("=", "%s in %.2f seconds" %(line, session_duration)) + diff --git a/creole/lint/terminalwriter.py b/creole/lint/terminalwriter.py new file mode 100755 index 0000000..cfb0d08 --- /dev/null +++ b/creole/lint/terminalwriter.py @@ -0,0 +1,139 @@ +# -*- coding: utf-8 -*- +""" + +Helper functions for writing to terminals and files. +XXX: Currently in progress, NOT IN WORKING STATE. + +""" + +import sys, os + +def _getdimensions(): + import termios,fcntl,struct + call = fcntl.ioctl(0,termios.TIOCGWINSZ,"\000"*8) + height,width = struct.unpack( "hhhh", call ) [:2] + return height, width + +def get_terminal_width(): + try: + height, width = _getdimensions() + except (SystemExit, KeyboardInterrupt): + raise + except: + # FALLBACK + width = int(os.environ.get('COLUMNS', 80))-1 + # XXX the windows getdimensions may be bogus, let's sanify a bit + width = max(width, 40) # we alaways need 40 chars + return width + +terminal_width = get_terminal_width() + +# XXX unify with _escaped func below +def ansi_print(text, file=None, newline=True, flush=False): + if file is None: + file = sys.stderr + text = text.strip() + if newline: + text += '\n' + file.write(text) + if flush: + file.flush() + if file: + file.close() + +def should_do_markup(file): + return hasattr(file, 'isatty') and file.isatty() \ + and os.environ.get('TERM') != 'dumb' + +class TerminalWriter(object): + _esctable = dict(black=30, red=31, green=32, yellow=33, + blue=34, purple=35, cyan=36, white=37, + Black=40, Red=41, Green=42, Yellow=43, + Blue=44, Purple=45, Cyan=46, White=47, + bold=1, light=2, blink=5, invert=7) + + def __init__(self, file=None, encoding=None): + self.encoding = encoding + + if file is None: + file = sys.stdout + + elif hasattr(file, '__call__'): + file = WriteFile(file, encoding=encoding) + self._file = file + self.fullwidth = get_terminal_width() + self.hasmarkup = should_do_markup(file) + + def _escaped(self, text, esc): + if esc and self.hasmarkup: + text = (''.join(['\x1b[%sm' % cod for cod in esc]) + + text +'\x1b[0m') + return text + + def markup(self, text, **kw): + esc = [] + for name in kw: + if name not in self._esctable: + raise ValueError("unknown markup: %r" %(name,)) + if kw[name]: + esc.append(self._esctable[name]) + return self._escaped(text, tuple(esc)) + + def sep(self, sepchar, title=None, fullwidth=None, **kw): + if fullwidth is None: + fullwidth = self.fullwidth + # the goal is to have the line be as long as possible + # under the condition that len(line) <= fullwidth + if title is not None: + # we want 2 + 2*len(fill) + len(title) <= fullwidth + # i.e. 2 + 2*len(sepchar)*N + len(title) <= fullwidth + # 2*len(sepchar)*N <= fullwidth - len(title) - 2 + # N <= (fullwidth - len(title) - 2) // (2*len(sepchar)) + N = (fullwidth - len(title) - 2) // (2*len(sepchar)) + fill = sepchar * N + line = "%s %s %s" % (fill, title, fill) + else: + # we want len(sepchar)*N <= fullwidth + # i.e. N <= fullwidth // len(sepchar) + line = sepchar * (fullwidth // len(sepchar)) + # in some situations there is room for an extra sepchar at the right, + # in particular if we consider that with a sepchar like "_ " the + # trailing space is not important at the end of the line + if len(line) + len(sepchar.rstrip()) <= fullwidth: + line += sepchar.rstrip() + + self.line(line, **kw) + + def write(self, s, **kw): + if s: + s = self._getbytestring(s) + if self.hasmarkup and kw: + s = self.markup(s, **kw) + self._file.write(s) + self._file.flush() + + def _getbytestring(self, s): + # XXX review this and the whole logic + if self.encoding and sys.version_info < (3,0) and isinstance(s, unicode): + return s.encode(self.encoding) + elif not isinstance(s, str): + return str(s) + return s + + def line(self, s='', **kw): + self.write(s, **kw) + self.write('\n') + +class WriteFile(object): + def __init__(self, writemethod, encoding=None): + self.encoding = encoding + self._writemethod = writemethod + + def write(self, data): + if self.encoding: + data = data.encode(self.encoding) + self._writemethod(data) + + def flush(self): + return + diff --git a/creole/lint/warning.py b/creole/lint/warning.py new file mode 100644 index 0000000..f4b1cc8 --- /dev/null +++ b/creole/lint/warning.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +import sys +from creole.lint import warnsymb + + +class Warn: + + def __init__(self, write_level, itemname, warnno, comment, checks): + self.warnno = warnno + self.comment = comment + self.checks = checks + self.write_level = getattr(warnsymb, write_level) + + def to_dict(self): + """ + formats a msg warn directly from a warning message + """ + dico_loc = {} + for var in self.checks: + if hasattr(var, 'location'): + locs = var.location + for vfile, vline in locs: + if vfile == 'dictionnaire': + raise Exception('vfile ne doit pas se nommer dictionnaire !!!') + if not dico_loc.has_key(vfile): + dico_loc[vfile] = [] + dico_loc[vfile].append((vline, var)) + else: + if not dico_loc.has_key('dictionnaire'): + dico_loc['dictionnaire'] = [] + dico_loc['dictionnaire'].append((None, var)) +# ret = ["[%s:%s:%s] %s : %s (dictionnaire)" %(level, name, self.itemname, self.comment, vname)] + return dico_loc diff --git a/creole/lint/warnsymb.py b/creole/lint/warnsymb.py new file mode 100755 index 0000000..4b57cb2 --- /dev/null +++ b/creole/lint/warnsymb.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +""" + Standard errno symbols +""" + +"""Dictionary providing a mapping from the errno value to the string +name in the underlying waring. For instance, +errno.errorcode[errno.EPERM] maps to 'EPERM'.""" + +errorlevel = { + 1: 'error', + 2: 'warning', + 3: 'info', +} + +errorcode = { + 1: ('ERROR', 1), + 2: ('WARNING', 2), + 3: ('INFO', 3), + 4: ('NAME', 1), + 5: ('NAME', 2), + 6: ('NAME', 3), + 7: ('UNUSED', 1), + 8: ('UNUSED', 2), + 9: ('UNUSED', 3), +} + +globs = globals() + +for key, value in errorlevel.items(): + globs[value] = key + + diff --git a/creole/loader.py b/creole/loader.py new file mode 100644 index 0000000..4a087fb --- /dev/null +++ b/creole/loader.py @@ -0,0 +1,873 @@ +"""creole loader +flattened XML specific +""" +from os.path import join, isfile, isdir +from os import listdir +#from ast import literal_eval +from lxml.etree import parse, DTD + +from tiramisu.option import (UnicodeOption, OptionDescription, PortOption, + IntOption, ChoiceOption, BoolOption, SymLinkOption, IPOption, + NetworkOption, NetmaskOption, DomainnameOption, BroadcastOption, + URLOption, EmailOption, FilenameOption, UsernameOption, DateOption, + PasswordOption, BoolOption, Leadership) +from tiramisu import Config, MetaConfig, MixConfig +from tiramisu.setting import groups +from tiramisu.error import ConfigError +from tiramisu.setting import owners +from tiramisu import Params, ParamOption, ParamValue, ParamContext + +from .config import (FLATTENED_CREOLE_DIR, dtdfilename, eoledirs, eoleextradico, forbiddenextra, + configeol, eoleextraconfig) +from .i18n import _ +from .var_loader import convert_tiramisu_value, modes_level, MACOption # FIXME YO +from .loader1 import load_config_eol, load_extras, _list_extras +#For compatibility +from .loader1 import config_save_values, config_load_store, config_get_values, add_eol_version +from .loader1 import load_store, load_config_store, load_values +from .xmlreflector import HIGH_COMPATIBILITY +#from . import eosfunc +from .objspace import CreoleObjSpace +import imp + + +class CreoleLoaderError(Exception): + pass + +CONVERT_OPTION = {'number': dict(opttype=IntOption), + 'choice': dict(opttype=ChoiceOption), + 'string': dict(opttype=UnicodeOption), + 'password': dict(opttype=PasswordOption), + 'mail': dict(opttype=EmailOption), + 'boolean': dict(opttype=BoolOption), + 'symlink': dict(opttype=SymLinkOption), + 'filename': dict(opttype=FilenameOption), + 'date': dict(opttype=DateOption), + 'unix_user': dict(opttype=UsernameOption), + 'ip': dict(opttype=IPOption, initkwargs={'allow_reserved': True}), + 'local_ip': dict(opttype=IPOption, initkwargs={'private_only': True, 'warnings_only': True}), + 'netmask': dict(opttype=NetmaskOption), + 'network': dict(opttype=NetworkOption), + 'broadcast': dict(opttype=BroadcastOption), + 'netbios': dict(opttype=DomainnameOption, initkwargs={'type_': 'netbios', 'warnings_only': True}), + 'domain': dict(opttype=DomainnameOption, initkwargs={'type_': 'domainname', 'allow_ip': True, 'allow_without_dot': True}), + 'domain_strict': dict(opttype=DomainnameOption, initkwargs={'type_': 'domainname', 'allow_ip': False}), + 'hostname': dict(opttype=DomainnameOption, initkwargs={'type_': 'hostname', 'allow_ip': True}), + 'hostname_strict': dict(opttype=DomainnameOption, initkwargs={'type_': 'hostname', 'allow_ip': False}), + 'web_address': dict(opttype=URLOption, initkwargs={'allow_ip': True, 'allow_without_dot': True}), + 'port': dict(opttype=PortOption, initkwargs={'allow_private': True}), + 'mac': dict(opttype=MACOption) # FIXME YO + } + + +REMOVED_ATTRIB = ['path', 'type'] + + +class Elt(object): + def __init__(self, attrib): + self.attrib = attrib + + +class PopulateTiramisuObjects(object): + def __init__(self): + self.storage = ElementStorage() + self.booleans = [] + self.force_store_values = set() + self.separators = {} + self.groups = {} + + def parse_dtd(self, dtdfilename): + """Loads the Creole DTD + + :raises IOError: if the DTD is not found + + :param dtdfilename: the full filename of the Creole DTD + """ + if not isfile(dtdfilename): + raise IOError(_("no such DTD file: {}").format(dtdfilename)) + with open(dtdfilename, 'r') as dtdfd: + dtd = DTD(dtdfd) + for elt in dtd.iterelements(): + if elt.name == 'variable': + for attr in elt.iterattributes(): + if set(attr.itervalues()) == set(['True', 'False']): + self.booleans.append(attr.name) + + def make_tiramisu_objects(self, xmlroot, creolefunc_file, load_extra=True): + elt = Elt({'name': 'baseoption'}) + family = Family(elt, self.booleans) + self.storage.add('.', family) + self.eosfunc = imp.load_source('eosfunc', creolefunc_file) + + elts = {} + for elt in xmlroot: + elts.setdefault(elt.tag, []).append(elt) + list_elts = list(elts.keys()) + if 'family' in list_elts: + list_elts.remove('family') + list_elts.insert(0, 'family') + for elt in list_elts: + xmlelts_ = elts[elt] + if elt == 'family': + xmlelts = [] + actions = None + # `creole` family has to be loaded before any other family + # because `extra` family could use `creole` variables. + # `actions` family has to be loaded at the very end + # because it may use `creole` or `extra` variables + for xml in xmlelts_: + if not load_extra and xml.attrib['name'] not in ['creole', 'containers']: + continue + if xml.attrib['name'] == 'creole': + xmlelts.insert(0, xml) + elif xml.attrib['name'] == 'actions': + actions = xml + else: + xmlelts.append(xml) + if actions is not None: + xmlelts.append(actions) + else: + xmlelts = xmlelts_ + for xmlelt in xmlelts: + if xmlelt.tag == 'family': + self._iter_family(xmlelt, family=family) + elif xmlelt.tag == 'help': + self._iter_help(xmlelt) + elif xmlelt.tag == 'constraints': + self._iter_constraints(xmlelt, load_extra) + else: + raise CreoleLoaderError(_('unknown tag {}').format(xmlelt.tag)) + + def _populate_variable(self, elt, subpath, is_slave, is_master): + variable = Variable(elt, self.booleans, self.storage, is_slave, is_master, self.eosfunc) + path = self._build_path(subpath, elt) + properties = variable.attrib.get('properties', []) + if 'force_store_value' in properties or "auto_freeze" in properties: + self.force_store_values.add(path) + self.storage.add(path, variable) + return variable + + def _populate_family(self, elt, subpath): + if subpath is None: + force_icon = False + else: + force_icon = not subpath.startswith('containers') and not subpath.startswith('actions') + family = Family(elt, self.booleans, force_icon) + path = self._build_path(subpath, elt) + self.storage.add(path, family) + return family + + def _build_path(self, subpath, elt): + if subpath is None: + subpath = elt.attrib['name'] + else: + subpath += '.' + elt.attrib['name'] + return subpath + + def _iter_constraints(self, xmlelt, load_extra): + for elt in xmlelt: + if elt.tag == 'fill': + self._parse_fill(elt, load_extra) + elif elt.tag == 'condition': + self._parse_condition(elt, load_extra) + elif elt.tag == 'check': + self._parse_check(elt, load_extra) + else: + raise CreoleLoaderError(_('unknown constraint {}').format(elt.tag)) + + def _check_extra(self, variable, load_extra): + if load_extra: + return True + return variable.startswith('creole.') or variable.startswith('containers.') + + + def _parse_fill(self, elt, load_extra): + if not self._check_extra(elt.attrib['target'], load_extra): + return + callback = getattr(self.eosfunc, elt.attrib['name']) + callback_params = {} + for param in elt: + name = param.attrib.get('name', '') + if param.attrib['type'] == 'string': + value = str(param.text) + elif param.attrib['type'] == 'eole': + hidden = param.attrib['hidden'] + if hidden == 'True': + hidden = False + elif hidden == 'False': + hidden = True + else: + raise CreoleLoaderError(_('unknown hidden boolean {}').format(hidden)) + if not self._check_extra(param.text, load_extra): + return + value = [self.storage.get(param.text), hidden] + elif param.attrib['type'] == 'number': + value = int(param.text) + elif param.attrib['type'] == 'context': + value = (None,) + else: + raise CreoleLoaderError(_('unknown param type {} in fill to {}').format(param.attrib['type'], elt.attrib['target'])) + callback_params.setdefault(name, []).append(value) + if callback_params == {}: + callback_params = None + self.storage.add_callback(elt.attrib['target'], callback, callback_params) + + def _parse_check(self, elt, load_extra): + if not self._check_extra(elt.attrib['target'], load_extra): + return + all_param_eole = True + for param in elt: + if param.attrib.get('type') != 'eole': + all_param_eole = False + break + if elt.attrib['name'] == 'valid_enum': + # only for valid_enum with checkval to True + if len(elt) != 1: + raise CreoleLoaderError(_('valid_enum cannot have more than one param for {}').format(elt.attrib['target'])) + if elt.attrib['probe'] == 'True': + proposed = elt[0].text + type_ = 'string' + elif elt[0].attrib['type'] == 'eole': + proposed = elt[0].text + type_ = 'eole' + else: + #proposed_value = literal_eval(elt[0].text) + proposed_value = eval(elt[0].text) + proposed = tuple(proposed_value) + type_ = 'string' + self.storage.add_information(elt.attrib['target'], 'proposed_value', {'value': proposed, 'type': type_}) + + validator = getattr(self.eosfunc, elt.attrib['name']) + elif elt.attrib['name'] == 'valid_differ' and all_param_eole: + if (HIGH_COMPATIBILITY and len(elt) not in [0, 1]) or (not HIGH_COMPATIBILITY and len(elt) != 1): + raise CreoleLoaderError(_('valid_differ length should be 1')) + if HIGH_COMPATIBILITY and len(elt) == 1: + if not self._check_extra(elt[0].text, load_extra): + return + variables = [self.storage.get(elt[0].text)] + else: + variables = [] + self.storage.add_consistency(elt.attrib['target'], + 'not_equal', + variables, + elt.attrib['warnings_only'], + elt.attrib['transitive']) + elif elt.attrib['name'] == 'valid_networknetmask': + if len(elt) != 1: + raise CreoleLoaderError(_('valid_networknetmask length should be 1')) + if not all_param_eole: + raise CreoleLoaderError(_('valid_networknetmask must have only eole variable')) + variables = [self.storage.get(elt[0].text)] + self.storage.add_consistency(elt.attrib['target'], + 'network_netmask', + variables, + elt.attrib['warnings_only'], + elt.attrib['transitive']) + elif elt.attrib['name'] == 'valid_ipnetmask': + if len(elt) != 1: + raise CreoleLoaderError(_('valid_ipnetmask length should be 1')) + if not all_param_eole: + raise CreoleLoaderError(_('valid_ipnetmask must have only eole variable')) + if not self._check_extra(elt[0].text, load_extra): + return + variables = [self.storage.get(elt[0].text)] + self.storage.add_consistency(elt.attrib['target'], + 'ip_netmask', + variables, + elt.attrib['warnings_only'], + elt.attrib['transitive']) + elif elt.attrib['name'] == 'valid_broadcast': + if len(elt) != 2: + raise CreoleLoaderError(_('valid_broadcast length should be 2')) + if not all_param_eole: + raise CreoleLoaderError(_('valid_broadcast must have only eole variable')) + if not self._check_extra(elt[0].text, load_extra): + return + variables = [self.storage.get(elt[0].text)] + if not self._check_extra(elt[1].text, load_extra): + return + variables.append(self.storage.get(elt[1].text)) + self.storage.add_consistency(elt.attrib['target'], + 'broadcast', + variables, + elt.attrib['warnings_only'], + elt.attrib['transitive']) + elif elt.attrib['name'] == 'valid_in_network': + if len(elt) != 2: + raise CreoleLoaderError(_('valid_in_network length should be 2')) + if not all_param_eole: + raise CreoleLoaderError(_('valid_in_network must have only eole variable')) + if not self._check_extra(elt[0].text, load_extra): + return + variables = [self.storage.get(elt[0].text)] + if not self._check_extra(elt[1].text, load_extra): + return + variables.append(self.storage.get(elt[1].text)) + self.storage.add_consistency(elt.attrib['target'], + 'in_network', + variables, + elt.attrib['warnings_only'], + elt.attrib['transitive']) + else: + validator = getattr(self.eosfunc, elt.attrib['name']) + validator_params = {} + for param in elt: + text = param.text + if param.attrib['type'] == 'eole': + hidden = param.attrib.get('hidden', 'True') + if hidden == 'True': + hidden = False + elif hidden == 'False': + hidden = True + else: + raise CreoleLoaderError(_('unknown hidden boolean {}').format(hidden)) + if not self._check_extra(text, load_extra): + return + text = [self.storage.get(text), hidden] + validator_params.setdefault(param.attrib.get('name', ''), []).append(text) + self.storage.add_validator(elt.attrib['target'], validator, validator_params) + + def _parse_condition(self, elt, load_extra): + if not self._check_extra(elt.attrib['source'], load_extra): + return + if elt.attrib['name'] == 'disabled_if_in': + actions = ['disabled'] + inverse = False + elif elt.attrib['name'] == 'disabled_if_not_in': + actions = ['disabled'] + inverse = True + elif elt.attrib['name'] == 'auto_frozen_if_in': + actions = ['frozen'] + inverse = False + elif elt.attrib['name'] == 'frozen_if_in': + actions = ['frozen', 'hidden', 'force_default_on_freeze'] + inverse = False + elif elt.attrib['name'] == 'frozen_if_not_in': + actions = ['frozen', 'hidden', 'force_default_on_freeze'] + inverse = True + elif elt.attrib['name'] == 'mandatory_if_in': + actions = ['mandatory'] + inverse = False + elif elt.attrib['name'] == 'mandatory_if_not_in': + actions = ['mandatory'] + inverse = True + else: + raise CreoleLoaderError(_('unknown condition type {} for {}').format(elt.attrib['name'], elt.attrib['source'])) + expected_values = [] + options = [] + for param in elt: + if param.tag == 'param': + expected_values.append(param.text) + elif param.tag == 'target': + if param.attrib['type'] in ['variable', 'family']: + if not self._check_extra(param.text, load_extra): + return + option = self.storage.get(param.text) + option_actions = actions + if 'force_store_value' in option.attrib.get('properties', []) and \ + 'force_default_on_freeze' in option_actions: + option_actions.remove('force_default_on_freeze') + options.append((param.text, option_actions)) + source = self.storage.get(elt.attrib['source']) + for option, actions in options: + conditions = [] + for action in actions: + for expected in expected_values: + conditions.append({'option': source, 'expected': expected, + 'action': action, 'inverse': inverse}) + self.storage.add_requires(option, conditions) + + def _iter_help(self, xmlelt): + for elt in xmlelt: + self.storage.add_help(elt.attrib['name'], elt.text) + + def _iter_master(self, master, subpath): + subpath = self._build_path(subpath, master) + family = Family(master, self.booleans) + family.set_master() + self.storage.add(subpath, family) + master_name = None + for var in master: + if master_name is None: + master_name = var.attrib['name'] + self.groups[master_name] = [] + else: + self.groups[master_name].append(var.attrib['name']) + self._iter_family(var, subpath=subpath, family=family) + return family + + def _iter_family(self, child, subpath=None, family=None): + if child.tag not in ['family', 'variable', 'separators', 'master']: + raise CreoleLoaderError(_('unknown tag {}').format(child.tag)) + if child.tag == 'family': + old_family = family + family = self._populate_family(child, subpath) + if old_family is not None: + old_family.add(family) + if child.tag == 'master': + master = self._iter_master(child, subpath) + family.add(master) + elif child.tag == 'separators': + self._parse_separators(child) + elif child.tag == 'variable': + if family is None: + raise CreoleLoaderError(_('variable without family')) + + is_slave = False + is_master = False + if family.is_master: + if child.attrib['name'] != family.attrib['name']: + is_slave = True + else: + is_master = True + variable = self._populate_variable(child, subpath, is_slave, is_master) + family.add(variable) + elif len(child) != 0: + subpath = self._build_path(subpath, child) + for c in child: + self._iter_family(c, subpath, family) + + def _parse_separators(self, separators): + for separator in separators: + elt = self.storage.get(separator.attrib['name']) + never_hidden = separator.attrib.get('never_hidden') + if never_hidden == 'True': + never_hidden = True + else: + never_hidden = None + info = (separator.text, never_hidden) + self.separators[separator.attrib['name']] = info + elt.add_information('separator', info) + + def build(self, persistent=False, session_id=None, meta_config=False): + if meta_config: + optiondescription = self.storage.paths['.'].get() + config = MetaConfig([], + optiondescription=optiondescription, + persistent=persistent, + session_id=session_id) + mixconfig = MixConfig(children=[], + optiondescription=optiondescription, + persistent=persistent, + session_id='m_' + session_id) + config.config.add(mixconfig) + else: + config = Config(self.storage.paths['.'].get(), + persistent=persistent, + session_id=session_id) + config.information.set('force_store_vars', self.force_store_values) + config.information.set('force_store_values', list(self.force_store_values)) + # XXX really usefull? + ro_append = frozenset(config.property.getdefault('read_only', 'append') - {'force_store_value'}) + rw_append = frozenset(config.property.getdefault('read_write', 'append') - {'force_store_value'}) + config.property.setdefault(ro_append, 'read_only', 'append') + config.property.setdefault(rw_append, 'read_write', 'append') + + config.property.read_only() + _modes = list(modes_level) + _modes.append('hidden') + config.permissive.set(frozenset(_modes)) + return config + + +class ElementStorage(object): + def __init__(self): + self.paths = {} + + def add(self, path, elt): + if path in self.paths: + raise CreoleLoaderError(_('path already loaded {}').format(path)) + self.paths[path] = elt + + def add_help(self, path, text): + elt = self.get(path) + self.paths[path].add_information('help', text) + + def add_callback(self, path, callback, callback_params): + elt = self.get(path) + elt.add_callback(callback, callback_params) + + def add_information(self, path, name, information): + elt = self.get(path) + elt.add_information(name, information) + + def add_validator(self, path, validator, validator_params): + elt = self.get(path) + elt.add_validator(validator, validator_params) + + def add_consistency(self, path, consistence, variables, warnings_only, transitive): + elt = self.get(path) + elt.add_consistency(consistence, variables, warnings_only, transitive) + + def add_requires(self, path, requires): + elt = self.get(path) + elt.add_requires(requires) + + def get(self, path): + if path not in self.paths: + raise CreoleLoaderError(_('there is no element for path {}').format(path)) + return self.paths[path] + + +class Variable(object): + def __init__(self, elt, booleans, storage, is_slave, is_master, eosfunc): + self.option = None + self.informations = {} + self.attrib = {} + self.callbacks = [] + self.requires = [] + self.validator = None + self.consistencies = [] + self.attrib['properties'] = [] + self.eosfunc = eosfunc + for key, value in elt.attrib.items(): + if key in REMOVED_ATTRIB: + continue + #if key != 'name': + # value = unicode(value) + + if key in booleans: + if value == 'True': + value = True + elif value == 'False': + value = False + else: + raise CreoleLoaderError(_('unknown value {} for {}').format(value, key)) + self.attrib[key] = value + convert_option = CONVERT_OPTION[elt.attrib['type']] + self.object_type = convert_option['opttype'] + if elt.attrib['type'] == 'choice': + if self.attrib.get('choice'): + self.attrib['values'] = getattr(self.eosfunc, self.attrib.get('choice')) + else: + self.attrib['values'] = [] + for child in elt: + if child.tag == 'choice': + value = child.text + if 'type' in child.attrib and child.attrib['type'] == 'number': + value = int(value) + if value is None: + value = u'' + self.attrib['values'].append(value) + self.attrib['values'] = tuple(self.attrib['values']) + for child in elt: + if "type" in child.attrib: + type_ = CONVERT_OPTION[child.attrib['type']]['opttype'] + else: + type_ = self.object_type + if child.tag == 'property': + self.attrib['properties'].append(child.text) + elif child.tag == 'value': + if self.attrib['multi'] and not is_slave: + if 'default' not in self.attrib: + self.attrib['default'] = [] + value = convert_tiramisu_value(child.text, type_) + self.attrib['default'].append(value) + if 'default_multi' not in self.attrib and not is_master: + self.attrib['default_multi'] = value + else: + if 'default' in self.attrib: + raise CreoleLoaderError(_('default value already set for {}' + '').format(self.attrib['path'])) + value = convert_tiramisu_value(child.text, type_) + if value is None: # and (elt.attrib['type'] != 'choice' or value not in self.attrib['values']): + value = u'' + if is_slave: + self.attrib['default_multi'] = value + else: + self.attrib['default'] = value + if 'initkwargs' in convert_option: + self.attrib.update(convert_option['initkwargs']) + self.attrib['properties'] = tuple(self.attrib['properties']) + if elt.attrib['type'] == 'symlink': + del self.attrib['properties'] + del self.attrib['multi'] + self.attrib['opt'] = storage.get(self.attrib['opt']) + + def add_information(self, key, value): + if key in self.informations: + raise CreoleLoaderError(_('key already exists in information {}').format(key)) + self.informations[key] = value + + def add_callback(self, callback, callback_params): + self.callbacks.append((callback, callback_params)) + + def add_requires(self, requires): + self.requires.extend(requires) + + def add_validator(self, validator, validator_params): + self.validator = (validator, validator_params) + + def add_consistency(self, consistence, variables, warnings_only, transitive): + self.consistencies.append((consistence, variables, warnings_only, transitive)) + + def build_params(self, params): + if params != None: + new_params = Params() + for key, values in params.items(): + new_values = [] + for value in values: + if isinstance(value, list): + # retrieve object + value = ParamOption(value[0].get(), value[1]) + elif value == (None,): + value = ParamContext() + else: + value = ParamValue(value) + if key == '': + args = list(new_params.args) + args.append(value) + new_params.args = tuple(args) + else: + new_params.kwargs[key] = value + return new_params + return params + + def get(self): + if self.option is None: + if self.object_type is SymLinkOption: + self.attrib['opt'] = self.attrib['opt'].get() + for callback, callback_params in self.callbacks: + self.attrib['callback'] = callback + self.attrib['callback_params'] = self.build_params(callback_params) + for require in self.requires: + if isinstance(require['option'], Variable): + require['option'] = require['option'].get() + if self.requires != []: + self.attrib['requires'] = self.requires + if self.validator: + self.attrib['validator'] = self.validator[0] + self.attrib['validator_params'] = self.build_params(self.validator[1]) + try: + option = self.object_type(**self.attrib) + except Exception as err: + import traceback + traceback.print_exc() + name = self.attrib['name'] + raise CreoleLoaderError(_('cannot create option {}: {}').format(name, err)) + for key, value in self.informations.items(): + option.impl_set_information(key, value) + for consistency in self.consistencies: + options = [] + for variable in consistency[1]: + options.append(variable.get()) + try: + kwargs = {} + if consistency[2] == 'True': + kwargs['warnings_only'] = True + if consistency[3] == 'False': + kwargs['transitive'] = False + option.impl_add_consistency(consistency[0], *options, **kwargs) + except ConfigError as err: + name = self.attrib['name'] + raise CreoleLoaderError(_('cannot load consistency for {}: {}').format(name, err)) + self.option = option + return self.option + + +class Family(object): + def __init__(self, elt, booleans, force_icon=False): + self.requires = [] + self.option = None + self.attrib = {} + self.is_master = False + if force_icon: + self.informations = {'icon': None} + else: + self.informations = {} + self.children = [] + self.attrib['properties'] = [] + for key, value in elt.attrib.items(): + if key in REMOVED_ATTRIB: + continue + if key in booleans: + if value == 'True': + value = True + elif value == 'False': + value = False + else: + raise CreoleLoaderError(_('unknown value {} for {}').format(value, key)) + if key == 'icon': + self.add_information('icon', value) + continue + elif key == 'hidden': + if value: + self.attrib['properties'].append(key) + elif key == 'mode': + self.attrib['properties'].append(value) + else: + self.attrib[key] = value + if 'doc' not in self.attrib: + self.attrib['doc'] = u'' + self.attrib['properties'] = tuple(self.attrib['properties']) + + def add(self, child): + self.children.append(child) + + def add_information(self, key, value): + if key in self.informations and not (key == 'icon' and self.informations[key] is None): + raise CreoleLoaderError(_('key already exists in information {}').format(key)) + self.informations[key] = value + + def set_master(self): + self.is_master = True + + def add_requires(self, requires): + self.requires.extend(requires) + + def get(self): + if self.option is None: + self.attrib['children'] = [] + for child in self.children: + self.attrib['children'].append(child.get()) + for require in self.requires: + if isinstance(require['option'], Variable): + require['option'] = require['option'].get() + if self.requires != []: + self.attrib['requires'] = self.requires + try: + if not self.is_master: + option = OptionDescription(**self.attrib) + else: + option = Leadership(**self.attrib) + #option = OptionDescription(**self.attrib) + except Exception as err: + raise CreoleLoaderError(_('cannot create optiondescription {}: {}').format(self.attrib['name'], err)) + for key, value in self.informations.items(): + option.impl_set_information(key, value) + self.option = option + #if self.is_master: + # self.option.impl_set_group_type(groups.master) + + return self.option + + +def _gen_eol_file(namespace): + if namespace == 'creole': + return configeol + else: + return join(eoleextraconfig, namespace, 'config.eol') + + +def creole_loader(load_values=True, rw=False, namespace='creole', + load_extra=False, reload_config=True, owner=None, + disable_mandatory=False, force_configeol=None, + try_upgrade=True, force_load_creole_owner=None, + force_dirs=None, warnings=None, force_instanciate=None, + force_dtdfile=None, force_flattened=None, + mandatory_permissive=True, from_zephir=None, + force_no_save=False, force_eoleextradico=None, + force_eoleextraconfig=None, only_load_flattened=False): + """ + Loads the Creole XML dictionnary files and return a tiramisu config object + + :param bool load_values: Loads (or not) the :file:`config.eol` file + :param bool rw: Config's read/write flag + :param str namespace: Root's namespace for the config (example: "creole", "bacula", ...) + :param bool load_extra: Loads (or not) the extra dictionnaries (if `namespace='creole'`) + :param bool reload_config: This parameter is kept for compatibility reasons + :param str owner: forces the owner on a modified variable + :param bool disable_mandatory: disables the mandatory variables + :param str force_configeol: Forces the used configuration file + :param bool try_upgrade: tries to upgrade + :param force_load_creole_owner: Forces the owner for the loaded variables + :param str force_dirs: Forces the folder's name containing the dictionnaries + :param warnings: Shows the validation's warnings + :param bool force_instanciate: tells us if the server is already instanciated or not + :param force_dtdfile: None or dtd filename + :param force_flattened: None or flatened filename's name + :param only_load_flattened: boolean to desactivate generated of flattened file + """ + if namespace is not 'creole': + raise CreoleLoaderError(_('Only creole namespace is supported')) + #if reload_config is not True: + # raise CreoleLoaderError(_('Cannot reload the configuration')) + if force_flattened is None: + force_flattened = join(FLATTENED_CREOLE_DIR, 'flattened_creole.xml') + if force_dtdfile is None: + force_dtdfile = dtdfilename + if force_configeol is not None: + if not isfile(force_configeol): + raise CreoleLoaderError(_("Configuration file unexistent : {0}").format( + force_configeol)) + if load_extra and force_eoleextraconfig is None: + # if force_configeol, cannot calculate extra configfile name + raise CreoleLoaderError(_('Unable to force_configeol with load_extra.')) + if force_dirs is not None and load_extra is True and force_eoleextradico is None: + raise CreoleLoaderError(_('If force_dirs is defined, namespace must be set to creole and ' + 'load_extra must be set to False.')) + if not only_load_flattened: + #should not load value now because create a Config + eolobj = CreoleObjSpace(force_dtdfile) + if force_dirs is not None: + dirs = force_dirs + else: + dirs = eoledirs + if from_zephir is not None and type(dirs) != list: + #if dirs is not a list, add subdirectory 'local' + #and 'variante' + orig_dir = dirs + dirs = [dirs] + for tdir in [join(orig_dir, 'local'), + join(orig_dir, 'variante')]: + if isdir(tdir): + dirs.append(tdir) + eolobj.create_or_populate_from_xml('creole', dirs, from_zephir=from_zephir) + + if load_extra: + if force_eoleextradico == None: + force_eoleextradico = eoleextradico + extranames = _list_extras(force_eoleextradico) + extranames.sort() + if isdir(force_eoleextradico): + for directory in extranames: + if directory in forbiddenextra: + raise CreoleLoaderError( + _('Namespace {} for extra dictionary not allowed').format(directory)) + dirname = join(force_eoleextradico, directory) + eolobj.create_or_populate_from_xml(directory, [dirname], from_zephir) + eolobj.space_visitor() + xmlroot = eolobj.save(force_flattened, force_no_save) + else: + with open(force_flattened, 'r') as fhd: + xmlroot = parse(fhd).getroot() + tiramisu_objects = PopulateTiramisuObjects() + tiramisu_objects.parse_dtd(force_dtdfile) + tiramisu_objects.make_tiramisu_objects(xmlroot) + config = tiramisu_objects.build() + if warnings is None: + # warnings is disabled in read-only mode and enabled in read-write mode by default + warnings = rw + if warnings is False: + config.cfgimpl_get_settings().remove('warnings') + if owner is not None: + if owner not in dir(owners): + owners.addowner(owner) + config.cfgimpl_get_settings().setowner(getattr(owners, owner)) + #load values + if force_configeol is not None: + configfile = force_configeol + else: + configfile = _gen_eol_file(namespace) + if load_values and isfile(configfile): + disable_mandatory = False + load_config_eol(config, configfile=configfile, try_upgrade=try_upgrade, + force_load_owner=force_load_creole_owner, + force_instanciate=force_instanciate) + else: + config.impl_set_information(namespace, configfile) + if load_extra: + load_extras(config, load_values=load_values, mandatory_permissive=mandatory_permissive, + extradico=force_eoleextradico, force_eoleextraconfig=force_eoleextraconfig) + if rw: + config.read_write() + elif rw is False: + config.read_only() + + if disable_mandatory: + config.cfgimpl_get_settings().remove('mandatory') + config.cfgimpl_get_settings().remove('empty') + if from_zephir is not None: + return tiramisu_objects.groups, tiramisu_objects.separators, config + else: + return config diff --git a/creole/loader1.py b/creole/loader1.py new file mode 100644 index 0000000..e22242f --- /dev/null +++ b/creole/loader1.py @@ -0,0 +1,769 @@ +# -*- coding: utf-8 -*- + +#import cjson +import json +import fcntl +import stat +import logging + +from os.path import isdir, isfile, join, basename, dirname, splitext +from os import listdir, makedirs, major, minor +from os import stat as os_stat +from distutils.version import StrictVersion +try: + from collections import OrderedDict +except: + from pyeole.odict import OrderedDict + +from tiramisu.option import UnicodeOption, OptionDescription, \ + IntOption, ChoiceOption, BoolOption, SymLinkOption, IPOption, \ + NetworkOption, NetmaskOption +from tiramisu.error import PropertiesOptionError, LeadershipError +from tiramisu.setting import owners + +from .config import configeol, eoledirs, dtdfilename, eoleextradico, \ + eoleextraconfig, forbiddenextra, VIRTROOT, \ + VIRTBASE, VIRTMASTER, templatedir +from .error import ConfigError +from .var_loader import modes_level, CreoleFamily, CreoleConstraint, \ + CreoleVarLoader +try: + from .client import CreoleClient, CreoleClientError + client = CreoleClient() +except: + client = None +from pyeole.encode import normalize +try: + from .eosfunc import is_instanciate, get_version +except: + pass + +from .i18n import _ + +log = logging.getLogger(__name__) + +class CreoleContainer(): + """ + Charge les conteneurs, les fichiers, les packages, services, interfaces + et disknods + """ + def gen_containers(self, paths): + """ + Generate Containers information in tiramisu tree + + :paths: paths variables (for added new option in paths's dictionnary) + """ + containers = [] + for name, container in self._get_containers().items(): + container['path'] = 'container_path_{0}'.format(name) + container['ip'] = 'container_ip_{0}'.format(name) + containers.append(container) + + key_type = {'id': IntOption, 'group': UnicodeOption, + 'ip': SymLinkOption, 'path': SymLinkOption, + 'level': UnicodeOption} + + return self._gen_tiramisu_config(paths, "container", containers, + key_type) + + def gen_networks(self, paths): + var = [] + descr = None + namespace = paths['adresse_ip_br0'].split('.')[0] + for descr_ in self.space: + if descr_._name == namespace: + descr = descr_ + break + if descr == None: + raise Exception(_(u'Unable to find namespace: {0}').format( + namespace)) + for name in ['adresse_ip_br0', 'adresse_netmask_br0', + 'adresse_network_br0', 'adresse_broadcast_br0']: + path = paths[name] + subpath = path.split('.')[1:] + opt = descr + for p in subpath: + opt = getattr(opt, p) + var.append(SymLinkOption(name, opt)) + return OptionDescription('network', '', var) + + def gen_interfaces(self, paths): + """Add per container interface linked to inter-containers bridge + + Theses interfaces must come before other containers ones as + default gateway. + + """ + lxc_net = OrderedDict() + if self.containers_enabled: + interfaces = OrderedDict() + containers = self._get_containers() + + for name, container in containers.items(): + if name in ['all', 'root']: + continue + lxc_net[name] = {'name': 'containers', + 'container': name, + 'linkto': 'br0', + 'method': 'bridge', + 'ip': 'container_ip_{0}'.format(name), + 'mask': 'adresse_netmask_br0', + 'bcast': 'adresse_broadcast_br0', + 'gateway': 'adresse_ip_br0'} + + # Insert default interfaces before + self.generic['interfaces'] = lxc_net.values() \ + + self.generic['interfaces'] + + return self.gen_generic('interfaces', paths, copy_requires='ip') + + def gen_service_accesss(self, paths): + return self.__gen_service_access_restriction('service_access', paths) + + def gen_service_restrictions(self, paths): + return self.__gen_service_access_restriction('service_restriction', paths) + + def __gen_service_access_restriction(self, service_type, paths): + """Add services requires to service_access/service_restriction + If a service is disabled, we remove, also, access to this service + """ + generic_name = service_type + 's' + list_name = service_type + 'list' + if 'service' in self.requires: + for gen in self.generic[generic_name]: + service_name = gen['service'] + requires_name = gen.get(list_name) + if requires_name is None: + requires_name = '___auto_{0}'.format(service_name) + gen[list_name] = requires_name + self.requires[service_type][requires_name] = {'optional': True, 'list': []} + if service_name in self.requires['service']: + service_requires = self.requires['service'][service_name]['list'] + if self.requires['service'][service_name]['optional'] is False: + self.requires['service'][service_name]['optional'] = False + self.requires[service_type][requires_name]['list'].extend(service_requires) + return self.gen_generic(generic_name, paths, verify_exists_redefine=False) + + def _gen_file(self, fdata, container, containers): + """Generate one file structure for one container + + :param fdata: file informations + :type fdata: `dict` + :param container: container of the file + :type container: `dict` + :return: file information for a container + :rtype: `dict` + + """ + file_infos = fdata.copy() + # take care of os.path.join and absolute part after first + # argument. + _file = fdata['name'] + if _file[0] == '/': + _file = _file[1:] + + file_infos['container'] = container['name'] + file_infos['full_name'] = fdata['name'] + if self.containers_enabled and container['name'] != VIRTMASTER: + # Prefix the full path with container rootfs + if fdata['container'] == 'all': + cont_grp = container['group'] + else: + cont_grp = fdata['container'] + cont_name = self.get_real_container_name(containers, cont_grp) + _file = join(VIRTROOT, cont_name, VIRTBASE, _file) + file_infos['full_name'] = _file + + source = file_infos.get('source', basename(_file)) + source = join(templatedir, source) + file_infos['source'] = source + return file_infos + + def gen_files(self, paths): + containers = self._get_containers() + files = [] + for fdata in self.generic.get('files', []): + if fdata['container'] == 'all': + # Generate a file per container + for container in containers.values(): + if container['name'] in ['all', VIRTMASTER]: + continue + files.append(self._gen_file(fdata, container, containers)) + else: + container = containers[fdata['container']] + files.append(self._gen_file(fdata, container, containers)) + + key_type = {'source': UnicodeOption, 'mode': UnicodeOption, + 'full_name': UnicodeOption, + 'owner': UnicodeOption, 'group': UnicodeOption, + 'mkdir': BoolOption, 'rm': BoolOption, + 'del_comment': UnicodeOption, + 'level': UnicodeOption} + return self._gen_tiramisu_config(paths, "file", files, key_type, + requires_key='activate') + + def gen_disknods(self, paths): + containers = self._get_containers() + disknods = [] + for fdata in self.generic.get('disknods', []): + stats = os_stat(fdata['name']) + if stat.S_ISBLK(stats.st_mode): + dev_type = u'b' + device = stats.st_rdev + elif stat.S_ISCHR(stats.st_mode): + dev_type = u'c' + device = stats.st_rdev + elif stat.S_ISDIR(stats.st_mode): + dev_type = u'b' + device = stats.st_dev + else: + dev_type = None + device = None + fdata['type'] = dev_type + if device is not None: + fdata['major'] = major(device) + fdata['minor'] = minor(device) + else: + fdata['major'] = None + fdata['minor'] = None + fdata['mode'] = u'rwm' + fdata['permission'] = 'allow' + disknods.append(fdata) + + key_type = {'major': IntOption, + 'minor': IntOption, + 'name': UnicodeOption, + 'permission': UnicodeOption, + 'mode': UnicodeOption, + 'type': UnicodeOption, + 'level': UnicodeOption} + return self._gen_tiramisu_config(paths, "disknod", disknods, key_type) + + def gen_packages(self, paths): + # c'est le dernier 'package' qui a raison + # (si présence de deux balises package avec le même nom dans le + # même conteneur) + return self.gen_generic('packages', paths, verify_exists_redefine=False) + + +class CreoleLoader(CreoleVarLoader, CreoleContainer): + """ + charge les variables + les conteneurs + """ + pass + + +def _gen_eol_file(namespace, root_path=None): + if namespace == 'creole': + return unicode(configeol) + else: + if root_path is None: + root_path = eoleextraconfig + return unicode(join(root_path, namespace, 'config.eol')) + + +def _list_extras(extradico=eoleextradico): + extranames = [] + if isdir(extradico): + for directory in listdir(extradico): + content = listdir(join(extradico, directory)) + if not len(content) == 0: + extensions = [splitext(filename)[1] for filename in content] + if ".xml" in extensions: + extranames.append(directory) + return extranames + + +def set_mandatory_permissive(config, action): + descr = config.cfgimpl_get_description() + parent = getattr(descr, action, None) + if parent is not None: + for family in parent.impl_getchildren(): + for option in family.impl_getchildren(): + if 'mandatory' in option.impl_getproperties(): + config.cfgimpl_get_settings().setpermissive(('mandatory',), option) + + +def load_extras(config, load_values=True, mandatory_permissive=False, extradico=eoleextradico, + force_eoleextraconfig=None): + actions = set() + if mandatory_permissive and hasattr(config, 'actions'): + for name, family in config.actions.iter_groups(): + for aname, action in family.iter_groups(): + actions.add(action.name) + for extraname in _list_extras(extradico=extradico): + if extraname in ['creole', 'containers', 'actions']: + raise Exception(_('extra name {} not allowed').format(extraname)) + eol_file = _gen_eol_file(extraname, root_path=force_eoleextraconfig) + config.impl_set_information(extraname, eol_file) + if extraname in actions: + set_mandatory_permissive(config, extraname) + if not load_values: + continue + #if file not exists, create it (for auto_freeze value) + if not isfile(eol_file): + try: + config_save_values(config, extraname, reload_config=False, check_mandatory=False) + except PropertiesOptionError: + pass + if isfile(eol_file): + config_load_values(config, extraname) + + +def load_config_eol(config, configfile=None, try_upgrade=True, force_load_owner=None, + current_eol_version=None, force_instanciate=None): + if not configfile: + configfile = _gen_eol_file('creole') + config.impl_set_information('creole', configfile) + config_load_values(config, 'creole', force_load_owner=force_load_owner, + force_instanciate=force_instanciate) + load_values(config, + configfile=configfile, + try_upgrade=try_upgrade, + force_load_owner=force_load_owner, + current_eol_version=current_eol_version) + +def load_config_store(config, store, unset_default=False, + force_load_owner=None, current_eol_version=None, + force_instanciate=None, remove_unknown_vars=False, + try_upgrade=False): + """used on Zéphir to upgrade values (2.4.X -> 2.4.X+1) on a configuration + that has already been migrated (2.2/2.3 −> 2.4) + """ + config_load_store(config, 'creole', store, force_load_owner=force_load_owner, + unset_default=unset_default, force_instanciate=force_instanciate) + load_values(config, + try_upgrade=try_upgrade, + force_load_owner=force_load_owner, + current_eol_version=current_eol_version, + remove_unknown_vars=remove_unknown_vars) + +def load_values(config, configfile=None, try_upgrade=True, force_load_owner=None, + current_eol_version=None, remove_unknown_vars=False): + load_error = config.impl_get_information('load_error', False) + if load_error and try_upgrade: + #Try to upgrade + from .upgrade import upgrade + try: + store_dico, version = upgrade(config, configfile) + config_load_store(config, 'creole', store_dico, unset_default=True, eol_version='1.0') + config.impl_set_information('upgrade', version) + remove_unknown_vars = True + load_error = False + except Exception as e: + log.error(_('Error when trying to upgrade config file: {}').format(e)) + config.impl_set_information('load_error', True) + #print "fichier de configuration invalide 2.2 ou 2.3: {0} : {1}".format(configfile, e) + if current_eol_version == None: + current_eol_version = get_version('EOLE_RELEASE') + eol_version = str(config.impl_get_information('eol_version')) + if try_upgrade and not load_error: + if StrictVersion(eol_version) > StrictVersion(current_eol_version): + raise Exception(_('eol_version ({0}) is greater than current version ({1})').format(eol_version, current_eol_version)) + if StrictVersion(eol_version) < StrictVersion(current_eol_version): + #can be used to edit lower versions on Zéphir + from .upgrade24 import upgrade2 + try: + # 2.4.x (greater than 2.4.0) + if StrictVersion(current_eol_version) >= StrictVersion('2.4.0') and StrictVersion(eol_version) < StrictVersion('2.5.0'): + upgrade2('2.4', eol_version, current_eol_version, config) + # 2.5.x (greater than 2.5.0) + if StrictVersion(current_eol_version) >= StrictVersion('2.5.0') and StrictVersion(eol_version) < StrictVersion('2.6.0'): + upgrade2('2.5', eol_version, current_eol_version, config) + # 2.6.x (greater than 2.6.0) + if StrictVersion(current_eol_version) >= StrictVersion('2.6.0') and StrictVersion(eol_version) < StrictVersion('2.7.0'): + upgrade2('2.6', eol_version, current_eol_version, config) + if config.impl_get_information('upgrade', '') == '': + #set the version only if it is the first upgrade + config.impl_set_information('upgrade', eol_version) + except Exception as e: + log.error(_('Error when trying to upgrade config file: {}').format(normalize(str(e)))) + config.impl_set_information('upgrade', False) + config.impl_set_information('load_error', True) + + if remove_unknown_vars: + # nettoyage des variables inconnues en dernier (#9858) + config.impl_set_information('unknown_options', {}) + +def creole_loader(load_values=True, rw=False, namespace='creole', + load_extra=False, reload_config=True, owner=None, + disable_mandatory=False, force_configeol=None, + try_upgrade=True, force_load_creole_owner=None, + force_dirs=None, warnings=None, force_instanciate=None): + """ + charge les dictionnaires Creole et retourne une config Tiramisu + + :load_values: boolean. Charge ou non le fichier config.eol (default True) + :rw: boolean. Mode de travail (lecture seule ou lecture/écriture) + :namespace: string. Espace de travail (ex: "creole", "bacula", ...) + :load_extra: boolean. Charge ou non les dictionnaire extra (si namespace='creole') + :reload_config: boolean. Cette option est conservée pour raison de compatibilité + ascendante mais n'a plus de justification, a ne pas utiliser + :owner: string. Owner forcé sur les variables modifiées + :disable_mandatory: boolean. + :force_configeol: string. Force le nom du fichier de configuration utilisé + :try_upgrade: boolean. + :force_dirs: string. Force le nom du réprtoire contenant les dictionnaires + :force_load_creole_owner: Owner forcé pour les variables chargées + :warnings: affiche les warnings de validation + """ + if force_configeol is not None: + if not isfile(force_configeol): + raise ConfigError(_(u"Configuration file unexistent : {0}").format( + force_configeol)) + if load_extra: + #if force_configeol, cannot calculated extra configfile name + raise Exception(_(u'Unable to force_configeol with load_extra.')) + if force_dirs is not None and (load_extra is True or namespace != 'creole'): + raise Exception(_(u'If force_dirs is defined, namespace must be set to creole and load_extra must be set to False.')) + if namespace != 'creole' and load_extra: + raise ValueError(_(u'namespace is not creole, so load_extra is forbidden.')) + #should not load value now because create a Config + loader = CreoleLoader() + if force_dirs is not None: + dirs = force_dirs + elif namespace == 'creole': + dirs = eoledirs + else: + dirs = join(eoleextradico, namespace) + #load config + loader.read_dir(dirs, namespace) + if load_extra: + extranames = _list_extras() + if isdir(eoleextradico): + for directory in extranames: + if directory in forbiddenextra: + raise ValueError( + _(u'Namespace {} for extra dictionary not allowed').format(directory)) + loader.read_dir(join(eoleextradico, directory), directory) + config = loader.get_config() + if warnings is None: + # warnings is disabled in read-only mode and enabled in read-write mode by default + warnings = rw + if warnings is False: + config.cfgimpl_get_settings().remove('warnings') + if owner is not None: + if owner not in dir(owners): + owners.addowner(owner) + config.cfgimpl_get_settings().setowner(getattr(owners, owner)) + #load values + if force_configeol is not None: + configfile = force_configeol + else: + configfile = _gen_eol_file(namespace) + if load_values and isfile(configfile): + disable_mandatory = False + load_config_eol(config, configfile=configfile, try_upgrade=try_upgrade, + force_load_owner=force_load_creole_owner, + force_instanciate=force_instanciate) + else: + config.impl_set_information(namespace, configfile) + if load_extra: + load_extras(config, load_values=load_values) + if rw: + config.read_write() + elif rw is False: + config.read_only() + + if disable_mandatory: + config.cfgimpl_get_settings().remove('mandatory') + config.cfgimpl_get_settings().remove('empty') + return config + + +def valid_store(store): + if not isinstance(store, dict): + raise Exception('store is not a dict: {0}'.format(store)) + for key, value in store.items(): + if not isinstance(key, unicode): + raise Exception('store key is not an unicode for {0}'.format(key)) + if key != '___version___' and (not isinstance(value, dict) or value.keys() != ['owner', 'val']): + raise Exception('store value is not a dict for {0}'.format(key)) + + +def load_store(config, eol_file=configeol): + if not isfile(eol_file): + store = {} + else: + fh = open(eol_file, 'r') + fcntl.lockf(fh, fcntl.LOCK_SH) + try: + store = cjson.decode(fh.read(), all_unicode=True) + except cjson.DecodeError: + config.impl_set_information('load_error', True) + store = {} + fh.close() + try: + valid_store(store) + except Exception as err: + config.impl_set_information('load_error', True) + store = {} + return store + + +def config_load_store(config, namespace, store, force_instanciate=None, + unset_default=False, force_load_owner=None, eol_version='2.4.0'): + subconfig = getattr(config, namespace) + cache_paths = config.cfgimpl_get_description()._cache_paths[1] + unknown_options = {} + + def reorder_store(path1, path2): + """ + sorter function. + + sort description : if varname1 is a master and varname 2 + is a slave, returns [varname1, varname2] + """ + idx_1 = cache_paths.index(path1) + idx_2 = cache_paths.index(path2) + return cmp(idx_1, idx_2) + + def store_path_and_reorder(eol_version): + """Convenience function to replace varnames with full paths + and to sort an unordered ConfigObj's + + :returns: a sorted ordereddict. + """ + store_path = {} + if namespace == 'creole': + paths = {} + for path in subconfig.cfgimpl_get_description().impl_getpaths(): + vname = path.split('.')[-1] + paths[vname] = namespace + '.' + path + #variable pas dans Tiramisu + for vname, value in store.items(): + if vname == '___version___': + eol_version = value + elif vname not in paths: + unknown_options[vname] = value + if vname not in paths or value == {}: + continue + store_path[paths[vname]] = value + else: + paths = [] + subpaths = subconfig.cfgimpl_get_description().impl_getpaths() + for path in subpaths: + paths.append(namespace + '.' + path) + for vname, value in store.items(): + if vname == '___version___': + eol_version = value + continue + elif vname not in paths: + continue + store_path[vname] = value + store_order = OrderedDict() + store_key = store_path.keys() + store_key.sort(reorder_store) + for path in store_key: + store_order[path] = store_path[path] + return eol_version, store_order + + #don't frozen auto_freeze before instance (or enregistrement_zephir for Zephir) + if force_instanciate is not None: + is_inst = force_instanciate + else: + is_inst = is_instanciate() + eol_version, store = store_path_and_reorder(eol_version) + orig_values = {} + for path, values in store.items(): + value = values['val'] + option = config.unwrap_from_path(path) + settings = config.cfgimpl_get_settings() + tiramisu_values = config.cfgimpl_get_values() + if force_load_owner is not None: + owner = force_load_owner + else: + owner = values['owner'] + if isinstance(owner, dict): + for towner in owner.values(): + if towner not in dir(owners): + owners.addowner(towner) + else: + if owner not in dir(owners): + owners.addowner(owner) + try: + #si unset_default, remet à la valeur par défaut si == à la valeur + if unset_default and value == getattr(config, path): + continue + if isinstance(value, tuple): + value = list(value) + values['val'] = value + orig_values[path.split('.')[-1]] = values + if option.impl_is_master_slaves('slave'): + if not isinstance(owner, dict): + new_owner = getattr(owners, owner) + multi = config.getattr(path, force_permissive=True) + if isinstance(value, list): + tval = {} + for idx, val in enumerate(value): + tval[idx] = val + value = tval + for idx, val in value.items(): + index = int(idx) + if len(multi) > index: + multi[index] = val + if isinstance(owner, dict): + new_owner = getattr(owners, owner[idx]) + tiramisu_values.setowner(option, new_owner, index=index) + else: + log.error(_("master's len is lower than the slave variable ({})").format(path)) + else: + if isinstance(owner, str): + owner = unicode(owner) + if not isinstance(owner, unicode): + raise Exception(_('owner must be a string for {}').format(path)) + new_owner = getattr(owners, owner) + try: + config.setattr(path, value, force_permissive=True) + except ValueError as e: + if path == 'schedule.schedule.weekday' and 'schedule.schedule.monthday' in store: + settings.remove('validator') + config.setattr(path, value, force_permissive=True) + config.setattr('schedule.schedule.monthday', store['schedule.schedule.monthday'], force_permissive=True) + settings.append('validator') + else: + raise e + tiramisu_values.setowner(option, new_owner) + except ValueError as e: + msg = str(e).decode('utf8') + #msg = unicode(e) + log.error(_('unable to load variable {} with value {}: {}').format(path, value, msg)) + settings[option].append('load_error') + config.impl_set_information('error_msg_{}'.format(path), msg) + config.impl_set_information('orig_value_{}'.format(path), value) + except LeadershipError: + # ne pas faire d'erreur #8380 + pass + try: + config.impl_get_information('force_store_vars').remove(path) + except (KeyError, ValueError) as err: + pass + + path_split = path.split('.') + family_option = config.unwrap_from_path(namespace + '.' + path_split[1]) + settings.setpermissive(tuple(modes_level), opt=family_option) + if len(path_split) == 4: + parent_option = config.unwrap_from_path(namespace + '.' + path_split[1] + '.' + path_split[2]) + settings.setpermissive(tuple(modes_level), opt=parent_option) + settings.setpermissive(tuple(modes_level), opt=option) + setting = config.cfgimpl_get_settings() + if 'auto_freeze' in setting[option] and is_inst == 'oui' and \ + not tiramisu_values.is_default_owner(option): + setting[option].append('frozen') + if namespace == 'creole': + config.impl_set_information('unknown_options', unknown_options) + config.impl_set_information('eol_version', eol_version) + config.impl_set_information('orig_values', orig_values) + +def config_load_values(config, namespace, eol_file=None, force_instanciate=None, + force_load_owner=None): + subconfig = getattr(config, namespace, None) + if subconfig is None: + return + if eol_file is None: + try: + eol_file = config.impl_get_information(namespace) + except AttributeError: + raise Exception(_(u'config must have eol_file attribute')) + else: + config.impl_set_information(namespace, eol_file) + if not isfile(eol_file): + raise IOError(_(u'Can not find file {0}').format( + eol_file)) + store = load_store(config, eol_file) + config_load_store(config, namespace, store, + force_instanciate=force_instanciate, + force_load_owner=force_load_owner) + +def config_get_values(config, namespace, check_mandatory=True, ignore_autofreeze=False): + """check_mandatory: allows to disable mandatory checking + (i.e : when returning values for partial configuration in Zéphir) + """ + def _get_varname(path): + if namespace == 'creole': + value_name = path.split('.')[-1] + else: + value_name = path + return value_name + + subconfig = getattr(config, namespace) + if check_mandatory: + mandatory_errors = list(config.cfgimpl_get_values( + ).mandatory_warnings(force_permissive=True)) + if mandatory_errors != []: + text = [] + for error in mandatory_errors: + if not error.startswith(namespace + '.'): + continue + error = error.split('.') + text.append(_(u"Mandatory variable '{0}' from family '{1}'" + u" is not set !").format(unicode(error[-1]), + unicode(error[1].capitalize())).encode('utf-8')) + if text != []: + raise PropertiesOptionError("\n".join(text), ('mandatory',)) + store = {} + opt_values = subconfig.cfgimpl_get_values().get_modified_values() + force_store_values = config.impl_get_information('force_store_values', None) + + for path, own_val in opt_values.items(): + #for variable not related to current namespace + if not path.startswith(namespace+'.'): + continue + if force_store_values and path in force_store_values: + force_store_values.remove(path) + store[_get_varname(path)] = {'val': own_val[1], 'owner': own_val[0]} + if force_store_values: + for path in force_store_values: + varname = _get_varname(path) + if varname not in store: + try: + store[varname] = {'val': config.getattr(path, force_permissive=True), 'owner': u'forced'} + except PropertiesOptionError: + pass + if namespace == 'creole': + #update with values in store with no known options + store.update(config.impl_get_information('unknown_options', {})) + return store + + +def add_eol_version(store, eol_version=None): + # on stocke la version passée en paramètre (si >= 2.4.1) ou celle du système le cas échéant + if eol_version: + if StrictVersion(eol_version) >= StrictVersion('2.4.1'): + store['___version___'] = eol_version + else: + store['___version___'] = get_version('EOLE_RELEASE') + + +def config_save_values(config, namespace, reload_config=True, eol_file=None, check_mandatory=True, eol_version=None): + subconfig = getattr(config, namespace) + if eol_file is not None: + config.impl_set_information(namespace, eol_file) + try: + eol_file = config.impl_get_information(namespace) + except AttributeError: + raise Exception(_(u'config must have eol_file attribute')) + store = config_get_values(config, namespace, check_mandatory) + add_eol_version(store, eol_version) + try: + dirn = dirname(eol_file) + if not isdir(dirn): + makedirs(dirn) + if not isfile(eol_file): + fh = file(eol_file, 'w') + fcntl.lockf(fh, fcntl.LOCK_EX) + else: + fh = file(eol_file, 'r+') + fcntl.lockf(fh, fcntl.LOCK_EX) + fh.truncate() # Here's where the magic happens #7073 + fh.write(cjson.encode(store)) + fh.close() + except Exception as err: + raise Exception(_(u"Error saving file: {0}").format(err)) + if client is not None and reload_config: + try: + client.reload_eol() + #client.reload_config() + except CreoleClientError: + pass + return True diff --git a/creole/lxml_parser.py b/creole/lxml_parser.py new file mode 100644 index 0000000..e7514e6 --- /dev/null +++ b/creole/lxml_parser.py @@ -0,0 +1,454 @@ +# -*- coding: utf-8 -*- +""" +Parseur LXML des fichiers XML de collecte des variables EOLE +""" +from lxml import etree +from copy import copy +from .error import ConfigError +from .utils import string_to_bool #, get_text_node +from .config import VIRTMASTER +from .dtd_parser import CONVERT_VALUE +from pyeole.odict import OrderedDict + +from .i18n import _ + +def parse_xml_file(filename, dtd, parse_all=True, test_duplicate=False): + """ + @param filename: nom du fichier xml source + @return: structure de données permettant de créer les objets Eole + """ + try: + document = etree.iterparse(filename, events=('end',), tag='creole') + return _parse_root_node(document, dtd, parse_all, test_duplicate) + except Exception as err: + raise ConfigError(_(u"Error while parsing file {0}: {1}").format(filename, err)) + +def parse_string(xml_string, dtd, parse_all=True, test_duplicate=False): + """ + @param xml_string: dictionnaire xml sous forme de chaîne + @return: structure de données permettant de créer les objets Eole + """ + try: + root_node = etree.fromstring(xml_string) + document = etree.iterwalk(root_node, events=('end',), tag='creole') + return _parse_root_node(document, dtd, parse_all, test_duplicate) + except Exception as err: + raise ConfigError(_(u"Error while parsing: {0}").format(err)) + +def _parse_root_node(document, dtd, parse_all, test_duplicate=False): + """ + @param document: le noeud XML racine + """ + def _parse_container(node, options, container_name): + for name in options: + key_name = '{0}s'.format(name) + ret.setdefault(key_name, []) + values = parse_generic(node.findall(name), + container_name, dtd, name) + if values != []: + ret[key_name].extend(values) + + for unused, first_node in document: + root_node = first_node + + #verifie les doublons de variable dans le meme dico + if test_duplicate: + all_var_dict = [] + for var in root_node.findall('variables/family/variable'): + name = var.attrib['name'] + if name in all_var_dict: + raise ConfigError(_(u'Error, var {0} already exists in current dictionaries').format(name)) + all_var_dict.append(name) + + ret = {'families': parse_families(root_node)} + families_action = parse_actions(root_node, dtd) + if len(families_action) != 0: + ret['families_action'] = families_action + + ret['containers'] = [] + ## balise (données sur le maître) + file_node = root_node.findall('files') + if file_node != []: + if len(file_node) != 1: + raise Exception(_(u"Error: extra tags in dictionaries.")) + if parse_all: + _parse_container(file_node[0], dtd['files']['options'], VIRTMASTER) + ret['containers'].append({'name': VIRTMASTER, 'id': '1'}) + + ## balise (données dans les conteneurs) + containers_node = root_node.findall('containers') + if containers_node != []: + if len(containers_node) != 1: + raise Exception(_(u"Error: extra tags in dictionaries.")) + container = containers_node[0] + for container_node in container.getiterator('container'): + name = container_node.attrib['name'] + if name in [VIRTMASTER, 'all']: + raise Exception(_(u"Name '{0}' is not allowed in tag .").format(name)) + if name in ret['containers']: + raise Exception( + _(u"There must be only one name '{0}' in a dictionary.").format(name)) + containerid = _get_optional(container_node, 'id') + groupid = _get_optional(container_node, 'group') + ret['containers'].append({'name': name, 'id': containerid, + 'group': groupid}) + if parse_all: + _parse_container(container_node, dtd['container']['options'], name) + if parse_all: + all_node = container.findall('all') + if all_node != []: + if len(all_node) != 1: + raise Exception(_(u"Error: extra tags in dictionaries.")) + ret['containers'].append({'name': 'all'}) + _parse_container(all_node[0], dtd['all']['options'], 'all') + + ## gestion des contraintes + #FIXME + ret.update(parse_constraints(root_node)) + + ## gestion des groupes de variables + ret['groups'] = parse_groups(root_node) + + ## gestion de l'aide + ret['helps'] = parse_help(root_node) + + ## gestion des séparateurs + ret['separators'] = parse_separators(root_node) + return ret + + +def _get_boolean_attr(node, attr_name, default=False): + """ + Gestion spécifique pour les attributs booléens + Ils sont à False par défaut + """ + val = node.get(attr_name) + if default: + return str(val).lower() != 'false' + elif val is None: + return None + else: + return str(val).lower() == 'true' + + +def _get_optional(node, attr_name): + """ + Valeur d'un attribut optionnel + """ + return node.get(attr_name) + + +def _parse_value(varnode, attr='value'): + """ + récupération des valeurs d'une variable + """ + res = [] + for val in varnode.findall(attr): + # FIX for ! + if val.text is not None: + res.append(val.text) + else: + res.append('') + return res + +def parse_value(varnode, name): + """ + récupération des valeurs d'une variable + """ + res = None + for val in varnode.findall('value'): + if val.text is not None: + tval = val.text + if res != None: + #str to list + if type(res) == str: + res = [res] + res.append(tval) + else: + res = tval + return res + +def parse_generic(nodes, container, dtd, name, old_result=None): + ret = [] + keys = dtd[name] + for node in nodes: + if old_result: + result = copy(old_result) + result['node_name'] = name + elif container is not None: + result = {'container': container} + else: + result = {} + if keys['type']: + if 'name' in keys['needs'] or 'name' in keys['optionals']: + raise Exception('PCDATA + name') + result['name'] = node.text + for key, values in keys['needs'].items(): + value = node.attrib[key] + value = CONVERT_VALUE.get(value, value) + if values['values'] is not None and value not in values['values']: + raise Exception(_(u"Value {0} not in {1}").format(value, values['values'])) + result[key] = value + for key, values in keys['optionals'].items(): + value = node.attrib.get(key, values['default']) + value = CONVERT_VALUE.get(value, value) + if value != None: + if values['values'] is not None and value not in values['values']: + raise Exception(_(u"Value {0} not in {1}").format(value, values['values'])) + result[key] = value + if keys['options'] == []: + ret.append(result) + else: + for option in keys['options']: + ret.extend(parse_generic(node.findall(option), container, dtd, option, result)) + return ret + + +def parse_variables(var_node): + """ + traitement des variables + @param var_node: noeud + """ + result = OrderedDict() + for var in var_node.getiterator('variable'): + # Default variables are handled in creole.loader + hidden = _get_boolean_attr(var, 'hidden') + multi = _get_boolean_attr(var, 'multi') + redefine = _get_boolean_attr(var, 'redefine') + mandatory = _get_boolean_attr(var, 'mandatory') + remove_check = _get_boolean_attr(var, 'remove_check') + remove_condition = _get_boolean_attr(var, 'remove_condition') + exists = _get_boolean_attr(var, 'exists', default=True) + disabled = _get_boolean_attr(var, 'disabled', default=False) + auto_freeze = _get_boolean_attr(var, 'auto_freeze') + auto_save = _get_boolean_attr(var, 'auto_save') + mode = _get_optional(var, 'mode') + name = var.attrib['name'] + value = parse_value(var, var.attrib['name']) + typ = _get_optional(var, 'type') + if typ == None: + typ = 'string' + desc = _get_optional(var, 'description') + if type(desc) == unicode: + desc = desc.encode('utf-8') + result[name] = dict(value=value, + type=typ, + description=desc, + hidden=hidden, + multi=multi, + auto='', + redefine=redefine, + exists=exists, + auto_freeze=auto_freeze, + auto_save=auto_save, + mode=mode, + mandatory=mandatory, + disabled=disabled, + remove_check=remove_check, + remove_condition=remove_condition + ) + return result + +def parse_families(var_node): + """ + traitement des familles + @param var_node: noeud + """ + result = OrderedDict() + for family in var_node.findall('variables/family'): #: getiterator('family'): + family_name = family.attrib['name'] + if family_name in result: + raise Exception(_(u"Family {0} is set several times.").format(family_name)) + hidden = _get_boolean_attr(family, 'hidden') + # FIXME: mode='' était admis avec domparser + mode = _get_optional(family, 'mode') + icon = _get_optional(family, 'icon') + variables = parse_variables(family) + result[family_name] = {'hidden': hidden, + 'mode': mode, + 'vars': variables, + 'icon': icon + } + return result + + +def parse_actions(root_node, dtd): + """ + traitement des familles + @param var_node: noeud + """ + result = OrderedDict() + def _parse_action(node, options): + parse = {} + for name in options: + key_name = '{0}'.format(name) + parse.setdefault(key_name, []) + values = parse_generic(node.findall(name), None, dtd, name) + if values != []: + parse[key_name].extend(values) + parse['type'] = node.get("type", "custom") + parse['title'] = node.get('title') + parse['description'] = node.get('description') + image = node.get('image') + if image: + parse['image'] = image + url = node.get('url', None) + if url: + parse['url'] = url + return parse + + for family in root_node.findall('family_action'): #: getiterator('family'): + family_name = family.attrib['name'] + if family_name in result: + raise Exception(_(u"Action Family {0} is set several times.").format(family_name)) + description = _get_optional(family, 'description') + color = _get_optional(family, 'color') + image = _get_optional(family, 'image') + ## balise + action_node = family.findall('action') + if action_node != [] and len(action_node) != 1: + raise Exception(_(u"Error: extra tags in dictionaries.")) + action = _parse_action(action_node[0], dtd['action']['options']) + result[family_name] = {'name': family_name, + 'description': description, + 'color': color, + 'image': image, + 'action': action + } + return result + +def parse_constraints(node): + """ + @param node: node des contraintes + """ + constraints = {'checks' : parse_funcs(node,'check'), + 'fills' : parse_funcs(node,'fill'), + 'autos' : parse_funcs(node,'auto'), + 'conditions' : parse_conditions(node) + } + return constraints + + +def _parse_param(param_node): + """ + traitement des paramètres d'une fonction + """ + return {'name' : _get_optional(param_node, 'name'), + 'type' : _get_optional(param_node, 'type'), + 'value' : param_node.text, + 'optional' : _get_optional(param_node, 'optional'), + 'hidden' : _get_optional(param_node, 'hidden'), + } + + +def parse_funcs(node, func_type): + """ + @param node: node des fonctions + @param func_type: TagName of the functions to find + @return: {target: [(param_name, _parse_params('param'))]} + """ + # fonctions de vérification + funcs = {} + for func in node.findall('constraints/%s' % func_type): + # lecture des paramètres + params = [] + #si balise + targets = _parse_value(func, 'target') + #sinon c'est un attribut target= + if not targets: + #met dans une liste parce que retourne une liste + targets = [_get_optional(func, 'target')] + level = _get_optional(func, 'level') + if not level: + level = 'error' + for target in targets: + if target is not None: + for param in func.getiterator('param'): + params.append(_parse_param(param)) + funcs.setdefault(target, []).append((func.attrib['name'], + params, level)) + return funcs + + +def parse_conditions(node): + """ + @param node: node des fonctions + """ + # fonctions de vérification + funcs = {} + for func in node.getiterator('condition'): + # lecture des paramètres + targets = [] + family_targets = [] + list_targets = [] + # paramètres de la fonction + params = [_parse_param(param) + for param in func.getiterator('param')] + # cibles de la dépendance + for target in func.getiterator('target'): + ttype = target.get('type') + optional = target.get('optional', False) + if ttype == 'family': + family_targets.append((target.text, optional)) + elif ttype in ['variable', None]: + targets.append((target.text, optional)) + else: + if ttype.endswith('list'): + #suppress list in ttype + list_targets.append((ttype[:-4], target.text, optional)) + else: + raise Exception(_(u'Unknown type {0} for condition target.').format(ttype)) + funcdef = {'name': func.attrib['name'], 'family': family_targets, + 'variable': targets, 'list': list_targets, 'param': params, + 'fallback': _get_boolean_attr(func, 'fallback')} + source = _get_optional(func, 'source') + if source == None: + raise Exception(_(u'Impossible condition without source for {0}.').format(funcdef)) + funcs.setdefault(source, []).append(funcdef) + return funcs + + +def parse_groups(node): + """ + Traitement des groupes de variables + """ + result = {} + for group in node.findall('constraints/group'): + slaves = _parse_value(group, 'slave') + result[group.attrib['master']] = slaves + return result + + +def parse_help(node): + """ + Traitement de l'aide + """ + var_help = {} + for var in node.findall('help/variable'): + name = var.attrib['name'] + try: + var_help[name] = var.text.strip() + except AttributeError: + raise Exception(_(u"Invalid help for variable {0}.").format(name)) + fam_help = {} + for var in node.findall('help/family'): + name = var.attrib['name'] + try: + fam_help[name] = var.text.strip() + except AttributeError: + raise Exception(_(u"Invalid help for family {0}").format(name)) + return {'variables':var_help, 'families': fam_help} + + +def parse_separators(node): + """dictionnaire des séparateurs, format {'variable':'text'} + variable : nom de la première variable après le sépateur""" + var_sep = {} + for var in node.findall('variables/separators/separator'): + if not var.text: + libelle = '' + else: + libelle = var.text.strip() + var_sep[var.attrib['name']] = (libelle, _get_boolean_attr(var, 'never_hidden')) + return var_sep + diff --git a/creole/maj.py b/creole/maj.py new file mode 100644 index 0000000..c929b91 --- /dev/null +++ b/creole/maj.py @@ -0,0 +1,148 @@ +# -*- coding: utf-8 -*- +########################################################################### +# +# Eole NG - 2010 +# Copyright Pole de Competence Eole (Ministere Education - Academie Dijon) +# Licence CeCill http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html +# eole@ac-dijon.fr +# +########################################################################### +""" +Librairie pour la gestion des mises à jour +""" +from os import system +from dateutil import parser +from pyeole.schedule import ManageSchedule, list_once, add_schedule, \ + del_schedule, apply_schedules, DAY_TO_STRING +from pyeole.process import system_out +from .client import CreoleClient + +from .i18n import _ + +# fichier d'information pour la mise à jour unique +DIFF_FILENAME = '/var/lib/eole/reports/maj-diff.txt' + +######################################### +## Mise à jour hebdomadaire (maj_auto) ## +######################################### + +client = CreoleClient() + +def maj_enabled(): + """ + vérifie si la mise à jour est activée ou non + """ + return client.get('/schedule/majauto/day') == 'weekly' + +def get_maj_day(): + """ + renvoie le jour et l'heure des mises à jour + par exemple : + {'hour': 5, 'minute': 4, 'weekday': 'vendredi'} + """ + shed = client.get('/schedule/schedule') + shed.pop('monthday') + shed['weekday'] = DAY_TO_STRING[shed['weekday']] + return shed + +def enable_maj_auto(): + """ + active la mise à jour hebdomadaire + """ + if not maj_enabled(): + manage_schedule = ManageSchedule() + manage_schedule.add('majauto', 'weekly', 'post') + manage_schedule.save() + apply_schedules() + +def disable_maj_auto(): + """ + désactive la mise à jour hebdomadaire + """ + if maj_enabled(): + manage_schedule = ManageSchedule() + manage_schedule.delete('majauto') + manage_schedule.save() + apply_schedules() + + +######################################### +## Mise à jour unique (schedule once) ## +######################################### + +def maj_once_enabled(): + """ + vérifie si la mise à jour est activée ou non + """ + return 'majauto' in list_once('post') + +def enable_maj_once(): + """ + active la mise à jour 'once' + """ + if not maj_once_enabled(): + cancel_maj_differee() + add_schedule('once', 'post', 'majauto') + write_diff(True, 'ce soir') + return True + +def disable_maj_once(): + """ + désactive la mise à jour 'once' + """ + if maj_once_enabled(): + del_schedule('once', 'post', 'majauto') + + +######################################### +## Mise à jour unique (maj_differee) ## +######################################### + +def write_diff(enable, heure=None): + """ ecrit les informations du gestionnaire de mise a jour + dans le fichier de config de l'ead """ + fic = file(DIFF_FILENAME, 'w') + if enable: + fic.write(_(u'An update is scheduled at {0}').format(heure)) + else: + fic.write("") + fic.close() + +def cancel_maj_differee(): + """ + déprogramme les mises à jour differées + """ + disable_maj_once() + cmd = """for i in `grep -l "Maj-Auto" /var/spool/cron/atjobs/* 2>/dev/null`; do rm -f $i ; done;""" + system(cmd) + write_diff(False) + return True + +def prog_maj_differee(heure, options='-R'): + """ + Programmation une mise à jour différée de quelques heures + Elle est lancée via la commande at pour l'utilisateur root + options : options à passer à Maj-Auto + """ + if heure == 'once': + return enable_maj_once() + # suppression des éventuelles autres maj différées + cancel_maj_differee() + stdin = "rm -f %s\nMaj-Auto %s\n" % (DIFF_FILENAME, options) + env_path = {'PATH': '/usr/share/eole:/usr/share/eole/sbin:/usr/local/sbin:' + '/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + 'LC_ALL': 'fr_FR.UTF-8'} + ret = system_out(['/usr/bin/at', 'now', '+', str(heure), 'hours'], stdin=stdin, env=env_path) + if ret[0] != 0: + return False + scheduled_maj = " ".join(ret[2].splitlines()[1].split()[3:7]) + scheduled_maj = parser.parse(scheduled_maj) + scheduled_day = "{0:0=2d}".format(scheduled_maj.day) + scheduled_month = "{0:0=2d}".format(scheduled_maj.month) + scheduled_year = "{0:0=2d}".format(scheduled_maj.year) + scheduled_hour = "{0:0=2d}".format(scheduled_maj.hour) + scheduled_minute = "{0:0=2d}".format(scheduled_maj.minute) + scheduled_maj = _(u'{0} the {1}').format(":".join((scheduled_hour, scheduled_minute)), \ + "/".join((scheduled_day, scheduled_month, scheduled_year))) + write_diff(True , scheduled_maj) + return True diff --git a/creole/objspace.py b/creole/objspace.py new file mode 100644 index 0000000..a7b297b --- /dev/null +++ b/creole/objspace.py @@ -0,0 +1,704 @@ +""" +Creole flattener. Takes a bunch of Creole XML dispatched in differents folders +as an input and outputs a human readable flatened XML + +Sample usage:: + + >>> from creole.objspace import CreoleObjSpace + >>> eolobj = CreoleObjSpace('/usr/share/creole/creole.dtd') + >>> eolobj.create_or_populate_from_xml('creole', ['/usr/share/eole/creole/dicos']) + >>> eolobj.space_visitor() + >>> eolobj.save('/tmp/creole_flatened_output.xml') + +The CreoleObjSpace + +- loads the XML into an internal CreoleObjSpace representation +- visits/annotates the objects +- dumps the object space as XML output into a single XML target + +The visit/annotation stage is a complex step that corresponds to the Creole +procedures. + +For example: a variable is redefined and shall be moved to another family +means that a variable1 = Variable() object in the object space who lives in the family1 parent +has to be moved in family2. The visit procedure changes the varable1's object space's parent. +""" +from collections import OrderedDict +from lxml.etree import Element, SubElement # pylint: disable=E0611 +import sys +from json import dump + + +from .i18n import _ +from .xmlreflector import XMLReflector, HIGH_COMPATIBILITY +from .annotator import ERASED_ATTRIBUTES, ActionAnnotator, ContainerAnnotator, SpaceAnnotator +from .utils import normalize_family +from .error import CreoleOperationError, SpaceObjShallNotBeUpdated, CreoleDictConsistencyError + +# CreoleObjSpace's elements like 'family' or 'slave', that shall be forced to the Redefinable type +FORCE_REDEFINABLES = ('family', 'slave', 'container', 'disknod', 'variables', 'family_action') +# CreoleObjSpace's elements that shall be forced to the UnRedefinable type +FORCE_UNREDEFINABLES = ('value', 'input', 'profile', 'ewtapp', 'tag', 'saltaction') +# CreoleObjSpace's elements that shall be set to the UnRedefinable type +UNREDEFINABLE = ('multi', 'type') + +PROPERTIES = ('hidden', 'frozen', 'auto_freeze', 'auto_save', 'force_default_on_freeze', + 'force_store_value', 'disabled', 'mandatory') +CONVERT_PROPERTIES = {'auto_save': ['force_store_value'], 'auto_freeze': ['force_store_value', 'auto_freeze']} + +RENAME_ATTIBUTES = {'description': 'doc'} + +#TYPE_TARGET_CONDITION = ('variable', 'family') + +# _____________________________________________________________________________ +# special types definitions for the Object Space's internal representation +class RootCreoleObject(object): + "" + + +class CreoleObjSpace(object): + """DOM XML reflexion free internal representation of a Creole Dictionary + """ + choice = type('Choice', (RootCreoleObject,), OrderedDict()) + # Creole ObjectSpace's Master variable class type + Master = type('Master', (RootCreoleObject,), OrderedDict()) + """ + This Atom type stands for singleton, that is + an Object Space's atom object is present only once in the + object space's tree + """ + Atom = type('Atom', (RootCreoleObject,), OrderedDict()) + "A variable that can't be redefined" + Redefinable = type('Redefinable', (RootCreoleObject,), OrderedDict()) + "A variable can be redefined" + UnRedefinable = type('UnRedefinable', (RootCreoleObject,), OrderedDict()) + + + def __init__(self, dtdfilename): # pylint: disable=R0912 + self.index = 0 + class ObjSpace(object): # pylint: disable=R0903 + """ + Base object space + """ + self.space = ObjSpace() + self.xmlreflector = XMLReflector() + self.xmlreflector.parse_dtd(dtdfilename) + self.redefine_variables = None + self.probe_variables = [] + + # elt container's attrs list + self.container_elt_attr_list = [] # + # ['variable', 'separator', 'family'] + self.forced_text_elts = set() + # ['disknod', 'slave', 'target', 'service', 'package', 'ip', 'value', 'tcpwrapper', + # 'interface', 'input', 'port'] + self.forced_text_elts_as_name = set(['choice']) + self.forced_choice_option = {} + self.paths = Path() + self.list_conditions = {} + + self.booleans_attributs = [] + + for elt in self.xmlreflector.dtd.iterelements(): + attrs = {} + clstype = self.UnRedefinable + atomic = True + forced_text_elt = False + if elt.type == 'mixed': + forced_text_elt = True + if elt.name == 'container': + self.container_elt_attr_list = [elt.content.left.name] + self.parse_dtd_right_left_elt(elt.content) + for attr in elt.iterattributes(): + atomic = False + if attr.default_value: + if attr.default_value == 'True': + default_value = True + elif attr.default_value == 'False': + default_value = False + else: + default_value = attr.default_value + attrs[attr.name] = default_value + if not attr.name.endswith('_type'): + values = list(attr.itervalues()) + if values != []: + self.forced_choice_option.setdefault(elt.name, {})[attr.name] = values + + if attr.name == 'redefine': + clstype = self.Redefinable + if attr.name == 'name' and forced_text_elt is True: + self.forced_text_elts.add(elt.name) + forced_text_elt = False + + if set(attr.itervalues()) == set(['True', 'False']): + self.booleans_attributs.append(attr.name) + + if forced_text_elt is True: + self.forced_text_elts_as_name.add(elt.name) + + if elt.name in FORCE_REDEFINABLES: + clstype = self.Redefinable + elif elt.name in FORCE_UNREDEFINABLES: + clstype = self.UnRedefinable + elif atomic: + clstype = self.Atom + + # Creole ObjectSpace class types, it enables us to create objects like: + # Service_restriction(), Ip(), Interface(), Host(), Fstab(), Package(), Disknod(), + # File(), Variables(), Family(), Variable(), Separators(), Separator(), Value(), + # Constraints()... and so on. Creole ObjectSpace is an object's reflexion of + # the XML elements + setattr(self, elt.name, type(elt.name.capitalize(), (clstype,), attrs)) + + def parse_dtd_right_left_elt(self, elt): + if elt.right.type == 'or': + self.container_elt_attr_list.append(elt.right.left.name) + self.parse_dtd_right_left_elt(elt.right) + else: + self.container_elt_attr_list.append(elt.right.name) + + def _convert_boolean(self, value): # pylint: disable=R0201 + """Boolean coercion. The Creole XML may contain srings like `True` or `False` + """ + if isinstance(value, bool): + return value + if value == 'True': + return True + elif value == 'False': + return False + else: + raise TypeError(_('{} is not True or False').format(value).encode('utf8')) # pragma: no cover + + def _is_already_exists(self, name, space, child, namespace): + if isinstance(space, self.family): # pylint: disable=E1101 + if namespace != 'creole': + name = space.path + '.' + name + return self.paths.path_is_defined(name) + if child.tag in ['family', 'family_action']: + norm_name = normalize_family(name) + else: + norm_name = name + return norm_name in getattr(space, child.tag, {}) + + def _translate_in_space(self, name, family, variable, namespace): + if not isinstance(family, self.family): # pylint: disable=E1101 + if variable.tag in ['family', 'family_action']: + norm_name = normalize_family(name) + else: + norm_name = name + return getattr(family, variable.tag)[norm_name] + if namespace == 'creole': + path = name + else: + path = family.path + '.' + name + old_family_name = self.paths.get_variable_family_name(path) + if normalize_family(family.name) == old_family_name: + return getattr(family, variable.tag)[name] + old_family = self.space.variables['creole'].family[old_family_name] # pylint: disable=E1101 + variable_obj = old_family.variable[name] + del old_family.variable[name] + if 'variable' not in vars(family): + family.variable = OrderedDict() + family.variable[name] = variable_obj + self.paths.append('variable', name, namespace, family.name, variable_obj) + return variable_obj + + def remove_check(self, name): # pylint: disable=C0111 + if hasattr(self.space, 'constraints') and hasattr(self.space.constraints, 'check'): + remove_checks = [] + for idx, check in enumerate(self.space.constraints.check): # pylint: disable=E1101 + if hasattr(check, 'target') and check.target == name: + remove_checks.append(idx) + + remove_checks = list(set(remove_checks)) + remove_checks.sort(reverse=True) + for idx in remove_checks: + self.space.constraints.check.pop(idx) # pylint: disable=E1101 + def remove_condition(self, name): # pylint: disable=C0111 + for idx, condition in enumerate(self.space.constraints.condition): # pylint: disable=E1101 + remove_targets = [] + if hasattr(condition, 'target'): + for target_idx, target in enumerate(condition.target): + if target.name == name: + remove_targets.append(target_idx) + remove_targets = list(set(remove_targets)) + remove_targets.sort(reverse=True) + for idx in remove_targets: + del condition.target[idx] + + def create_or_update_space_object(self, subspace, space, child, namespace): + """Creates or retrieves the space object that corresponds + to the `child` XML object + + Two attributes of the `child` XML object are important: + + - with the `redefine` boolean flag attribute we know whether + the corresponding space object shall be created or updated + + - `True` means that the corresponding space object shall be updated + - `False` means that the corresponding space object shall be created + + - with the `exists` boolean flag attribute we know whether + the corresponding space object shall be created + (or nothing -- that is the space object isn't modified) + + - `True` means that the corresponding space object shall be created + - `False` means that the corresponding space object is not updated + + In the special case `redefine` is True and `exists` is False, + we create the corresponding space object if it doesn't exist + and we update it if it exists. + + :return: the corresponding space object of the `child` XML object + """ + if child.tag in self.forced_text_elts_as_name: + name = child.text + else: + name = subspace['name'] + if self._is_already_exists(name, space, child, namespace): + if child.tag in FORCE_REDEFINABLES: + redefine = self._convert_boolean(subspace.get('redefine', True)) + else: + redefine = self._convert_boolean(subspace.get('redefine', False)) + exists = self._convert_boolean(subspace.get('exists', True)) + if redefine is True: + return self._translate_in_space(name, space, child, namespace) + elif exists is False: + raise SpaceObjShallNotBeUpdated() + else: + raise CreoleDictConsistencyError(_('Already present in another XML file, {} ' + 'cannot be re-created').format(name).encode('utf8')) + else: + redefine = self._convert_boolean(subspace.get('redefine', False)) + exists = self._convert_boolean(subspace.get('exists', False)) + if redefine is False or exists is True: + return getattr(self, child.tag)() + else: + raise CreoleDictConsistencyError(_('Redefined object: ' + '{} does not exist yet').format(name).encode('utf8')) + + def generate_creoleobj(self, child, space, namespace): + """ + instanciates or creates Creole Object Subspace objects + """ + if issubclass(getattr(self, child.tag), self.Redefinable): + creoleobj = self.create_or_update_space_object(child.attrib, space, child, namespace) + else: + # instanciates an object from the CreoleObjSpace's builtins types + # example : child.tag = constraints -> a self.Constraints() object is created + creoleobj = getattr(self, child.tag)() + # this Atom instance has to be a singleton here + # we do not re-create it, we reuse it + if isinstance(creoleobj, self.Atom) and child.tag in vars(space): + creoleobj = getattr(space, child.tag) + self.create_tree_structure(space, child, creoleobj) + return creoleobj + + def create_tree_structure(self, space, child, creoleobj): # pylint: disable=R0201 + """ + Builds the tree structure of the object space here + we set containers attributes in order to be populated later on + for example:: + + space = Family() + space.variable = OrderedDict() + another example: + space = Variable() + space.value = list() + """ + if child.tag not in vars(space): + if isinstance(creoleobj, self.Redefinable): + setattr(space, child.tag, OrderedDict()) + elif isinstance(creoleobj, self.UnRedefinable): + setattr(space, child.tag, []) + elif isinstance(creoleobj, self.Atom): + pass + else: # pragma: no cover + raise CreoleOperationError(_("Creole object {} " + "has a wrong type").format(type(creoleobj))) + + def _add_to_tree_structure(self, creoleobj, space, child): # pylint: disable=R0201 + if isinstance(creoleobj, self.Redefinable): + name = creoleobj.name + if child.tag == 'family' or child.tag == 'family_action': + name = normalize_family(name) + getattr(space, child.tag)[name] = creoleobj + elif isinstance(creoleobj, self.UnRedefinable): + getattr(space, child.tag).append(creoleobj) + else: + setattr(space, child.tag, creoleobj) + + def _set_text_to_obj(self, child, creoleobj): + if child.text is None: + text = None + else: + text = child.text.strip() + if text: + if child.tag in self.forced_text_elts_as_name: + creoleobj.name = text + else: + creoleobj.text = text + + def _set_xml_attributes_to_obj(self, child, creoleobj): + redefine = self._convert_boolean(child.attrib.get('redefine', False)) + has_value = hasattr(creoleobj, 'value') + if HIGH_COMPATIBILITY and has_value: + has_value = len(child) != 1 or child[0].text != None + if (redefine is True and child.tag == 'variable' and has_value + and len(child) != 0): + del creoleobj.value + for attr, val in child.attrib.items(): + if redefine and attr in UNREDEFINABLE: + # UNREDEFINABLE concerns only 'variable' node so we can fix name + # to child.attrib['name'] + name = child.attrib['name'] + raise CreoleDictConsistencyError(_("cannot redefine attribute {} for variable {}").format(attr, name).encode('utf8')) + if isinstance(getattr(creoleobj, attr, None), bool): + if val == 'False': + val = False + elif val == 'True': + val = True + else: # pragma: no cover + raise CreoleOperationError(_('value for {} must be True or False, ' + 'not {}').format(attr, val).encode('utf8')) + if not (attr == 'name' and getattr(creoleobj, 'name', None) != None): + setattr(creoleobj, attr, val) + + def _creoleobj_tree_visitor(self, child, creoleobj, namespace): + """Creole object tree manipulations + """ + if child.tag == 'variable' and child.attrib.get('remove_check', False): + self.remove_check(creoleobj.name) + if child.tag == 'variable' and child.attrib.get('remove_condition', False): + self.remove_condition(creoleobj.name) + if child.tag in ['auto', 'fill', 'check']: + variable_name = child.attrib['target'] + # XXX not working with variable not in creole and in master/slave + if variable_name in self.redefine_variables: + creoleobj.redefine = True + else: + creoleobj.redefine = False + if not hasattr(creoleobj, 'index'): + creoleobj.index = self.index + if child.tag in ['auto', 'fill', 'condition', 'check', 'action']: + creoleobj.namespace = namespace + + def xml_parse_document(self, document, space, namespace, is_in_family=False): + """Parses a Creole XML file + populates the CreoleObjSpace + """ + family_names = [] + for child in document: + # this index enables us to reorder the 'fill' and 'auto' objects + self.index += 1 + # doesn't proceed the XML commentaries + if not isinstance(child.tag, str): + continue + if child.tag == 'family': + is_in_family = True + if child.attrib['name'] in family_names: + raise CreoleDictConsistencyError(_('Family {} is set several times').format(child.attrib['name']).encode('utf8')) + family_names.append(child.attrib['name']) + if child.tag == 'variables': + child.attrib['name'] = namespace + if HIGH_COMPATIBILITY and child.tag == 'value' and child.text == None: + continue + # creole objects creation + try: + creoleobj = self.generate_creoleobj(child, space, namespace) + except SpaceObjShallNotBeUpdated: + continue + self._set_text_to_obj(child, creoleobj) + self._set_xml_attributes_to_obj(child, creoleobj) + self._creoleobj_tree_visitor(child, creoleobj, namespace) + self._fill_creoleobj_path_attribute(space, child, namespace, document, creoleobj) + self._add_to_tree_structure(creoleobj, space, child) + if list(child) != []: + self.xml_parse_document(child, creoleobj, namespace, is_in_family) + + def _fill_creoleobj_path_attribute(self, space, child, namespace, document, creoleobj): # pylint: disable=R0913 + """Fill self.paths attributes + """ + if not isinstance(space, self.help): # pylint: disable=E1101 + if child.tag == 'variable': + family_name = normalize_family(document.attrib['name']) + self.paths.append('variable', child.attrib['name'], namespace, family_name, + creoleobj) + if child.attrib.get('redefine', 'False') == 'True': + if namespace == 'creole': + self.redefine_variables.append(child.attrib['name']) + else: + self.redefine_variables.append(namespace + '.' + family_name + '.' + + child.attrib['name']) + + if child.tag == 'family': + family_name = normalize_family(child.attrib['name']) + if namespace != 'creole': + family_name = namespace + '.' + family_name + self.paths.append('family', family_name, namespace, creoleobj=creoleobj) + creoleobj.path = self.paths.get_family_path(family_name, namespace) + + def create_or_populate_from_xml(self, namespace, xmlfolders, from_zephir=None): + """Parses a bunch of XML files + populates the CreoleObjSpace + """ + documents = self.xmlreflector.load_xml_from_folders(xmlfolders, from_zephir) + for xmlfile, document in documents: + try: + self.redefine_variables = [] + self.xml_parse_document(document, self.space, namespace) + except Exception as err: + #print(_('error in XML file {}').format(xmlfile)) + raise err + + def populate_from_zephir(self, namespace, xmlfile): + self.redefine_variables = [] + document = self.xmlreflector.parse_xmlfile(xmlfile, from_zephir=True, zephir2=True) + self.xml_parse_document(document, self.space, namespace) + + def space_visitor(self, eosfunc_file): # pylint: disable=C0111 + ActionAnnotator(self.space, self.paths, self) + ContainerAnnotator(self.space, self.paths, self) + SpaceAnnotator(self.space, self.paths, self, eosfunc_file) + + def save(self, filename, force_no_save=False): + """Save an XML output on disk + + :param filename: the full XML filename + """ + xml = Element('creole') + self._xml_export(xml, self.space) + if not force_no_save: + self.xmlreflector.save_xmlfile(filename, xml) + return xml + + def save_probes(self, filename, force_no_save=False): + """Save an XML output on disk + + :param filename: the full XML filename + """ + ret = {} + for variable in self.probe_variables: + args = [] + kwargs = {} + if hasattr(variable, 'param'): + for param in variable.param: + list_param = list(vars(param).keys()) + if 'index' in list_param: + list_param.remove('index') + if list_param == ['text']: + args.append(param.text) + elif list_param == ['text', 'name']: + kwargs[param.name] = param.text + else: + print(vars(param)) + raise Exception('hu?') + ret[variable.target] = {'function': variable.name, + 'args': args, + 'kwargs': kwargs} + if not force_no_save: + with open(filename, 'w') as fhj: + dump(ret, fhj) + return ret + + def _get_attributes(self, space): # pylint: disable=R0201 + for attr in dir(space): + if not attr.startswith('_'): + yield attr + + def _sub_xml_export(self, name, node, node_name, space): + if isinstance(space, dict): + space = list(space.values()) + if isinstance(space, list): + for subspace in space: + if isinstance(subspace, self.Master): + _name = 'master' + subspace.doc = subspace.variable[0].description + #subspace.doc = 'Master {}'.format(subspace.name) + else: + _name = name + if name in ['containers', 'variables', 'actions']: + _name = 'family' + if HIGH_COMPATIBILITY and not hasattr(subspace, 'doc'): + subspace.doc = '' + if _name == 'value' and (not hasattr(subspace, 'name') or subspace.name is None): + continue + child_node = SubElement(node, _name) + self._xml_export(child_node, subspace, _name) + elif isinstance(space, self.Atom): + if name == 'containers': + child_node = SubElement(node, 'family') + child_node.attrib['name'] = name + else: + child_node = SubElement(node, name) + for subname in self._get_attributes(space): + subspace = getattr(space, subname) + self._sub_xml_export(subname, child_node, name, subspace) + elif isinstance(space, self.Redefinable): + child_node = SubElement(node, 'family') + child_node.attrib['name'] = name + for subname in self._get_attributes(space): + subspace = getattr(space, subname) + self._sub_xml_export(subname, child_node, name, subspace) + else: + if name in PROPERTIES and node.tag == 'variable': + if space is True: + for prop in CONVERT_PROPERTIES.get(name, [name]): + if sys.version_info[0] < 3: + SubElement(node, 'property').text = unicode(prop) + else: + SubElement(node, 'property').text = prop + + elif name not in ERASED_ATTRIBUTES: + if name == 'name' and node_name in self.forced_text_elts_as_name: + if sys.version_info[0] < 3 and isinstance(space, unicode): + node.text = space + elif isinstance(space, str): + if sys.version_info[0] < 3: + node.text = space.decode('utf8') + else: + node.text = space + else: + node.text = str(space) + elif name == 'text' and node_name in self.forced_text_elts: + node.text = space + elif node.tag == 'family' and name == 'name': + if 'doc' not in node.attrib.keys(): + node.attrib['doc'] = space + node.attrib['name'] = normalize_family(space, check_name=False) + elif node.tag == 'variable' and name == 'mode': + if space is not None: + SubElement(node, 'property').text = space + else: + if name in RENAME_ATTIBUTES: + name = RENAME_ATTIBUTES[name] + if space is not None: + if sys.version_info[0] < 3: + node.attrib[name] = unicode(space) + else: + node.attrib[name] = str(space) + + def _xml_export(self, node, space, node_name='creole'): + for name in self._get_attributes(space): + subspace = getattr(space, name) + self._sub_xml_export(name, node, node_name, subspace) + + +class Path(object): + """Helper class to handle the `path` attribute of a CreoleObjSpace + instance. + + sample: path="creole.general.condition" + """ + def __init__(self): + self.variables = {} + self.families = {} + + def append(self, pathtype, name, namespace, family=None, creoleobj=None): # pylint: disable=C0111 + if pathtype == 'family': + self.families[name] = dict(name=name, namespace=namespace, creoleobj=creoleobj) + elif pathtype == 'variable': + if namespace == 'creole': + varname = name + else: + if '.' in name: + varname = name + else: + varname = '.'.join([namespace, family, name]) + self.variables[varname] = dict(name=name, family=family, namespace=namespace, + master=None, creoleobj=creoleobj) + else: # pragma: no cover + raise Exception('unknown pathtype {}'.format(pathtype)) + + def get_family_path(self, name, current_namespace): # pylint: disable=C0111 + if current_namespace is None: # pragma: no cover + raise CreoleOperationError('current_namespace must not be None') + dico = self.families[normalize_family(name, check_name=False)] + if dico['namespace'] != 'creole' and current_namespace != dico['namespace']: + raise CreoleDictConsistencyError(_('A family located in the {} namespace ' + 'shall not be used in the {} namespace').format( + dico['namespace'], current_namespace).encode('utf8')) + path = dico['name'] + if dico['namespace'] is not None and '.' not in dico['name']: + path = '.'.join([dico['namespace'], path]) + return path + + def get_family_namespace(self, name): # pylint: disable=C0111 + dico = self.families[name] + if dico['namespace'] is None: + return dico['name'] + return dico['namespace'] + + def get_family_obj(self, name): # pylint: disable=C0111 + if name not in self.families: + raise CreoleDictConsistencyError(_('unknown family {}').format(name).encode('utf8')) + dico = self.families[name] + return dico['creoleobj'] + + def get_variable_name(self, name): # pylint: disable=C0111 + dico = self._get_variable(name) + return dico['name'] + + def get_variable_obj(self, name): # pylint: disable=C0111 + dico = self._get_variable(name) + return dico['creoleobj'] + + def get_variable_family_name(self, name): # pylint: disable=C0111 + dico = self._get_variable(name) + return dico['family'] + + def get_variable_family_path(self, name): # pylint: disable=C0111 + dico = self._get_variable(name) + list_path = [dico['namespace'], dico['family']] + if dico['master'] is not None: + list_path.append(dico['master']) + return '.'.join(list_path) + + def get_variable_namespace(self, name): # pylint: disable=C0111 + return self._get_variable(name)['namespace'] + + def get_variable_path(self, name, current_namespace, allow_source=False): # pylint: disable=C0111 + if current_namespace is None: # pragma: no cover + raise CreoleOperationError('current_namespace must not be None') + dico = self._get_variable(name) + if not allow_source: + if dico['namespace'] != 'creole' and current_namespace != dico['namespace']: + raise CreoleDictConsistencyError(_('A variable located in the {} namespace ' + 'shall not be used in the {} namespace').format( + dico['namespace'], current_namespace).encode('utf8')) + if '.' in dico['name']: + return dico['name'] + list_path = [dico['namespace'], dico['family']] + if dico['master'] is not None: + list_path.append(dico['master']) + list_path.append(dico['name']) + return '.'.join(list_path) + + def path_is_defined(self, name): # pylint: disable=C0111 + return name in self.variables + + def set_master(self, name, master): # pylint: disable=C0111 + dico = self._get_variable(name) + namespace = dico['namespace'] + if dico['master'] != None: + raise CreoleDictConsistencyError(_('Already defined master {} for variable' + ' {}'.format(dico['master'], name)).encode('utf8')) + dico['master'] = master + if namespace != 'creole': + new_path = self.get_variable_path(name, namespace) + self.append('variable', new_path, namespace, family=dico['family'], creoleobj=dico['creoleobj']) + self.variables[new_path]['master'] = master + del self.variables[name] + + def _get_variable(self, name): + if name not in self.variables: + if name.startswith('creole.'): + raise CreoleDictConsistencyError( + _("don't set full path variable in creole's namespace " + "(set '{}' not '{}')").format(name.split('.')[-1], name).encode('utf8')) + raise CreoleDictConsistencyError(_('unknown option {}').format(name).encode('utf8')) + return self.variables[name] + + def get_master(self, name): # pylint: disable=C0111 + dico = self._get_variable(name) + return dico['master'] diff --git a/creole/reconfigure.py b/creole/reconfigure.py new file mode 100644 index 0000000..975bc0e --- /dev/null +++ b/creole/reconfigure.py @@ -0,0 +1,1006 @@ +# -*- coding: utf-8 -*- + +"""Apply configuration of EOLE servers. + +""" + +import os +import argparse +import time +import shutil + +from glob import glob + +import spwd +import getpass +from itertools import count + +from pyeole.log import getLogger +from pyeole.log import init_logging +from pyeole.log import set_formatter +from pyeole.log import set_filters + +from pyeole import scriptargs +from pyeole.lock import acquire, release +from pyeole import process +from pyeole.schedule import display_schedules, apply_schedules +from pyeole import ihm +from pyeole.pkg import report, EolePkg, _configure_sources_mirror, _MIRROR_DIST +from pyeole.pkg import PackageNotFoundError, RepositoryError, AptProxyError, AptCacherError +from pyeole.service import manage_service, unmanaged_service, manage_services, \ + ServiceError +from pyeole.encode import normalize +from pyeole.diagnose.diagnose import MAJ_SUCCES_LOCK + +from .error import FileNotFound, LockError, UnlockError +from .error import UserExit, UserExitError +from .error import VirtError +from .client import CreoleClient, CreoleClientError, NotFoundError +import fonctionseole, template, cert +from .eosfunc import is_instanciate +from .config import configeol, INSTANCE_LOCKFILE, UPGRADE_LOCKFILE, \ + container_instance_lockfile, gen_conteneurs_needed, VIRTROOT, charset +from .containers import is_lxc_enabled, is_lxc_running, is_lxc_started, \ + generate_lxc_container, create_mount_point, lxc_need_restart +from .error import NetworkConfigError + +from pyeole.i18n import i18n +_ = i18n('creole') + +try: + from zephir.lib_zephir import lock, unlock + zephir_libs = True +except Exception: + zephir_libs = False + +client = CreoleClient() + +global PKGMGR +PKGMGR = None + +error_msg_documentation = _(u"""For more informations, read section +'Mise en œuvre des modules EOLE' in module documentation or +common documentation.""") +def load_pkgmgr(): + global PKGMGR + if PKGMGR is None: + cache() + PKGMGR = EolePkg('apt', container_mode=CACHE['is_lxc_enabled']) + PKGMGR.pkgmgr.groups = CACHE + PKGMGR.pkgmgr._load_apt_cache() + eoles = [] + for eole in client.get_creole(u'serveur_maj'): + eoles.append('http://{0}/eole/'.format(eole)) + ubuntus = [] + for ubuntu in client.get_creole(u'ubuntu_update_mirrors'): + ubuntus.append('http://{0}/ubuntu/'.format(ubuntu)) + envoles = [] + try: + for envole in client.get_creole(u'envole_update_mirrors'): + envoles.append('http://{0}/envole/'.format(envole)) + except NotFoundError: + pass + for cache_ in PKGMGR.pkgmgr.cache._list.list: + if cache_.uri in eoles: + PKGMGR.pkgmgr._test_mirror(cache_.uri, _MIRROR_DIST['EOLE']) + eoles = [] + if cache_.uri in ubuntus: + PKGMGR.pkgmgr._test_mirror(cache_.uri, _MIRROR_DIST['Ubuntu']) + ubuntus = [] + if cache_.uri in envoles: + PKGMGR.pkgmgr._test_mirror(cache_.uri, _MIRROR_DIST['Envole']) + envoles = [] + fonctionseole.PkgManager = PKGMGR + +_LOGFILENAME = '/var/log/reconfigure.log' + +# Command line options +class Option: + """Manage commande line options with defaults + + """ + def __init__(self): + self.parser = argparse.ArgumentParser( + description=_(u"Applying EOLE configuration."), + parents=[scriptargs.container(), + scriptargs.logging(level='info')]) + self.parser.add_argument('-i', '--interactive', action='store_true', + help=_(u"leave process in interactive mode")) + self.parser.add_argument('-f', '--force', action='store_true', + help=_(u"override Zéphir lock")) + self.parser.add_argument('-a', '--auto', action='store_true', + help=_(u"automatic reboot if necessary")) + self.__opts = self.parser.parse_args([]) + + def update_from_cmdline(self, force_args=None, force_options=None): + """Parse command line + """ + self.__opts = self.parser.parse_args(force_args) + if self.__opts.verbose: + self.__opts.log_level = 'info' + if self.__opts.debug: + self.__opts.log_level = 'debug' + if force_options is not None: + for key, value in force_options.items(): + setattr(self.__opts, key, value) + self.__dict__.update(self.__opts.__dict__) + + def __getattr__(self, name): + if name in ['__opts', 'update_from_cmdline']: + return self.__dict__[name] + else: + return getattr(self.__opts, name) + +options = Option() + +# To use log from every functions +log = getLogger(__name__) + +# Same name for instance and reconfigure +LOCK_NAME = u'reconfigure' + +# Run scripts in directories +RUNPARTS_PATH = u'/usr/share/eole' +RUNPARTS_CMD = u'/bin/run-parts --exit-on-error -v {directory} --arg {compat} 2>&1' + +# Compatibility +COMPAT_NAME = u'reconfigure' + +#def parse_cmdline(): +# """Parse command line +# """ +# descr = u"Application de la configuration EOLE" +# parser = argparse.ArgumentParser(description=descr, +# parents=[scriptargs.container(), +# scriptargs.logging(level='info')]) +# parser.add_argument('-i', '--interactive', action='store_true', +# help=u"lancer le processus en mode interactif") +# parser.add_argument('-f', '--force', action='store_true', +# help=u"force l'action même s'il existe des verrous") +# parser.add_argument('-a', '--auto', action='store_true', +# help=u"redémarrage automatique si nécessaire") +# +# opts = parser.parse_args() +# if opts.verbose: +# opts.log_level = 'info' +# if opts.debug: +# opts.log_level = 'debug' +# return opts + +def copyDirectoryContent(src, dst): + for fic in os.listdir(src): + # Skip links or we ovewrite existing certificates + if os.path.islink(os.path.join(src, fic)): + continue + try: + shutil.copy2(os.path.join(src, fic), dst) + except shutil.Error, err: + # ignore if files already exists + pass + +def user_exit(*args, **kwargs): + """ + sortie utilisateur "propre" + """ + log.warn(_(u'! Abandoning configuration !')) + log.warn(_(u'System may be in an incoherent state.\n\n')) + raise UserExitError() + +def unlock_actions(need_lock=True): + if zephir_libs: + #FIXME: lock de Zephir ! + unlock('actions') + try: + release(LOCK_NAME, level='system') + except Exception, err: + # FIXME: move lock exception to pyeole.lock #7400 + if need_lock: + raise UnlockError(str(err)) + +def lock_actions(): + try: + acquire(LOCK_NAME, level="system") + except Exception, err: + # FIXME: move lock exception to pyeole.lock #7400 + raise LockError(str(err)) + if zephir_libs: + #FIXME: lock de Zephir ! + lock('actions') + +def reset_compat_name(): + """ + Réinitialise le nom de la procédure en cours + en fonction de l'environnement + """ + global COMPAT_NAME + if options.interactive: + COMPAT_NAME = u'instance' + else: + COMPAT_NAME = u'reconfigure' + +def run_parts(directory): + """Run scripts in a directory + + @param directory: name of a directory + @type directory: C{str} + """ + dirpath = os.path.join(RUNPARTS_PATH, directory) + if os.path.isdir(dirpath): + ihm.print_title(_(u'Running scripts {0}').format(directory)) + code = os.system(RUNPARTS_CMD.format(directory=dirpath, compat=COMPAT_NAME)) + if code != 0: + raise Exception(_(u'Error {0}').format(directory)) + +def restart_creoled(): + """ + Restart creoled service and verify if the client is OK + """ + unmanaged_service(u'restart', u'creoled', u'service', display='console') + try: + client.get_creole(u'eole_version') + except CreoleClientError: + msg = _(u"Please check creoled's log (/var/log/rsyslog/local/creoled/creoled.info.log)\nand restart service with command 'service creoled start'") + raise CreoleClientError(msg) + +def prepare(need_lock=True): + """Sanity checks. + + """ + global RUNPARTS_CMD + # Clean exit + if need_lock: + ihm.catch_signal(user_exit) + lock_actions() + + if options.container != None: + RUNPARTS_CMD += u" --regex '^[09][09]-{0}$'".format(options.container) + + ihm.print_title(_(u"Preparation for {0}").format(COMPAT_NAME)) + + if not os.path.isfile(configeol): + print _(u"Server is not configured.") + print + print error_msg_documentation + print + raise FileNotFound(_(u'Missing file {0}.').format(configeol)) + + display_info = False + + if not options.interactive and (is_instanciate() == 'non' or os.path.isfile(UPGRADE_LOCKFILE)): + ihm.print_red(_(u"Server must be instantiated before any reconfiguration can occur.")) + display_info = True + + if options.interactive and is_instanciate() == 'oui' and \ + not os.path.isfile(UPGRADE_LOCKFILE) and \ + not os.path.isfile(container_instance_lockfile): + ihm.print_red(_(u"Server already instantiated.")) + print + print _(u"To modify configuration parameter (e.g. IP address), use:") + print _(u"'gen_config'") + print _(u"then 'reconfigure' to apply changes.") + display_info = True + + if os.path.isfile(container_instance_lockfile) and not options.interactive: + raise Exception(_('you have run gen_conteneurs, please use instance instead of reconfigure')) + + if os.path.isfile(gen_conteneurs_needed): + raise Exception(_('You have to run gen_conteneurs before instance')) + + if display_info: + print + print error_msg_documentation + print + if not options.interactive: + raise Exception(_(u"First instantiate server.")) + else: + if ihm.prompt_boolean(_(u"Proceeding with instantiation ?"), + interactive=options.interactive, + default=False) is False: + raise UserExit() + else: + fonctionseole.zephir("MSG", "Instance forcée par l'utilisateur", + COMPAT_NAME.upper()) + + # redémarrage du service creoled + restart_creoled() + + if fonctionseole.init_proc(COMPAT_NAME.upper()) == False and not options.force: + log.warn(_(u"This process is blocked, contact Zéphir administrator.")) + if ihm.prompt_boolean(_(u"Force execution?"), + interactive=options.interactive, + default=False) is False: + if not options.interactive: + log.warn(_(u"Use -f option if you want to force execution")) + raise UserExitError() + else: + fonctionseole.zephir("MSG", + "Instance forcée par l'utilisateur", + COMPAT_NAME.upper()) + + +def valid_mandatory(need_lock): + try: + client.valid_mandatory() + except Exception, err: + log.warn(_('Configuration validation problem, please check server configuration.')) + print + print error_msg_documentation + print + unlock_actions(need_lock) + raise ValueError(str(err)) + +def _start_containers(): + """ Try to start containers and make sure they are started + """ + cache() + for group_name in CACHE['groups_container']: + group = CACHE['group_infos'][group_name] + create_mount_point(group) + + if os.access('/usr/share/eole/preservice/00-lxc-net', os.X_OK): + log.debug("Override lxc-net systemd script") + process.system_code(['/usr/share/eole/preservice/00-lxc-net']) + + unmanaged_service(u'start', u'lxc-net', u'systemd', display='console', ctx=CACHE['group_infos']['root']) + try: + unmanaged_service(u'status', u'lxc', u'systemd') + except ServiceError: + unmanaged_service(u'start', u'lxc', u'systemd', display='console', ctx=CACHE['group_infos']['root']) + #if lxc not started, do not wait for it + #(we already waiting for it in systemd service) + #if started, waiting for ssh access + + max_try = 10 + for count in range(max_try): + s_code, s_out, s_err = process.system_out(['lxc-ls', '--stopped']) + stopped = s_out.split() + f_code, f_out, f_err = process.system_out(['lxc-ls', '--frozen']) + frozen = f_out.split() + + if stopped or frozen: + not_running = stopped + frozen + else: + # Everything is started by LXC + # Are they reachable by SSH? + not_running = [] + for group_name in CACHE['groups_container']: + group_infos = CACHE['group_infos'][group_name] + if not is_lxc_running(group_infos): + not_running.append(group_name) + + log.debug('Waiting 1 second for SSH access') + time.sleep(1) + + if not not_running: + break + + if stopped: + for cont in stopped: + log.debug('Manual start of stopped container “{0}”'.format(cont)) + process.system_out(['lxc-start', '--name', cont, '--daemon', + '-o', '/var/log/lxc-{0}.log'.format(cont)]) + + if frozen: + for cont in frozen: + log.debug('Manual unfreeze of frozen container “{0}”'.format(cont)) + process.system_out(['lxc-unfreeze', '--name', cont, + '-o', '/var/log/lxc-{0}.log'.format(cont)]) + + if not_running: + waiting_for = ', '.join(not_running) + msg = _(u'Unable to start LXC container : {0}', + u'Unable to start LXC containers : {0}', len(not_running)) + raise VirtError(msg.format(waiting_for)) + + +def containers(minimal=False, log_=None): + """Generate containers + """ + if log_ is None: + log_ = log + VAR_LXC='/var/lib/lxc' + OPT_LXC='/opt/lxc' + + cache() + if not CACHE['is_lxc_enabled']: + log.debug(_(u'Container mode is disabled.')) + return True + if not options.interactive: + for group in CACHE['groups_container']: + if not os.path.isdir(os.path.join(VIRTROOT, group)): + raise Exception(_(u'container {0} does not already exist, please use gen_conteneurs to create this container').format(group)) + else: + # make /var/lib/lxc -> /opt/lxc + if os.path.isdir(VAR_LXC) and not os.path.exists(OPT_LXC): + ihm.print_title(_(u"Setting up {0}").format(OPT_LXC)) + unmanaged_service(u'stop', u'lxc', u'systemd', display='console') + unmanaged_service(u'stop', u'lxc-net', u'systemd', display='console') + shutil.move(VAR_LXC, OPT_LXC) + os.symlink(OPT_LXC, VAR_LXC) + #first instance should be in minimal mode + minimal = True + + ihm.print_title(_(u'Generating containers')) + + engine = template.CreoleTemplateEngine() + rootctx = CACHE['group_infos']['root'] + if minimal: + # inject var _minimal_mode in creole's vars that can be used in template + engine.creole_variables_dict['_minimal_mode'] = True + engine.instance_file(u'/etc/ssh/ssh_config', ctx=rootctx) + engine.instance_file(u'/etc/lxc/default.conf', ctx=rootctx) + engine.instance_file(u'/etc/dnsmasq.d/lxc', ctx=rootctx) + engine.instance_file(u'/etc/default/lxc-net', ctx=rootctx) + engine.instance_file(u'/etc/apt/apt.conf.d/02eoleproxy', ctx=rootctx) + if CACHE['module_instancie'] == 'oui': + engine.instance_file(u'/etc/resolv.conf', ctx=rootctx) + + load_pkgmgr() + PKGMGR.pkgmgr._prepare_cache() + for group in CACHE['groups_container']: + generate_lxc_container(group) + groupctx = CACHE['group_infos'][group] + if minimal: + engine.instance_file(u'../fstab', container=group, ctx=groupctx) + engine.instance_file(u'../config', container=group, ctx=groupctx) + engine.instance_file(u'../devices.hook', container=group, ctx=groupctx) + engine.instance_file(u'/etc/network/interfaces', container=group, ctx=groupctx) + engine.instance_file(u'/etc/apt/apt.conf.d/02eoleproxy', container=group, ctx=groupctx) + engine.instance_file(u'/etc/ssh/sshd_config', container=group, ctx=groupctx) + if CACHE['module_instancie'] == 'oui': + container_path = os.path.join(groupctx['path'], 'etc/resolv.conf') + if os.path.islink(container_path): + os.remove(container_path) + engine.instance_file(u'/etc/resolv.conf', container=group, ctx=groupctx) + PKGMGR.pkgmgr._umount_cdrom() + + ihm.print_title(_(u'Starting containers')) + _start_containers() + +def remove_packages(): + """ Remove packages listed in /usr/share/eole/remove.d/ files + param: repo: EoleApt Object + """ + torm_conf = glob(u'/usr/share/eole/remove.d/*.conf') + pkg_list = [] + for config in torm_conf: + try: + f_h = open(config, 'r') + for line in f_h.readlines(): + pkg_list.append(line.strip('\n')) + f_h.close() + except IOError, err: + log.error(_(u'Can not read file {0}: {1}').format(config, err)) + + try: + load_pkgmgr() + except (RepositoryError, AptProxyError, AptCacherError), err: + pass + + kernels = fonctionseole.get_kernel_to_remove() + + if kernels: + ihm.print_line(_(u"Removing old linux kernels and associate headers.")) + pkg_list.extend(kernels) + + if pkg_list != []: + try: + PKGMGR.remove(packages=pkg_list) + except (PackageNotFoundError, SystemError), err: + msg = _(u'Unable to remove some packages: {0}') + log.warn(msg.format(err)) + log.warn(_(u"These packages will be removed next 'reconfigure'")) + + +CACHE = {} +def cache(): + global CACHE + if not 'groups' in CACHE: + CACHE['groups'] = client.get_groups() + CACHE['groups_container'] = [] + for group in CACHE['groups']: + if group not in ['root', 'all']: + CACHE['groups_container'].append(group) + CACHE['group_infos'] = {} + for group_name in CACHE['groups']: + group_infos = client.get_group_infos(group_name) + CACHE['group_infos'][group_name] = group_infos + CACHE['is_lxc_enabled'] = is_lxc_enabled() + CACHE['module_instancie'] = client.get_creole('module_instancie') + + + +def install_packages(silent=False): + """Install package for each container group + """ + load_pkgmgr() + + cache() + header = _(u'Checking Packages for container') + for group_name, group_infos in CACHE['group_infos'].items(): + package_names = [pkg[u'name'] for pkg in group_infos[u'packages']] + if package_names != []: + msg = header + ' {0}: {1}'.format(group_name, ' '.join(package_names)) + ihm.print_line(msg) + PKGMGR.install(packages=package_names, + silent=silent, + container=group_infos[u'name']) + + +def packages(): + """Manage packages + """ + ihm.print_title(_(u'Managing packages')) + log.info(_(u' Removing packages')) + ihm.print_line(_(u'Removing packages')) + remove_packages() + log.info(_(u' Installing packages')) + ihm.print_line(_(u'Installing packages')) + install_packages() + + +def templates(): + """Run pretemplate scripts and manage templates + """ + ihm.print_title(_(u'Generating configuration files')) + log.info(_(u'Generating configuration files')) + cache() + try: + tmpl = template.CreoleTemplateEngine() + tmpl.instance_files(container=options.container, containers_ctx=CACHE['group_infos'].values()) + except Exception, err: + if options.debug: + log.debug(err, exc_info=True) + else: + log.error(err) + raise err + + +def services(action, display_title=True, try_restart_lxc=True): + """Manage services + """ + cache() + exclude = None + if action == u'stop': + if display_title: + ihm.print_title(_(u"Stopping services")) + exclude = (('root', 'networking'),) + elif action == u'start': + if display_title: + ihm.print_title(_(u"Starting services")) + # ne pas demarrer le service certbot, c'est un service oneshot + # et pyeole.service n'a pas l'air d'aimer ... #22092 + exclude = (('root', 'networking'), ('root', 'certbot')) + ctx = CACHE['group_infos']['root'] + manage_services(action, u'networking', display='console', containers_ctx=[ctx]) + if try_restart_lxc and CACHE['is_lxc_enabled']: + if lxc_need_restart(): + unmanaged_service(u'stop', u'lxc', u'systemd', display='console', ctx=ctx) + unmanaged_service(u'stop', u'lxc-net', u'systemd', display='console', ctx=ctx) + _start_containers() + elif action == u'configure': + if display_title: + ihm.print_title(_(u"Configuring services")) + else: + raise ValueError(_(u"Unknown service action: {0}").format(action)) + if options.container is not None: + containers_ctx = [CACHE['group_infos'][options.containers]] + else: + containers_ctx = CACHE['group_infos'].values() + manage_services(action, container=options.container, display='console', exclude=exclude, containers_ctx=containers_ctx) + + +def _gen_user_list(): + """Generate list of users for password modification + + Start with basic one and ask for supplementary users. + """ + yield 'root' + + node = client.get_creole(u'activer_onenode', 'non') + master = client.get_creole(u'activer_onesinglenode', 'non') + if node == 'oui' and master == 'non': + yield 'oneadmin' + + for number in count(1): + if number == 1: + yield 'eole' + else: + yield 'eole{0}'.format(number) + + + +def users(): + """Manage users + """ + from passlib.context import CryptContext + ihm.print_title(_(u'Managing system user accounts')) + schemes = [u'sha512_crypt', u'sha256_crypt', u'sha1_crypt', u'md5_crypt'] + cryptctx = CryptContext(schemes=schemes) + default_pass = {u'root': u'$eole&123456$', + u'eole': u'$fpmf&123456$', + u'oneadmin': u'$eole&123456$'} + + if not options.interactive: + log.debug(_(u'No system user account management in non-interactive mode.')) + return + + for user in _gen_user_list(): + try: + user_infos = spwd.getspnam(user) + except KeyError: + if user == u'root': + msg = _(u"'root' user unknown. This is abnormal.") + raise Exception(msg) + + # no new administrator with NFS (#16321) + if user != 'eole' and client.get_creole(u'adresse_serveur_nfs', None) is not None: + log.warn(_(u'No new EOLE account with /home on NFS')) + break + + prompt = _('Create new administrator user account {0}?') + if user != 'eole' and ihm.prompt_boolean(prompt.format(user)) is False: + break + + msg = _(u"Creating unexistent user {0}") + log.info(msg.format(user)) + + cmd = ['adduser', '--quiet', '--shell', '/usr/bin/manage-eole', + '--gecos', '{0} user'.format(user.upper()), + '--disabled-password', user] + code = process.system_code(cmd) + if code != 0: + msg = _(u"Unable to create user {0}") + raise Exception(msg.format(user)) + + cmd = ['usermod', '--append', '--groups', 'adm,mail', user] + code, out, err = process.system_out(cmd) + if code != 0: + msg = _(u"Unable to add '{0}' to group 'adm'.") + raise Exception(msg.format(user)) + + # Update informations + user_infos = spwd.getspnam(user) + + if user not in default_pass and user_infos.sp_pwd not in ['!', '*']: + msg = _(u"No modification of password of administrator user account {0}.") + log.warn(msg.format(user)) + continue + + # Change password: + # - on first instance + # - if user is not an EOLE default user + # - if user password match default ones + if (not os.path.isfile(INSTANCE_LOCKFILE) + or (user not in default_pass or user_infos.sp_pwd in ['!', '*'] + or cryptctx.verify(default_pass[user], user_infos.sp_pwd))): + + msg = _(u"# Modificating password for user account {0} #") + msg = msg.format(user) + log.warn(u'#' * len(msg)) + log.warn(msg) + log.warn(u'#' * len(msg)) + max_try = 5 + prompt = u'{0}{1}: ' + first_prompt = _(u"New password") + second_prompt = _(u"Confirming new password") + loop_counter = u'' + for attempt in range(1, max_try+2): + if attempt == max_try+1: + msg = _(u"Password input errors for {0}. Abandon.") + raise Exception(msg.format(user)) + + loop_counter = loop_counter.format(attempt, max_try) + passwd = getpass.getpass(prompt.format(first_prompt, + loop_counter)) + confirm_pass = getpass.getpass(prompt.format(second_prompt, + loop_counter)) + if passwd == confirm_pass: + if user in default_pass and default_pass[user] == passwd: + log.error(_(u"Can not use default password.")) + else: + # Now we have the password + stdin = '{0}:{1}'.format(user, passwd) + code, stdout, stderr = process.system_out(['chpasswd'], + stdin=stdin) + if code == 0: + msg = _(u'User {0} password updated.') + log.info(msg.format(user)) + # Success + break + msg = _(u"Error changing password for {0}.") + try_again_pos = stdout.find('Try again.') + chpassmsg = stdout[0:try_again_pos] + log.error(msg.format(user)) + print chpassmsg + else: + log.error(_(u"Passwords mismatch.")) + + # Display counter + loop_counter = u' ({0}/{1})' + + +def certificates(): + """Manage certificates + + """ + ihm.print_title(_(u'Managing certificates')) + try: + # regénération des hashes des certificats SSL après avec créé les nouveaux certificats + # porté de 2.3 #8488 + cert.rehash_if_needed() + cert.gen_certs() + except Exception, err: + if options.debug: + log.debug(err, exc_info=True) + else: + log.error(err) + raise Exception(_(u"Error while generating certificates: {0}").format(err)) + cache() + if CACHE['is_lxc_enabled']: + src = os.path.join(cert.ssl_dir, "certs") + for group_name in CACHE['groups_container']: + group = CACHE['group_infos'][group_name] + ihm.print_line(_("Copying certificates in {0}").format(group['name'])) + dst = os.path.join('/', group['path'].lstrip('/').encode(charset), src.lstrip('/')) + copyDirectoryContent(src, dst) + process.system_out(['/usr/bin/c_rehash'], container=group_name) + + +def param_kernel(): + """Manage kernel parameters + """ + ihm.print_title(_(u'Applying kernel parameters')) + os.system('/sbin/sysctl -p >/dev/null') + +def kill_dhclient(): + """Kill dhclient for static IP configuration. + + """ + if client.get_creole(u'eth0_method') == u'statique': + os.system('killall dhclient dhclient3 2>/dev/null') + +def finalize(need_lock=True): + """Clean up + """ + ihm.print_title(_(u'Finalizing configuration')) + # enregistrement + try: + process.system_out("/usr/share/creole/diag.py") + except Exception: + pass + fonctionseole.zephir("FIN", "Configuration terminée", COMPAT_NAME.upper()) + if not os.path.isfile(INSTANCE_LOCKFILE): + # l'instance est allée à son terme (#7051) + file(INSTANCE_LOCKFILE, 'w').close() + + if os.path.isfile(UPGRADE_LOCKFILE): + os.unlink(UPGRADE_LOCKFILE) + + if os.path.isfile(container_instance_lockfile): + os.unlink(container_instance_lockfile) + + # sauvegarde des 2 dernières versions de la configuration (#8455) + old = '{0}.bak'.format(configeol) + old1 = '{0}.bak.1'.format(configeol) + if not os.path.isfile(old): + log.debug(_(u'Backup {0} in {1}'.format(configeol, old))) + shutil.copy(configeol, old) + elif process.system_out(['diff', '-q', configeol, old])[0] == 0: + log.debug(_(u"{0} was not modified".format(configeol))) + else: + log.debug(_(u'Backup {0} in {1}'.format(old, old1))) + shutil.copy(old, old1) + log.debug(_(u'Backup {0} in {1}'.format(configeol, old))) + shutil.copy(configeol, old) + if need_lock: + unlock_actions() + +def update_server(): + """Manage server update + """ + if os.path.isfile(MAJ_SUCCES_LOCK): + os.remove(MAJ_SUCCES_LOCK) + if options.interactive: + log.info(_(u'Managing update')) + + ihm.print_title(_(u'Updating server')) + if ihm.prompt_boolean(_(u"""An update is recommended. +Do you want to proceed with network update now ?"""), + default=True, level='warn', + default_uninteractive=False) is True: + report(2) + try: + load_pkgmgr() + _configure_sources_mirror(PKGMGR.pkgmgr) + PKGMGR.update(silent=True) + upgrades = PKGMGR.get_upgradable_list(silent=True) + require_dist_upgrade = False + for container, upgrades in upgrades.items(): + if upgrades: + require_dist_upgrade = True + break + if require_dist_upgrade: + # At least one container require upgrade + PKGMGR.dist_upgrade() + # Update lock => OK, will be deleted at next reconfigure + report(0) + # recall reconfigure + main(force_options={'interactive': False}) + # back to instance + options.interactive = True + reset_compat_name() + else: + log.warn(_(u"No updates available.")) + report(3) + except Exception, err: + report(1, normalize(err)) + raise err + + +def schedule(): + """Manage task scheduling + """ + ihm.print_title(_(u'Task scheduling')) + apply_schedules() + display_schedules() + # 1er lancement de instance + #if not os.path.isfile(schedule.SCHEDULE_FILE): + # schedule.add_post_schedule('majauto', 'weekly') + #schedule.prog_schedule() + +def is_valid_ip_eth0(): + """Check if adresse_ip_eth0 is 169.254.0.1 + """ + ip_eth0 = client.get_creole(u'adresse_ip_eth0') + if ip_eth0 == "169.254.0.1": + return False + else: + return True + + +def reboot_server(): + """Reboot the server if required + """ + if fonctionseole.controle_kernel(): + if options.interactive: + print + if ihm.prompt_boolean(_(u"""Reboot is necessary. +Do you want to reboot now?"""), + default=True, level='warn') is True: + fonctionseole.zephir("MSG", + "Demande de redémarrage acceptée par l'utilisateur", + COMPAT_NAME.upper()) + process.system_code(['reboot']) + else: + fonctionseole.zephir("MSG", + "Demande de redémarrage refusée par l'utilisateur", + COMPAT_NAME.upper()) + else: + print + ihm.print_orange(_(u'Reboot necessary')) + time.sleep(1) + print + if options.auto: + fonctionseole.zephir("MSG", "Redémarrage automatique", + COMPAT_NAME.upper()) + process.system_code(['reboot']) + else: + fonctionseole.zephir("MSG", "Redémarrage du serveur à planifier", + COMPAT_NAME.upper()) + + +def main(force_options=None, force_args=None, need_lock=True): + """Entry point + """ + global log + options.update_from_cmdline(force_args=force_args, + force_options=force_options) + + try: + # module level logger + log = init_logging(name=u'reconfigure', level=options.log_level, + console=['stderr', 'stddebug'], + filename=_LOGFILENAME) + + # Remove module name prefix from Warn/error messages emitted + # from here + set_formatter(log, 'stderr', 'brief') + + # Define handlers for additional loggers + # Thoses logger are not for use + # Log pyeole.service + pyeole_service_log = init_logging(name=u'pyeole.service', + level=options.log_level, + filename=_LOGFILENAME, + console=['stderr']) + # Log pyeole.pkg + pyeole_pkg_log = init_logging(name=u'pyeole.pkg', + level=options.log_level, + filename=_LOGFILENAME) + passlib_log = init_logging(name=u'passlib.registry', + level='error', + filename=_LOGFILENAME) + + # Disable warnings from pyeole.service + set_filters(pyeole_service_log, 'stderr', + ['error', 'critical']) + + if options.verbose or options.debug: + # Enable creole logs + creole_log = init_logging(name=u'creole', level=options.log_level, + filename=_LOGFILENAME) + # Define a root logger when verbose or debug is activated + root_log = init_logging(level=options.log_level) + else: + # Enable creole logs + creole_log = init_logging(name=u'creole', level=options.log_level, + filename=_LOGFILENAME, + console=['stderr']) + + creolemajauto_log = init_logging(name=u'creole.majauto', level=options.log_level, + filename=_LOGFILENAME, console=['stderr', 'stdout']) + + ihm.print_title(_(u'Beginning of configuration')) + # instance or reconfigure ? + reset_compat_name() + fonctionseole.zephir("INIT", "Début de configuration", + COMPAT_NAME.upper()) + prepare(need_lock) + valid_mandatory(need_lock) + cache() + containers() + packages() + run_parts(u'preservice') + services(action=u'stop') + run_parts(u'pretemplate') + templates() + if not is_valid_ip_eth0(): + log.info(_(u"eth0 network interface does not have a valid IP address.")) + log.info(_(u"Restarting networking service")) + manage_service(u'restart', u'networking', display='console') + templates() + if not is_valid_ip_eth0(): + log.info(_(u"eth0 network interface does not have a valid IP address.")) + msg = _(u"Unable to obtain IP address.") + raise NetworkConfigError(msg) + + services(action=u'configure') + # posttemplate/00-annuaire needs the certificates + certificates() + run_parts(u'posttemplate') + #close all connexion before param kernel #17408 + client.close() + param_kernel() + kill_dhclient() + services(action=u'start') + users() + run_parts(u'postservice') + schedule() + finalize(need_lock) + ihm.print_title(_(u'Reconfiguration OK')) + update_server() + # IMPORTANT : Ne rien faire après ces lignes + # car le serveur est susceptible d'être redémarré + reboot_server() + + except (UserExit, UserExitError), err: + unlock_actions(need_lock) + fonctionseole.zephir("FIN", "Abandon par l'utilisateur", + COMPAT_NAME.upper()) + raise err + + except Exception, err: + if options.debug: + log.debug(err, exc_info=True) + else: + log.error(err) + fonctionseole.zephir('ERR', str(err), + COMPAT_NAME.upper(), + console=False) + if need_lock: + release(LOCK_NAME, valid=False, level='system') + raise err + +if __name__ == '__main__': + main() diff --git a/creole/server.py b/creole/server.py new file mode 100644 index 0000000..c114470 --- /dev/null +++ b/creole/server.py @@ -0,0 +1,651 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +########################################################################## +# creole.server - distribute creole variables through REST API +# Copyright © 2012,2013 Pôle de compétences EOLE +# +# License CeCILL: +# * in french: http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html +# * in english http://www.cecill.info/licences/Licence_CeCILL_V2-en.html +########################################################################## + +"""Distribute Creole configuration through REST API + +Setup a daemon based on `cherrypy` listening by default on +127.0.0.1:8000 for queries on Creole configuration. + +""" + +import os +import sys +import argparse +import threading + +from creole import eosfunc + +from traceback import format_exc + +from os.path import basename, dirname, isdir, samefile, splitext + +from pyeole.log import init_logging, getLogger +from pyeole import scriptargs + +from .config import configeoldir, eoledirs, eoleextradico, \ + eoleextraconfig +from .loader import creole_loader, load_config_eol, load_extras + +from .i18n import _ + +from tiramisu.config import Config, SubConfig, undefined +from tiramisu.error import PropertiesOptionError + +from pyeole.cherrypy_plugins import InotifyMonitor + +import cherrypy +import socket + +from pyinotify import ProcessEvent +from pyinotify import IN_DELETE +from pyinotify import IN_CREATE +from pyinotify import IN_MODIFY +from pyinotify import IN_MOVED_TO +from pyinotify import IN_MOVED_FROM + +from systemd import daemon + +import logging + +# Global logger +log = getLogger(__name__) + +lock = threading.Lock() + +num_error = [(PropertiesOptionError, 1), (KeyError, 2), + (AttributeError, 4), (Exception, 3)] + +# For pyinotify handler and filtering +_INOTIFY_EOL_DIRS = [configeoldir, eoleextraconfig] + +_INOTIFY_MASK = IN_DELETE | IN_CREATE | IN_MODIFY | IN_MOVED_TO | IN_MOVED_FROM + + +def _inotify_filter(event): + """Check if the path must be excluded from being watched. + + :param event: event to look for + :type event: :class:`pyinotify.Event` + :return: if the :data:`event` must be excluded + :rtype: `bool` + + """ + + _INOTIFY_EOL = True + + if isdir(event.pathname): + # Always ok for EOLE directories + for directory in _INOTIFY_EOL_DIRS: + if not os.access(directory, os.F_OK): + continue + if samefile(event.pathname, directory): + _INOTIFY_EOL = False + + if not _INOTIFY_EOL: + return {"EOL": _INOTIFY_EOL} + + extension = splitext(event.name)[1] + + if event.mask != IN_DELETE and not os.access(event.pathname, os.F_OK): + log.debug(_(u'File not accessible: {0}').format(event.pathname)) + return {"EOL": True} + + if event.mask != IN_DELETE and os.stat(event.pathname).st_size == 0: + log.debug(_(u'File with null size: {0}').format(event.pathname)) + return {"EOL": True} + + # Check only for files in EOLE directories + + for directory in _INOTIFY_EOL_DIRS: + if not os.access(directory, os.F_OK): + continue + if samefile(event.path, directory) or str(event.path).startswith(directory): + _INOTIFY_EOL = extension != '.eol' + break + + return {"EOL": _INOTIFY_EOL} + + +class CreoleInotifyHandler(ProcessEvent): + """Process inotify events + + """ + + _server = None + """Instance of :class:`CreoleServer`. + + """ + + def my_init(self, server): + """Subclass constructor. + + This is the constructor, it is automatically called from + :meth:`ProcessEvent.__init__()`, + + Extra arguments passed to ``__init__()`` would be delegated + automatically to ``my_init()``. + + """ + self._server = server + + def process_default(self, event): + """Reload :class:`CreoleServer` on all managed inotify events + + """ + inotify_data = _inotify_filter(event) + if not inotify_data["EOL"]: + log.warn(_(u'Reload config.eol due to {0} on {1}').format(event.maskname, + event.pathname)) + try: + self._server.reload_eol() + except: + pass + else: + log.debug(_(u'Filtered inotify event for {0}').format(event.pathname)) + + +class CreoleServer(object): + """Cherrypy application answering REST requests + """ + + def __init__(self, running=True): + """Initialize the server + + Load the tiramisu configuration. + + :param `bool` running: Is the web server running during server + initialization. + + """ + + log.debug(_(u"Loading tiramisu configuration")) + self.config = None + self.reload_config(running) + + @cherrypy.expose + @cherrypy.tools.json_out() + def reload_config(self, running=True): + lock.acquire() + + if running: + # Tell systemd that we are reloading the configuration + daemon.notify('RELOADING=1') + + try: + log.debug(u"Set umask to 0022") + os.umask(0022) + reload(eosfunc) + eosfunc.load_funcs(force_reload=True) + self.config = creole_loader(load_extra=True, reload_config=False, + disable_mandatory=True, owner='creoled', + try_upgrade=False) + if log.isEnabledFor(logging.DEBUG) and self.config.impl_get_information('load_error', False): + msg = _('Load creole configuration with errors') + log.debug(msg) + ret = self.response() + + except Exception, err: + # Avoid using format as exception message could be undecoded + msg = _('Unable to load creole configuration: ') + msg += unicode(str(err), 'utf-8') + if log.isEnabledFor(logging.DEBUG): + log.debug(msg, exc_info=True) + else: + log.error(msg) + + #self.config = None + ret = self.response(status=3) + + if running: + # Tell systemd that we are now ready again + daemon.notify('READY=1') + + lock.release() + + return ret + + @cherrypy.expose + @cherrypy.tools.json_out() + def reload_eol(self): + if not self.config: + return self.reload_config() + + lock.acquire() + + # Tell systemd that we are reloading the configuration + daemon.notify(u'RELOADING=1') + + config = Config(self.config.cfgimpl_get_description()) + try: + load_config_eol(config) + except Exception, err: + # Avoid using format as exception message could be undecoded + msg = _('Unable to load creole configuration from config.eol: ') + msg += unicode(str(err), 'utf-8') + if log.isEnabledFor(logging.DEBUG): + log.debug(msg, exc_info=True) + else: + log.error(msg) + + #self.config = None + ret = self.response(status=3) + try: + load_extras(config) + except: + msg = _('Unable to load creole configuration from extra: ') + msg += unicode(str(err), 'utf-8') + if log.isEnabledFor(logging.DEBUG): + log.debug(msg, exc_info=True) + else: + log.error(msg) + + #self.config = None + ret = self.response(status=3) + else: + config.read_only() + self.config = config + ret = self.response() + + + # Tell systemd that we are now ready again + daemon.notify(u'READY=1') + + lock.release() + + return ret + + @cherrypy.expose + @cherrypy.tools.json_out() + def valid_mandatory(self): + if self.config is None: + return self._no_config() + try: + msg = _(u'All variables are not set, please configure your system:') + error = False + mandatory_errors = set(self.config.cfgimpl_get_values().mandatory_warnings(force_permissive=True)) + if mandatory_errors != set(): + error = True + msg += ' ' + _('variables are mandatories') + ' (' + ', '.join(mandatory_errors) + ')' + force_vars = set() + for force_store_var in self.config.impl_get_information('force_store_vars'): + if force_store_var not in mandatory_errors: + try: + getattr(self.config, force_store_var) + force_vars.add(force_store_var) + except: + pass + if force_vars != set(): + error = True + msg += ' ' + _('variables must be in config file') + ' (' + ', '.join(force_vars) + ')' + + if error: + log.debug(mandatory_errors) + return self.response(msg, 3) + except Exception, err: + log.debug(err, exc_info=True) + return self.response(str(err), 3) + return self.response() + + @staticmethod + def response(response='OK', status=0): + """Generate a normalized response + + :param response: message of the response + :type response: `object` + :param status: status code for the response, ``0`` for OK + :type status: `int` + :return: response of the form: ``{"status": `int`, "response": `message`}`` + :rtype: `dict` + + """ + return {u'status': status, u'response': response} + + @cherrypy.expose + @cherrypy.tools.json_out() + def get(self, *args, **kwargs): + """Return the content of a tiramisu path + + :param args: path elements of the query + :type args: `list` + :return: Value of a single variable or sub tree + :rtype: `dict` + + """ + def _remove_properties_error(val): + new_val = [] + for v in val: + if isinstance(v, PropertiesOptionError): + new_val.append({'err': str(v)}) + else: + new_val.append(v) + return new_val + + if self.config is None: + return self._no_config() + try: + config = self.config + if len(args) != 0: + subconfig = getattr(config, '.'.join(args)) + else: + subconfig = config + if isinstance(subconfig, SubConfig): + if u'variable' in kwargs: + name = kwargs[u'variable'] + path = subconfig.find_first(byname=name, + type_=u'path', + check_properties=False) + try: + val = getattr(config, path) + except PropertiesOptionError as err: + if err.proptype == ['mandatory']: + raise Exception(_(u'Mandatory variable {0} ' + u'is not set.').format(name)) + raise err + if isinstance(val, list): + val = _remove_properties_error(val) + return self.response(val) + else: + withoption = kwargs.get(u'withoption') + withvalue = kwargs.get(u'withvalue') + if withvalue is None: + withvalue = undefined + dico = subconfig.make_dict(withoption=withoption, withvalue=withvalue) + for key, val in dico.items(): + if isinstance(val, list): + dico[key] = _remove_properties_error(val) + return self.response(dico) + else: + #if config is a value, not a SubConfig + if isinstance(subconfig, list): + subconfig = _remove_properties_error(subconfig) + return self.response(subconfig) + except Exception, err: + log.debug(err, exc_info=True) + for error_match in num_error: + if isinstance(err, error_match[0]): + break + return self.response(str(err), error_match[1]) + + @cherrypy.expose + @cherrypy.tools.json_out() + def list(self, *args): + """List subtree pointed by :data:`args` + + List the nodes and variables under a path. + + If the path point to a single variable, then return its value. + + :param args: path elements of the query + :type args: `list` + + :return: Nodes and/or variables under a path, or value of a + variable + :rtype: `list` + + """ + if self.config is None: + return self._no_config() + try: + config = self.config + if len(args) == 0: + # root of configuration + obj = config + else: + # Path to a sub configuration + base = '.'.join(args) + obj = getattr(config, base) + if isinstance(obj, SubConfig): + # Path is a node + groups = [u'%s/' % g[0] for g in obj.iter_groups()] + items = [u'%s' % i[0] for i in obj] + return self.response(groups + items) + else: + # Path is a leaf + value = self.get(*args)[u'response'] + return self.response([value]) + except Exception, err: + log.debug(err, exc_info=True) + for error_match in num_error: + if isinstance(err, error_match[0]): + break + return self.response(str(err), error_match[1]) + + def _no_config(self): + """Return an error message when no configuration is loaded + + :return: a failure response + :rtype: `dict` + + """ + return self.response(_(u'No configuration'), status=3) + +class CreoleDaemon(object): + """Run the CreoleServer + """ + + def __init__(self): + """Initialize the cherrypy daemon + """ + + # Built-in configuration + self.argparse = self._load_argparse() + # Read command line arguments + self.option = self.argparse.parse_args() + if self.option.verbose: + self.option.log_level = u'info' + if self.option.debug: + self.option.log_level = u'debug' + self._configure_log() + + def _load_argparse(self): + """Parse command line arguments + + :return: command line parser + :rtype: `argparse.ArgumentParser` + + """ + parser = argparse.ArgumentParser(description=u'Run creole daemon', + parents=[scriptargs.logging('warning')], + conflict_handler='resolve') + parser.add_argument("-b", "--base-dir", default='/tmp', + help=_(u"Base directory in which the server" + " is launched (default: /tmp)")) + parser.add_argument("-c", "--conf-file", + default='/etc/eole/creoled.conf', + help=_(u"Configuration file of the server" + " (default: /etc/eole/creoled.conf")) + parser.add_argument("-d", "--daemon", action='store_true', + help=_(u"Run the server as a daemon (default: false)")) + parser.add_argument("-l", "--listen", action='store', + default='127.0.0.1:8000', + help=_(u"Listen on the specified IP:PORT" + " (default: 127.0.0.1:8000)")) + parser.add_argument("-m", "--mount-base", default='/', + help=_(u"Base under which the application is mounted" + " (default: /)")) + parser.add_argument("-p", "--pidfile", + default='/tmp/{0}.pid'.format( + basename(sys.argv[0])), + help=_(u"Base under which the application is mounted" + " (default: /)")) + parser.add_argument("-u", "--user", default='nobody', + help=_(u"User of the running process" + " (default: nobody)")) + parser.add_argument("-g", "--group", default='nogroup', + help=_(u"Group of the running process" + " (default: nogroup)")) + parser.add_argument("--umask", default='0640', + help=_(u"Umask of the running process" + " (default: 0644)")) + return parser + + def _get_conf(self, name): + """Map command line arguments to cherrypy configuration + + :param name: internal name of argparse option store + :returns: piece of cherrypy configuration + :rtype: `dict` + """ + try: + option_map = { 'listen' : + { 'server.socket_host' : + self.option.listen.split(':')[0], + 'server.socket_port' : + int(self.option.listen.split(':')[1])}, + } + return option_map[name] + except KeyError: + return {} + + def load_conf(self): + """Load daemon configuration + + Take care to load the configuration in proper order and avoid + overriding configuration file parameter by default command + line arguments. + + Order is: + + - default values from command line option parser + + - option from a configuration file + + - command line arguments + + """ + # Load all default value + config = {'engine.autoreload.on': False} + for opt in vars(self.option): + config.update(self._get_conf(opt)) + + cherrypy.config.update( { 'global' : config} ) + + # Load configuration file + if os.access(self.option.conf_file, os.F_OK): + cherrypy.config.update(self.option.conf_file) + + # Override config file option present on command line + config = {} + for opt in sys.argv[1:]: + config.update(self._get_conf(opt)) + cherrypy.config.update( {'global' : config } ) + + def _configure_log(self): + """Configure the module logger + + Avoid logging apache style time since the logger does it. + + """ + global log + log_filename = None + if self.option.daemon: + log_filename = u'/var/log/creoled.log' + + log = init_logging(name=u'creoled', as_root=True, + level=self.option.log_level, + console=not self.option.daemon, + syslog=None, + filename=log_filename) + + # Cherrypy do not handle logs + cherrypy.log.error_file = None + cherrypy.log.access_file = None + # Do not output on screen + cherrypy.log.screen = False + # Hack to avoid time in log message + cherrypy.log.time = lambda : '' + + def run(self): + """Start the cherrypy server. + """ + engine = cherrypy.engine + + # Load server but we are not running now + # Do not let him tell systemd otherwise + server = CreoleServer(running=False) + + inotify_handler = CreoleInotifyHandler(server=server) + + if hasattr(engine, "signal_handler"): + engine.signal_handler.subscribe() + # Error exit on SIGINT (Ctl-c) #6177 + engine.signal_handler.set_handler(2, self._kill) + + if hasattr(engine, "console_control_handler"): + engine.console_control_handler.subscribe() + + cherrypy.tree.mount(server, self.option.mount_base, + config={'global' : {} }) + + # Merge configuration from build-in, configuration file and command line + self.load_conf() + + if server.config is None: + msg = _(u"No configuration found: do not check for container mode.") + log.warn(msg) + elif server.config.creole.general.mode_conteneur_actif == 'oui': + container_ip = server.config.creole.containers.adresse_ip_br0 + container_port = cherrypy.config.get('server.socket_port') + # Start a server for containers if ip can be bounded + try: + container_socket = socket.socket(socket.AF_INET, + socket.SOCK_STREAM) + container_socket.setsockopt(socket.SOL_SOCKET, + socket.SO_REUSEADDR, + 1) + container_socket.bind((container_ip, container_port)) + container_socket.close() + except socket.error, err: + log.error(_(u"Unable to listen for containers: {0}").format(err)) + else: + container_server = cherrypy._cpserver.Server() + container_server.socket_host = container_ip + container_server.socket_port = container_port + container_server.subscribe() + + monitor = InotifyMonitor(engine, inotify_handler) + monitor.subscribe() + + monitor.watch.add_watch(_INOTIFY_EOL_DIRS, _INOTIFY_MASK, auto_add=True, rec=True) + + if self.option.pidfile: + cherrypy.process.plugins.PIDFile(engine, + self.option.pidfile).subscribe() + + if self.option.daemon: + cherrypy.process.plugins.Daemonizer(engine).subscribe() + + # Drop priviledges + cherrypy.process.plugins.DropPrivileges(engine, + uid = self.option.user, + gid = self.option.group, + umask = self.option.umask) + + # Let's start the CherryPy engine so that + # everything works + engine.start() + + # Tell systemd that we are ready + daemon.notify(u'READY=1') + + # Run the engine main loop + engine.block() + + @staticmethod + def _kill(): + """Exit the server with non zero exit code + """ + sys.exit(1) + +if __name__ == '__main__': + daemon = CreoleDaemon() + daemon.run() diff --git a/creole/service.py b/creole/service.py new file mode 100644 index 0000000..0f509d8 --- /dev/null +++ b/creole/service.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +from pyeole.service import manage_services +from pyeole.decorator import deprecated + +from .i18n import _ + + +@deprecated(_(u'Use new API “manage_services()”')) +def instance_services(container=None): + """ + instancie les services + """ + manage_services(u'configure', container=container) + + +@deprecated(_(u'Use new API “manage_services()”')) +def stop_services(container=None): + """Stop all services + + The networking service is never stopped. + + @param container: name of the container + @type container: C{str} + """ + manage_services(u'stop', container=container) + + +@deprecated(_(u'Use new API “manage_services()”')) +def start_services(container=None): + """Start all services + + The networking service is a special case. + + @param container: name of the container + @type container: C{str} + """ + manage_services(u'start', container=container) + + +@deprecated(_(u'Use new API “manage_services()”')) +def restart_services(container=None): + """ + redemarrage des services + """ + manage_services(u'restart', container=container) diff --git a/creole/template.py b/creole/template.py new file mode 100644 index 0000000..5fde033 --- /dev/null +++ b/creole/template.py @@ -0,0 +1,607 @@ +# -*- coding: utf-8 -*- +""" +Gestion du mini-langage de template +On travaille sur les fichiers cibles +""" + +import sys +import shutil +import logging + +import traceback +import os +from os import listdir, unlink +from os.path import basename, join + +from tempfile import mktemp + +from Cheetah import Parser +# l'encoding du template est déterminé par une regexp (encodingDirectiveRE dans Parser.py) +# il cherche un ligne qui ressemble à '#encoding: utf-8 +# cette classe simule le module 're' et retourne toujours l'encoding utf-8 +# 6224 +class FakeEncoding(): + def groups(self): + return ('utf-8',) + + def search(self, *args): + return self +Parser.encodingDirectiveRE = FakeEncoding() + +from Cheetah.Template import Template as ChtTemplate +from Cheetah.NameMapper import NotFound as CheetahNotFound + +import config as cfg + +from .client import CreoleClient, CreoleClientError +from .error import FileNotFound, TemplateError, TemplateDisabled +import eosfunc + +from .i18n import _ + +import pyeole + +log = logging.getLogger(__name__) +log.addHandler(logging.NullHandler()) + +class IsDefined(object): + """ + filtre permettant de ne pas lever d'exception au cas où + la variable Creole n'est pas définie + """ + def __init__(self, context): + self.context = context + + def __call__(self, varname): + if '.' in varname: + splitted_var = varname.split('.') + if len(splitted_var) != 2: + msg = _(u"Group variables must be of type master.slave") + raise KeyError(msg) + master, slave = splitted_var + if master in self.context: + return slave in self.context[master].slave.keys() + return False + else: + return varname in self.context + + +class CreoleGet(object): + def __init__(self, context): + self.context = context + + def __call__(self, varname): + return self.context[varname] + + def __getitem__(self, varname): + """For bracket and dotted notation + """ + return self.context[varname] + + def __contains__(self, varname): + """Check variable existence in context + """ + return varname in self.context + + +@classmethod +def cl_compile(kls, *args, **kwargs): + kwargs['compilerSettings'] = {'directiveStartToken' : u'%', + 'cheetahVarStartToken' : u'%%', + 'EOLSlurpToken' : u'%', + 'PSPStartToken' : u'µ' * 10, + 'PSPEndToken' : u'µ' * 10, + 'commentStartToken' : u'µ' * 10, + 'commentEndToken' : u'µ' * 10, + 'multiLineCommentStartToken' : u'µ' * 10, + 'multiLineCommentEndToken' : u'µ' * 10} + return kls.old_compile(*args, **kwargs) +ChtTemplate.old_compile = ChtTemplate.compile +ChtTemplate.compile = cl_compile + + +class CheetahTemplate(ChtTemplate): + """classe pour personnaliser et faciliter la construction + du template Cheetah + """ + def __init__(self, filename, context, current_container): + """Initialize Creole CheetahTemplate + + @param filename: name of the file to process + @type filename: C{str} + @param context: flat dictionary of creole variables as 'name':'value', + @type context: C{dict} + @param current_container: flat dictionary describing the current container + @type current_container: C{dict} + """ + eos = {} + for func in dir(eosfunc): + if not func.startswith('_'): + eos[func] = getattr(eosfunc, func) + # ajout des variables decrivant les conteneurs + #FIXME chercher les infos dans le client ! + ChtTemplate.__init__(self, file=filename, + searchList=[context, eos, {u'is_defined' : IsDefined(context), + u'creole_client' : CreoleClient(), + u'current_container':CreoleGet(current_container), + }]) + + +class CreoleMaster(object): + def __init__(self, value, slave=None, index=None): + """ + On rend la variable itérable pour pouvoir faire: + for ip in iplist: + print ip.network + print ip.netmask + print ip + index is used for CreoleLint + """ + self._value = value + if slave is not None: + self.slave = slave + else: + self.slave = {} + self._index = index + + def __getattr__(self, name): + """Get slave variable or attribute of master value. + + If the attribute is a name of a slave variable, return its value. + Otherwise, returns the requested attribute of master value. + """ + if name in self.slave: + value = self.slave[name] + if isinstance(value, Exception): + raise value + return value + else: + return getattr(self._value, name) + + def __getitem__(self, index): + """Get a master.slave at requested index. + """ + ret = {} + for key, values in self.slave.items(): + ret[key] = values[index] + return CreoleMaster(self._value[index], ret, index) + + def __iter__(self): + """Iterate over master.slave. + + Return synchronised value of master.slave. + """ + for i in range(len(self._value)): + ret = {} + for key, values in self.slave.items(): + ret[key] = values[i] + yield CreoleMaster(self._value[i], ret, i) + + def __len__(self): + """Delegate to master value + """ + return len(self._value) + + def __repr__(self): + """Show CreoleMaster as dictionary. + + The master value is stored under 'value' key. + The slaves are stored under 'slave' key. + """ + return repr({u'value': self._value, u'slave': self.slave}) + + def __eq__(self, value): + return value == self._value + + def __ne__(self, value): + return value != self._value + + def __lt__(self, value): + return self._value < value + + def __le__(self, value): + return self._value <= value + + def __gt__(self, value): + return self._value > value + + def __ge__(self, value): + return self._value >= value + + def __str__(self): + """Delegate to master value + """ + return str(self._value) + + def __add__(self, val): + return self._value.__add__(val) + + def __radd__(self, val): + return val + self._value + + def __contains__(self, item): + return item in self._value + + def add_slave(self, name, value): + """Add a slave variable + + Minimal check on type and value of the slave in regards to the + master one. + + @param name: name of the slave variable + @type name: C{str} + @param value: value of the slave variable + """ + if isinstance(self._value, list): + if not isinstance(value, list): + raise TypeError + elif len(value) != len(self._value): + raise ValueError(_(u'length mismatch')) + new_value = [] + for val in value: + if isinstance(val, dict): + new_value.append(ValueError(val['err'])) + else: + new_value.append(val) + value = new_value + elif isinstance(value, list): + raise TypeError + self.slave[name] = value + +class CreoleTemplateEngine(object): + """Engine to process Creole cheetah template + """ + def __init__(self, force_values=None): + #force_values permit inject value and not used CreoleClient (used by CreoleLint) + self.client = CreoleClient() + self.creole_variables_dict = {} + self.force_values = force_values + self.load_eole_variables() + + def load_eole_variables(self): + # remplacement des variables EOLE + self.creole_variables_dict = {} + if self.force_values is not None: + values = self.force_values + else: + values = self.client.get_creole() + for varname, value in values.items(): + if varname in self.creole_variables_dict: + # Creation of a slave create the master + continue + if varname.find('.') != -1: + #support des groupes + mastername, slavename = varname.split('.') + if not mastername in self.creole_variables_dict or not \ + isinstance(self.creole_variables_dict [mastername], + CreoleMaster): + # Create the master variable + if mastername in values: + self.creole_variables_dict[mastername] = CreoleMaster(values[mastername]) + else: + #only for CreoleLint + self.creole_variables_dict[mastername] = CreoleMaster(value) + #test only for CreoleLint + if mastername != slavename: + self.creole_variables_dict[mastername].add_slave(slavename, value) + else: + self.creole_variables_dict[varname] = value + + def patch_template(self, filevar, force_no_active=False): + """Apply patch to a template + """ + var_dir = os.path.join(cfg.patch_dir,'variante') + patch_cmd = ['patch', '-d', cfg.templatedir, '-N', '-p1'] + patch_no_debug = ['-s', '-r', '-', '--backup-if-mismatch'] + + tmpl_filename = os.path.split(filevar[u'source'])[1] + # patches variante + locaux + for directory in [var_dir, cfg.patch_dir]: + patch_file = os.path.join(directory, '{0}.patch'.format(tmpl_filename)) + if os.access(patch_file, os.F_OK): + msg = _(u"Patching template '{0}' with '{1}'") + log.info(msg.format(filevar[u'source'], patch_file)) + ret, out, err = pyeole.process.system_out(patch_cmd + patch_no_debug + ['-i', patch_file]) + if ret != 0: + msg = _(u"Error applying patch: '{0}'\nTo reproduce and fix this error {1}") + log.error(msg.format(patch_file, ' '.join(patch_cmd + ['-i', patch_file]))) + #8307 : recopie le template original et n'arrête pas le processus + self._copy_to_template_dir(filevar, force_no_active) + #raise TemplateError(msg.format(patch_file, err)) + + def strip_template_comment(self, filevar): + """Strip comment from template + + This apply if filevar has a del_comment attribut + """ + # suppression des commentaires si demandé (attribut del_comment) + strip_cmd = ['sed', '-i'] + if u'del_comment' in filevar and filevar[u'del_comment'] != '': + log.info(_(u"Cleaning file '{0}'").format( filevar[u'source'] )) + ret, out, err = pyeole.process.system_out(strip_cmd + + ['/^\s*{0}/d ; /^$/d'.format(filevar[u'del_comment']), + filevar[u'source'] ]) + if ret != 0: + msg = _(u"Error removing comments '{0}': {1}") + raise TemplateError(msg.format(filevar[u'del_comment'], err)) + + def _check_filevar(self, filevar, force_no_active=False): + """Verify that filevar is processable + + :param filevar: template file informations + :type filevar: `dict` + + :raise CreoleClientError: if :data:`filevar` is disabled + inexistant or unknown. + + """ + if not force_no_active and (u'activate' not in filevar or not filevar[u'activate']): + + raise CreoleClientError(_(u"Template file not enabled:" + u" {0}").format(basename(filevar[u'source']))) + if u'source' not in filevar or filevar[u'source'] is None: + raise CreoleClientError(_(u"Template file not set:" + u" {0}").format(basename(filevar['source']))) + + if u'name' not in filevar or filevar[u'name'] is None: + raise CreoleClientError(_(u"Template target not set:" + u" {0}").format(basename(filevar[u'source']))) + + def _copy_to_template_dir(self, filevar, force_no_active=False): + """Copy template to processing temporary directory. + + :param filevar: template file informations + :type filevar: `dict` + :param force_no_active: copy disabled template if `True` + :type filevar: `bool` + :raise FileNotFound: if source template does not exist + + """ + self._check_filevar(filevar, force_no_active) + tmpl_source_name = os.path.split(filevar[u'source'])[1] + tmpl_source_file = os.path.join(cfg.distrib_dir, tmpl_source_name) + if not os.path.isfile(tmpl_source_file): + msg = _(u"Template {0} unexistent").format(tmpl_source_file) + raise FileNotFound(msg) + else: + log.info(_(u"Copy template: '{0}' -> '{1}'").format(tmpl_source_file, cfg.templatedir)) + shutil.copy(tmpl_source_file, cfg.templatedir) + + def prepare_template(self, filevar, force_no_active=False): + """Prepare template source file + """ + self._copy_to_template_dir(filevar, force_no_active) + self.patch_template(filevar, force_no_active) + self.strip_template_comment(filevar) + + def verify(self, filevar): + """ + verifie que les fichiers existent + @param mkdir : création du répertoire si nécessaire + """ + if not os.path.isfile(filevar[u'source']): + raise FileNotFound(_(u"File {0} does not exist.").format(filevar[u'source'])) + destfilename = filevar[u'full_name'] + dir_target = os.path.dirname(destfilename) + if dir_target != '' and not os.path.isdir(dir_target): + if not filevar[u'mkdir']: + raise FileNotFound(_(u"Folder {0} does not exist but is required by {1}").format(dir_target, destfilename)) + os.makedirs(dir_target) + # FIXME: pose plus de problème qu'autre chose (cf. #3048) + #if not isfile(target): + # system('cp %s %s' % (source, target)) + + def process(self, filevar, container): + """Process a cheetah template + + Process a cheetah template and copy the file to destination. + @param filevar: dictionary describing the file to process + @type filevar: C{dict} + @param container: dictionary describing the container + @type container: C{dict} + """ + UTF = "#encoding: utf-8" + + self._check_filevar(filevar) + + # full path of the destination file + destfilename = filevar[u'full_name'] + + log.info(_(u"Cheetah processing: '{0}' -> '{1}'").format(filevar[u'source'], + destfilename)) + + # utilisation d'un fichier temporaire + # afin de ne pas modifier l'original + tmpfile = mktemp() + shutil.copy(filevar[u'source'], tmpfile) + + # ajout de l'en-tête pour le support de l'UTF-8 + # FIXME: autres encodages ? + #os.system("sed -i '1i{0}' {1}".format(UTF, tmpfile)) (supprimé depuis #6224) + + try: + cheetah_template = CheetahTemplate(tmpfile, self.creole_variables_dict, container) + os.unlink(tmpfile) + # suppression de l'en-tête UTF-8 ajouté !!! (supprimé depuis #6224) + data = str(cheetah_template) # .replace("{0}\n".format(UTF), '', 1) + except CheetahNotFound, err: + varname = err.args[0][13:-1] + msg = _(u"Error: unknown variable used in template {0} : {1}").format(filevar[u'name'], varname) + raise TemplateError, msg + except UnicodeDecodeError, err: + msg = _(u"Encoding issue detected in template {0}").format(filevar[u'name']) + raise TemplateError, msg + except Exception, err: + msg = _(u"Error while instantiating template {0}: {1}").format(filevar[u'name'], err) + raise TemplateError, msg + + # écriture du fichier cible + if destfilename == '': + # CreoleCat may need to write on stdout (#10065) + sys.stdout.write(data) + else: + try: + file_h = file(destfilename, 'w') + file_h.write(data) + file_h.close() + except IOError, e: + msg = _(u"Unable to write in file '{0}': '{1}'").format(destfilename, e) + raise FileNotFound, msg + + def change_properties(self, filevar, container=None, force_full_name=False): + chowncmd = [u'chown'] + chownarg = '' + chmodcmd = [u'chmod'] + chmodarg = '' + + if not force_full_name: + destfilename = filevar[u'name'] + else: + destfilename = filevar[u'full_name'] + + if u'owner' in filevar and filevar[u'owner']: + chownarg = filevar[u'owner'] + else: + chownarg = u'root' + + if u'group' in filevar and filevar[u'group']: + chownarg += ":" + filevar[u'group'] + else: + chownarg += u':root' + + if u'mode' in filevar and filevar[u'mode']: + chmodarg = filevar[u'mode'] + else: + chmodarg = u'0644' + + chowncmd.extend( [chownarg, destfilename] ) + chmodcmd.extend( [chmodarg, destfilename] ) + + log.info(_(u'Changing properties: {0}').format(' '.join(chowncmd)) ) + ret, out, err = pyeole.process.creole_system_out( chowncmd, container=container, context=False ) + if ret != 0: + log.error(_(u'Error changing properties {0}: {1}').format(ret, err) ) + + log.info(_(u'Changing properties: {0}').format(' '.join(chmodcmd)) ) + ret, out, err = pyeole.process.creole_system_out( chmodcmd, container=container, context=False ) + if ret != 0: + log.error(_(u'Error changing properties {0}: {1}').format(ret, err) ) + + def remove_destfile(self, filevar): + """ + suppression du fichier de destination + """ + destfilename = filevar[u'full_name'] + if os.path.isfile(destfilename): + os.unlink(destfilename) + else: + log.debug(_(u"File '{0}' unexistent.").format(destfilename)) + + + def _instance_file(self, filevar, container=None): + """Run templatisation on one file of one container + + @param filevar: Dictionary describing the file + @type filevar: C{dict} + @param container: Dictionary describing a container + @type container: C{dict} + """ + if not filevar.get(u'activate', False): + try: + # copy and patch disabled templates too (#11029) + self.prepare_template(filevar, force_no_active=True) + except FileNotFound: + pass + + if u'rm' in filevar and filevar[u'rm']: + log.info(_(u"Removing file '{0}'" + u" from container '{1}'").format(filevar[u'name'], + container[u'name'])) + self.remove_destfile(filevar) + + # The caller handles if it's an error + raise TemplateDisabled(_(u"Instantiation of file '{0}' disabled").format(filevar[u'name'])) + + log.info(_(u"Instantiating file '{0}'" + u" from '{1}'").format(filevar[u'name'], filevar[u'source'])) + self.prepare_template(filevar) + self.verify(filevar) + self.process(filevar, container) + if filevar['name'].startswith('..') and container not in [None, 'root']: + self.change_properties(filevar, None, True) + else: + self.change_properties(filevar, container) + + + def instance_file(self, filename=None, container='root', ctx=None): + """Run templatisation on one file + + @param filename: name of a file + @type filename: C{str} + @param container: name of a container + @type container: C{str} + """ + if container == 'all': + if ctx is None: + groups = self.client.get_groups() + else: + groups = ctx.keys() + for group in groups: + if group in ['all', 'root']: + continue + if ctx is None: + lctx = None + else: + lctx = ctx[group] + self.instance_file(filename=filename, container=group, ctx=lctx) + else: + if ctx is None: + ctx = self.client.get_container_infos(container) + + filevars = [f for f in ctx[u'files'] if f[u'name'] == filename] + for f in filevars: + self._instance_file(f, ctx) + + def instance_files(self, filenames=None, container=None, containers_ctx=None): + """Run templatisation on all files of all containers + + @param filenames: names of files + @type filename: C{list} + @param container: name of a container + @type container: C{str} + """ + if containers_ctx is None: + containers_ctx = [] + if container is not None: + containers_ctx = [self.client.get_container_infos(container)] + else: + for group_name in self.client.get_groups(): + containers_ctx.append(self.client.get_group_infos(group_name)) + if filenames is None: + all_files = set(listdir(cfg.distrib_dir)) + prev_files = set(listdir(cfg.templatedir)) + all_declared_files = set() + for ctx in containers_ctx: + for fdict in ctx[u'files']: + all_declared_files.add(basename(fdict['source'])) + undeclared_files = all_files - all_declared_files + toremove_files = prev_files - all_files + # delete old templates (#6600) + for fname in toremove_files: + rm_file = join(cfg.templatedir, fname) + log.debug(_(u"Removing file '{0}'").format(rm_file)) + unlink(rm_file) + # copy template not referenced in a dictionary (#6303) + for fname in undeclared_files: + fobj = {'source': join(cfg.templatedir, fname), 'name': ''} + self.prepare_template(fobj, True) + + for ctx in containers_ctx: + for fdict in ctx[u'files']: + if not filenames or fdict[u'name'] in filenames: + try: + self._instance_file(fdict, container=ctx) + except TemplateDisabled, err: + # Information on disabled template only useful + # in debug + log.debug(err, exc_info=True) diff --git a/creole/upgrade.py b/creole/upgrade.py new file mode 100644 index 0000000..5fd32b6 --- /dev/null +++ b/creole/upgrade.py @@ -0,0 +1,799 @@ +#!/usr/bin/env python +#-*- coding: utf-8 -*- +""" + +utilitaire d'importation de configuration config.eol 2.2 ou config.eol 2.3 +vers config.eol 2.4 + +usage : + + %prog + +""" +from ConfigParser import ConfigParser + +from tiramisu.option import SymLinkOption, ChoiceOption +from .eosfunc import is_empty +from .var_loader import convert_value +import re +from itertools import product + +from .i18n import _ + +# ____ logger utility ____ +# log_filename = u'/var/log/creole.log' +# try: +# from pyeole.log import init_logging +# except: +# # compatibilité pour Zéphir 2.3 +# from pyeole.log import make_logger +# log = make_logger(u'creole3.upgrade', +# logfile=log_filename, +# loglevel='INFO') +# else: +# log = init_logging(name=u'creoleUpgrade', +# level='info', +# console=False, +# syslog=None, +# filename=log_filename) + +import logging +log = logging.getLogger(__name__) + +KEYS = ['val', 'valprec', 'valdefault'] + + +def migration_23_to_tiramisu(opt, val): + if not opt.impl_is_multi(): + if (val == [] or val == ['']) and not isinstance(opt, ChoiceOption): + val = None + else: + if val == []: + val = None + else: + try: + val = convert_value(opt, val[0]) + except ValueError: + #s'il y une erreur sur la conversion de la variable + #met la valeur incorrect pour que la valeur soit + #marquée en erreur dans tiramisu (donc affiché dans + #l'interface) + val = val[0] + else: + if val == ['']: + val = [] + else: + new_val = [] + for v in val: + if v == '': + new_val.append(None) + else: + try: + new_val.append(convert_value(opt, v)) + except ValueError: + #s'il y une erreur sur la conversion de la variable + #met la valeur incorrect pour que la valeur soit + #marquée en erreur dans tiramisu (donc affiché dans + #l'interface) + new_val.append(v) + val = new_val + return val + +class Dico(ConfigParser): + + def get_val(self, var, default=''): + """ + Renvoie la valeur d'une variable + """ + if self.has_section(var): + return self.get(var, 'val') + return default + + def copy(self, old, new, keep=True): + """ + Renomme ou copie une variable + vers une autre + """ + if self.has_section(old): + if not self.has_section(new): + self.add_section(new) + for key in KEYS: + value = self.get(old, key) + self.set(new, key, value) + if keep: + log.info(_(u"Variable {0} has been copied in {1}").format(old, new)) + else: + self.remove_section(old) + log.info(_(u"Variable {0} has been renamed to {1}").format(old, new)) + + def move(self, old, new): + """ + Renomme ou copie une variable + vers une autre + """ + self.copy(old, new, keep=False) + + def remove(self, old): + if self.has_section(old): + self.remove_section(old) + log.info(_(u"Variable {0} has been removed").format(old)) + + def simple2multi(self, src, new): + """ + n variables simples => 1 multi + """ + res = [] + for var in src: + if self.has_section(var): + try: + value = eval(self.get(var, 'val'))[0] + if value != '': + res.append(value) + except: + log.error(_(u"Source variable {0} invalid").format(var)) + if res != []: + self.fill_var(new, res) + + def fill_var(self, var, val, valprec=[], valdefault=[]): + """ + Crée ou met à jour une variable + """ + if type(val) != list: + val = [val] + if not self.has_section(var): + self.add_section(var) + log.info(_(u"Variable updated: {0} = {1}").format(var, val)) + self.set(var, 'val', str(val)) + self.set(var, 'valprec', valprec) + self.set(var, 'valdefault', valdefault) + + def save(self, fichier): + """ + Enregistre le résultat + """ + fic = file(fichier, 'w') + self.write(fic) + fic.close() + +def upgrade(config, configfile): + """ + Mise à jour d'un fichier .eol + de 2.2 vers 2.4 + ou de 2.3 vers 2.4 + + :param dico: configparser instance + :param version: config.eol version ('2.3' ou '2.4') + """ + log.info(_(u"config.eol upgrade started")) + dico = Dico() + dico.read(configfile) + version = get_version(dico) + if version == '2.2': + upgrade22to23(dico) + upgrade23to24(dico) + # FIXME do stuff on 2.4 variables + # chargement des valeurs par default depuis les dicos XML 2.4 + owner = u"upgrade" + store_dico = export_to_store(dico, config) + return store_dico, version + +def export_to_store(dico, config): + """ + exporte depuis un dico vers un dico qui a été mis à jour par les + valeurs par défaut creole 2.4:: + + {"libelle_etab": {"owner": "gen_config", "val": "monchapet"}, + {"owner": "gen_config", "val": ["0.0.0.0"]} + + :param dico: configparser dict + :returns: config parser dico + """ + default_owner = u'upgrade' + store = {} + # modification des settings pour accéder aux options disabled + config.cfgimpl_get_settings().remove('disabled') + old_format = False + for section in dico.sections(): + val = eval(dico.get_val(section)) + try: + path = config.find_first(byname=section, type_='path', check_properties=False) + if not path.startswith('creole.') or path.startswith('creole.containers.'): + continue + + opt = config.unwrap_from_path(path) + if isinstance(opt, SymLinkOption): + continue + val = migration_23_to_tiramisu(opt, val) + except AttributeError: + log.error(_(u"Unknown variable: {0}").format(section)) + old_format = True + if val is None or val == []: + continue + store[section] = {"owner": default_owner, "val": val} + if old_format: + store[section]['old_format'] = True + return store + +def upgrade22to23(dico): + """ + Mise à jour d'un fichier .eol + de 2.2 vers 2.3 + + :param dico: configparser instance + """ + log.info(_(u"Starting {0} to {1} upgrade").format('2.2', '2.3')) + # famille General + dico.move('proxy', 'activer_proxy_client') + dico.move('proxy_server', 'proxy_client_adresse') + dico.move('proxy_port', 'proxy_client_port') + dico.simple2multi(['serveur_maj', 'serveur_maj2'], 'serveur_maj') + # spécifique Amon + domaine = dico.get_val('nom_domaine_academique') + if domaine != '': + if '.' in domaine: + ac, dom = eval(domaine)[0].rsplit('.', 1) + else: + # gère le cas particulier de sphynx ou le suffixe n'était pas + # dans le domaine académique (.fr par défaut) + ac = eval(domaine)[0] + dom = 'fr' + dico.fill_var('nom_academie', ac) + dico.fill_var('suffixe_domaine_academique', dom) + # rien sur Zéphir 2.2 + if dico.has_section('ip_ssh_eth0'): + # ip/netmask facultatifs sur Scribe-2.2 + if 'oui' in dico.get_val('ssh_eth0') and dico.get_val('ip_ssh_eth0') == '[]': + dico.fill_var('ip_ssh_eth0', '0.0.0.0') + dico.fill_var('netmask_ssh_eth0', '0.0.0.0') + # pas de ssh_eth0 sur Horus-2.2 + if not dico.has_section('ssh_eth0'): + # FIXME ip_ssh_eth0 semble faculatif + dico.fill_var('ssh_eth0', 'oui') + # familles Interface-X + for num in range(0, 5): + dico.copy('ssh_eth%s' % num, 'admin_eth%s' % num) + dico.copy('ip_ssh_eth%s' % num, 'ip_admin_eth%s' % num) + dico.copy('netmask_ssh_eth%s' % num, 'netmask_admin_eth%s' % num) + dico.move('agregation', 'activer_agregation') + + # famille Services + dico.move('cups', 'activer_cups') + dico.move('ftp_perso', 'activer_proftpd') + dico.move('ead_web', 'activer_ead_web') + dico.move('apache', 'activer_apache') + dico.move('mysql', 'activer_mysql') + dico.move('xinet_interbase', 'activer_interbase') + if 'oui' in dico.get_val('sso'): + dico.fill_var('activer_sso', 'local') + else: + dico.fill_var('activer_sso', 'non') + + # migration DHCP + dhcp = dico.get_val('dhcp', None) + if dhcp is not None: + dico.move('dhcp', 'activer_dhcp') + if dico.get_val('adresse_network_dhcp', None) is None: + #migration d'un Horus 2.2 + len_dhcp = len(eval(dico.get_val('ip_basse_dhcp', "[]"))) + #recuperation des variables a migrer + adresse_network_dhcp = eval(dico.get_val("adresse_network_eth0")) + dico.fill_var("adresse_network_dhcp", adresse_network_dhcp * len_dhcp) + adresse_netmask_dhcp = eval(dico.get_val("adresse_netmask_eth0")) + dico.fill_var("adresse_netmask_dhcp", adresse_netmask_dhcp * len_dhcp) + adresse_ip_gw_dhcp = eval(dico.get_val("adresse_ip_gw", "[]")) + if adresse_ip_gw_dhcp != []: + dico.fill_var("adresse_ip_gw_dhcp", adresse_ip_gw_dhcp * len_dhcp) + nom_domaine_dhcp = eval(dico.get_val("nom_domaine_local", "[]")) + if nom_domaine_dhcp != []: + dico.fill_var("nom_domaine_dhcp", nom_domaine_dhcp * len_dhcp) + adresse_ip_dns_dhcp = eval(dico.get_val("adresse_ip_dns", "[]")) + if adresse_ip_dns_dhcp != []: + dico.fill_var("adresse_ip_dns_dhcp", [adresse_ip_dns_dhcp[0]] * len_dhcp) + + # famille Messagerie + dico.move('passerelle_smtp_aca', 'passerelle_smtp') + dico.move('spamassassin', 'activer_spamassassin') + if 'oui' in dico.get_val('courier_imap'): + if 'oui' in dico.get_val('courier_pop'): + dico.fill_var('activer_courier', 'pop - imap') + else: + dico.fill_var('activer_courier', 'imap') + elif 'oui' in dico.get_val('courier_pop'): + dico.fill_var('activer_courier', 'pop') + else: + dico.fill_var('activer_courier', 'non') + # Zéphir + dico.move('serveur_smtp', 'passerelle_smtp') + dico.move('compte_smtp', 'system_mail_from') + if '465' in dico.get_val('port_smtp'): + dico.fill_var('tls_smtp', 'port 465') + + # famille Client_ldap + dico.move('base_ldap', 'ldap_base_dn') + serveur_ldap = dico.get_val('serveur_ldap', '[]') + if serveur_ldap != '[]': + dico.move('serveur_ldap', 'adresse_ip_ldap') + if eval(serveur_ldap)[0] not in ['127.0.0.1', 'localhost']: + dico.fill_var('activer_client_ldap', 'distant') + + # famille Eole-sso + dico.move('adresse_ip_sso', 'eolesso_adresse') + dico.move('port_sso', 'eolesso_port') + # eolesso_ldap (multi) + dico.move('ldap_sso', 'eolesso_ldap') + dico.move('port_ldap_sso', 'eolesso_port_ldap') + dico.move('base_ldap_sso', 'eolesso_base_ldap') + dico.move('sso_ldap_label', 'eolesso_ldap_label') + dico.move('sso_ldap_reader', 'eolesso_ldap_reader') + dico.move('sso_ldap_reader_passfile', 'eolesso_ldap_reader_passfile') + # la "suite" + dico.move('adresse_sso_parent', 'eolesso_adresse_parent') + dico.move('port_sso_parent', 'eolesso_port_parent') + dico.move('sso_pam_securid', 'eolesso_pam_securid') + dico.move('sso_cert', 'eolesso_cert') + dico.move('sso_ca_location', 'eolesso_ca_location') + dico.move('sso_session_timeout', 'eolesso_session_timeout') + dico.move('sso_css', 'eolesso_css') + + # famille Applications web + dico.move('phpmyadmin', 'activer_phpmyadmin') + dico.move('posh', 'activer_envole') + dico.move('web_domain', 'web_url') + dico.move('web_default', 'web_redirection') + posh_path = dico.get_val('posh_path', '[]') + if posh_path != '[]' and eval(posh_path)[0] != '': + dico.fill_var('alias_envole', '/' + eval(posh_path)[0]) + + # famille Bacula + if 'oui' in "%s%s%s" % (dico.get_val('active_bacula_dir'), + dico.get_val('active_bacula_fd'), + dico.get_val('active_bacula_sd')): + dico.fill_var('activer_bacula', 'oui') + dico.move('active_bacula_dir', 'activer_bacula_dir') + dico.move('active_bacula_sd', 'activer_bacula_sd') + # bacula_fd n'est plus géré + else: + dico.fill_var('activer_bacula', 'non') + + # famille Clamav + dico.move('enable_clamd', 'dansguardian_clam') + + # famille Certifs-ssl + dico.move('ssl_serveur_name', 'ssl_server_name') + + # famille Authentification + dico.move('active_nufw', 'activer_nufw') + dico.move('freeradius', 'activer_freeradius') + + # famille Logs + if 'Oui' in dico.get_val('activate_tls'): + dico.fill_var('rsyslog_tls', 'oui') + + # famille Reverse proxy + revprox = dico.get_val('revprox_domainname', '[]') + if revprox != '[]' and eval(revprox)[0] != '': + dico.fill_var('revprox_activate_http', 'oui') + + # famille réseau avancé + route = dico.get_val('route_adresse', '[]') + if route != '[]' and eval(route)[0] != '': + dico.fill_var('activer_route', 'oui') + + # famille Vpn-pki + dico.simple2multi(['url_crl1', 'url_crl2'], 'url_crl') + + +def upgrade23to24(dico): + """ + Mise à jour d'un fichier .eol + de 2.3 vers 2.4 + + :param dico: configparser instance + """ + log.info(_(u"Starting {0} to {1} upgrade").format('2.3', '2.4')) + cache_dir = dico.get_val('cache_dir', '[]') + if cache_dir != '[]' and eval(cache_dir)[0] == '/var/spool/squid': + dico.fill_var('cache_dir', '') + + system_mail_to = dico.get_val('system_mail_to', '[]') + if system_mail_to != '[]' and eval(system_mail_to)[0] == 'postmaster': + dico.fill_var('system_mail_to', '') + + varname = 'alias_gw_eth0' + var = dico.get_val(varname, '[]') + if var != '[]' and eval(var)[0] == 'aucun': + dico.fill_var(varname, '') + + for i in range(0, 5): + dico.move('adresse_ip_vlan_eth{0}'.format(i), 'vlan_ip_eth{0}'.format(i)) + dico.move('adresse_netmask_vlan_eth{0}'.format(i), 'vlan_netmask_eth{0}'.format(i)) + dico.move('adresse_network_vlan_eth{0}'.format(i), 'vlan_network_eth{0}'.format(i)) + dico.move('adresse_broadcast_vlan_eth{0}'.format(i), 'vlan_broadcast_eth{0}'.format(i)) + dico.move('adresse_gw_vlan_eth{0}'.format(i), 'vlan_gw_eth{0}'.format(i)) + dico.move('id_vlan_eth{0}'.format(i), 'vlan_id_eth{0}'.format(i)) + + varname = 'vlan_gw_eth0' + var = dico.get_val(varname, '[]') + if var != '[]' and eval(var)[0] == 'aucun': + dico.fill_var(varname, '') + + dico.move('proxy_eth0_adresse', 'proxy_eth0_ip') + dico.move('proxy_eth0_network', 'proxy_eth0_network') + dico.move('nom_interface1', 'nom_zone_eth1') + dico.move('era_proxy_bypass', 'era_proxy_bypass_eth1') + dico.move('smb_adresse_ip_wins', 'smb_wins_server') + + dico.remove('http_port') + dico.remove('http_port_2') + dico.remove('test_nutmaster') + dico.remove('test_activer_routage_ipv6') + dico.remove('test_activer_kerberos') + dico.remove('test_activer_clam_proxy') + dico.remove('test_activer_proxy_eth0') + dico.remove('revprox_poshadmin') + dico.remove('ip_client_logs_udp') + dico.remove('adresse_ip_conteneur_dns') + + dico.simple2multi(['test_distant_domaine1', 'test_distant_domaine2'], 'test_distant_domaine') + dico.remove('test_distant_domaine1') + dico.remove('test_distant_domaine2') + dico.simple2multi(['ssl_subjectaltname_ip', 'ssl_subjectaltname_ns'], 'ssl_subjectaltname') + dico.remove('ssl_subjectaltname_ip') + dico.remove('ssl_subjectaltname_ns') + + old_serveur_maj = eval(dico.get_val('serveur_maj', '[]')) + if old_serveur_maj != []: + serveur_maj = [] + for maj in old_serveur_maj: + if maj == 'eoleng.ac-dijon.fr': + maj = 'eole.ac-dijon.fr' + if maj == 'test-eoleng.ac-dijon.fr': + maj = 'test-eole.ac-dijon.fr' + serveur_maj.append(maj) + dico.fill_var('serveur_maj', serveur_maj) + + ssl_country_name = eval(dico.get_val('ssl_country_name', '[""]'))[0].upper() + dico.fill_var('ssl_country_name', ssl_country_name) + + tmp_short_name = [] + tmp_long_name = [] + tmp_ip = [] + nom_domaine_local = eval(dico.get_val('nom_domaine_local', "['']"))[0] + def _append_tmp_name(ip, long_name, short_name="NONE"): + splitted_labels = long_name.split('.') + if short_name == "NONE": + short_name = splitted_labels[0] + # ajout si non déjà défini dans Réseau avancé + if long_name not in tmp_long_name: + if short_name not in tmp_short_name: + #le nom court n'existe pas dans la liste, donc l'ajoute + tmp_short_name.append(short_name) + else: + if '.'.join(splitted_labels[1:]) == nom_domaine_local: + # le nom court est déjà présent + # privilégie le nom court pour le nom de domaine local + tmp_short_name[tmp_short_name.index(short_name)] = None + tmp_short_name.append(short_name) + else: + # ne pas doublonner le nom court + tmp_short_name.append(None) + if len(splitted_labels) > 1: + tmp_long_name.append(long_name) + else: + # si nom court, transforme en nom long + tmp_long_name.append(long_name + '.' + nom_domaine_local) + tmp_ip.append(ip) + + if eval(dico.get_val('activer_ajout_hosts', '["non"]'))[0] == 'oui': + # récupération et passage en minuscules des + # nom_court_hosts et nom_long_hosts existants #11473 + ips = eval(dico.get_val('adresse_ip_hosts', '[]').lower()) + long_names = eval(dico.get_val('nom_long_hosts', '[]').lower()) + for idx, short_name in enumerate(eval(dico.get_val('nom_court_hosts', '[]').lower())): + _append_tmp_name(ips[idx], long_names[idx], short_name) + + # Migration des variables hosts #2795 + # noms d'hôtes forcés en minuscules #9790 + nom_host_dns = eval(dico.get_val('nom_host_dns', '[]').lower()) + if not is_empty(nom_host_dns): + ips = eval(dico.get_val('ip_host_dns')) + # transforme les nom_host_dns en nom_court_hosts et nom_long_hosts + # donc force activer_ajout_hosts à oui + dico.fill_var('activer_ajout_hosts', 'oui') + for idx, long_name in enumerate(nom_host_dns): + _append_tmp_name(ips[idx], long_name) + + if not is_empty(tmp_short_name): + dico.fill_var('adresse_ip_hosts', tmp_ip) + dico.fill_var('nom_court_hosts', tmp_short_name) + dico.fill_var('nom_long_hosts', tmp_long_name) + dico.remove('nom_host_dns') + dico.remove('ip_host_dns') + + # Ajout du point devant chaque zone #7008 + old_nom_zone_dns_cache = eval(dico.get_val('nom_zone_dns_cache', '[]')) + if not is_empty(old_nom_zone_dns_cache): + nom_zone_dns_cache = [] + for old in old_nom_zone_dns_cache: + nom_zone_dns_cache.append('.' + old) + dico.fill_var('nom_zone_dns_cache', nom_zone_dns_cache) + + # Modification du chemin de la corbeille Samba #7463 + smb_trash_dir = eval(dico.get_val('smb_trash_dir', '["/"]'))[0] + if not smb_trash_dir.startswith('/'): + dico.fill_var('smb_trash_dir', 'perso/{0}'.format(smb_trash_dir)) + + # antivirus temps réel => remis à default #19833 + if dico.get_val('smb_vscan', "['non']") == "['oui']": + dico.remove('smb_vscan') + + # Famille Proxy parent #7823 + if not is_empty(eval(dico.get_val('nom_cache_pere', '[]'))): + dico.fill_var('activer_cache_pere', 'oui') + if not is_empty(eval(dico.get_val('nom_cache_pere_zone', '[]'))): + dico.fill_var('activer_cache_pere_zone', 'oui') + if not is_empty(eval(dico.get_val('proxy_sibling_ip', '[]'))): + dico.fill_var('activer_proxy_sibling', 'oui') + + # Autorisation proxy eth0 #8167 + if not is_empty(eval(dico.get_val('proxy_eth0_ip', '[]'))): + dico.fill_var('activer_supp_proxy_eth0', 'oui') + + # Famille Rvp #8164 + if not is_empty(eval(dico.get_val('adresse_network_zone_rvp', '[]'))): + dico.fill_var('acces_proxy_zone_rvp', 'oui') + + # half_closed_clients => remise à default #19813 + if dico.get_val('half_closed_clients', "['off']") == "['on']": + dico.remove('half_closed_clients') + + ## + ## Modification de la configuration exim + ## + # passerelle SMTP + log.info(_(u"Migrating SMTP parameters")) + passerelle_smtp = dico.get_val('passerelle_smtp', '[]') + dico.move('passerelle_smtp', 'exim_relay_smtp') + if is_empty(passerelle_smtp): + # No SMTP gateway + dico.fill_var('activer_exim_relay_smtp', u'non') + + # Type de serveur SMTP + exim_mail_type = eval(dico.get_val('exim_mail_type', '["satellite"]'))[0] + log.info("Migration de exim_mail_type: '{0}'".format(exim_mail_type)) + dico.remove('exim_mail_type') + if exim_mail_type == 'satellite': + # Nothing to do + pass + elif exim_mail_type == 'local': + # Local is smarthost without relay, should not happen + dico.fill_var('exim_smarthost', u'oui') + elif exim_mail_type == 'smarthost': + dico.fill_var('exim_smarthost', u'oui') + elif exim_mail_type == 'mailhub': + dico.fill_var('exim_relay', u'oui') + dico.fill_var('exim_relay_manual_routes', u'oui') + elif exim_mail_type == 'internet': + dico.fill_var('activer_exim_relay_smtp', u'non') + dico.fill_var('exim_relay', u'oui') + dico.fill_var('exim_relay_manual_routes', u'oui') + else: + log.warn(_(u'Mail configuration not recognised, not processed')) + + # Réécriture + mail_rewrite_domain = eval(dico.get_val('mail_rewrite_domain', '["non"]'))[0] + dico.remove('mail_rewrite_domain') + if mail_rewrite_domain == 'oui': + dico.fill_var('exim_qualify_domain', 'nom de domaine local') + + # Modèle Era utilisé (#9082) + mapping = {'2zones-amonecole-nginx' : u'2zones-amonecole', + '3zones-scribe-nginx' : u'3zones-dmz', + '3zones-scribe' : u'3zones-dmz', + '4zones-scribe-nginx' : u'4zones', + '4zones-scribe-nufw' : u'4zones', + '4zones-scribe' : u'4zones', + '5zones-scribe-nginx' : u'5zones', + '5zones-scribe' : u'5zones', + } + model = eval(dico.get_val('type_amon', '[""]'))[0] + if model in mapping: + dico.fill_var('type_amon', mapping[model]) + + # Migration des modules ecdl + if dico.get_val('ecdl_regles_filtrage_supplementaires', 'Pas un eCDL') != 'Pas un eCDL': + dico.move('ecdl_ldap_machine_suffix', 'ldap_machine_suffix') + dico.move('ecdl_ldap_group_suffix', 'ldap_group_suffix') + dico.move('ecdl_smb_share_model', 'smb_share_model') + dico.move('ecdl_smb_vscan', 'smb_vscan') + dico.move('ecdl_smb_ports', 'smb_ports') + dico.move('ecdl_smb_server_string', 'smb_server_string') + dico.move('ecdl_smb_trash', 'smb_trash') + dico.move('ecdl_smb_trash_dir', 'smb_trash_dir') + dico.move('ecdl_smb_trash_purge', 'smb_trash_purge') + dico.move('ecdl_smb_quotawarn' , 'smb_quotawarn') + dico.move('ecdl_smb_guest', 'smb_guest') + dico.move('ecdl_smb_wins_support', 'smb_wins_support') + dico.move('ecdl_smb_adresse_ip_wins', 'smb_wins_server') + dico.move('ecdl_smb_dns_proxy', 'smb_dns_proxy') + dico.move('ecdl_smb_oplocks', 'smb_oplocks') + dico.move('ecdl_smb_dos_attributes', 'smb_dos_attributes') + dico.move('ecdl_smb_unixextensions', 'smb_unixextensions') + dico.move('ecdl_smb_partage_nom', 'smb_partage_nom') + dico.move('ecdl_smb_partage_path', 'smb_partage_path') + dico.move('ecdl_smb_partage_visibilite', 'smb_partage_visibilite') + dico.move('ecdl_smb_partage_ecriture', 'smb_partage_ecriture') + dico.move('ecdl_regles_filtrage_supplementaires', 'activer_regles_filtrage_port_source') + dico.move('ecdl_smb_os_level', 'smb_os_level') + dico.move('ecdl_smb_domain_master', 'smb_domain_master') + dico.move('ecdl_ca_cert', 'ldap_ca_cert') + dico.move('meddtl_suffixe_ldap_nss_base_passwd', 'ldap_nss_base_passwd_filter') + dico.move('meddtl_suffixe_ldap_nss_base_group', 'ldap_nss_base_group_filter') + dico.move('ecdl_ldap_timeout', 'ldap_timeout') + dico.move('ecdl_smb_netbios_name', 'smb_netbios_name') + dico.move('ecdl_smb_workgroup', 'smb_workgroup') + dico.move('ecdl_smb_usershare_max_shares', 'smb_usershare_max_shares') + dico.move('ecdl_smb_activer_partages', 'smb_activer_partages') + dico.remove('ecdl_smb_log_level') + # fin de migration des modules ecdl + + # migration des modules esbl + if dico.get_val('activer_lister_repertoires_apache', 'Pas un eSBL') != 'Pas un eSBL': + dico.fill_var('smb_log_level', 0) + smb_activer_ordre_resolution_nom = dico.get_val('smb_activer_ordre_resolution_nom', 'non') + if smb_activer_ordre_resolution_nom == 'oui': + smb_name_resolve_order = " ".join(eval(dico.get_val('smb_procede_recherche_nom'))) + dico.fill_var('smb_name_resolve_order', smb_name_resolve_order) + smb_ad_nom_long_controleur = dico.get_val('smb_ad_nom_long_controleur', "['']") + if smb_ad_nom_long_controleur != "['']": + dico.fill_var('smb_ad_server', smb_ad_nom_long_controleur) + smb_ad_realm = dico.get_val('smb_ad_realm', "['']") + if smb_ad_realm != "['']": + dico.fill_var('smb_realm', smb_ad_realm) + dico.move('activer_lister_repertoires_apache', 'apache_lister_repertoires') + + # répartition des variables pour les répertoires ftp + ftps = {} + for ftp_rep, ftp_anon in zip(eval(dico.get_val('acces_ftp', '[]')), + eval(dico.get_val('acces_ftp_anonymous', '[]'))): + ftps[ftp_anon] = ftps.get(ftp_anon, []) + [ftp_rep] + # si len(ftps['oui']) > 1, pas de reprise automatique + # sinon ftps['oui'] -> ftp_anonymous_directory + # ftps['non'] -> ftp_access_directory + + if 'oui' in ftps and len(ftps['oui']) == 1: + dico.fill_var('ftp_anonymous_directory', ftps['oui'][0]) + dico.fill_var('activer_ftp_anonymous_access', 'oui') + if 'non' in ftps: + dico.fill_var('ftp_access_directory', ftps['non']) + dico.fill_var('activer_ftp_access', 'oui') + ftp_maxretrievefilesize = dico.get_val('ftp_maxretrievefilesize', '') + if ftp_maxretrievefilesize != '': + ftp_maxretrievefilesize = re.search(r'[0-9]+', ftp_maxretrievefilesize).group() + dico.fill_var('ftp_maxretrievefilesize', ftp_maxretrievefilesize) + ftp_maxstorefilesize = dico.get_val('ftp_maxstorefilesize', '') + if ftp_maxstorefilesize != '': + ftp_maxstorefilesize = re.search(r'[0-9]+', ftp_maxstorefilesize).group() + dico.fill_var('ftp_maxstorefilesize', ftp_maxstorefilesize) + + dico.move('activer_pare_feu', 'activer_firewall') + # fin de migration des modules esbl + + # migration des modules essl + if dico.get_val('ecdl_serveurs_ip', "Pas un eSSL") != "Pas un eSSL": + # variables ftp_max* + ftp_maxretrievefilesize = dico.get_val('ftp_maxretrievefilesize', '') + if ftp_maxretrievefilesize != '': + ftp_maxretrievefilesize = re.search(r'[0-9]+', ftp_maxretrievefilesize).group() + dico.fill_var('ftp_maxretrievefilesize', ftp_maxretrievefilesize) + ftp_maxstorefilesize = dico.get_val('ftp_maxstorefilesize', '') + if ftp_maxstorefilesize != '': + ftp_maxstorefilesize = re.search(r'[0-9]+', ftp_maxstorefilesize).group() + dico.fill_var('ftp_maxstorefilesize', ftp_maxstorefilesize) + # variables renommées + dico.move('sites_distants_morea_ip', 'sites_distants_ip') + dico.move('sites_distants_morea_netmask', 'sites_distants_netmask') + dico.move('nagios_morea_ip', 'nagios_dist_ip') + dico.move('nagios_morea_netmask', 'nagios_dist_netmask') + dico.move('morea_routeur_ip', 'wan_routeur_ip') + dico.move('morea_interface', 'wan_interface') + dico.move('surf_lan_ip', 'sites_dist_ip') + dico.move('surf_lan_netmask', 'sites_dist_netmask') + dico.move('morea_route_adresse', 'wan_route_adresse') + dico.move('morea_route_netmask', 'wan_route_netmask') + # conversions de valeurs + variante_type_mapping = {'standard': 'production', + 'Applis Web': 'Applis_Web', + 'eSSL Morea': 'eSSL', + 'eSSL Internet': 'eSSL_Internet', + 'eSSL SPC': 'eSSL_SPC', + 'ppp': 'PPP', + '': 'production'} + variante_type = eval(dico.get_val('variante_type', "['']"))[0] + dico.fill_var('variante_type', variante_type_mapping[variante_type]) + + # migration des variables dhcp + exxl_dhcp = dico.has_section('dhcp_lease_max') + if dico.get_val('activer_dhcp', "['non']") == "['oui']" and exxl_dhcp: + # récupération des valeurs de la multi + ip_basse = eval(dico.get_val('ip_basse_dhcp', '[""]')) + ip_haute = eval(dico.get_val('ip_haute_dhcp', '[""]')) + restriction = eval(dico.get_val('activer_dhcp_hotes_autorises', "['']")) + lease_default = eval(dico.get_val('dhcp_lease_default', "['']")) + lease_max = eval(dico.get_val('dhcp_lease_max', "['']")) + # récupération des valeurs communes simples + network = [eval(dico.get_val('adresse_network_dhcp', "['']"))[0]] + netmask = [eval(dico.get_val('adresse_netmask_dhcp', "['']"))[0]] + nom_domaine_dhcp = [eval(dico.get_val('nom_domaine_dhcp', "['']"))[0]] + gateway_dhcp = [eval(dico.get_val('adresse_ip_gw_dhcp', "['']"))[0]] + # récupération des valeurs communes multiples + dns_dhcp = eval(dico.get_val('adresse_ip_dns_dhcp', "['']")) + wins = eval(dico.get_val('adresse_ip_wins_dhcp', "['']")) + wins_primaire = wins[0] + if len(wins) > 1: + wins_secondaire = wins[1] + else: + wins_secondaire = wins_primaire + ntp_dhcp = eval(dico.get_val('adresse_ip_ntp_dhcp', "['']")) + # création des nouvelles listes, produit cartésien + ranges, dns_dhcp, ntp_dhcp = zip(*list(product(zip(ip_basse, ip_haute, restriction, lease_default, lease_max), dns_dhcp, ntp_dhcp))) + dns_dhcp = list(dns_dhcp) + ntp_dhcp = list(ntp_dhcp) + ip_basse, ip_haute, restriction, lease_default, lease_max = [list(l) for l in zip(*ranges)] + nb_ranges = len(ip_basse) + nom_domaine_dhcp = nom_domaine_dhcp*nb_ranges + gateway_dhcp = gateway_dhcp*nb_ranges + wins_primaire = [wins_primaire]*nb_ranges + wins_secondaire = [wins_secondaire]*nb_ranges + network = network*nb_ranges + netmask = netmask*nb_ranges + # chargement des valeurs dans le dictionnaire + dico.fill_var('adresse_network_dhcp', network) + dico.fill_var('adresse_netmask_dhcp',netmask) + dico.fill_var('ip_basse_dhcp', ip_basse) + dico.fill_var('ip_haute_dhcp', ip_haute) + dico.fill_var('nom_domaine_dhcp', nom_domaine_dhcp) + dico.fill_var('adresse_ip_gw_dhcp', gateway_dhcp) + dico.fill_var('adresse_ip_dns_dhcp', dns_dhcp) + dico.fill_var('adresse_ip_wins_primaire_dhcp', wins_primaire) + dico.fill_var('adresse_ip_wins_secondaire_dhcp', wins_secondaire) + dico.fill_var('adresse_ip_ntp_dhcp', ntp_dhcp) + dico.fill_var('interdire_hotes_inconnus', restriction) + dico.fill_var('dhcp_lease_default', lease_default) + dico.fill_var('dhcp_lease_max', lease_max) + + #envole + if dico.get_val('activer_envole', "['non']") == "['oui']" and dico.get_val('force_envole', "['non']") == "['oui']": + alias_envole = eval(dico.get_val('alias_envole'))[0] + if alias_envole != '/': + dico.fill_var('web_redirection', alias_envole) + dico.remove('alias_envole') + +def get_version(dico): + """ + recupère la version en fonction de la présence ou non + de la variable 'serveur_maj2' + + :param dico: ConfigParser object + :return version: '2.2' ou '2.3' + """ + # ________ version du config.eol ________ + + if dico.has_section('serveur_maj2') and not \ + dico.has_section('activer_bash_completion'): + version = '2.2' + else: + version = '2.3' + return version + + +def main(config_file): + """main entry point""" + pass + +if __name__ == '__main__': + import sys + if len(sys.argv) != 2: + print __doc__ + sys.exit(1) + main(sys.argv[1]) diff --git a/creole/upgrade24.py b/creole/upgrade24.py new file mode 100644 index 0000000..6939153 --- /dev/null +++ b/creole/upgrade24.py @@ -0,0 +1,735 @@ +#!/usr/bin/env python +#-*- coding: utf-8 -*- +""" + +Utilitaire de mise à jour des variables +pour les versions >= 2.4.1 + +""" +from .upgrade import log, migration_23_to_tiramisu +from .var_loader import convert_value +from pyeole.i18n import i18n +from tiramisu.setting import owners +from tiramisu.setting import undefined +from distutils.version import StrictVersion +from pyeole.encode import normalize +_ = i18n('creole') + +class Upgrade(): + """ + Méthodes pour la mise à niveau des variables + """ + def __init__(self, config): + owner = u'upgrade' + if owner not in dir(owners): + owners.addowner(owner) + self.config = config + self.owner = getattr(owners, owner) + self.unknown_options = config.impl_get_information(u'unknown_options') + + def get_old_value(self, variable, old_variable, default=None): + """ + Retourne la valeur d'une variable "disparue" + """ + try: + old_obj = self.unknown_options[old_variable] + if old_obj.get('old_format', False): + try: + path = self.get_path(variable) + except AttributeError: + return default + opt = self.config.unwrap_from_path(path) + val = migration_23_to_tiramisu(opt, old_obj['val']) + else: + val = old_obj['val'] + return val + except KeyError: + return default + + def get_value(self, variable, default=None): + """ + Retourne la valeur d'une variable "connue" + """ + try: + path = self.get_path(variable) + except AttributeError: + return default + return self.config.getattr(path, + force_permissive=True) + + def get_unvalid_value(self, variable, default=None): + try: + path = self.get_path(variable) + except AttributeError: + return default + try: + return self.config.impl_get_information('orig_value_{}'.format(path)) + except ValueError: + return default + + def get_noncalculated_value_for_auto(self, variable): + """ + Retourne la valeur contenue dans le fichier config.eol dans le cas où la variable + est calculée (auto), forcé à la valeur par défaut, ... + """ + try: + path = self.get_path(variable) + except AttributeError: + log.error(_('get_noncalculated_value_for_auto: unknown variable {}').format(variable)) + return None + values = self.config.cfgimpl_get_values() + if values._contains(path): + idx = 0 + vals = [] + while True: + val = values._p_.getvalue(path, values._p_.getsession(), idx) + if val is undefined: + break + vals.append(val) + idx += 1 + if len(vals) > 0: + return vals + else: + return None + return None + + def var_exists(self, variable): + try: + self.get_path(variable) + return True + except AttributeError: + return False + + def get_path(self, variable): + """ + Retourne le chemin complet d'une variable + """ + return self.config.find_first(byname=variable, type_='path') + + def modify_owner(self, path, value=None, index=None): + """ + Modifie le propriétaire d'une variable + """ + option = self.config.unwrap_from_path(path) + if option.impl_is_master_slaves('slave'): + if index is not None: + self.config.cfgimpl_get_values().setowner(option, + self.owner, + index=index) + elif value is not None: + for idx in xrange(len(value)): + self.config.cfgimpl_get_values().setowner(option, + self.owner, + index=idx) + else: + raise Exception('must have value or index for slave') + + else: + self.config.cfgimpl_get_values().setowner(option, + self.owner) + + def is_default(self, variable, default=True): + """ + Retourne True si la valeur n'a pas été personnalisée par l'utilisateur + """ + try: + path = self.get_path(variable) + except AttributeError: + return default + option = self.config.unwrap_from_path(path) + return self.config.cfgimpl_get_values().is_default_owner(option) + + def set_value(self, variable, value): + """ + Modifie la valeur d'une variable + """ + try: + path = self.get_path(variable) + except AttributeError: + log.error(_(u"Try to set value to unknown option: {0} = {1}").format(variable, value)) + else: + try: + self.config._setattr(path, value, + force_permissive=True) + self.modify_owner(path, value) + log.info(_(u"Variable updated: {0} = {1}").format(variable, value)) + self.config.impl_del_information('error_msg_{}'.format(path), raises=False) + self.config.impl_del_information('orig_value_{}'.format(path), raises=False) + option = self.config.unwrap_from_path(path) + self.config.cfgimpl_get_settings()[option].remove('load_error') + except ValueError: + option = self.config.unwrap_from_path(path) + try: + # the value could be in Creole 2.3 format #13957 + if not option.impl_is_multi() and isinstance(value, list) and len(value) == 1: + value = value[0] + if value in ['', ['']]: + err_msg = _(u"empty value") + log.error(_(u"{0} for {1}").format(err_msg, variable)) + return + self.config._setattr(path, convert_value(option, value), + force_permissive=True) + self.modify_owner(path, value) + log.info(_(u"Variable updated: {0} = {1}").format(variable, value)) + except Exception, err: + log.error(_(u"{0} for {1}").format(err, variable)) + self.config.cfgimpl_get_settings()[option].append('load_error') + except Exception, err: + option = self.config.unwrap_from_path(path) + log.error(_("{0} for {1}").format(normalize(str(err)), variable)) + self.config.cfgimpl_get_settings()[option].append('load_error') + + def del_value(self, variable): + try: + path = self.get_path(variable) + except AttributeError: + log.error(_('Try to delete an unknown option: {0}').format(variable)) + else: + option = self.config.unwrap_from_path(path) + self.config.cfgimpl_get_values().__delitem__(option) + log.info(_(u"Variable {0} reinitialized").format(variable)) + + def append_value(self, variable, value): + """ + Ajoute une valeur à une variable multi + """ + try: + path = self.get_path(variable) + except AttributeError: + log.error(_('Try to append a value to an unknown option: {0} += {1}').format(variable, value)) + else: + multi = self.config.getattr(path, + force_permissive=True) + multi.append(value) + self.modify_owner(path, index=len(multi) - 1) + + def modify_last_value(self, variable, value): + """ + Modifie la dernière valeur d'une variable multi + """ + try: + path = self.get_path(variable) + except AttributeError: + log.error(_('Try to modify last value of an unknown option: {0}[-1] = {1}').format(variable, value)) + else: + multi = self.config.getattr(path, + force_permissive=True) + multi[-1] = value + self.modify_owner(path, index=len(multi) - 1) + + def move(self, old_variable, new_variable): + """ + Déplace les données d'une variable "disparue" + vers une nouvelle variable + """ + if old_variable in self.unknown_options: + value = self.unknown_options[old_variable][u'val'] + path = self.get_path(new_variable) + option = self.config.unwrap_from_path(path) + if value in ['', ['']]: + err_msg = _(u"empty value") + log.error(_(u"{0} for {1}").format(err_msg, old_variable)) + return + if option.impl_is_multi() and isinstance(value, list): + for val in value: + self.append_value(new_variable, val) + else: + self.set_value(new_variable, value) + del(self.unknown_options[old_variable]) + log.info(_(u"Variable {0} has been renamed to {1}").format(old_variable, new_variable)) + + def copy(self, old_variable, new_variable, only_if_modified=True): + """ + Copie la valeur d'une variable existante vers une autre + Si la valeur "old" est une multi et pas la "new" => copie la 1er valeur de la liste + Si la valeur "old" n'est pas une multi et la "new" ne l'est pas => transforme la valeur en liste + only_if_modified: si True ne copie que les valeurs qui sont modifiées + """ + try: + # si les deux variables existe => migration + old_path = self.get_path(old_variable) + new_path = self.get_path(new_variable) + except AttributeError: + pass + else: + old_option = self.config.unwrap_from_path(old_path) + new_option = self.config.unwrap_from_path(new_path) + # si la nouvelle option n'est pas modifié et si la valeur est modifié ou only_if_modified est False + if self.config.cfgimpl_get_values().is_default_owner(new_option) and \ + (not only_if_modified or + not self.config.cfgimpl_get_values().is_default_owner(old_option)): + old_value = self.config.getattr(old_path, + force_permissive=True) + if old_option.impl_is_multi() and not new_option.impl_is_multi(): + if len(old_value) != 0: + old_value = old_value[0] + else: + old_value = None + if not old_option.impl_is_multi() and new_option.impl_is_multi(): + if old_value is None: + old_value = [] + else: + old_value = [old_value] + self.set_value(new_variable, old_value) + + + +class Upgrade_2_4_1(Upgrade): + """ + Mise à jour d'une configuration + de 2.4.0 vers 2.4.1 + """ + + def run(self): + """ + Lancement des traitements + """ + log.info(_(u"Starting {0} to {1} upgrade").format('2.4.0', '2.4.1')) + + # renommage des variables "era_proxy_bypass" + for i in range(1, 5): + self.move('era_proxy_bypass_eth{0}'.format(i), 'proxy_bypass_network_eth{0}'.format(i)) + + # fusion des variables "proxy_bypass" et "wpad_exclude" + if 'adresse_ip_wpad_exclude' in self.unknown_options: + #le 1er argument sert a récupérer les propriétés des option (choiceoption, multi, ...) + #on lui passe la variable de la 1er interface + old_interfaces = self.get_old_value('proxy_bypass_network_eth1', 'interface_wpad_exclude') + netmasks = self.get_old_value('proxy_bypass_netmask_eth1', 'adresse_netmask_wpad_exclude') + for idx, value in enumerate(self.get_old_value('proxy_bypass_network_eth1', 'adresse_ip_wpad_exclude')): + interface = old_interfaces[idx] + if interface == 'Toutes': + interfaces = range(1, 5) + elif int(interface) in range(1, 5): + interfaces = [interface] + else: + log.error(_(u"Invalid value : {0} in old variable {1}").format(interface, 'interface_wpad_exclude')) + continue + for i in interfaces: + self.append_value('proxy_bypass_network_eth{0}'.format(i), value) + self.modify_last_value('proxy_bypass_netmask_eth{0}'.format(i), netmasks[idx]) + del(self.unknown_options['adresse_ip_wpad_exclude']) + del(self.unknown_options['adresse_netmask_wpad_exclude']) + del(self.unknown_options['interface_wpad_exclude']) + + # passage à oui des variables "proxy_bypass_ethX" si nécessaire + for i in range(1, 5): + if len(self.get_value('proxy_bypass_network_eth{0}'.format(i), [])) > 0: + self.set_value('proxy_bypass_eth{0}'.format(i), u'oui') + + # transfert des variables nom_domaine_wpad_exclude + if 'nom_domaine_wpad_exclude' in self.unknown_options: + old_interfaces = self.get_old_value('proxy_bypass_domain_eth1', 'nom_interface_wpad_exclude') + for idx, value in enumerate(self.get_old_value('proxy_bypass_domain_eth1', 'nom_domaine_wpad_exclude')): + interface = old_interfaces[idx] + if interface == 'Toutes': + interfaces = range(1, 5) + elif int(interface) in range(1, 5): + interfaces = [interface] + else: + log.error(_(u"Invalid value : {0} in old variable {1}").format(interface, 'nom_interface_wpad_exclude')) + continue + for i in interfaces: + self.append_value('proxy_bypass_domain_eth{0}'.format(i), value) + del(self.unknown_options['nom_domaine_wpad_exclude']) + del(self.unknown_options['nom_interface_wpad_exclude']) + + # nom_serveur_scribe_dmz/ip_serveur_scribe_dmz => mandatory (#11713) + if self.get_value('install_scribe_dmz') == u'oui': + if self.get_value('nom_serveur_scribe_dmz') == None or self.get_value('ip_serveur_scribe_dmz') == None: + self.set_value('install_scribe_dmz', u'non') + + +class Upgrade_2_4_2(Upgrade): + """ + Mise à jour d'une configuration + de 2.4.1 vers 2.4.2 + """ + + def run(self): + """ + Lancement des traitements + """ + log.info(_(u"Starting {0} to {1} upgrade").format('2.4.1', '2.4.2')) + # migration des variables eolesso vers client LDAP #10821 + self.copy('eolesso_port_ldap', 'ldap_port') + self.copy('eolesso_ldap_reader', 'ldap_reader') + self.copy('eolesso_ldap_reader_passfile', 'ldap_reader_passfile') + self.copy('eolesso_ldap_match_attribute', 'ldap_match_attribute') + self.copy('eolesso_ldap_filter_user', 'ldap_filter_user') + self.copy('eolesso_ldap_filter_group', 'ldap_filter_group') + self.copy('eolesso_ldap_dntree_user', 'ldap_dntree_user') + self.copy('eolesso_ldap_dntree_group', 'ldap_dntree_group') + self.copy('eolesso_ldap_fill_displayname', 'ldap_fill_displayname') + self.copy('eolesso_ldap_fill_mail', 'ldap_fill_mail') + self.copy('eolesso_ldap_fill_fonction', 'ldap_fill_fonction') + self.copy('eolesso_ldap_fill_categorie', 'ldap_fill_categorie') + self.copy('eolesso_ldap_fill_rne', 'ldap_fill_rne') + self.copy('eolesso_ldap_fill_fredurne', 'ldap_fill_fredurne') + self.copy('eolesso_ldap_fill_displaygroup', 'ldap_fill_displaygroup') + + # migration des variables courier #10987 + courier_val = self.get_old_value('activer_recuperation_courriel', 'activer_courier') + if courier_val is not None: + if courier_val == 'non': + self.set_value('activer_recuperation_courriel', 'non') + elif not 'imap' in courier_val: + self.set_value('activer_courier_imap', 'non') + if 'pop' in courier_val: + self.set_value('activer_courier_pop', 'oui') + + +class Upgrade_2_5_0(Upgrade): + """ + Mise à jour d'une configuration + de 2.4.X vers 2.5.0 + """ + + def run(self): + """ + Lancement des traitements + """ + log.info(_(u"Starting {0} to {1} upgrade").format('2.4.X', '2.5.0')) + + # migration des variables nut #11608 + monitor = self.get_value('nut_monitor_user') + if monitor != []: + self.set_value('nut_monitor', 'oui') + + # migration des variables postgresql pour Zéphir #11974 + old_pg_shared_buffers = self.get_value('pg_shared_buffers') + if old_pg_shared_buffers is not None: + if int(old_pg_shared_buffers) == 3072: + self.del_value('pg_shared_buffers') + else: + self.set_value('pg_shared_buffers_unit', u'kB') + self.del_value('pg_effective_cache_size') + + +class Upgrade_2_5_1(Upgrade): + """ + Mise à jour d'une configuration + de 2.5.0 vers 2.5.1 + """ + + def run(self): + """ + Lancement des traitements + """ + log.info(_(u"Starting {0} to {1} upgrade").format('2.5.0', '2.5.1')) + + # migration des variables zone_forward (#11922) + zone_forward = self.get_value('nom_zone_forward', []) + if zone_forward != []: + self.set_value('activer_zone_forward', 'oui') + + # passage de bacula à bareos (#12425) + for var in ['activer_bareos_dir', 'activer_bareos_sd', + 'bareos_dir_name', 'bareos_full_retention', + 'bareos_full_retention_unit', 'bareos_diff_retention', + 'bareos_diff_retention_unit', 'bareos_inc_retention', + 'bareos_inc_retention_unit', 'bareos_max_run_time', + 'bareos_compression', 'bareos_dir_password', + 'bareos_fd_password', 'bareos_sd_local', + 'bareos_sd_adresse', 'bareos_sd_password', + 'bareos_sd_name', 'bareos_sd_remote_dir_name', + 'bareos_sd_remote_ip', 'bareos_sd_remote_password']: + self.move(var.replace('bareos', 'bacula'), var) + + if self.get_value('activer_bareos_dir') == u'oui': + #sauvegarde déjà programmé en sqlite3, ne gère pas la migration vers mysql + self.set_value('bareos_db_type', 'sqlite3') + + if self.get_value('ldap_ca_cert') == '/etc/certs/CA2008.pem': + self.set_value('ldap_ca_cert', '/etc/certs/certificat.pem') + + +class Upgrade_2_5_2(Upgrade): + """ + Mise à jour d'une configuration + de 2.5.1 vers 2.5.2 + """ + + def run(self): + """ + Lancement des traitements + """ + log.info(_(u"Starting {0} to {1} upgrade").format('2.5.1', '2.5.2')) + + # haute dispo présente + if self.var_exists('activer_haute_dispo'): + # migration HD sphynx #14881 + if self.var_exists('activer_resource_arv'): + activer_haute_dispo = self.get_value('activer_haute_dispo') + if activer_haute_dispo == 'maitre': + service_resource_name = self.get_noncalculated_value_for_auto('service_resource_name') + service_resource_startdelay = self.get_noncalculated_value_for_auto('service_resource_startdelay') + need_update = False + startdelay_index = 1 + need_disabled_arv = False + if service_resource_startdelay is not None: + if service_resource_name is not None: + need_update = 'arv_rsc' in service_resource_name + if need_update: + startdelay_index = service_resource_name.index('arv_rsc') + need_disabled_arv = not need_update + else: + need_update = True + self.del_value('service_resource_name') + self.del_value('service_resource_script') + self.del_value('service_resource_interval') + self.del_value('service_resource_timeout') + self.del_value('service_resource_startdelay') + if need_update and service_resource_startdelay[startdelay_index] != 15: + self.set_value('service_resource_arv_startdelay', service_resource_startdelay[startdelay_index]) + if need_disabled_arv: + self.set_value('activer_resource_arv', u'non') + # + vip_resource_adresseip = self.get_noncalculated_value_for_auto('vip_resource_adresseip') + self.del_value('vip_resource_name') + self.del_value('vip_resource_if') + self.del_value('vip_resource_adresseip') + self.del_value('vip_resource_location') + if vip_resource_adresseip is not None: + if len(vip_resource_adresseip) > 0: + self.set_value('vip_externe', vip_resource_adresseip[0]) + if len(vip_resource_adresseip) > 1: + self.set_value('vip_interne', vip_resource_adresseip[1]) + # migration HD non Sphynx #14951 + else: + vip_resource_if = self.get_noncalculated_value_for_auto('vip_resource_if') + vip_netmask = [] + for vip_if in vip_resource_if: + netmask_var = 'adresse_netmask_{0}'.format(vip_if.lower()) + vip_netmask.append(self.get_value(netmask_var)) + if len(vip_netmask) > 0: + self.set_value('vip_resource_netmask', vip_netmask) + service_resource_name = self.get_noncalculated_value_for_auto('service_resource_name') + if len(service_resource_name) > 0: + self.set_value('activer_service_resource', 'oui') + + +class Upgrade_2_6_0(Upgrade): + """ + Mise à jour d'une configuration + de 2.5.X vers 2.6.0 + """ + + def get_eth_no(self, eth): + """ + Retourne le numéro X du nom de l'interface ethX + """ + try: + return eth.split("eth")[1] + except: + log.error(_(u"Interface {0} name has not an 'ethX' format").format(eth)) + + def run(self): + """ + Lancement des traitements + """ + log.info(_(u"Starting {0} to {1} upgrade").format('2.5.X', '2.6.0')) + + # migration des variables faisant référence au nom des interfaces ethX + eth_vars = ['route_int', 'fw_rule_int', 'dhcrelay_server_interface', 'freerad_listen_int', + 'sw_force_ip_src', 'corosync_dial_if', 'dhcrelay_interfaces'] + for eth_var in eth_vars: + eth_name = self.get_unvalid_value(eth_var) + if isinstance(eth_name, list): + eth_no = [] + for eth in eth_name: + if eth == 'all': + eth_no.append(eth) + else: + eth_no.append(self.get_eth_no(eth)) + if eth_no != [] and eth_no != eth_name: + self.set_value(eth_var, eth_no) + elif isinstance(eth_name, dict): + eth_no = [] + for eth_key, eth_value in eth_name.items(): + if eth_value == 'all': + eth_no.append(eth_value) + else: + eth_no.append(self.get_eth_no(eth_value)) + if eth_no != [] and eth_no != eth_name: + self.set_value(eth_var, eth_no) + elif eth_name is not None: + eth_no = self.get_eth_no(eth_name) + self.set_value(eth_var, eth_no) + elif eth_var == 'dhcrelay_server_interface' and self.get_value('adresse_ip_dhcp_dhcrelay') is not None: + # migration de l'ancienne valeur par défaut de dhcrelay_server_interface #18329 + self.set_value(eth_var, u'3') + # haute dispo présente + if self.var_exists('activer_haute_dispo'): + # migration HD non sphynx + if not self.var_exists('activer_resource_arv'): + eth_name = self.get_noncalculated_value_for_auto('vip_resource_if') + eth_no = [] + for eth in eth_name: + eth_no.append(self.get_eth_no(eth)) + self.set_value('vip_resource_if', eth_no) + + +class Upgrade_2_6_1(Upgrade): + """ + Mise à jour d'une configuration + de 2.6.0 vers 2.6.1 + """ + + def run(self): + """ + Lancement des traitements + """ + log.info(_(u"Starting {0} to {1} upgrade").format('2.6.0', '2.6.1')) + + # migration des variables NTLM/SMB : multi -> non multi (#18277) + if self.var_exists('nom_serveur_smb'): + for varname in ('nom_serveur_smb', 'nom_domaine_smb', 'ip_serveur_smb'): + value = self.get_unvalid_value(varname) + if isinstance(value, list) and len(value) > 1: + self.set_value(varname, value[0]) + + # nom_carte_ethX => multi-valuées (#18609) + for numint in range(0, 5): + varname = 'nom_carte_eth{}'.format(numint) + value = self.get_unvalid_value(varname) + if value != None: + self.set_value(varname, [value]) + + # migration variable 'module_type' pour le module esbl ('ESBL') -> ('eSBL') (#21677) + if self.get_value('eole_module') == u'esbl': + self.set_value('module_type', u'eSBL') + + +class Upgrade_2_6_2(Upgrade): + """ + Mise à jour d'une configuration + de 2.6.1 vers 2.6.2 + """ + + def run(self): + """ + Lancement des traitements + """ + log.info(_(u"Starting {0} to {1} upgrade").format('2.6.1', '2.6.2')) + + adresse_network_dhcp = self.get_value('adresse_network_dhcp') + if adresse_network_dhcp: + plages = [] + for idx in xrange(len(adresse_network_dhcp)): + plages.append(u'plage{}'.format(idx)) + self.set_value('nom_plage_dhcp', plages) + if self.var_exists('acces_distant_backend_ead'): + self.set_value('acces_distant_backend_ead', 'oui') + for interface in [str(n) for n in range(5)]: + variable = 'frontend_ead_distant_eth' + interface + if self.var_exists(variable): + self.set_value(variable, 'oui') + variable = 'ip_frontend_ead_distant_eth' + interface + if self.var_exists(variable): + self.set_value(variable, ['0.0.0.0']) + variable = 'netmask_frontend_ead_distant_eth' + interface + if self.var_exists(variable): + self.set_value(variable, ['0.0.0.0']) + # Upgrade Seth + # AD firewall - mix old multi variables ad_clients_ip and + # ad_servers_ip in ad_peer_ip + ad_servers_ip = self.get_old_value('ad_peer_ip', 'ad_servers_ip') + ad_clients_ip = self.get_old_value('ad_peer_ip', 'ad_clients_ip') + if ad_servers_ip or ad_clients_ip: + self.set_value('ad_filter_network', 'oui') + if ad_servers_ip: + ad_servers_netmask = self.get_old_value('ad_peer_netmask', 'ad_servers_netmask') + for ip, netmask in zip(ad_servers_ip, [nm[1] for nm in sorted(ad_servers_netmask.items())]): + self.append_value('ad_peer_ip', ip) + self.modify_last_value('ad_peer_netmask', netmask) + del(self.unknown_options['ad_servers_ip']) + del(self.unknown_options['ad_servers_netmask']) + if ad_clients_ip: + ad_clients_netmask = self.get_old_value('ad_peer_netmask', 'ad_clients_netmask') + for ip, netmask in zip(ad_clients_ip, [nm[1] for nm in sorted(ad_clients_netmask.items())]): + self.append_value('ad_peer_ip', ip) + self.modify_last_value('ad_peer_netmask', netmask) + del(self.unknown_options['ad_clients_ip']) + del(self.unknown_options['ad_clients_netmask']) + # Force SID + force_sid = self.get_value('ad_domain_sid') + if force_sid: + self.set_value('ad_force_domain_sid', 'oui') + # Squid modified variables : minutes -> seconds + for squidvar in ['forward_timeout', 'connect_timeout', 'read_timeout', 'request_timeout', 'persistent_request_timeout']: + squidval = self.get_value(squidvar) + if squidval is not None and not self.is_default(squidvar): + self.set_value(squidvar, squidval*60) + # Exim relay : force to "activate" when upgrade from Scribe 2.6.1 only + if self.var_exists('synchro_aaf'): + self.set_value('exim_relay', 'oui') + if self.get_value('activer_dhcp') == 'oui' and self.is_default('exim_relay_dhcp'): + self.set_value('exim_relay_dhcp', 'oui') + # Autosign certificat modified by user must be manual + if self.get_value('cert_type') == u'autosigné': + cert_is_modified = False + # set manuel to access to variable + self.set_value('cert_type', u'manuel') + for cert in ['server_cert', 'server_key', 'server_pem']: + if not self.is_default(cert): + cert_is_modified = True + break + if not cert_is_modified: + self.set_value('cert_type', u'autosigné') + # Store autosign certificat in manual type + if self.get_value('cert_type') == u'manuel': + for cert, filename in [('server_cert', u'/etc/ssl/certs/eole.crt'), ('server_pem', u'/etc/ssl/certs/eole.pem')]: + if self.is_default(cert): + self.set_value(cert, filename) + # gaspacho agent needs to pass by port 8080 has in 2.6.1 and ealier + if self.var_exists('gaspacho_https'): + self.set_value('gaspacho_https', 'non') + + +def upgrade2(major_version, old_release, current_release, config): + """ + major_version: version des scripts de migration (ex : 2.4) + old_release: version du config.eol à migrer (ex : 2.4.0) + current_release: version du serveur (ex : 2.5.1) + config: objet de configuration Tiramisu + """ + def _get_max_release(): + """ + Calcul du dernier numéro de release disponible pour la version majeure + """ + ends = 0 + for func in globals(): + if func.startswith(func_start): + ends = max(ends, int(func.split('_')[-1])) + return ends + + old_version = '.'.join(old_release.split('.')[0:2]) + current_version = '.'.join(current_release.split('.')[0:2]) + func_start = 'Upgrade_' + "_".join(major_version.split('.')) + if StrictVersion(current_version) == StrictVersion(old_version): + # upgrade au sein d'une même version + # ex : 2.5.1 -> 2.5.4 en 2.5 + starts = int(old_release.split('.')[-1]) + ends = int(current_release.split('.')[-1]) + elif StrictVersion(major_version) == StrictVersion(old_version): + # upgrade "de base" vers une version supérieure + # ex : 2.4.2 -> 2.6.1 en 2.4 + starts = int(old_release.split('.')[-1]) + ends = _get_max_release() + elif StrictVersion(major_version) == StrictVersion(current_version): + # upgrade "final" vers une version supérieure + # ex : 2.4.2 -> 2.6.1 en 2.6 + starts = -1 + ends = int(current_release.split('.')[-1]) + else: + # upgrade "intermédiaire" vers une version supérieure + # ex : 2.4.2 -> 2.6.1 en 2.5 + starts = -1 + ends = _get_max_release() + + for i in xrange(starts + 1, ends + 1): + func = func_start + '_' + str(i) + if func in globals(): + upgrade = globals()[func](config) + upgrade.run() diff --git a/creole/utils.py b/creole/utils.py new file mode 100644 index 0000000..d2968a0 --- /dev/null +++ b/creole/utils.py @@ -0,0 +1,197 @@ +# -*- coding: UTF-8 -*- +""" +utilitaires créole +""" + +import sys +from .error import NoneError, OutOfRange +from .config import charset +try: + from pyeole.ansiprint import * +except: + pass +import time, hashlib, random, unicodedata + +# définition des classes d'adresse IP existantes +classes = { + u'128.0.0.0' : u'1' + , u'192.0.0.0' : u'2' + , u'224.0.0.0' : u'3' + , u'240.0.0.0' : u'4' + , u'248.0.0.0' : u'5' + , u'252.0.0.0' : u'6' + , u'254.0.0.0' : u'7' + , u'255.0.0.0' : u'8' + , u'255.128.0.0' : u'9' + , u'255.192.0.0' : u'10' + , u'255.224.0.0' : u'11' + , u'255.240.0.0' : u'12' + , u'255.248.0.0' : u'13' + , u'255.252.0.0' : u'14' + , u'255.254.0.0' : u'15' + , u'255.255.0.0' : u'16' + , u'255.255.128.0' : u'17' + , u'255.255.192.0' : u'18' + , u'255.255.224.0' : u'19' + , u'255.255.240.0' : u'20' + , u'255.255.248.0' : u'21' + , u'255.255.252.0' : u'22' + , u'255.255.254.0' : u'23' + , u'255.255.255.0' : u'24' + , u'255.255.255.128' : u'25' + , u'255.255.255.192' : u'26' + , u'255.255.255.224' : u'27' + , u'255.255.255.240' : u'28' + , u'255.255.255.248' : u'29' + , u'255.255.255.252' : u'30' + , u'255.255.255.254' : u'31' + , u'255.255.255.255' : u'32' +} + +def string_to_bool(string): + """ + Transforme les chaines 'True' ou 'False' en valeurs booléennes + """ + if string == "": + raise ValueError('empty string') + result = eval(string) + if result not in [True, False]: + raise TypeError("string must be like 'True' or 'False'") + else: return result + + +def get_text_node(node): + """ + @param node: node minidom contenant du texte + Utilitaire minidom permettant de récupérer le texte d'un node texte + """ + texte = "" + nodelist = node.childNodes + for textnode in nodelist: + if textnode.nodeType == textnode.TEXT_NODE: + texte = texte + textnode.data + return texte + + +# utilitaires pour la +# ligne de commande + +def raw(text): + """ + Question en ligne de commande : permet de repérer si l'utilisateur a renvoyé quelque chose + + @param text: le libellé de message + @return: la variable demandée + """ + var = raw_input(text + " : ") + if var: + return var + else: + raise NoneError + + +def stringify(string): + """ + Encodage des chaînes avec le charset local + """ + try: + return string.encode(charset) + except: + return string + +def encode_list(_list): + """ encode une liste en utf-8 si les éléments sont de type dico ou str ou liste, unicode""" + encoded_list = [] + for element in _list: + if type(element) == str: + encoded_list.append(encode_str(element)) + elif type(element) == dict: + encoded_list.append(encode_dico(element)) + elif type(element) == list: + encoded_list.append(encode_list(element)) + elif type(element) == unicode: + encoded_list.append(encode_str(element)) + else: + encoded_list.append(element) + return encoded_list + +def encode_str(string): + """ encode une string ou un unicode en utf8 """ + try: + string = string.encode(charset) + except: + pass + return string + +def encode_dico(dico): + """ encode un dico en utf8 dans le cas ou les valeurs soient de type dico, liste, str, unicode """ + for key in dico.keys(): + if type(dico[key]) == str: + dico[key] = encode_str(dico[key]) + elif type(dico[key]) == unicode: + dico[key] = encode_str(dico[key]) + elif type(dico[key]) == dict: + dico[key] = encode_dico(dico[key]) + elif type(dico[key]) == list: + dico[key] = encode_list(dico[key]) + return dico + + +def select_list(selection): + """ + Utilitaire de construction d'une sélection en ligne de commande + @param selection : liste + @return : l'identifiant sélectionné (entier) + """ + # affichage de la liste (ordonnée) + for i in selection: + print(selection.index(i) , ':', stringify(i)) + # print selection.index(i) , ':', i[0] + + # recuperation du numero + try: + number = int(raw(stringify(_("Choose a number in the list")))) + except: + raise OutOfRange + if number not in range(len(selection)): + raise OutOfRange + return number + +def gen_random(length=None): + """ + length: longueur de la chaine aléatoire attendu + """ + try: + random_id = str(time.time()).split('.')[0] + random_str = hashlib.sha224('{}/{}'.format(random_id, str(random.randrange(2**100))).encode('utf-8')).hexdigest() + return random_str[:length] + except: + import traceback + traceback.print_exc() + +def normalize_family(family_name, check_name=True): + """ + il ne faut pas d'espace, d'accent, de majuscule, de tiré, ... + dans le nom des familles + """ + if sys.version_info[0] < 3: + f = unicode(family_name) + else: + f = family_name + f = f.replace('-', '_') + #f = f.replace(u'é', 'e') + #f = f.replace(u'è', 'e') + nfkd_form = unicodedata.normalize('NFKD', f) + f = u"".join([c for c in nfkd_form if not unicodedata.combining(c)]) + f = f.replace(' ', '_') + f = f.lower() + try: + int(f[0]) + except ValueError: + pass + else: + raise ValueError(u'Le nom de la famille ne doit pas commencer par un chiffre : {0}'.format(f)) + if check_name and f.lower() in ['containers']: + raise ValueError(u'nom de la famille interdit {0}'.format(f)) + return f + diff --git a/creole/valid/__init__.py b/creole/valid/__init__.py new file mode 100644 index 0000000..9f9a373 --- /dev/null +++ b/creole/valid/__init__.py @@ -0,0 +1,28 @@ +# -*- coding:utf-8 -*- + +""" +callbacks de validation personnalisés pour tiramisu + +**utilisation** + + faire des callbacks standards en cas de validation + sur la configuration entière. + la possibilité de validation personnalisable doit + être utilisée *uniquement* pour des validations locales + +**important** + + la fonction ne doit pas lever d'exception, elle doit + aboutir. + +api + :param value: premier paramètre, valeur de l'option + les autres paramètres doivent être des + paramètres **nommés** + :return: True ou False suivant que l'option a été validée ou non + + + + + +""" diff --git a/creole/valid/string.py b/creole/valid/string.py new file mode 100644 index 0000000..d2a585b --- /dev/null +++ b/creole/valid/string.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- + +from formencode.validators import UnicodeString +from formencode.api import Invalid + +def valid_string(value, min=None, max=None, not_empty=True): + try: + UnicodeString(min=min, max=max, not_empty=not_empty + ).to_python(value) + return True + except Invalid: + return False diff --git a/creole/var_loader.py b/creole/var_loader.py new file mode 100644 index 0000000..0ea07e0 --- /dev/null +++ b/creole/var_loader.py @@ -0,0 +1,1750 @@ +# -*- coding: utf-8 -*- +try: + from collections import OrderedDict +except: + from pyeole.odict import OrderedDict +from copy import copy +from os.path import isdir, isfile, join, basename, dirname +from os import listdir + +from .error import FileNotFound, ConfigError +from .config import dtdfilename, VIRTBASE, VIRTROOT, VIRTMASTER +from .dtd_parser import parse_dtd +#from .lxml_parser import parse_xml_file, parse_string +#don't touch this, for variables with eosfunc value +#import eosfunc +#from .utils import normalize_family + +from .i18n import _ + +import tiramisu.option + +from tiramisu.option import UnicodeOption, OptionDescription, PortOption, \ + IntOption, ChoiceOption, BoolOption, SymLinkOption, IPOption, \ + NetworkOption, NetmaskOption, DomainnameOption, BroadcastOption, \ + URLOption, EmailOption, FilenameOption, UsernameOption, DateOption, \ + PasswordOption, Option, Leadership + +from tiramisu import Config +from tiramisu.setting import groups +#from tiramisu.error import PropertiesOptionError + +#################################################### +# FIXME : Ajout option adresse mac +from tiramisu import RegexpOption +import re +class MACOption(RegexpOption): + __slots__ = tuple() + _regexp = re.compile(r"^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$") + _display_name = _('mac address') +#################################################### + + +CONVERT_DATA = {IntOption: int, UnicodeOption: str, PortOption: str, + DomainnameOption: str, EmailOption: str, URLOption: str, + IPOption: str, NetmaskOption: str, NetworkOption: str, + BroadcastOption: str, FilenameOption: str} +COMMON_KEY = {'container': UnicodeOption, 'container_group': UnicodeOption, + 'real_container': UnicodeOption, 'instance_mode': None, + 'exists': None, 'redefine': UnicodeOption} + + +CONVERT_OPTION = {'number': (IntOption, None, None), + 'string': (UnicodeOption, None, None), + 'password': (PasswordOption, None, None), + 'mail': (EmailOption, None, None), + 'filename': (FilenameOption, None, None), + 'date': (DateOption, None, None), + #restriction approchante + 'unix_user': (UsernameOption, None, None), + 'ip': (IPOption, None, {'allow_reserved': True}), + 'local_ip': (IPOption, None, {'private_only': True, 'warnings_only': True}), + 'netmask': (NetmaskOption, None, None), + 'network': (NetworkOption, None, None), + 'broadcast': (BroadcastOption, None, None), + 'netbios': (DomainnameOption, None, {'type_': 'netbios', 'warnings_only': True}), + 'domain': (DomainnameOption, None, {'type_': 'domainname', 'allow_ip': True, 'allow_without_dot': True}), + 'domain_strict': (DomainnameOption, None, {'type_': 'domainname', 'allow_ip': False}), + 'hostname': (DomainnameOption, None, {'type_': 'hostname', 'allow_ip': True}), + 'hostname_strict': (DomainnameOption, None, {'type_': 'hostname', 'allow_ip': False}), + 'web_address': (URLOption, None, {'allow_ip': True, 'allow_without_dot': True}), + 'port': (PortOption, None, {'allow_private': True}), + 'oui/non': (ChoiceOption, [u'oui', u'non'], None), + 'on/off': (ChoiceOption, [u'on', u'off'], None), + 'yes/no': (ChoiceOption, [u'yes', u'no'], None), + 'schedule': (ChoiceOption, [u'none', u'daily', u'weekly', u'monthly'], None), + 'schedulemod': (ChoiceOption, [u'pre', u'post'], None)} + +type_option = {UnicodeOption: 'str', ChoiceOption: 'choice', IntOption: 'int', + OptionDescription: 'optiondescription', Leadership: 'optiondescription', IPOption: 'ip', + DomainnameOption: 'str', NetworkOption: 'ip', NetmaskOption: 'ip', + FilenameOption: 'str', DateOption: 'str', EmailOption: 'str', URLOption: 'str', + BroadcastOption: 'str', PortOption: 'str', UsernameOption: 'str', MACOption: 'str', # FIXME YO + PasswordOption:'password'} +type_option_convert = {'int': int, 'str': str, 'ip': str, + 'password': str, + } + + +#def force_unicode(val): +# if val is not None and type(val) != unicode: +# return unicode(val, 'utf-8') +# else: +# return val + +def convert_value(option, value, config=None): + _type = type_option[type(option)] + if _type in type_option_convert: + if value is not None: + return type_option_convert[_type](value) + elif _type == 'choice': + values = option.impl_get_values(config) + if value is None and u'' in values: + value = u'' + if value not in values: + raise ValueError(_("option {0}'s value should be in {1}".format(option._name, str(values)))) + return value + +#===DUPLIQUE DANS ANNOTATOR +#mode order is important +modes_level = ('basic', 'normal', 'expert') +class Mode(object): + def __init__(self, name, level): + self.name = name + self.level = level + + def __cmp__(self, other): + return cmp(self.level, other.level) + + def __eq__(self, other): + return self.level == other.level + + def __ne__(self, other): + return self.level != other.level + + def __gt__(self, other): + return other.level < self.level + + def __ge__(self, other): + return not self.level < other.level + + def __le__(self, other): + return not other.level < self.level + + +def mode_factory(): + mode_obj = {} + for idx in range(len(modes_level)): + name = modes_level[idx] + mode_obj[name] = Mode(name, idx) + return mode_obj + +modes = mode_factory() +#/=== +def convert_tiramisu_value(value, obj): + """ + convertit les variables dans le bon type si nécessaire + """ + def _convert_boolean(value): + if isinstance(value, bool): + return value + if value == 'True': + return True + elif value == 'False': + return False + elif value is None: + return None + else: + raise Exception('unknown value {} while trying to cast {} to boolean'.format(value, obj)) + + if obj is BoolOption: + if isinstance(value, list): + # variable multi + return [_convert_boolean(val) for val in value] + else: + return _convert_boolean(value) + func = CONVERT_DATA.get(obj, None) + if value == None or func == None: + return value + if type(value) is list: + # variable multi + return [func(val) for val in value] + else: + return func(value) + +class CreoleGeneric(): + def gen_generic(self, name, paths, copy_requires=None, + verify_exists_redefine=True): + def _get_type(values): + """get type and values for ChoiceOption + """ + if values == None: + return UnicodeOption, None + elif set([True, False]) == set(values): + return BoolOption, None + else: + return ChoiceOption, values + + def build_key_type(name, pnode=''): + #build key_type and choice_constrainte with 'needs' and 'optionals' + #attribut + key_type = {} + for mode in ['needs', 'optionals']: + for key, value in self.dtd[name][mode].items(): + #don't load COMMON_KEY and xxxlist and parentnodelist + if key not in COMMON_KEY and key != '{0}list'.format(name) and key != '{0}list'.format(pnode): + choice = None + if value['type'] is not None: + type_ = value['type'] + else: + type_, choice = _get_type(value['values']) + if choice != None: + choice_constrainte[key] = choice + key_type[key] = type_ + return key_type + + containers = self._get_containers() + tgeneric_vars = self.generic.get(name, []) + generic_vars = [] + for data in tgeneric_vars: + if data['container'] == 'all': + # Generate per container + for container in containers.values(): + if container['name'] in ['all', VIRTMASTER]: + continue + tdata = copy(data) + tdata['container'] = container['name'] + generic_vars.append(tdata) + else: + generic_vars.append(data) + #remove last 's' in name (hosts => host) + if name[-1] == 's': + name = name[:-1] + #if name is a key of self.requires set requires_key to 'activate' + if name in self.requires: + requires_key = 'activate' + else: + requires_key = None + choice_constrainte = {} + key_type = build_key_type(name) + #if sub node add subkeys to key_type, be carefull, all sub node + #are mixed, 'node_name' is it's node name + for option in self.dtd[name]['options']: + key_type.update(build_key_type(option, name)) + key_type['node_name'] = UnicodeOption + key_type['level'] = UnicodeOption + return self._gen_tiramisu_config(paths, name, generic_vars, key_type, + choice_constrainte, requires_key, + copy_requires=copy_requires, + verify_exists_redefine=verify_exists_redefine) + + def _check_instance_mode(self, data): + """Verify if the resource is to be instanciated + + A resource can tagged to be instanciate only when containers + is enabled or disabled. + + We check if the tagged instance mode match the current state + of the containers activation. + + :param data: resource informations + :type data: `dict` + :return: resource instance mode match containers activation + :rtype: `bool` + + """ + check = True + if 'instance_mode' in data: + mode = data['instance_mode'] + if self.containers_enabled and mode == 'when_no_container': + check = False + elif not self.containers_enabled and mode == 'when_container': + check = False + return check + + def _config_list_to_dict(self, gvariables, verify_exists_redefine): + """ + valid variables in container context and return a dict + (with variable's name has key) + variables: list of variables + """ + def _test_new_variable(variable): + """ + test if variable redefine and exists attribut + variable: attribute of the variable + """ + return + if variable.get('redefine', False): + raise ConfigError( + _(u"{0} {1} redefined but unexistent.").format(gtype, name)) + if not variable.get('exists', True): + raise ConfigError(_(u'{0} {1} existent.').format(gtype, name)) + + + variables = OrderedDict() + containers = self._get_containers() + for variable in gvariables: + # Check if we activate the variable or not + if not self._check_instance_mode(variable): + continue + name = variable['name'] + if variable.has_key('container'): + #add container group + variable['container_group'] = containers[variable['container']]['group'] + if self.containers_enabled: + tcontainer = self.get_real_container_name(containers, variable['container_group']) + variable['real_container'] = tcontainer + else: + variable['real_container'] = VIRTMASTER + else: + variable['container_group'] = variable['group'] + if self.containers_enabled: + variable['real_container'] = variable['group'] + else: + variable['real_container'] = VIRTMASTER + #if variable already exist, verify if not in same container + #if same container, verify redefine and exists attributs + if variable.has_key('container') and name in variables: + if verify_exists_redefine: + is_exists = False + for test in variables[name]: + if test['container'] == variable['container']: + is_exists = True + break + #if variable exists in same container + if is_exists: + if not variable.get('exists', True): + continue + if not variable.get('redefine', False): + #var already exists + raise ConfigError(_(u"Name ({0}) already used.").format(name)) + else: + #variable exists in an other container + _test_new_variable(variable) + #FIXME : ajoute mais je modifie pas si exists ! + variables[name].append(variable) + else: + #var does not exists + if verify_exists_redefine: + _test_new_variable(variable) + variables[name] = [variable] + return variables + + def _gen_tiramisu_config(self, paths, gtype, gvariables, key_type={}, + choice_constrainte={}, requires_key=None, copy_requires=None, + verify_exists_redefine=True): + """ + Generate tiramisu's config for container's attributs + + paths: paths of all Creole variables + gtype: type of Creole attributs (file, service, ...) + gvariables: attributs for generate tiramisu config + key_type: type of each attribut key + choice_constrainte: + requires_key: apply requires for this key + copy_requires: copy all requires for Symlink to OptionDescription + """ + variables = self._config_list_to_dict(gvariables, verify_exists_redefine) + + #add common key type + key_type.update(COMMON_KEY) + key_type['{0}list'.format(gtype)] = UnicodeOption + var = [] + + #parse dictionary generated by _config_list_to_dict + for name, var_datas in variables.items(): + #parse attributs of variable + for var_data in var_datas: + force_requires = [] + properties = tuple() + if var_data.get('{0}list'.format(gtype), None) in \ + self.requires.get(gtype, {}): + props, req = self.update_requires( + self.requires[gtype][ + var_data['{0}list'.format(gtype)]]['list'], namespace='creole', option=True) + if props != []: + properties = tuple(props) + requires = None + else: + requires = req + else: + requires = None + options = [] + #add option in tiramisu for a specified attribut + for option_type, option_value in var_data.items(): + #if option's type is define in key_type + if option_type in key_type: + #get tiramisu's object + option_obj = key_type[option_type] + if isinstance(option_obj, str): + option_obj = getattr(tiramisu.option, var_data[option_obj]) + elif option_type == 'name': + #default option_obj + option_obj = UnicodeOption + #if type is set, get type + if self.dtd[gtype]['type']: + option_obj = self.dtd[gtype]['type'] + elif 'node_name' in var_data: + #if no type, search node_name and get type in node (this it's a str, not an option) + option_obj = getattr(tiramisu.option, var_data[self.dtd[var_data['node_name']]['type']]) + else: + raise Exception(_(u'Unknown key {0}').format(option_type)) + option_value = convert_tiramisu_value(option_value, option_obj) + #if value is None, don't generate tiramisu's option + if option_obj and option_value is not None: + #if option_type is requires_key, unset requires_key + #and add requires for this key + if option_type == requires_key: + requires_key = None + r = requires + p = properties + requires = None + properties = tuple() + else: + r = None + p = None + + #gen tiramisu object + if option_obj == ChoiceOption: + options.append(option_obj(option_type, '', + tuple(choice_constrainte[option_type]), + default=option_value, requires=r, + properties=p)) + elif option_obj == SymLinkOption: + if r != None: + raise Exception( + _(u'No requires for SymLinkOption')) + try: + path = paths[option_value] + except KeyError: + raise Exception( + _(u"SymLinkOption targetting unexistent variable: {0}.").format(option_value)) + namespace = path.split('.')[0] + for descr in self.space: + if descr._name == namespace: + bopt = OptionDescription('baseconfig', + 'baseconfigdescr', + [descr]) + opt = bopt + for p in path.split('.'): + opt = getattr(opt, p) + if option_type == copy_requires: + #aggrege tous les requirements des familles/option + #pour les appliquer aussi sur l'OptionDescription + opt_path = path.split('.') + for p in opt_path[:-1]: + try: + force_requires.extend(self.update_requires(self.requires['family'][p]['list'], 'creole', option=True)[1]) + except KeyError: + pass + try: + force_requires.extend(self.update_requires(self.requires['variable'][opt_path[-1]]['list'],'creole', option=True)[1]) + not_mandatory = False + for req_ in force_requires: + if req_[2] == 'disabled' and req_[3] != False: + not_mandatory = True + if not not_mandatory and 'mandatory' in opt._properties: + force_requires.append((opt, None, 'disabled', False, True, False)) + except KeyError: + pass + break + + options.append(option_obj(option_type, opt)) + else: + options.append(option_obj(option_type, '', + default=option_value, requires=r, properties=p)) + + #if requires_key is not already set + if requires_key: + options.append(BoolOption(requires_key, '', default=True, + requires=requires, properties=properties)) + requires = None + properties = tuple() + level = len(var) + if force_requires != []: + if requires == None: + requires = force_requires + else: + requires.extend(force_requires) + + var.append(OptionDescription(gtype + str(level), + '', options, requires=requires, properties=properties)) + return OptionDescription('{0}s'.format(gtype), '', var) + + def gen_container(self, paths, namespace): + ret = [] + if 'gen_networks' in dir(self): + ret.append(self.gen_networks(paths)) + for name in self.generic: + func_name = 'gen_{0}'.format(name) + if func_name in dir(self): + ret.append(getattr(self, func_name)(paths)) + else: + ret.append(self.gen_generic(name, paths)) + return ret + + def _get_containers(self): + """ + Load container's description + """ + containers = OrderedDict() + containers_id = OrderedDict() + for container in self.generic.get('containers', []): + name = container['name'] + if not containers.has_key(name): + containers[name] = {'name': name, 'group': name} + if container.has_key('id') and container['id'] is not None: + id_ = container['id'] + if id_ in containers_id and containers_id[id_] != name: + raise ConfigError(_(u"Two containers with the same id ({0})").format(id_)) + if name in containers_id.values() and containers_id.get(id_) != name: + raise ConfigError(_(u"Multiple ids for the container {0}").format(name)) + containers_id[id_] = name + containers[name]['id'] = id_ + if container.has_key('group') and container['group'] is not None: + containers[name]['group'] = container['group'] + + for name, container in containers.items(): + group = container['group'] + if name != group and group in containers: + containers[name]['id'] = containers[group]['id'] + return containers + + def gen_containers_creole(self, paths, namespace): + """ + Generate fake config.creole.containers hidden family. + Each container has two UnicodeOption: + container_ip_//name// and container_path_//name// + + :paths: paths variables (for added new option in paths's dictionnary) + """ + if self.containers_enabled: + ip_br0 = u'192.0.2.1' + mask_br0 = u'255.255.255.0' + network_br0 = u'192.0.2.0' + bcast_br0 = u'192.0.2.255' + else: + ip_br0 = u'127.0.0.1' + mask_br0 = u'255.0.0.0' + network_br0 = u'127.0.0.0' + bcast_br0 = u'127.255.255.255' + + variables = [] + args = {'name': 'adresse_ip_br0', 'doc': _(u"Bridge IP address"), 'default': ip_br0, 'requires': None} + variables.append({'optiontype': 'option', 'obj': UnicodeOption, 'args': args, 'option': None}) + args = {'name': 'adresse_netmask_br0', 'doc': _(u"Bridge IP subnet mask"), 'default': mask_br0, 'requires': None} + variables.append({'optiontype': 'option', 'obj': UnicodeOption, 'args': args, 'option': None}) + args = {'name': 'adresse_network_br0', 'doc': _(u"Bridge IP network_br0 address"), 'default': network_br0, 'requires': None} + variables.append({'optiontype': 'option', 'obj': UnicodeOption, 'args': args, 'option': None}) + args = {'name': 'adresse_broadcast_br0', 'doc': _(u"Bridge broadcast IP address"), 'default': bcast_br0, 'requires': None} + variables.append({'optiontype': 'option', 'obj': UnicodeOption, 'args': args, 'option': None}) + for name in ['adresse_ip_br0', 'adresse_netmask_br0', + 'adresse_network_br0', 'adresse_broadcast_br0']: + paths[name] = 'creole.containers.{0}'.format(name) + + containers = self._get_containers() + for name, container in containers.items(): + if name == 'all': + ip = None + path = None + real_name = u'all' + elif not self.containers_enabled or name == VIRTMASTER: + path = u'' + ip = u'127.0.0.1' + real_name = unicode(VIRTMASTER) + else: + tcontainer = self.get_real_container_name(containers, container['name']) + real_name = unicode(tcontainer) + path = unicode(join(VIRTROOT, real_name, VIRTBASE)) + #FIXME : pas toujours ca l'IP + ip = u"192.0.2." + container['id'] + # Variable : container_path_ + path_name = 'container_path_{0}'.format(name) + args = {'name': path_name, 'doc': _(u'Path of container {0}').format(name), 'default': path, 'requires': None} + variables.append({'optiontype': 'option', 'obj': UnicodeOption, 'args': args, 'option': None}) + paths[path_name] = 'creole.containers.{0}'.format(path_name) + # Variable : container_ip_ + ip_name = 'container_ip_{0}'.format(name) + args = {'name': ip_name, 'doc': _(u'IP address of container {0}').format(name), 'default': ip, 'requires': None} + variables.append({'optiontype': 'option', 'obj': UnicodeOption, 'args': args, 'option': None}) + paths[ip_name] = 'creole.containers.{0}'.format(ip_name) + # Variable : container_name_ + name_name = 'container_name_{0}'.format(name) + args = {'name': name_name, 'doc': _(u'Group name of container {0}').format(name), 'default': real_name, 'requires': None} + variables.append({'optiontype': 'option', 'obj': UnicodeOption, 'args': args, 'option': None}) + paths[name_name] = 'creole.containers.{0}'.format(name_name) + # Variable : adresse_ip_ + # adresse_ip_ added for compat 2.3 (#5701, #5868) + adresse_name = 'adresse_ip_{0}'.format(name) + if adresse_name not in self.variables: + if not self.containers_enabled: + # hack to have "localhost" in non container mode #7183 + args = {'name': adresse_name, 'doc': _(u'Path of container {0}').format(name), 'default': u'localhost', + 'properties': ('frozen', 'force_default_on_freeze'), 'requires': None} + variables.append({'optiontype': 'option', 'obj': UnicodeOption, 'args': args, 'option': None}) + else: + variables.append({'optiontype': 'symlinkoption', 'obj': SymLinkOption, 'path': paths[ip_name], 'args': {'name': adresse_name}, 'option': None}) + paths[adresse_name] = 'creole.containers.{0}'.format(adresse_name) + variables_path = [] + for var in variables: + path = 'containers.' + var['args']['name'] + self.options[namespace][path] = var + variables_path.append(path) + fname = 'containers' + self.options[namespace][fname] = {'optiontype': 'optiondescription', + 'args': {'name': fname, + 'doc': _('Containers informations'), + 'children': variables_path, + 'properties': ('hidden', 'normal'), + 'requires': None}, + 'group_type': 'family', + 'informations': {'icon': 'puzzle-piece'}, + 'option': None} + return fname + + +class CreoleFamily(): + """ + charge les familles, les variables, les aides et séparateurs + """ + def _init_creole_family(self): + """ + initialise les variables pour les familles + """ + self.families = OrderedDict() + #only for find old variable + self.variables = {} + self.helps = {'variables':{}, 'families':{}} + self.separators = {} + self.groups = {} + + def populate_families(self, families, namespace): + for family, fdata in families.items(): + nfamily = normalize_family(family) + lvars = OrderedDict() + for var, vdata in fdata['vars'].items(): + variable = self.get_variable(var, vdata, nfamily, namespace) + if variable is not None: + lvars[var] = variable + if vdata.get('remove_check', False): + try: + self.valid_enum.pop(var) + except KeyError: + pass + try: + self.consistency.pop(var) + except KeyError: + pass + try: + self.check.pop(var) + except KeyError: + pass + if vdata.get('remove_condition', False): + try: + self.requires['variable'].pop(var) + except KeyError: + pass + # si famille inexistant, on l'ajoute + if not self.families.has_key(nfamily): + # définition de la famille + fdata['vars'] = OrderedDict() + self.families[nfamily] = copy(fdata) + self.families[nfamily]['mode'] = modes_level[0] + self.families[nfamily]['hidden'] = False + self.families[nfamily]['doc'] = str(family.encode('utf8')) + self.families[nfamily]['vars'].update(lvars) + #ne pas remettre a normal dans ce cadre d'un redefine + if 'mode' in fdata and fdata['mode'] not in [modes_level[0], None]: + self.families[nfamily]['mode'] = fdata['mode'] + if 'icon' in fdata and fdata['icon'] is not None: + self.families[nfamily]['icon'] = fdata['icon'] + if 'hidden' in fdata: + self.families[nfamily]['hidden'] = fdata['hidden'] + self.families[nfamily]['vars'].update(lvars) + + + def get_variable(self, var, vdata, family, namespace): + #si la derniere variable ne devait pas etre prise en compte + #existe == False => on quitte brutalement + #et il ne faut pas prendre en compte la suite + if namespace == 'creole' and var in self.variables: + if not vdata['exists']: + return None + if not vdata['redefine']: + # on ne devrait pas avoir 2 fois la meme variable + raise ConfigError(_(u"Two variables with the same name ({0})").format(var)) + elif vdata['redefine']: + raise ConfigError(_(u"Attempt to redefine unexistent variable: {0}.").format(var)) + #si c'est une nouvelle variable + if not vdata['redefine']: + # Be sure to have defaults on new variables + tvar = self._update_variable_attributes(var, vdata) + #uniquement dans le cadre de redefine + else: + old_family = self.variables[var] + if old_family != family: + tvar = self.families[old_family]['vars'][var] + self.families[old_family]['vars'].pop(var) + else: + tvar = self.families[family]['vars'][var] + if vdata['value'] != None: + tvar['value'] = vdata['value'] + tvar = self._update_variable_attributes(var, tvar, vdata) + self.variables[var] = family + return tvar + + def _update_variable_attributes(self, var, vdata, newdata=None): + """Update variable attributes. + + If :data:`newdata` is ``None``, set default, update to new + value otherwise. + + :param var: variable name + :type var: `str` + :param vdata: variable attributes + :type vdata: `dict` + :param newdata: new variable attributes + :type newdata: `dict` + :return: variable attributes + + """ + attrs = vdata.copy() + + if newdata and newdata['multi']: + raise ValueError(_(u"Redefining multi attribute is not allowed" + " for variable {0}").format(var)) + if newdata and newdata['type'] != 'string': + raise ValueError(_(u"Redefining type attribute is not allowed" + " for variable {0}").format(var)) + for attr in ['auto_freeze', 'auto_save', 'hidden', 'mandatory', 'redefine']: + # Default value is False + if attr not in vdata or vdata[attr] is None: + attrs[attr] = False + elif newdata is not None and attr in newdata \ + and newdata[attr] is not None \ + and vdata[attr] != newdata[attr]: + attrs[attr] = newdata[attr] + + if 'exists' not in vdata or vdata['exists'] is None: + attrs['exists'] = True + elif newdata is not None and 'exists' in newdata \ + and newdata['exists'] is not None \ + and vdata['exists'] != newdata['exists']: + attrs['exists'] = newdata['exists'] + + if 'mode' not in vdata or vdata['mode'] is None: + attrs['mode'] = 'normal' + elif newdata is not None and 'mode' in newdata \ + and newdata['mode'] is not None \ + and vdata['mode'] != newdata['mode']: + attrs['mode'] = newdata['mode'] + + if newdata is not None and 'description' in newdata \ + and newdata['description'] is not None \ + and vdata['description'] != newdata['description']: + attrs['description'] = newdata['description'] + + if vdata['disabled'] is True or (newdata is not None and newdata['disabled'] is True): + attrs['disabled'] = True + + return attrs + + def populate_helps(self, helps, namespace): + """ + """ + for key, values in helps['variables'].items(): + vdata = self.families[self.variables[key]]['vars'][key] + if self.helps['variables'].has_key(key) and not vdata['redefine']: + raise ConfigError(_(u"help already set for {0}").format(key)) + else: + self.helps['variables'][key] = values + for key, values in helps['families'].items(): + key = normalize_family(key) + fdata = self.families[key] + if self.helps['families'].has_key(key) and not fdata['redefine']: + raise ConfigError(_(u"help already set for {0}").format(key)) + else: + self.helps['families'][key] = values + + def populate_separators(self, separators, namespace): + """ + """ + #devrait être dans la variable plutot que dans self.separators + for var, value in separators.items(): + if self.separators.has_key(var): + raise ConfigError(_(u"More than one separator for " + "{0}").format(var)) + else: + self.separators[var] = value + + def populate_groups(self, groups_, namespace): + for grp_name, grps in groups_.items(): + self.groups.setdefault(grp_name, []).extend(grps) + +class CreoleConstraint(): + """ + charge les contraintes + """ + def _init_creole_constrainte(self): + self.valid_enum = {} + self.mandatory = [] + self.fill = {} + self.auto = {} + self.check = {} + self.consistency = {} + + def populate_conditions(self, conditions, namespace): + #FIXME juste les conditions/hidden_if_in|hidden_if_not_in + for var, _conditions in conditions.items(): + for condition in _conditions: + if condition['name'] in ['hidden_if_in', 'disabled_if_in']: + conds = [('disabled', False)] + elif condition['name'] in ['hidden_if_not_in', + 'disabled_if_not_in']: + conds = [('disabled', True)] + elif condition['name'] == 'frozen_if_in': + conds = [('frozen', False), ('hidden', False), ('force_default_on_freeze', False)] + elif condition['name'] == 'frozen_if_not_in': + conds = [('frozen', True), ('hidden', True), ('force_default_on_freeze', True)] + elif condition['name'] in ['mandatory_if_in']: + conds = [('mandatory', False)] + elif condition['name'] in ['mandatory_if_not_in']: + conds = [('mandatory', True)] + else: + raise Exception(_(u'Unknown condition type for {0}').format( + condition['name'])) + families = condition['family'] + variables = condition['variable'] + for params in condition['param']: + if params['type']: + raise Exception(_(u'Unknown type {0}').format( + params['type'])) + if params['hidden']: + raise Exception(_(u'Unknown hidden {0}').format( + params['hidden'])) + if params['name']: + raise Exception(_(u'Unknown name {0}').format( + params['name'])) + if params['optional']: + raise Exception(_(u'Unknown optional {0}').format( + params['optional'])) + value = params['value'] + tconditions = [] + for cond in conds: + tconditions.append((var, value, cond[0], cond[1])) + for variable, optional in variables: + #if optional is not set for only one condition, always not optional + self.requires['variable'].setdefault(variable, {'optional': True, 'list': []}) + if not optional: + self.requires['variable'][variable]['optional'] = optional + self.requires['variable'][variable]['list'].extend(tconditions) + for family, optional in families: + #FIXME optional not used + family = normalize_family(family) + #if optional is not set for only one condition, always not optional + self.requires['family'].setdefault(family, {'optional': True, 'list': []}) + if not optional: + self.requires['family'][family]['optional'] = optional + self.requires['family'][family]['list'].extend(tconditions) + for list_name, list_value, optional in condition['list']: + #FIXME optional not used + #if optional is not set for only one condition, always not optional + self.requires[list_name].setdefault(list_value, {'optional': True, 'list': []}) + if not optional: + self.requires[list_name][list_value]['optional'] = optional + self.requires[list_name][list_value]['list'].extend(tconditions) + self.fallback[var] = condition['fallback'] + + def _populate_func(self, datas, _type, namespace): + """ + to populate auto or fill + """ + data = {} + for target, funcs in datas.items(): + if len(funcs) != 1: + raise Exception(_(u'More than one function for target: {0}').format(target)) + func_name = funcs[0][0] + func_params = funcs[0][1] + func_level = funcs[0][2] + if func_level != 'error': + raise Exception(_(u"Can not set level to {0} for this kind of callback").format(func_level)) + params = {} + for param in func_params: + name = {None: ''}.get(param['name'], param['name']) + if param['type'] == None: + params.setdefault(name, []).append(unicode(param['value'])) + elif param['type'] == 'eole': + check_disabled = param['hidden'] == "False" + optional = param['optional'] == 'True' + value = param['value'] + if '.' in value: + ns, value = value.split('.', 1) + if ns != namespace: + raise Exception(_('Namespace different in param not allowed: {} - {}').format(ns, namespace)) + params.setdefault(name, []).append({'optional': optional, + 'check_disabled': check_disabled, + 'value': value}) + elif param['type'] == 'number': + params.setdefault(name, []).append(int(param['value'])) + elif param['type'] == 'container': + #pour compatibilté dicos 2.3 (#6240) + # remplace le dictionnaire d'infos conteneur + # par l'ip du conteneur demandé + params.setdefault(name, []).append({'optional': False, + 'check_disabled': False, + 'value': 'container_ip_' + param['value']}) + elif param['type'] == 'context': + params.setdefault(name, []).append((None,)) + else: + raise Exception(_(u'Type {0} not yet implemented ' + u'for {1} for {2}').format(param['type'], _type, + target)) + if namespace != 'creole' and '.' in target: + #if extra and variable in extra (so with complet path) + #don't support redefine + vdata = {'redefine': False} + else: + vdata = self.families[self.variables[target]]['vars'][target] + #6016 + if _type in ['auto', 'fills'] and vdata.get('value') is not None and \ + vdata['redefine']: + vdata['value'] = None + if (_type == 'check' and target in self.check.keys()) or \ + (_type != 'check' and (target in self.fill.keys() or + target in self.auto.keys()) and not vdata['redefine']): + raise Exception(_(u"Computing function already defined for {0}").format( + target)) + if _type != 'check': + if target in self.fill: + del(self.fill[target]) + if target in self.auto: + del(self.auto[target]) + data[target] = (func_name, params) + return data + + def populate_checks(self, checks, namespace): + #FIXME faudrait voir pour supprimer les anciens comme avant + for var, _checks in checks.items(): + for check in _checks: + if check[0] == 'valid_enum': + open_values = False + for param in check[1]: + if param['name'] == 'checkval': + open_values = not {'True': True, + 'False': False}.get(param['value']) + tvalues = eval(check[1][0]['value']) + values = [] + for value in tvalues: + if type(value) == str: + values.append(unicode(value, 'utf-8')) + else: + values.append(value) + self.valid_enum[var] = (values, open_values) + elif check[0] == 'obligatoire': + self.mandatory.append(var) + elif check[0] == 'valid_differ' and check[1][0]['type'] == 'eole': + if len(check[1]) != 1: + raise Exception(_(u'valid_differ length should be 1')) + self.consistency.setdefault(var, []).append(('not_equal', check[1][0], check[2])) + elif check[0] == 'valid_networknetmask': + if len(check[1]) != 1: + raise Exception(_(u'valid_networknetmask length should be 1')) + if check[1][0]['type'] != 'eole': + raise Exception(_(u'valid_networknetmask must have only eole variable')) + self.consistency.setdefault(var, []).append(('network_netmask', check[1][0], check[2])) + elif check[0] == 'valid_ipnetmask': + if len(check[1]) != 1: + raise Exception(_(u'valid_ipnetmask length should be 1')) + if check[1][0]['type'] != 'eole': + raise Exception(_(u'valid_ipnetmask must have only eole variable')) + self.consistency.setdefault(var, []).append(('ip_netmask', check[1][0], check[2])) + elif check[0] == 'valid_broadcast': + if len(check[1]) != 2: + raise Exception(_(u'valid_broadcast length should be 2')) + error = False + try: + if check[1][0]['type'] != 'eole' or check[1][1]['type'] != 'eole': + error = True + except IndexError: + error = True + if error: + raise Exception(_(u'valid_broadcast must have only eole variable')) + self.consistency.setdefault(var, []).append(('broadcast', check[1][0], check[1][1], check[2])) + elif check[0] == 'valid_in_network': + if len(check[1]) != 2: + raise Exception(_(u'valid_in_network length should be 2')) + error = False + try: + if check[1][0]['type'] != 'eole' or check[1][1]['type'] != 'eole': + error = True + except IndexError: + error = True + if error: + raise Exception(_(u'valid_in_network must have only eole variable')) + self.consistency.setdefault(var, []).append(('in_network', check[1][0], check[1][1], check[2])) + else: + self.check.update(self._populate_func({var: [check]}, + 'check', namespace)) + + def populate_fills(self, fills, namespace): + self.fill.update(self._populate_func(fills, 'fill', namespace)) + + def populate_autos(self, autos, namespace): + self.auto.update(self._populate_func(autos, 'auto', namespace)) + +class CreoleVarLoader(CreoleFamily, CreoleConstraint, CreoleGeneric): + def __init__(self, no_auto_store=False): + self.space = [] + self._config = None + self.is_lint = False + self.dtd = parse_dtd(dtdfilename) + self.containers_enabled = None + self.options = {} + self.paths = {} + self.no_auto_store = no_auto_store + self.force_store_vars = set() + self.actions = {} + + def _init_creole_varloader(self): + self.variables = OrderedDict() + self.generic = {} + # Generate empty trees + for opt in self.dtd['container']['options']: + self.generic[opt + 's'] = [] + + def read_string(self, data_dicts, namespace, test_duplicate): + """ + lecture d'un ensemble de dictionnaires et d'un + configuration passés en paramètres (Zéphir) + data_dicts : données des dictionnaires encodés en base64 et ordonnés + """ + self._pre_populate(namespace) + # parsing des dictionnaires fournis + for dico in data_dicts: + is_creole_constrainte = 'gen_container' in dir(self) + parse_result = parse_string(dico, self.dtd, is_creole_constrainte, test_duplicate) + #FIXME: voir pour autre chose que 'module' + self._populate(parse_result, namespace, 'module') + self._post_populate(namespace) + # chargement des valeurs depuis le format json + self._gen_descr(namespace) + + def read_dir(self, dir_config, namespace, force_test_duplicate=None): + """ + lecture d'un répertoire entier de dictionnaires + """ + self._pre_populate(namespace) + if type(dir_config) != list: + #if dir_config is not a list, add subdirectory 'local' + #and 'variante' + orig_dir = dir_config + dir_config = [dir_config] + for tdir in [join(orig_dir, 'local'), + join(orig_dir, 'variante')]: + if isdir(tdir): + dir_config.append(tdir) + if namespace == 'creole': + if force_test_duplicate is not None: + test_duplicate = force_test_duplicate + else: + test_duplicate = True + else: + test_duplicate = False + for mydir in dir_config: + if type(mydir) in (list, tuple): + # directory group : collect files from each + # directory and sort them before loading + group_files = [] + for idx, subdir in enumerate(mydir): + if isdir(subdir): + for filename in listdir(subdir): + group_files.append((filename, idx, subdir)) + else: + group_files.append(basename(subdir), idx, dirname(subdir)) + def sort_group(file1, file2): + if file1[0] == file2[0]: + # sort by initial mydir order if same name + return file1[1].__cmp__(file2[1]) + # sort by filename + elif file1[0] > file2[0]: + return 1 + else: + return -1 + group_files.sort(sort_group) + filenames = [join(f[2], f[0]) for f in group_files] + elif isdir(mydir): + filenames = [] + for filename in listdir(mydir): + filenames.append(join(mydir, filename)) + filenames.sort() + else: + filenames = [mydir] + for filename in filenames: + if filename.endswith('.xml'): + if not isfile(filename): + raise FileNotFound(_(u"File {0} does not exist").format(filename)) + # level indicates the level of dictionary (module, variante or local) + level = {'local': 'local', + 'variante': 'variante'}.get(basename(dirname(filename)), 'module') + #print filename + #hack to detect if CreoleVarLoader or CreoleLoader is used + is_creole_constrainte = 'gen_files' in dir(self) + parse = parse_xml_file(filename, self.dtd, is_creole_constrainte, test_duplicate) + self._populate(parse, namespace, level) + self._post_populate(namespace) + self._gen_descr(namespace) + + def _pre_populate(self, namespace): + # initialisation avant chargement des données d'un dictionnaire + if self._config is not None: + raise Exception(_(u'Unable to run read_dir if Config already exists.')) + #Re init all variables + for func in dir(self): + if func.startswith('_init_creole_'): + getattr(self, func)() + # chargement des dictionnaires + #FIXME devrait être automatique ... + self.requires = {'variable': {}, 'family': {}, 'service': {}, + 'interface': {}, 'file': {}, 'filelist': {}, 'fstab': {}, + 'host': {}, 'service_restriction': {}, 'service_access': {}, "action": {}} + # this information should be a self.requires, but we need to change + # too much code to do that (#5717) + self.fallback = {} + self.options[namespace] = {} + + def _populate(self, parse, namespace, level): + parse_keys = parse.keys() + #families always in first place + parse_keys.remove('families') + parse_keys.insert(0, 'families') + for keys in parse_keys: + func_name = 'populate_' + keys + if func_name in dir(self): + try: + getattr(self, 'populate_' + keys)(parse[keys], namespace) + except Exception as err: + raise ConfigError(_(u"Unable to populate {0}: {1}").format(keys, err)) + else: + for var in parse[keys]: + var['level'] = level + self.generic.setdefault(keys, []).append(var) + + def populate_families_action(self, var, namespace): + for family_name, family in var.items(): + if family_name not in self.actions.keys(): + self.actions[family_name] = {} + for key, value in family.items(): + if key == 'action': + if 'actions' not in self.actions[family_name]: + self.actions[family_name]['actions'] = [] + value['name'] = namespace + self.actions[family_name]['actions'].append(value) + else: + self.actions[family_name][key] = value + + def _post_populate(self, namespace): + if namespace == 'creole': + if self.families['general']['vars']['mode_conteneur_actif']['value'] == 'oui': + self.containers_enabled = True + else: + self.containers_enabled = False + + def gen_actions(self): + objactions = [] + #name = 'actions' + #for name_family, families in self.actions.items(): + # opts = [] + # for type_, infos in families.items(): + # if isinstance(infos, str): + # opts.append(UnicodeOption(type_, '', unicode(infos))) + # elif isinstance(infos, unicode): + # opts.append(UnicodeOption(type_, '', infos)) + # elif infos == None: + # pass + # else: + # for index, info in enumerate(infos): + # optstype = [] + # for key, val in info.items(): + # if key == 'type': + # optstype.append(ChoiceOption(key, '', ('form', 'custom', 'external'), unicode(val))) + # elif isinstance(val, list): + # lst = [] + # for val_ in val: + # lst.append(unicode(val_['name'])) + # if lst != []: + # optstype.append(UnicodeOption(key, '', default=lst, default_multi=lst[0], multi=True)) + # else: + # optstype.append(UnicodeOption(key, '', unicode(val))) + + # opts.append(OptionDescription(type_[:-1] + str(index), '', optstype)) + # objactions.append(OptionDescription(str(normalize_family(name_family)), name_family, opts)) + + descr = OptionDescription('actions', 'actions', objactions) + return descr + + def gen_paths(self, namespace): + if namespace in self.paths: + return self.paths[namespace] + paths = {} + all_slaves = {} + for master, slaves in self.groups.items(): + for slave in slaves: + all_slaves[slave] = master + for fname, fdata in self.families.items(): + for vname in fdata['vars']: + if vname in self.groups: + paths[vname] = '{0}.{1}.{2}.{2}'.format(namespace, + fname, vname) + else: + if vname in all_slaves: + paths[vname] = '{0}.{1}.{2}.{3}'.format( + namespace, fname, all_slaves[vname], vname) + else: + paths[vname] = '{0}.{1}.{2}'.format(namespace, + fname, vname) + self.paths[namespace] = paths + return paths + + def update_requires(self, values, namespace, option=False): + """ + replace variable name with paths in self.requires + """ + force_properties = [] + requires = [] + for value in values: + try: + if not '.' in value[0]: + ns = 'creole' + #path without namespace + path = '.'.join(self.paths[ns][value[0]].split('.')[1:]) + else: + ns = namespace + path = '.'.join(value[0].split('.')[1:]) + opt = self.options[ns][path] + except KeyError: + if self.fallback[value[0]]: + force_properties.append(value[2]) + continue + else: + raise Exception(_(u"Condition using unexistent variable {0} as parameter.").format(value[0])) + val = value[1] + if opt['obj'] is ChoiceOption: + if val not in opt['args']['values']: + if value[3]: + force_properties.append(value[2]) + else: + continue + val = convert_tiramisu_value(val, opt['obj']) + if option: + ropt = self._get_option(ns, path) + else: + ropt = (ns, value[0]) + + requires.append({'option': ropt, 'expected': val, 'action': value[2], 'inverse': value[3]}) + return force_properties, requires + + def _populate_requires(self, namespace): + for vname, values in self.requires['variable'].items(): + try: + if not '.' in vname: + ns = 'creole' + #path without namespace + path = '.'.join(self.paths[ns][vname].split('.')[1:]) + else: + ns = namespace + path = '.'.join(vname.split('.')[1:]) + opt = self.options[ns][path] + except KeyError: + if values['optional']: + continue + raise Exception(_(u"Condition targetting unexistent variable {0}").format(vname)) + props, req = self.update_requires(values['list'], namespace) + if props != []: + if opt['args']['requires'] is not None: + raise Exception(_(u'requires already set for this option preventing changing properties {0}').format(vname)) + opt['args']['properties'] = tuple(list(opt['args']['properties']) + props) + else: + if opt['args']['requires'] is not None: + raise Exception(_(u'requires already set for this option {0}').format(vname)) + #if force_store_value is set, remove force_default_on_freeze #7854 + if 'force_store_value' in opt['args']['properties']: + new_rep = [] + for nreq in req: + if nreq['action'] != 'force_default_on_freeze': + new_rep.append(nreq) + req = new_rep + opt['args']['requires'] = req + calc_properties = set() + for r in req: + calc_properties.add(r['action']) + opt['args']['properties'] = tuple(set(opt['args']['properties']) - calc_properties) + + def _get_option(self, namespace, vname): + option = self.options[namespace][vname] + if option['option'] is None: + if option['optiontype'] == 'option': + if option['args']['requires'] is not None: + for require in option['args']['requires']: + name = require['option'][1] + if "." in name: + path = name + else: + path = self.paths[namespace][require['option'][1]] + path = '.'.join(path.split('.')[1:]) + require['option'] = self._get_option(require['option'][0], path) + if 'callback_params' in option['args'] and option['args']['callback_params'] is not None: + new_call_params = option['args']['callback_params'] + for key, callback_params in option['args']['callback_params'].items(): + new_cp = [] + for callback_param in callback_params: + if isinstance(callback_param, tuple) and len(callback_param) == 2: + path = callback_param[0][1] + if '.' not in path: + path = '.'.join(self.paths['creole'][path].split('.')[1:]) + new_cp.append((self._get_option(callback_param[0][0], path), callback_param[1])) + else: + new_cp.append(callback_param) + new_call_params[key] = tuple(new_cp) + option['args']['callback_params'] = new_call_params + opt = option['obj'](**option['args']) + elif option['optiontype'] == 'optiondescription': + children = [] + for child in option['args']['children']: + children.append(self._get_option(namespace, child)) + option['args']['children'] = children + if option['args']['requires'] is not None: + for require in option['args']['requires']: + opt_name = require['option'][1] + if '.' not in opt_name: + path = '.'.join(self.paths['creole'][opt_name].split('.')[1:]) + require['option'] = self._get_option(require['option'][0], path) + opt = OptionDescription(**option['args']) + if option['group_type'] == 'master': + opt.impl_set_group_type(groups.master) + elif option['group_type'] == 'family': + opt.impl_set_group_type(groups.family) + else: + raise Exception('Unknown group {}'.format(option['group_type'])) + elif option['optiontype'] == 'symlinkoption': + sym_path = option['path'].split('.') + sym_opt = self._get_option(sym_path[0], '.'.join(sym_path[1:])) + option['args']['opt'] = sym_opt + opt = option['obj'](**option['args']) + else: + raise Exception('unknown type {0}'.format(option['optiontype'])) + try: + for key, info in self.options[namespace][vname]['informations'].items(): + opt.impl_set_information(key, info) + except KeyError: + pass + self.options[namespace][vname]['option'] = opt + return self.options[namespace][vname]['option'] + + def _gen_consistencies(self, namespace): + for vname, params in self.consistency.items(): + path = '.'.join(self.paths[namespace][vname].split('.')[1:]) + opt = self._get_option(namespace, path) + for param in params: + dopt = [] + c_params = {} + if param[-1] == 'warning': + c_params['warnings_only'] = True + for dvdict in param[1:-1]: + dvname = dvdict['value'] + try: + path = '.'.join(self.paths[namespace][dvname].split('.')[1:]) + dopt.append(self._get_option(namespace, path)) + except KeyError: + if dvdict['optional'] != 'True': + raise Exception(_(u"Check using unexistent variable {0} as parameter.").format(dvname)) + if dvdict['hidden'] == 'False': + c_params['transitive'] = False + opt.impl_add_consistency(param[0], *dopt, **c_params) + + def _is_hidden(self, vname, vdata): + #si la variable est hidden mais pas disabled + if not vname in self.requires['variable'] and vdata['hidden']: + return True + return False + + def _is_multi(self, vname, vdata, group_master): + #if not a list + if not vdata['multi'] and (group_master == None or + (group_master != None and \ + vname not in self.groups[group_master])): + return False + return True + + def _is_mandatory(self, vname, vdata): + if vname in self.mandatory or vdata['mandatory']: + return True + return False + + def _is_auto(self, vname): + if vname in self.auto: + return True + return False + + def _gen_func(self, path, obj, callback, callback_params, namespace): + if callback_params is None: + callback_params = {} + if namespace == 'creole': + vname = path.split('.')[-1] + else: + vname = path + if vname in obj: + callback, params = obj[vname] + try: + callback = getattr(eosfunc, callback) + except AttributeError: + raise ValueError(_(u'unknown function {0} in eosfunc').format(callback)) + for param, pvalues in params.items(): + for pvalue in pvalues: + if type(pvalue) == dict: + if namespace == 'creole': + ns = 'creole' + #it's a Tiramisu's **Option**, that is, a variable + #optional could be None, False or True + if pvalue['optional'] == True and \ + pvalue['value'] not in self.variables and \ + pvalue['value'] not in self.options[namespace]: + continue + path = '.'.join(self.paths[namespace][pvalue['value']].split('.')[1:]) + if not path in self.options[namespace]: + if self.is_lint: + return None, {} + else: + raise Exception(_(u"Variable computing function" + u" using unknown variable " + u"{0}").format(pvalue['value'])) + else: + #Support extra + try: + # when we don't deal with the 'creole' namespace + # the pvalues are paths, ex: schedule.bacula.day + if namespace != 'creole' and not '.' in pvalue['value']: + ns = 'creole' + else: + ns = namespace + except KeyError: + raise Exception(_(u"Variable computing function" + u" using unknown variable " + u"{0}").format(pvalue['value'])) + callback_params.setdefault(param, []).append(((ns, pvalue['value']), + pvalue['check_disabled'])) + else: + callback_params.setdefault(param, []).append(pvalue) + normalize_callback_params = {} + for callback_name, parameters in callback_params.items(): + normalize_callback_params[callback_name] = tuple(parameters) + return callback, normalize_callback_params + + def _gen_callback(self, namespace): + for path, option in self.options[namespace].items(): + if option['optiontype'] != 'option': + continue + callback = None + callback_params = {} + if namespace != 'creole': + path = namespace + '.' + path + callback, callback_params = self._gen_func(path, self.fill, callback, + callback_params, namespace) + callback, callback_params = self._gen_func(path, self.auto, callback, + callback_params, namespace) + #pas de callback_params => None + if callback_params == {}: + callback_params = None + if callback is not None: + option['args']['callback'] = callback + option['args']['callback_params'] = callback_params + + + def _gen_check(self, namespace): + for path, option in self.options[namespace].items(): + validator = self._gen_func(path, self.check, None, None, namespace=namespace) + if validator[0] is not None: + option['args']['validator'] = validator[0] + if validator[1] is not None: + option['args']['validator_params'] = validator[1] + + def _gen_option(self, fname, vname, vdata, group_master, family_mode, namespace, goptions): + """ + generate an option with given information + + :vname: variable name + :vdata: variable informations load in XML file + :group_master: name of master + """ + informations = {} + #FIXME master_slaves + if group_master is not None: + path = '.'.join([fname, group_master, vname]) + else: + path = '.'.join([fname, vname]) + + if namespace == 'creole': + cname = vname + else: + cname = namespace + '.' + path + has_callback = cname in self.fill or cname in self.auto + if not has_callback: + value = vdata['value'] + else: + value = None + multi = self._is_multi(vname, vdata, group_master) + if value != None and multi and type(value) != list: + value = [value] + default_multi = None + if multi and value is not None and vname != group_master: + default_multi = value[0] + #il n'y a pas de valeur pour les esclaves + if value is not None and self._is_a_masterslave(vname, group_master): + if len(value) != 1: + # exception à la règle pas d'esclave pour maître sans valeur + # certains dictionnaires définissent une valeur esclave + # par défaut : on tolère une et une seule valeur. + raise Exception(_(u"Slave value length can not be greater " + u"than 1.")) + if vname != group_master: + value = [] + if vdata['description'] is None: + doc = vname + else: + doc = vdata['description'] + args = {'name': vname, 'doc': doc, + 'multi': multi} + #args['callback'], args['callback_params'] = self._gen_callback(path, paths, namespace) + args['properties'] = self._gen_properties(vname, value, vdata, + has_callback, family_mode, + default_multi, group_master, + goptions, namespace, path) + is_choiceoption = False + ovalue = None + if namespace == 'creole': + valid_enum_path = vname + else: + valid_enum_path = namespace + '.' + path + valid_enum_path = vname + if self.valid_enum.has_key(valid_enum_path): + valid_enum = self.valid_enum[valid_enum_path] + ovalue = valid_enum[0][0] + open_values = valid_enum[1] + if open_values: + informations['proposed_value'] = tuple(valid_enum[0]) + else: + obj = ChoiceOption + olist = tuple(valid_enum[0]) + forceargs = None + is_choiceoption = True + if not is_choiceoption: + obj, olist, forceargs = CONVERT_OPTION.get(vdata['type'], (None, None, None)) + if olist is not None: + ovalue = olist[0] + if obj is None: + raise Exception(_(u'Unknown type {0}').format(vdata['type'])) + #args['validator'], args['validator_params'] = self._gen_check(vname, namespace) + args['default'] = convert_tiramisu_value(value, obj) + args['default_multi'] = convert_tiramisu_value(default_multi, obj) + if olist: + args['values'] = tuple(olist) + if ovalue is not None: + #if default list dans no value + if args['default'] is None and not args['multi'] and not has_callback: + args['default'] = ovalue + #if value but not in list + if args['default'] != None and args['multi'] and type(args['default']) != list: + args['default'] = [args['default']] + if forceargs is not None: + args.update(forceargs) + if vname in self.helps['variables']: + informations['help'] = self.helps['variables'][vname] + if vname in self.separators: + informations['separator'] = self.separators[vname] + args['requires'] = None + option = {'optiontype': 'option', 'obj': obj, 'args': args, + 'informations': informations, 'option': None} + self.options[namespace][path] = option + return path + + def _gen_master_group(self, namespace, fname, group_master, goptions): + path = '.'.join((fname, group_master)) + properties = [] + mode = False + for mode in modes_level: + if mode in self.options[namespace][goptions[0]]['args']['properties']: + properties.append(mode) + mode = True + if not mode: + properties.append(modes_level[1]) + self.options[namespace][path] = {'optiontype': 'optiondescription', + 'args': {'name': group_master, + 'doc': 'Master {0}'.format(group_master), + 'children': goptions, + 'properties': tuple(properties), + 'requires': None}, + 'group_type': 'master', + 'option': None} + return path + + def _gen_properties(self, vname, value, vdata, has_callback, family_mode, + default_multi, group_master, goptions, namespace, path): + if self._is_hidden(vname, vdata) or self._is_auto(vname): + properties = ['hidden', 'frozen'] + #7854 + if vdata['auto_save'] is False and not self.no_auto_store: + properties.append('force_default_on_freeze') + else: + properties = [] + mode = vdata['mode'] + #mandatory variable with no value is a basic value + if self._is_mandatory(vname, vdata): + properties.append('mandatory') + if value in (None, []) and vname not in self.auto and \ + vname not in self.fill: + mode = modes_level[0] + #non mandatory variable with a value becomes mandatory (#7141) + elif value not in (None, []) or default_multi is not None: + properties.append('mandatory') + + if vdata['auto_freeze'] == True: + if self._is_auto(vname): + raise Exception(_('{0} is auto, so must not be auto_freeze or auto_save').format(vname)) + if not self.no_auto_store: + properties.extend(['auto_freeze']) + if mode != 'expert': + mode = modes_level[0] + self.force_store_vars.add(self.paths[namespace][vname]) + if vdata['auto_save'] is True: + if self._is_auto(vname): + raise Exception(_('{0} is auto, so must not be auto_freeze or auto_save').format(vname)) + if not self.no_auto_store: + properties.append('force_store_value') + if mode != 'expert': + mode = modes_level[0] + self.force_store_vars.add(self.paths[namespace][vname]) + if self._is_a_masterslave(vname, group_master) and goptions != []: + master_mode = 'normal' + for mod in self.options[namespace][goptions[0]]['args']['properties']: + if mod in modes_level: + master_mode = mod + break + if modes[mode] < modes[master_mode]: + properties.append(master_mode) + else: + properties.append(mode) + else: + if modes[mode] < modes[family_mode]: + properties.append(family_mode) + else: + properties.append(mode) + if vdata.get('disabled') == True: + properties.append('disabled') + return tuple(properties) + + def _is_a_masterslave(self, vname, group_master): + return group_master != None and (vname == group_master or + vname in self.groups[group_master]) + + def _gen_options_by_family(self, fname, fdata, namespace): + #if var is in a group + options = [] + family_mode = fdata['mode'] + slaves = [] + for vname, vdata in fdata['vars'].items(): + goptions = [] + if vname in self.groups: + slaves.extend(self.groups[vname]) + goptions.append(self._gen_option(fname, vname, vdata, vname, family_mode, namespace, goptions)) + for sname in self.groups[vname]: + sdata = fdata['vars'][sname] + goptions.append(self._gen_option(fname, sname, sdata, vname, family_mode, namespace, goptions)) + options.append(self._gen_master_group(namespace, fname, vname, goptions)) + elif vname in slaves: + pass + else: + options.append(self._gen_option(fname, vname, vdata, None, family_mode, namespace, goptions)) + #family + fname = unicode.encode(unicode(fname), 'utf-8') + properties = [fdata['mode']] + if fname in self.requires['family']: + props, req = self.update_requires(self.requires['family'][fname]['list'], namespace) + if props != []: + properties.extend(props) + requires = None + else: + requires = req + else: + requires = None + if fdata['hidden'] == True: + #if hidden_if_in or hidden_if_not_in for this family, don't + #hidden family + hide = True + for var, val, act, inv in self.requires['family'].get(fname, {'list': []})['list']: + if act == 'disabled': + hide = False + break + if hide: + properties.append('hidden') + + informations = {} + if 'icon' in fdata: + informations['icon'] = fdata['icon'] + if fname in self.helps['families']: + informations['help'] = self.helps['families'][fname] + family = {'optiontype': 'optiondescription', + 'args': {'name': fname, 'doc': fdata['doc'], + 'children': options, 'requires': requires, + 'properties': tuple(properties), + 'requires': requires}, + 'group_type': 'family', + 'informations': informations, + 'option': None} + self.options[namespace][fname] = family + return fname + + def _gen_descr(self, namespace): + is_creole_constrainte = 'gen_files' in dir(self) + paths = self.gen_paths(namespace) + if namespace == 'creole': + flist = [self.gen_containers_creole(paths, namespace)] + else: + flist = [] + for fname in self.requires['family']: + if fname not in self.families and not self.requires['family'][fname]['optional']: + raise Exception(_(u'Unknown family {0} has requires').format(fname)) + for fname, fdata in self.families.items(): + flist.append(self._gen_options_by_family(fname, fdata, namespace)) + self.families = {} + self._populate_requires(namespace) + self._gen_callback(namespace) + self._gen_check(namespace) + self._gen_consistencies(namespace) + options = [] + for fl in flist: + options.append(self._get_option(namespace, fl)) + + self.space.append(OptionDescription(namespace, '', options)) + if namespace == 'creole' and is_creole_constrainte: + containers = self.gen_container(paths, namespace='containers') + self.space.append(OptionDescription('containers', '', + containers)) + + def get_config(self): + if self._config is None: + if self.actions != {}: + self.space.append(self.gen_actions()) + descr = OptionDescription('baseconfig', 'baseconfigdescr', + self.space) + self._config = Config(descr) + self._config.impl_set_information('force_store_vars', self.force_store_vars) + self._config.impl_set_information('force_store_values', list(self.force_store_vars)) + self._config.cfgimpl_get_settings().remove('hidden') + _modes = list(modes_level) + _modes.append('hidden') + self._config.cfgimpl_get_settings().setpermissive(tuple(_modes)) + return self._config + + def get_real_container_name(self, containers, cont): + while containers[cont]['group'] != cont: + cont = containers[cont]['group'] + return cont diff --git a/creole/wpkg_secrets.py b/creole/wpkg_secrets.py new file mode 100644 index 0000000..8e9ed54 --- /dev/null +++ b/creole/wpkg_secrets.py @@ -0,0 +1,67 @@ +#! /usr/bin/env python +# -*- coding: UTF-8 -*- + + +import base64 + +KEY_LENGTH = 40 +KEYS = [ + 0x50, + 0xF7, + 0x82, + 0x69, + 0xEA, + 0x2D, + 0xDD, + 0x2D, + 0x6A, + 0xB4, + 0x33, + 0x8F, + 0xD5, + 0xC7, + 0x90, + 0x9C, + 0x22, + 0x95, + 0x61, + 0xE5, + 0x65, + 0xF6, + 0xB0, + 0x4B, + 0x94, + 0x47, + 0xB0, + 0xBD, + 0x73, + 0x58, + 0x56, + 0x87, + 0x79, + 0x7B, + 0xE6, + 0xB0, + 0xD2, + 0x20, + 0x28, + 0xE1 +] + +def bitwise(s): + res = '' + idx = 0 + for i in range(len(s)): + res += chr(ord(s[i]) ^ KEYS[idx]) + idx+=1 + if idx > (KEY_LENGTH - 1): + idx = 0 + return res + +def wcrypt(s): + s = bitwise(s) + return base64.encodestring(s)[:-1] # encodestring renvoie la chaine avec un '\n', on le vire + +def wdecrypt(s): + s = base64.decodestring(s) + return bitwise(s) diff --git a/creole/xml_compare.py b/creole/xml_compare.py new file mode 100644 index 0000000..9c06e85 --- /dev/null +++ b/creole/xml_compare.py @@ -0,0 +1,161 @@ +try: + import doctest + doctest.OutputChecker +except (AttributeError, ImportError): # Python < 2.4 + import util.doctest24 as doctest +try: + import xml.etree.ElementTree as ET +except ImportError: + import elementtree.ElementTree as ET +from xml.parsers.expat import ExpatError as XMLParseError + +RealOutputChecker = doctest.OutputChecker + + +def debug(*msg): + import sys + print >> sys.stderr, ' '.join(map(str, msg)) + + +class HTMLOutputChecker(RealOutputChecker): + + def check_output(self, want, got, optionflags): + normal = RealOutputChecker.check_output(self, want, got, optionflags) + if normal or not got: + return normal + try: + want_xml = make_xml(want) + except XMLParseError: + pass + else: + try: + got_xml = make_xml(got) + except XMLParseError: + pass + else: + if xml_compare(want_xml, got_xml): + return True + return False + + def output_difference(self, example, got, optionflags): + actual = RealOutputChecker.output_difference( + self, example, got, optionflags) + want_xml = got_xml = None + try: + want_xml = make_xml(example.want) + want_norm = make_string(want_xml) + except XMLParseError as e: + if example.want.startswith('<'): + want_norm = '(bad XML: %s)' % e + # '%s' % example.want + else: + return actual + try: + got_xml = make_xml(got) + got_norm = make_string(got_xml) + except XMLParseError as e: + if example.want.startswith('<'): + got_norm = '(bad XML: %s)' % e + else: + return actual + s = '%s\nXML Wanted: %s\nXML Got : %s\n' % ( + actual, want_norm, got_norm) + if got_xml and want_xml: + result = [] + xml_compare(want_xml, got_xml, result.append) + s += 'Difference report:\n%s\n' % '\n'.join(result) + return s + + +def xml_sort(children): + tcl1 = {} + #idx = 0 + + for child in children: + if 'name' in child.attrib: + key = child.attrib['name'] + else: + key = child.tag + if key not in tcl1: + tcl1[key] = [] + tcl1[key].append(child) + cl1_keys = list(tcl1.keys()) + cl1_keys.sort() + cl1 = [] + for key in cl1_keys: + cl1.extend(tcl1[key]) + return cl1 + +def xml_compare(x1, x2): + if x1.tag != x2.tag: + print ('Tags do not match: %s and %s' % (x1.tag, x2.tag)) + return False + for name, value in x1.attrib.items(): + if x2.attrib.get(name) != value: + print ('Attributes do not match: %s=%r, %s=%r' + % (name, value, name, x2.attrib.get(name))) + return False + for name in x2.attrib: + if name not in x1.attrib: + print ('x2 has an attribute x1 is missing: %s' + % name) + return False + if not text_compare(x1.text, x2.text): + print ('text: %r != %r' % (x1.text, x2.text)) + return False + if not text_compare(x1.tail, x2.tail): + print ('tail: %r != %r' % (x1.tail, x2.tail)) + return False + + cl1 = xml_sort(x1.getchildren()) + cl2 = xml_sort(x2.getchildren()) + + if len(cl1) != len(cl2): + cl1_tags = [] + for c in cl1: + cl1_tags.append(c.tag) + cl2_tags = [] + for c in cl2: + cl2_tags.append(c.tag) + print ('children length differs, %i != %i (%s != %s)' + % (len(cl1), len(cl2), cl1_tags, cl2_tags)) + return False + i = 0 + for c1, c2 in zip(cl1, cl2): + i += 1 + if not xml_compare(c1, c2): + if 'name' in c1.attrib: + name = c1.attrib['name'] + else: + name = i + print ('in tag "%s" with name "%s"' + % (c1.tag, name)) + return False + return True + + +def text_compare(t1, t2): + if not t1 and not t2: + return True + if t1 == '*' or t2 == '*': + return True + return (t1 or '').strip() == (t2 or '').strip() + + +def make_xml(s): + return ET.XML('%s' % s) + + +def make_string(xml): + if isinstance(xml, (str, unicode)): + xml = make_xml(xml) + s = ET.tostring(xml) + if s == '': + return '' + assert s.startswith('') and s.endswith(''), repr(s) + return s[5:-6] + + +def install(): + doctest.OutputChecker = HTMLOutputChecker + diff --git a/creole/xmlreflector.py b/creole/xmlreflector.py new file mode 100644 index 0000000..4340b37 --- /dev/null +++ b/creole/xmlreflector.py @@ -0,0 +1,107 @@ +# coding: utf-8 +from os.path import join, isfile, basename, isdir +from os import listdir +from base64 import decodestring +from io import BytesIO +from collections import OrderedDict +import sys + +from lxml.etree import DTD, parse, tostring, XMLParser # pylint: disable=E0611 + +from .i18n import _ +from .utils import normalize_family +from .error import CreoleDictConsistencyError +from .config import VIRTBASE, VIRTROOT, VIRTMASTER, templatedir + +HIGH_COMPATIBILITY = True + +class XMLReflector(object): + """Helper class for loading the Creole XML file, + parsing it, validating against the Creole DTD, + writing the xml result on the disk + """ + def __init__(self): + self.dtd = None + + def parse_dtd(self, dtdfilename): + """Loads the Creole DTD + + :raises IOError: if the DTD is not found + + :param dtdfilename: the full filename of the Creole DTD + """ + if not isfile(dtdfilename): + raise IOError(_("no such DTD file: {}").format(dtdfilename)) + with open(dtdfilename, 'r') as dtdfd: + self.dtd = DTD(dtdfd) + + def parse_xmlfile(self, xmlfile, from_zephir=None, zephir2=False): + """Parses and validates some Creole XML against the Creole DTD + + :returns: the root element tree object + """ + if from_zephir: + if zephir2: + document = parse(BytesIO(xmlfile), XMLParser(remove_blank_text=True)) + else: + document = parse(BytesIO(decodestring(xmlfile)), XMLParser(remove_blank_text=True)) + else: + document = parse(xmlfile) + assert self.dtd.validate(document), _("not a valid xml file: {}").format(xmlfile) + return document.getroot() + + def load_xml_from_folders(self, xmlfolders, from_zephir): + """Loads all the XML files located in the xmlfolders' list + + :param xmlfolders: list of full folder's name + """ + documents = [] + if from_zephir: + for idx, xmlfile in enumerate(xmlfolders): + documents.append(('generate_{}'.format(idx), self.parse_xmlfile(xmlfile, from_zephir=from_zephir))) + else: + if not isinstance(xmlfolders, list): + xmlfolders = [xmlfolders] + for xmlfolder in xmlfolders: + if isinstance(xmlfolder, list) or isinstance(xmlfolder, tuple): + # directory group : collect files from each + # directory and sort them before loading + group_files = [] + for idx, subdir in enumerate(xmlfolder): + if isdir(subdir): + for filename in listdir(subdir): + group_files.append((filename, idx, subdir)) + else: + group_files.append(basename(subdir), idx, dirname(subdir)) + def sort_group(file1, file2): + if file1[0] == file2[0]: + # sort by initial xmlfolder order if same name + return file1[1].__cmp__(file2[1]) + # sort by filename + elif file1[0] > file2[0]: + return 1 + else: + return -1 + group_files.sort(sort_group) + filenames = [join(f[2], f[0]) for f in group_files] + elif isdir(xmlfolder): + filenames = [] + for filename in listdir(xmlfolder): + filenames.append(join(xmlfolder, filename)) + filenames.sort() + else: + filenames = [xmlfolder] + for xmlfile in filenames: + if xmlfile.endswith('.xml'): + #xmlfile_path = join(xmlfolder, xmlfile) + documents.append((xmlfile, self.parse_xmlfile(xmlfile))) + return documents + + def save_xmlfile(self, xmlfilename, xml): # pylint: disable=R0201 + """Write a bunch of XML on the disk + """ + with open(xmlfilename, 'w') as xmlfh: + if sys.version_info[0] < 3: + xmlfh.write(tostring(xml, pretty_print=True, encoding="UTF-8", xml_declaration=True)) + else: + xmlfh.write(tostring(xml, pretty_print=True, encoding="UTF-8", xml_declaration=True).decode('utf8')) diff --git a/data/creole.dtd b/data/creole.dtd new file mode 100644 index 0000000..1ff16ce --- /dev/null +++ b/data/creole.dtd @@ -0,0 +1,235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/diag.py b/data/diag.py new file mode 100755 index 0000000..4c85cca --- /dev/null +++ b/data/diag.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +########################################################################### +# Eole NG - 2009 +# Copyright Pole de Competence Eole (Ministere Education - Academie Dijon) +# http://eole.orion.education.fr - eole@ac-dijon.fr +# +# Licence CeCill +# cf: http://www.cecill.info/licences.fr.html +########################################################################### + +import sys +import socket +from os.path import isfile +from os import system, stat +from pyeole.httprequest import HTTPRequest +from creole.config import configeol +from creole.client import CreoleClient + +client = CreoleClient() + +# adresse IP et port du serveur d'enregistrement +server = "http://194.167.18.21/apps/AutoDiag/index.n/diagnose" +md5file = "/etc/eole/.server.MD5" +module = "%s-%s" % (client.get_creole('eole_module'), client.get_creole('eole_version')) + +def get_md5(): + """ calcul de l'identifiant md5 """ + if not isfile(md5file) or stat(md5file).st_size == 0: + system("md5sum %s | awk '{print $1}' > %s" % (configeol, md5file)) + fp = file(md5file) + return (fp.read().split()[0]) + +def get_proxy(): + """ récupération du proxy à utiliser """ + if client.get_creole('activer_proxy_client') == 'oui': + return "http://{0}:{1}".format( + client.get_creole('proxy_client_adresse'), + client.get_creole('proxy_client_port')) + return '' + +if __name__ == "__main__": + id5 = get_md5() + rne = client.get_creole('numero_etab') + data = {"ID5":id5, "module":module, "rne":rne, "dep":rne[0:3]} + socket.setdefaulttimeout(5) + proxy = get_proxy() + if proxy != '': + # essai avec proxy + try: + req = HTTPRequest(proxy={'http':proxy}) + req.request(server, post_datas=data) + except: + pass + else: + sys.exit(0) + # essai sans proxy + try: + req = HTTPRequest() + req.request(server, post_datas=data) + except: + sys.exit(1) + else: + sys.exit(0) diff --git a/data/funcs/__init__.py b/data/funcs/__init__.py new file mode 100644 index 0000000..5f83389 --- /dev/null +++ b/data/funcs/__init__.py @@ -0,0 +1,2 @@ +"""Module de fonctions supplémentaires accessibles à creole. Tous les fichiers python +contenus dans ce répertoire sont lus par le module eosfunc de creole""" diff --git a/data/gen_certif.py b/data/gen_certif.py new file mode 100755 index 0000000..18038f7 --- /dev/null +++ b/data/gen_certif.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- +""" +script de generation d'un certificat ssl +prend un nom de fichier facultatif en argument (destination du certificat) + +usage:: + + soit + %prog (-fc) [nom_certif] + soit + %prog (-f) + + si [nom_certif] non renseigne, regenere tous les certificats par defaut ainsi que la ca locale. + Sinon, ne genere que [nom_certif] + + -f :force la regeneration du (ou des) certificat(s) s'il(s) existe(nt) + -c : dans le cas de la generation d'un seul certificat, on copie la clef + +""" +import sys, os +from optparse import OptionParser + +from creole import cert +from pyeole.encode import normalize + +def parse_command_line(): + parser = OptionParser(__doc__) + parser.add_option("-c", + action="store_true", dest="copy", default=False, + help="copie de la clef") + + parser.add_option("-f", + action="store_true", dest="regen", default=False, + help="force la regeneration de la clef") + + options, args = parser.parse_args() + if len(args) > 1: + parser.error("Il faut au maximum un certificat") + return options, args + +options, args = parse_command_line() + +regen = options.regen +copy = options.copy + +if len(args) == 1: + certfile = args[0] +else: + certfile = None + +try: + cert.rehash_if_needed() + if certfile != None: + certfile = os.path.abspath(certfile) + dest_dir = os.path.dirname(certfile) + if not os.path.isdir(dest_dir): + print "Répertoire de destination inexistant (%s)" % dest_dir + sys.exit(1) + print "Generation du certificat machine" + cert.gen_certif(certfile, regen=regen, copy_key=copy) + else: + # génération de tous les certificats (CA, eole, scribe...) + cert.gen_certs(regen=regen) + sys.exit(0) +except Exception, err: + print "Erreur : " + print u'{0}'.format(normalize(err)) + sys.exit(1) diff --git a/data/testpatches.py b/data/testpatches.py new file mode 100755 index 0000000..90da6c9 --- /dev/null +++ b/data/testpatches.py @@ -0,0 +1,26 @@ +#! /usr/bin/env python +# -*- coding: UTF-8 -*- +""" +Test des patches pour diagnose +réutilisation du code de zephir-client +""" +import sys +from glob import glob +from os.path import basename +from creole import utils +from creole.config import patch_dir +from zephir.monitor.agents import patches +from os.path import join + +patchs = glob(join(patch_dir, '*.patch')) +patchs.extend(glob(join(patch_dir, 'variante', '*.patch'))) +err = [] +for patch in patchs: + verif = patches.verify_patch(patch).values() + if len(verif) > 0 and len(verif[0]) > 0: + err.append(basename(patch)) +if len(err) != 0: + utils.print_red('Erreur') + print "fichiers : %s" % (", ".join(err),) +else: + utils.print_green('Ok') diff --git a/deprecated/FonctionsEoleNg b/deprecated/FonctionsEoleNg new file mode 100755 index 0000000..79898fa --- /dev/null +++ b/deprecated/FonctionsEoleNg @@ -0,0 +1,10 @@ +#!/bin/sh + +echo "La bibliothèque shell FonctionsEoleNg ne doit plus être utilisée." >&2 +if [ -n "${0}" ] +then + echo "Merci de corriger le code de '${0}'" >&2 +fi +echo '' +echo "Voir la documentation http://dev-eole.ac-dijon.fr/projects/eole/wiki/PrepareEOLE24" >&2 +exit 255 diff --git a/doc/api/epydoc.css b/doc/api/epydoc.css new file mode 100644 index 0000000..46080bd --- /dev/null +++ b/doc/api/epydoc.css @@ -0,0 +1,100 @@ + +/* Body color */ +body { background: #ffffff; color: #000000; } + +/* Tables */ +table.summary, table.details, table.index + { background: #e8f0f8; color: #000000; } +tr.summary, tr.details, tr.index + { background: #70b0f0; color: #000000; + text-align: left; font-size: 120%; } +tr.group { background: #c0e0f8; color: #000000; + text-align: left; font-size: 120%; + font-style: italic; } + +/* Documentation page titles */ +h2.module { margin-top: 0.2em; } +h2.class { margin-top: 0.2em; } + +/* Headings */ +h1.heading { font-size: +140%; font-style: italic; + font-weight: bold; } +h2.heading { font-size: +125%; font-style: italic; + font-weight: bold; } +h3.heading { font-size: +110%; font-style: italic; + font-weight: normal; } + +/* Base tree */ +pre.base-tree { font-size: 80%; margin: 0; } + +/* Details Sections */ +table.func-details { background: #e8f0f8; color: #000000; + border: 2px groove #c0d0d0; + padding: 0 1em 0 1em; margin: 0.4em 0 0 0; } +h3.func-detail { background: transparent; color: #000000; + margin: 0 0 1em 0; } + +table.var-details { background: #e8f0f8; color: #000000; + border: 2px groove #c0d0d0; + padding: 0 1em 0 1em; margin: 0.4em 0 0 0; } +h3.var-details { background: transparent; color: #000000; + margin: 0 0 1em 0; } + +/* Function signatures */ +.sig { background: transparent; color: #000000; + font-weight: bold; } +.sig-name { background: transparent; color: #006080; } +.sig-arg, .sig-kwarg, .sig-vararg + { background: transparent; color: #008060; } +.sig-default { background: transparent; color: #602000; } +.summary-sig { background: transparent; color: #000000; } +.summary-sig-name { background: transparent; color: #204080; } +.summary-sig-arg, .summary-sig-kwarg, .summary-sig-vararg + { background: transparent; color: #008060; } + +/* Doctest blocks */ +.py-src { background: transparent; color: #000000; } +.py-prompt { background: transparent; color: #005050; + font-weight: bold;} +.py-string { background: transparent; color: #006030; } +.py-comment { background: transparent; color: #003060; } +.py-keyword { background: transparent; color: #600000; } +.py-output { background: transparent; color: #404040; } +pre.doctestblock { background: #f4faff; color: #000000; + padding: .5em; margin: 1em; + border: 1px solid #708890; } +table pre.doctestblock + { background: #dce4ec; color: #000000; + padding: .5em; margin: 1em; + border: 1px solid #708890; } + +/* Variable values */ +pre.variable { background: #dce4ec; color: #000000; + padding: .5em; margin: 0; + border: 1px solid #708890; } +.variable-linewrap { background: transparent; color: #604000; } +.variable-ellipsis { background: transparent; color: #604000; } +.variable-quote { background: transparent; color: #604000; } +.re { background: transparent; color: #000000; } +.re-char { background: transparent; color: #006030; } +.re-op { background: transparent; color: #600000; } +.re-group { background: transparent; color: #003060; } +.re-ref { background: transparent; color: #404040; } + +/* Navigation bar */ +table.navbar { background: #a0c0ff; color: #0000ff; + border: 2px groove #c0d0d0; } +th.navbar { background: #a0c0ff; color: #0000ff; } +th.navselect { background: #70b0ff; color: #000000; } +.nomargin { margin: 0; } + +/* Links */ +a:link { background: transparent; color: #0000ff; } +a:visited { background: transparent; color: #204080; } +a.navbar:link { background: transparent; color: #0000ff; + text-decoration: none; } +a.navbar:visited { background: transparent; color: #204080; + text-decoration: none; } + +/* Lists */ +ul { margin-top: 0; } diff --git a/doc/certifs.txt b/doc/certifs.txt new file mode 100644 index 0000000..53fca31 --- /dev/null +++ b/doc/certifs.txt @@ -0,0 +1,60 @@ +génération des certificats +========================== + +mode opératoire + + +au premier lancement de ``gen_certif.py`` +------------------------------------------ + +- vérifie l'existence d'une CA ou non +- génère la CA +- génère les certificats par défaut (clef privée, requète de certificat) +- signature des certificats + +aux lancements ultérieurs +------------------------- + + +- vérifie l'existence d'une CA ou non +- génère le certificat passé en argument + +:: + + gen_certif.py (-f) [nom_certif] + + si [nom_certif] non renseigné, regénère tous les certificats par défaut + ainsi que la CA locale. Sinon, ne génère que [nom_certif] + -f :force la regénération du (ou des) certificat(s) s'il(s) existe(nt) + + +``regen`` + + attribut permettant de forcer (ou pas) la regénération + si ``regen==True`` alors les cerficats sont regénérés même s'ils existent + si ``regen==False`` alors les cerficats ne sont générés que s'ils + n'existent pas. + +api +---- + +- génération d'un seul certificat : + +``cert.gen_certif(certfile,regen=regen, copy_key=copy)`` + + +- génération de tous les certificats : + +``cert.gen_certs(regen=regen)`` + + + +:: + + gen_certs() + |-> gen_ca() + |-> certif_loader() + |-> gen_certif() + |-> finalise_certs() + + diff --git a/doc/clean.sh b/doc/clean.sh new file mode 100755 index 0000000..9a48f15 --- /dev/null +++ b/doc/clean.sh @@ -0,0 +1,2 @@ +rm -f *.html +rm -f api/*.html diff --git a/doc/commande.txt b/doc/commande.txt new file mode 100644 index 0000000..affea64 --- /dev/null +++ b/doc/commande.txt @@ -0,0 +1,15 @@ + + +process +------- + +- point d'entrée : `process.py` méthode *run()* +- lecture des fichiers dictionnaires *xml* +- lecture du fichier */etc/eole/config.eol* pour remplir l'objet + dictionnaire + + +mapping avec la ligne de commande +--------------------------------- + +.. TODO \ No newline at end of file diff --git a/doc/default.css b/doc/default.css new file mode 100644 index 0000000..e149019 --- /dev/null +++ b/doc/default.css @@ -0,0 +1,377 @@ +/* +:Author: David Goodger +:Contact: goodger at users.sourceforge.net +:date: $Date: 2004/11/11 23:11:44 $ +:version: $Revision: 1.1 $ +:copyright: This stylesheet has been placed in the public domain. + +Default cascading style sheet for the HTML output of Docutils. +*/ + +/* "! important" is used here to override other ``margin-top`` and + ``margin-bottom`` styles that are later in the stylesheet or + more specific. See . */ + +html, body { + margin: 0; + padding: 0; +} + +body { + font-family: Georgia, arial, sans-serif; + padding: 3em; +} + +h1 { + font-size: 130%; +} + +h2 { + font-size: 110%; +} + +blockquote { + width: 70%; + margin: 2em auto; + padding: 1em; + background-color: #FFEEEE; + border: 1px solid #EEDDDD; + text-align: left; +} + +.title { + font-size: 180%; +} + +.subtitle { + font-size: 100%; +} + +.first { + margin-top: 0 ! important } + +.last { + margin-bottom: 0 ! important } + +.hidden { + display: none } + +a.toc-backref { + text-decoration: none ; + color: black } + +blockquote.epigraph { + margin: 2em 5em ; } + +dd { + margin-bottom: 0.5em } + +/* Uncomment (& remove this text!) to get bold-faced definition list terms +dt { + font-weight: bold } +*/ + +div.abstract { + margin: 2em 5em } + +div.abstract p.topic-title { + font-weight: bold ; + text-align: center } + +div.admonition, div.attention, div.caution, div.danger, div.error, +div.hint, div.important, div.note, div.tip, div.warning { + margin: 2em ; + border: medium outset ; + padding: 1em } + +div.admonition p.admonition-title, div.hint p.admonition-title, +div.important p.admonition-title, div.note p.admonition-title, +div.tip p.admonition-title { + font-weight: bold ; + font-family: sans-serif } + +div.attention p.admonition-title, div.caution p.admonition-title, +div.danger p.admonition-title, div.error p.admonition-title, +div.warning p.admonition-title { + color: red ; + font-weight: bold ; + font-family: sans-serif } + +div.compound .compound-first, div.compound .compound-middle { + margin-bottom: 0.5em } + +div.compound .compound-last, div.compound .compound-middle { + margin-top: 0.5em } + +div.dedication { + margin: 2em 5em ; + text-align: center ; + font-style: italic } + +div.dedication p.topic-title { + font-weight: bold ; + font-style: normal } + +div.figure { + margin-left: 2em } + +div.footer, div.header { + font-size: smaller } + +div.line-block { + display: block ; + margin-top: 1em ; + margin-bottom: 1em } + +div.line-block div.line-block { + margin-top: 0 ; + margin-bottom: 0 ; + margin-left: 1.5em } + +div.sidebar { + margin-left: 1em ; + border: medium outset ; + padding: 0em 1em ; + background-color: #ffffee ; + width: 40% ; + float: right ; + clear: right } + +div.sidebar p.rubric { + font-family: sans-serif ; + font-size: medium } + +div.system-messages { + margin: 5em } + +div.system-messages h1 { + color: red } + +div.system-message { + border: medium outset ; + padding: 1em } + +div.system-message p.system-message-title { + color: red ; + font-weight: bold } + +div.topic { + margin: 2em } + +h1.title { + text-align: center } + +h2.subtitle { + text-align: center } + +hr { + width: 75% } + +ol.simple, ul.simple { + margin-bottom: 1em } + +ol.arabic { + list-style: decimal } + +ol.loweralpha { + list-style: lower-alpha } + +ol.upperalpha { + list-style: upper-alpha } + +ol.lowerroman { + list-style: lower-roman } + +ol.upperroman { + list-style: upper-roman } + +p.attribution { + text-align: right ; + margin-left: 50% } + +p.caption { + font-style: italic } + +p.credits { + font-style: italic ; + font-size: smaller } + +p.label { + white-space: nowrap } + +p.rubric { + font-weight: bold ; + font-size: larger ; + color: maroon ; + text-align: center } + +p.sidebar-title { + font-family: sans-serif ; + font-weight: bold ; + font-size: larger } + +p.sidebar-subtitle { + font-family: sans-serif ; + font-weight: bold } + +p.topic-title { + font-weight: bold } + +pre.address { + margin-bottom: 0 ; + margin-top: 0 ; + font-family: serif ; + font-size: 100% } + +pre.line-block { + font-family: serif ; + font-size: 100% } + +.literal { + color: #333; + background-color: #EEE; +} + +pre.literal-block, pre.doctest-block { + margin-left: 2em ; + margin-right: 2em ; + padding: 1em; + color: #333; + background-color: #EEE;} + +span.classifier { + font-family: sans-serif ; + font-style: oblique } + +span.classifier-delimiter { + font-family: sans-serif ; + font-weight: bold } + +span.interpreted { + font-family: sans-serif } + +span.option { + white-space: nowrap } + +span.option-argument { + font-style: italic } + +span.pre { + white-space: pre } + +span.problematic { + color: red } + +table { + margin-top: 0.5em ; + margin-bottom: 0.5em } + +table.citation { + border-left: solid thin gray } + +table.docinfo { + margin: 2em 4em } + +table.footnote { + border-left: solid thin black } + +td, th { + padding-left: 0.5em ; + padding-right: 0.5em ; + vertical-align: top } + +th.docinfo-name, th.field-name { + font-weight: bold ; + text-align: left ; + white-space: nowrap } + +h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { + font-size: 100% } + +tt { + background-color: #eeeeee +} + +ul.auto-toc { + list-style-type: none } + +.code-block { + font-family: Courier New, Courier, monospace; + font-size: 14px; + margin: 0 2em; + padding: 1em; + color: #000; + background-color: #EEE; + border: 1px solid #DDD; +} + +/* Python markup *********************************************/ +/*Python keyword*/ +.p_word { + color: #036; +} +/*Python identifier*/ +.p_identifier { + color: #36C; +} +/*Python number*/ +.p_number { + color: #36C; +} +/*other text*/ +.p_default { + color: #036; +} +/*Python operator*/ +.p_operator { + color: #036; +} +/*Python comment*/ +.p_commentline { + color: #036; +} +/*function name*/ +.p_defname { + color: #F63; + font-weight: bold; +} +/*class name*/ +.p_classname { + color: #F00; + font-weight: bold; +} +/*string literals*/ +.p_character { + color: green; +} +/*string literals*/ +.p_string { + color: green; +} +/*triple-quoted strings*/ +.p_triple { + color: green; +} + +/* HTML markup *********************************************/ +/*an html tag*/ +.h_tag { + color: #36C; +} +/*text in a tag*/ +.h_default { + color: #036; +} +/*attribute name*/ +.h_attribute { + color: #6C3; +} +/*a double-quoted attribute value*/ +.h_doublestring { + color: green; +} +/*attribute equals sign, for example*/ +.h_other { + color: #036; +} + diff --git a/doc/docutils.sh b/doc/docutils.sh new file mode 100755 index 0000000..6fadabc --- /dev/null +++ b/doc/docutils.sh @@ -0,0 +1 @@ +buildhtml.py --embed --stylesheet default.css --output-encoding iso-8859-1 --prune .svn --prune api/ --prune pydoctor --prune data . diff --git a/doc/epydoc.sh b/doc/epydoc.sh new file mode 100755 index 0000000..7623680 --- /dev/null +++ b/doc/epydoc.sh @@ -0,0 +1,3 @@ +cd ../creole +epydoc --html --no-private --output ../doc/api . + diff --git a/doc/template.txt b/doc/template.txt new file mode 100644 index 0000000..4fbb5e9 --- /dev/null +++ b/doc/template.txt @@ -0,0 +1,57 @@ +Templates crole +================ + +comportement des templates +-------------------------- + +Template_ + +.. _Template: api/creole.template.Template-class.html + +validations +----------- + +Template.verify_ + +.. _Template.verify: api/creole.template.Template-class.html#verify + + + +fichiers cibles + fichiers modle qui vont tre instancis au final (fichier destination) + + +- le fichier source (templatis) *doit* exister ainsi que le + fichier de destination (le fichier de configuration effectif) + portant le mme nom : + +- le fichier cible, c'est--dire le fichier de configuration + instanci, doit tre prsent + + +>>> import creole +>>> from creole.template import Template + +>>> try: +... t = Template('nexistepas.txt', templatedir= '/tmp') +... t.verify() +... except creole.error.FileNotFound, e: +... print e +... +le fichier /tmp/nexistepas.txt n'existe pas +>>> + +.. note:: les deux vrifications (template source et fichier + destination) sont faites en mme temps + +- le rpertoire source *doit* exister + +>>> try: +... t = Template('/etc/group', templatedir= '/reperoire/qui/n/existe/pas') +... t.verify() +... except creole.error.FileNotFound, e: +... print e +... +le fichier /reperoire/qui/n/existe/pas/group n'existe pas +>>> + diff --git a/doc/utils.txt b/doc/utils.txt new file mode 100644 index 0000000..67a38f3 --- /dev/null +++ b/doc/utils.txt @@ -0,0 +1,41 @@ +utilitaires techniques crole +============================= + +utilitaire de tests +------------------- + + +creolecat_ + +.. _creolecat: api/creole.creolecat-module.html + + +un utilitaire de tests est mis disposition pour ceux qui +souhaitent tester leur fichiers de template sans pour autant lancer +une instanciation: + +usage:: + + creolecat.py -x /eole.xml -o /test.txt testtemplate.tmpl + +testtemplate est le fichier instancier + +lancer l'option --help pour plus de dtails + +utilitaire de conversion +------------------------ + +conversion dans l'ancien langage de templating (notations *[%*) + +pour ceux qui avaient dj commenc leur activits de templating pour +crole 2 (donc avec une autre notation), un utilitaire de conversion +est mis disposition. +Il est dans la lib python creole et s'appelle creole2cheetah_ + +.. _creole2cheetah: api/creole.creole2cheetah-module.html + +usage : + + cd creole + [creole] ./creole2cheetah.py [nom du fichier source] > [nom du fichier destination] + diff --git a/doc/variables.txt b/doc/variables.txt new file mode 100644 index 0000000..9cde56e --- /dev/null +++ b/doc/variables.txt @@ -0,0 +1,201 @@ +Variables crole +================ + +typeole_ + +.. _typeole: api/creole.typeole-module.html + +variable crole + + instance d'un objet type eole, un nom de variable correspond + peut-tre plusieurs valeurs + +>>> from creole import typeole +>>> var = typeole.EoleVar('mavariable') +>>> var.val +[] +>>> var.set_value('valeur') +>>> var.set_value('defaut', default=True) +>>> var.val +['valeur'] +>>> var.valdefault +['defaut'] +>>> var.description = 'variable de test' +>>> var.description +'variable de test' +>>> + +il est possible de crer une variable Eole l'aide +d'une factory : + +>>> var2 = typeole.type_factory('string', 'test_string', valeole=["eole"], valdefault=["def"]) +>>> var2.get_value() +['def'] +>>> + +des vrifications de type sont faites au moment du *set_value()* + +collecte des variables crole +----------------------------- + +collecte + + Rcupration de variables qui serviront a la constitution du dictionnaire Eole + +Les donnes du dictionnaire sont collectes partir de diffrents fichiers dans un premier format XML. + +sur une machine cible, une collecte des variables eole est faite avec parse_dico_:: + + from creole.parsedico import parse_dico + parse_dico() + +.. ce test n'est pas lanc car il peut y avoir un dico sur le poste + de travail + +.. _parse_dico: api/creole.parsedico-module.html + +Le dictionnaire crole est vide. Pour le remplir, il faut +rcuprer des donnes depuis un fichier xml initial:: + + my_dict = EoleDict() + my_dict.read(join('/etc/eole/','eole.xml')) + +.. TODO: read_string(self, xml_string) + +Utilisation du dictionnaire +--------------------------- + +dictionnaire + + fichier au format xml contenant : + - une liste de fichiers + - une liste de variables + +famille + + Il s'agit d'un regroupement de variable utilis pour la saisie : on parle alors de famille de variables + +groupe + + Il s'agit de variables de type `liste` dont les lments sont lies aux lments correspondants des autres + eth[2] aura un lien avec netmask[2] et network[2]. + +Plutt que d'utiliser `parsedico`, construisons un dictionnaire creole EoleDict_ : + +>>> from creole import cfgparser +>>> from creole import typeole +>>> +>>> dico = cfgparser.EoleDict() +>>> dico.variables['ip_eth'] = typeole.type_factory('string', 'ip_eth', val=['ip0', 'ip1', 'ip2']) +>>> dico.variables['nom_etab'] = typeole.type_factory('string', 'nom_etab', val=['etab']) +>>> dico.variables['vrai'] = typeole.type_factory('boolean', 'vrai', val=[True]) +>>> dico.variables['faux'] = typeole.type_factory('string', 'faux', val=['faux']) +>>> dico.variables['toto'] = typeole.type_factory('string', 'toto', val=['toto']) + +voici comment accder aux variables crole + +>>> assert dico.get_value('ip_eth') == ['ip0', 'ip1', 'ip2'] +>>> assert dico.get_value('nom_etab') == ['etab'] + +.. _EoleDict : api/creole.cfgparser.EoleDict-class.html + + +variables de template +----------------------- + + +lorsqu'on utilise un appel de bas niveau de traitement de template, +c'est--dire l'appel direct la +mthode process_ d'un template, il faut vrifier qu'une variable +est bien instancie avec le bon contexte de dictionnaire : + +.. _process: api/creole.template.Template-class.html + +>>> from creole.cfgparser import EoleDict +>>> from creole import typeole +>>> from creole.template import Template +>>> dico = EoleDict() +>>> dico.variables['toto'] = typeole.type_factory('string', +... 'toto', val=['toto'], context=dico) +>>> t = Template('data/dst/test.tmpl', templatedir= 'data/src') +>>> t.verify() +>>> t.process(dico) +>>> f = open('data/dst/test.tmpl') +>>> res = f.read() +>>> f.close() +>>> assert 'titi' not in res +>>> dico.set_value('toto', 'titi') +>>> t.process(dico) +>>> f = open('data/dst/test.tmpl') +>>> res = f.read() +>>> f.close() +>>> assert 'titi' in res + +le contexte `dico` est pass la variable `toto`:: + + dico.variables['toto'] = typeole.type_factory('string', + 'toto', val=['toto'], context=dico) + +variables automatiques +---------------------- + +variable automatique + + variable prsente dans le dictionnaire xml mais pas dans le fichier *.ini* de configuration. + la valeur de cette variable (sont appel *.get_value()* est soumis une fonction de traitement + spcifie dans le xml, qui calcule la variable au lieu de formater sa valeur. + +Une variable automatique simple n'est pas traite diffremment d'une variable dont la valeur est prsente dans le dictionnaire et qui est soumise une condition de vrification de sa valeur. Simplement, aucune vrification n'est effectue et la valeur est calcule. + +dclaration de la variable:: + + + +dclaration de la fonction de remplissage:: + + + +deux fonctions strictement automatiques sont implmentes: `server_mem` et `kernel_version` + +variable semi-automatique + + variable remplit automatiquement dans le cas d'une condition sur une autre variable, + si cette condition n'est pas remplie, c'est l'uilisateur qui la remplit (ou une autre fonction). + la condition est traite deux niveaux, dans la fonction de remplissage, et au niveau de l'affichage. + On remplit donc deux fonctions pour ce conditionnement (une fonction fill avec la variable + conditionnante en paramtre et une fonction condition qui conditionne l'affichage de la variable. + exemple : rcupration des adresses eth dans le cas o l'on a pas de dhcp. + +dclaration de la variable semi-auto:: + + + +dclaration de la variable qui dfinit la condition:: + + + non + + + ['oui','non'] + + +dclaration de la fonction de contrle d'automatisme, la variable eth0 est remplie automatiquement par la fonction +*auto_eth* si le paramtre dhcp est gal la condition *oui*:: + + + eth0 + oui + dhcp + + +dclaration de la fonction de contrle d'ditabilit:: + + + oui + eth0 + + +pour l'instant sont diposnible auto_eth, auto_netmask, auto_broadcast et auto_network. + + + diff --git a/doc/xml.txt b/doc/xml.txt new file mode 100644 index 0000000..3d9d32a --- /dev/null +++ b/doc/xml.txt @@ -0,0 +1,8 @@ +le fichier de configuration crole +================================== + +format xml +---------- + +Pour plus de documentation sur le format xml du dictionnaire crole, +se rfrer la documentation l'diteur xml crole ( *exc*) diff --git a/en.man8/Maj-Auto.8 b/en.man8/Maj-Auto.8 new file mode 100644 index 0000000..1351db8 --- /dev/null +++ b/en.man8/Maj-Auto.8 @@ -0,0 +1,187 @@ +.\" +.\" Manual page for Maj-Auto command +.\" +.TH Maj-Auto 8 "2016 september" "Maj-Auto 2.6.0" "Ceole command - EOLE" + +.SH NAME +Maj-Auto \- Automatic update for EOLE servers + +.SH SYNOPSIS +.SY Maj-Auto +.OP \-l {debug,info,warning,error,critical} +.OP \-v +.OP \-d +.OP \-h] +.OP \-n +.OP \-f +.OP \-F +.OP \-s +.OP \-C\ |\ \-D [{eole,envole}\ [{eole,envole}\ ...]] +.OP \-r +.OP \-R +.OP \-\-download +.OP \-S \fIEOLE_MIRROR\fR +.OP \-U \fIUBUNTU_MIRROR\fR +.OP \-V \fIENVOLE_MIRROR\fR +.OP \-c +.OP \-W +.OP \-i +.YS +.SH DESCRIPTION +.B Maj-Auto +command allows you to manually initiate the update of all packages changed since the release of the latest stable version. +.br +You benefit from security updates and critical bugfixes, but not the latest improvements. +.br +To take advantage of feature additions to the current version of the server, use the \fBMaj-Release\fR. +.br +For it the apt-get source file must be set up properly and the network must operate (\fBdiagnose\fR command). +.br +Mirror address is : +\fIhttp://eole.ac-dijon.fr/eole\fB/eole\fR : EOLE repository +.RS 48 +.br +\fB/ubuntu\fR : Ubuntu repository +.br +\fB/envole\fR : Envole repository +.SH OPTIONS +The following options are supported: +.TP +\fB\-h\fR, \fB\-\-help\fR +show this help message and exit +.TP +\fB\-n\fR, \fB\-\-dry\-run\fR +run in dry\-run mode (force to True when using Query\-Auto). +.TP +\fB\-f\fR, \fB\-\-force\fR +bypass Zephir authorizations. +.TP +\fB\-F\fR, \fB\-\-force_update\fR +update your server without any confirmation. +.TP +\fB\-s\fR, \fB\-\-simulate\fR +ask apt\-get to simulate packages installation +.TP +\fB\-C\fR [{eole,envole} [{eole,envole} ...]], \fB\-\-candidat\fR [{eole,envole} [{eole,envole} ...]] +use testing packages. +.TP +\fB\-D\fR [{eole,envole} [{eole,envole} ...]], \fB\-\-devel\fR [{eole,envole} [{eole,envole} ...]] +use development packages. +.TP +\fB\-r\fR, \fB\-\-reconfigure\fR +run reconfigure on successful upgrade. +.TP +\fB\-R\fR, \fB\-\-reboot\fR +run reconfigure on successful upgrade and reboot if +necessary (implies \fB\-r\fR). +.TP +\fB\-\-download\fR +only download packages in cache. +.TP +\fB\-S\fR EOLE_MIRROR, \fB\-\-eole\-mirror\fR EOLE_MIRROR +EOLE repository server. +.TP +\fB\-U\fR UBUNTU_MIRROR, \fB\-\-ubuntu\-mirror\fR UBUNTU_MIRROR +Ubuntu repository server. +.TP +\fB\-V\fR \fIENVOLE_MIRROR\fR, \fB\-\-envole\-mirror\fR \fIENVOLE_MIRROR\fR +Envole repository server. +.TP +fB\-c\fR, \fB\-\-cdrom\fR +use CDROM as source. +.TP +\fB\-W\fR +specific output for EAD. +.TP +\fB\-i\fR, \fB\-\-ignore\fR +ignore local configuration if creoled not responding. +.SS "logging:" +.TP +\fB\-l\fR {debug,info,warning,error,critical}, \fB\-\-log\-level\fR {debug,info,warning,error,critical} +Log level +.TP +\fB\-v\fR, \fB\-\-verbose\fR +Verbose mode, equivalent to -l info +.TP +\fB\-d\fR, \fB\-\-debug\fR +Debug mode, equivalent to -l debug +.SH EXAMPLES +.TP +Use testing packages for EOLE repository and keep stable ones for other repositories: +.RS +.nf +\fBMaj-Auto -C eole\fP +.fi +.RE +.TP +Use testing packages for Envole repository and keep stable ones for other repositories: +.RS +.nf +\fBMaj-Auto -C envole\fP +.fi +.RE +.TP +Use testing packages for EOLE and Envole repositories and keep stable ones for other repositories: +.RS +.nf +\fBMaj-Auto -C eole envole\fP +.fi +.RE +.TP +Use testing packages for all repositories: +.RS +.nf +\fBMaj-Auto -C\fP +.fi +.RE +.TP +Use development packages for EOLE repository and keep stable ones for other repositories: +.RS +.nf +\fBMaj-Auto -D eole\fP +.fi +.RE +.TP +Use development packages for Envole repository and keep stable ones for other repositories: +.RS +.nf +\fBMaj-Auto -D envole\fP +.fi +.RE +.TP +Use development packages for EOLE and Envole repositories and keep stable ones for other repositories: +.RS +.nf +\fBMaj-Auto -D eole envole\fP +.fi +.RE +.TP +Use development packages for all repositories: +.RS +.nf +\fBMaj-Auto -D\fP +.fi +.RE +.SH "SEE ALSO" +.B Maj-Cd +(8), +.B diagnose +(8), +.B Query-Auto +(8), +.B apt-eole +(8), +.B apt-get +(8), +.B creole +(8). +.SH "BOGUES" +.PP +To report a bug , check the following address \fIhttps://dev-eole.ac-dijon.fr/projects/eole/wiki/Accueil\fR + +.SH "AUTHORS" +.PP +.B EOLE team +.br +\fIhttp://eole.orion.education.fr\fP +.\" Maj-Auto.8 2.5.2 diff --git a/en.man8/Maj-Release.8 b/en.man8/Maj-Release.8 new file mode 100644 index 0000000..aab1633 --- /dev/null +++ b/en.man8/Maj-Release.8 @@ -0,0 +1,52 @@ +.\" +.\" Manual page for Maj-Release command +.\" +.TH Maj-Release 8 "2015 december" "Maj-Release 2.5.0" "Ceole command - EOLE" + +.SH NAME +Maj-Release \- Automatic release update for EOLE servers + +.SH DESCRIPTION +.B Maj-Release +command allows you to manually initiate the release update to the last stables releases. +.br +It is not an upgrade to a new version. +.br +You benefit from the latest improvements for the actual server version as well as updates and security bugfixes. +.br +For it the apt-get source file must be set up properly and the network must operate (\fBdiagnose\fP command). +.br +Mirror address is : +\fIhttp://eole.ac-dijon.fr/eole\fB/eole\fR : EOLE repository +.RS 48 +.br +\fB/ubuntu\fR : Ubuntu repository +.br +\fB/envole\fR : Envole repository +.SH "SEE ALSO" +.B Maj-Auto +(8), +.B Maj-Cd +(8), +.B diagnose +(8), +.B Query-Auto +(8), +.B Upgrade-Auto +(8), +.B apt-eole +(8), +.B apt-get +(8), +.B creole +(8). +.SH "BOGUES" +.PP +To report a bug , check the following address \fIhttps://dev-eole.ac-dijon.fr/projects/eole/wiki/Accueil\fR + +.SH "AUTHORS" +.PP +.B EOLE team +.br +\fIhttp://eole.orion.education.fr\fP +.\" Maj-Release.8 2.5.0 diff --git a/en.man8/Query-Auto.8 b/en.man8/Query-Auto.8 new file mode 100644 index 0000000..2a73866 --- /dev/null +++ b/en.man8/Query-Auto.8 @@ -0,0 +1,185 @@ +.\" +.\" Manual page for Query-Auto command +.\" +.TH Query-Auto 8 "2015 september" "Query-Auto 2.6.0" "Ceole command - EOLE" + +.SH NAME +Query-Auto \- Automatic update for EOLE servers + +.SH SYNOPSIS +.SY Query-Auto +.OP \-l {debug,info,warning,error,critical} +.OP \-v +.OP \-d +.OP \-h] +.OP \-n +.OP \-f +.OP \-F +.OP \-s +.OP \-C\ |\ \-D [{eole,envole}\ [{eole,envole}\ ...]] +.OP \-r +.OP \-R +.OP \-\-download +.OP \-S \fIEOLE_MIRROR\fR +.OP \-U \fIUBUNTU_MIRROR\fR +.OP \-V \fIENVOLE_MIRROR\fR +.OP \-c +.OP \-W +.OP \-i +.YS +.SH DESCRIPTION +.B Query-Auto +command allows you to manually initiate the update of all packages changed since the release of the latest stable version. +.br +You benefit from the latest improvements , updates and security bugfixes. +.br +For it the apt-get source file must be set up properly and the network must operate (\fBdiagnose\fP command). +.br +Mirror address is : +\fIhttp://eole.ac-dijon.fr/eole\fB/eole\fR : EOLE repository +.RS 48 +.br +\fB/ubuntu\fR : Ubuntu repository +.br +\fB/envole\fR : Envole repository +.SH OPTIONS +The following options are supported: +.TP +\fB\-h\fR, \fB\-\-help\fR +show this help message and exit +.TP +\fB\-n\fR, \fB\-\-dry\-run\fR +run in dry\-run mode (force to True when using Query\-Auto). +.TP +\fB\-f\fR, \fB\-\-force\fR +bypass Zephir authorizations. +.TP +\fB\-F\fR, \fB\-\-force_update\fR +update your server without any confirmation. +.TP +\fB\-s\fR, \fB\-\-simulate\fR +ask apt\-get to simulate packages installation +.TP +\fB\-C\fR [{eole,envole} [{eole,envole} ...]], \fB\-\-candidat\fR [{eole,envole} [{eole,envole} ...]] +use testing packages. +.TP +\fB\-D\fR [{eole,envole} [{eole,envole} ...]], \fB\-\-devel\fR [{eole,envole} [{eole,envole} ...]] +use development packages. +.TP +\fB\-r\fR, \fB\-\-reconfigure\fR +run reconfigure on successful upgrade. +.TP +\fB\-R\fR, \fB\-\-reboot\fR +run reconfigure on successful upgrade and reboot if +necessary (implies \fB\-r\fR). +.TP +\fB\-\-download\fR +only download packages in cache. +.TP +\fB\-S\fR EOLE_MIRROR, \fB\-\-eole\-mirror\fR EOLE_MIRROR +EOLE repository server. +.TP +\fB\-U\fR UBUNTU_MIRROR, \fB\-\-ubuntu\-mirror\fR UBUNTU_MIRROR +Ubuntu repository server. +.TP +\fB\-V\fR \fIENVOLE_MIRROR\fR, \fB\-\-envole\-mirror\fR \fIENVOLE_MIRROR\fR +Envole repository server. +.TP +fB\-c\fR, \fB\-\-cdrom\fR +use CDROM as source. +.TP +\fB\-W\fR +specific output for EAD. +.TP +\fB\-i\fR, \fB\-\-ignore\fR +ignore local configuration if creoled not responding. +.SS "logging:" +.TP +\fB\-l\fR {debug,info,warning,error,critical}, \fB\-\-log\-level\fR {debug,info,warning,error,critical} +Log level +.TP +\fB\-v\fR, \fB\-\-verbose\fR +Verbose mode, equivalent to -l info +.TP +\fB\-d\fR, \fB\-\-debug\fR +Debug mode, equivalent to -l debug +.SH EXAMPLES +.TP +Use testing packages for EOLE repository and keep stable ones for other repositories: +.RS +.nf +\fBQuery-Auto -C eole\fP +.fi +.RE +.TP +Use testing packages for Envole repository and keep stable ones for other repositories: +.RS +.nf +\fBQuery-Auto -C envole\fP +.fi +.RE +.TP +Use testing packages for EOLE and Envole repositories and keep stable ones for other repositories: +.RS +.nf +\fBQuery-Auto -C eole envole\fP +.fi +.RE +.TP +Use testing packages for all repositories: +.RS +.nf +\fBQuery-Auto -C\fP +.fi +.RE +.TP +Use development packages for EOLE repository and keep stable ones for other repositories: +.RS +.nf +\fBQuery-Auto -D eole\fP +.fi +.RE +.TP +Use development packages for Envole repository and keep stable ones for other repositories: +.RS +.nf +\fBQuery-Auto -D envole\fP +.fi +.RE +.TP +Use development packages for EOLE and Envole repositories and keep stable ones for other repositories: +.RS +.nf +\fBQuery-Auto -D eole envole\fP +.fi +.RE +.TP +Use development packages for all repositories: +.RS +.nf +\fBQuery-Auto -D\fP +.fi +.RE +.SH "SEE ALSO" +.B Maj-Cd +(8), +.B diagnose +(8), +.B Query-Auto +(8), +.B apt-eole +(8), +.B apt-get +(8), +.B creole +(8). +.SH "BOGUES" +.PP +To report a bug , check the following address \fIhttps://dev-eole.ac-dijon.fr/projects/eole/wiki/Accueil\fR + +.SH "AUTHORS" +.PP +.B EOLE team +.br +\fIhttp://eole.orion.education.fr\fP +.\" Query-Auto.8 2.5.2 diff --git a/en.man8/Upgrade-Auto.8 b/en.man8/Upgrade-Auto.8 new file mode 100644 index 0000000..9ee4225 --- /dev/null +++ b/en.man8/Upgrade-Auto.8 @@ -0,0 +1,48 @@ +.\" +.\" Manual page for Maj-Release command +.\" +.TH Upgrade-Auto 8 "2015 december" "Version 2.4.2" "Ceole command - EOLE" + +.SH NAME +Upgrade-Auto \- EOLE distribution upgrade tool + +.SH DESCRIPTION +.B Upgrade-Auto +command allows you to manually initiate a module upgrade to the lastest stables versions. +.br +You benefit from the latest improvements as well as updates and security bugfixes. +.br +For it the apt-get source file must be set up properly and the network must operate (\fBdiagnose\fP command). +.br +Mirror address is : +\fIhttp://eole.ac-dijon.fr/eole\fB/eole\fR : EOLE repository +.RS 48 +.br +\fB/ubuntu\fR : Ubuntu repository +.br +\fB/envole\fR : Envole repository +.SH "SEE ALSO" +.B Maj-Auto +(8), +.B Maj-Cd +(8), +.B diagnose +(8), +.B Query-Auto +(8), +.B apt-eole +(8), +.B apt-get +(8), +.B creole +(8). +.SH "BOGUES" +.PP +To report a bug , check the following address \fIhttps://dev-eole.ac-dijon.fr/projects/eole/wiki/Accueil\fR + +.SH "AUTHORS" +.PP +.B EOLE team +.br +\fIhttp://eole.orion.education.fr\fP +.\" Upgrade-Auto.8 2.4.2 diff --git a/en.man8/maj-auto.8 b/en.man8/maj-auto.8 new file mode 100644 index 0000000..eed9e9a --- /dev/null +++ b/en.man8/maj-auto.8 @@ -0,0 +1,73 @@ +.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.4. +.TH MAJ-AUTO "1" "October 2014" "Maj-Auto 2.4.1" "User Commands" +.SH NAME +Maj-Auto \- manual page for Maj-Auto 2.4.1 +.SH DESCRIPTION +usage: Maj\-Auto|Query\-Auto [\-h] [\-c CONTAINER] +.IP +[\-l {debug,info,warning,error,critical}] [\-v] [\-d] +[\-n] [\-f] [\-C | \fB\-D]\fR [\-r] [\-R] [\-\-download] +[\-S EOLE_MIRROR] [\-U UBUNTU_MIRROR] [\-W] +.PP +Manage EOLE server automatic update +.SS "optional arguments:" +.TP +\fB\-h\fR, \fB\-\-help\fR +show this help message and exit +.TP +\fB\-n\fR, \fB\-\-dry\-run\fR +run in dry\-run mode (force to True when using QueryAuto). +.TP +\fB\-f\fR, \fB\-\-force\fR +bypass Zephir authorizations. +.TP +\fB\-C\fR, \fB\-\-candidat\fR +use testing packages. +.TP +\fB\-D\fR, \fB\-\-devel\fR +use development packages. +.TP +\fB\-r\fR, \fB\-\-reconfigure\fR +run reconfigure on successful upgrade. +.TP +\fB\-R\fR, \fB\-\-reboot\fR +run reconfigure on successful upgrade and reboot if +necessary (implies \fB\-r\fR). +.TP +\fB\-\-download\fR +only download packages in cache. +.TP +\fB\-S\fR EOLE_MIRROR, \fB\-\-eole\-mirror\fR EOLE_MIRROR +EOLE repository server. +.TP +\fB\-U\fR UBUNTU_MIRROR, \fB\-\-ubuntu\-mirror\fR UBUNTU_MIRROR +Ubuntu repository server. +.TP +\fB\-W\fR +specific output for EAD. +.SS "container:" +.TP +\fB\-c\fR CONTAINER, \fB\-\-container\fR CONTAINER +Name of LXC container +.SS "logging:" +.TP +\fB\-l\fR {debug,info,warning,error,critical}, \fB\-\-log\-level\fR {debug,info,warning,error,critical} +Log level +.TP +\fB\-v\fR, \fB\-\-verbose\fR +Verbose mode +.TP +\fB\-d\fR, \fB\-\-debug\fR +Debug mode +.SH "SEE ALSO" +The full documentation for +.B Maj-Auto +is maintained as a Texinfo manual. If the +.B info +and +.B Maj-Auto +programs are properly installed at your site, the command +.IP +.B info Maj-Auto +.PP +should give you access to the complete manual. diff --git a/en.man8/upgrade-auto.8 b/en.man8/upgrade-auto.8 new file mode 120000 index 0000000..8d0c30f --- /dev/null +++ b/en.man8/upgrade-auto.8 @@ -0,0 +1 @@ +Upgrade-Auto.8 \ No newline at end of file diff --git a/eole.mk b/eole.mk new file mode 100644 index 0000000..cdad403 --- /dev/null +++ b/eole.mk @@ -0,0 +1,200 @@ +# +# NE PAS EDITER CE FICHIER +# +# Utiliser .mk à inclure à la fin de Makefile + +################# +# Sanity checks # +################# + +ifeq (, $(DESTDIR)) +$(warning $$(DESTDIR) is empty, installation will be done in /) +endif + +ifeq (, $(filter-out XXX-XXX, $(strip $(SOURCE)))) +$(error $$(SOURCE) variable has incorrect value '$(SOURCE)') +endif + +######################### +# Variables definitions # +######################### + +INSTALL := install +INSTALL_DATA := install -m 644 +INSTALL_PROGRAM := install -m 755 +INSTALL_DIRECTORY := install -m 755 -d +INSTALL_RECURSIVE := cp -dr --no-preserve=ownership + +# Base +eole_DIR := $(DESTDIR)/usr/share/eole + +ifeq ($(strip $(EOLE_VERSION)), 2.3) +diagnose_PROG_DIR := $(eole_DIR)/diagnose/module +else +diagnose_PROG_DIR := $(eole_DIR)/diagnose/ +endif + +# Creole +creole_DIR := $(eole_DIR)/creole +dicos_DATA_DIR := $(creole_DIR)/dicos +tmpl_DATA_DIR := $(creole_DIR)/distrib +pretemplate_PROG_DIR := $(eole_DIR)/pretemplate +posttemplate_PROG_DIR := $(eole_DIR)/posttemplate +postservice_PROG_DIR := $(eole_DIR)/postservice +firewall_DATA_DIR := $(eole_DIR)/firewall +bareos_restore_DATA_DIR := $(eole_DIR)/bareos/restore +bareos_fichier_DATA_DIR := $(DESTDIR)/etc/bareos/bareosfichiers.d +schedule_scripts_PROG_DIR := $(eole_DIR)/schedule/scripts +extra_REC_DIR := $(creole_DIR)/extra + +# Zéphir +zephir_DATA_DIR := $(DESTDIR)/usr/share/zephir +zephir_configs_DATA_DIR := $(zephir_DATA_DIR)/monitor/configs +zephir_srv_DATA_DIR := $(zephir_configs_DATA_DIR)/services + +# SSO +sso_DATA_DIR := $(DESTDIR)/usr/share/sso +sso_filtres_DATA_DIR := $(sso_DATA_DIR)/app_filters +sso_user-info_DATA_DIR := $(sso_DATA_DIR)/user_infos + +# EAD +ead_DATA_DIR := $(DESTDIR)/usr/share/ead2/backend/config +ead_actions_DATA_DIR := $(ead_DATA_DIR)/actions +ead_perms_DATA_DIR := $(ead_DATA_DIR)/perms +ead_roles_DATA_DIR := $(ead_DATA_DIR)/roles + +# Program libraries goes under /usr/lib// +lib_$(SOURCE)_DATA_DIR := $(DESTDIR)/usr/lib/$(SOURCE) + +# Scripts Eole +scripts_PROG_DIR := $(eole_DIR)/sbin +lib_eole_DATA_DIR := $(DESTDIR)/usr/lib/eole + +# LDAP +ldap_passwords_DATA_DIR := $(eole_DIR)/annuaire/password_files + +# LXC +lxc_DATA_DIR := $(eole_DIR)/lxc +lxc_fstab_DATA_DIR := $(lxc_DATA_DIR)/fstab +lxc_hosts_DATA_DIR := $(lxc_DATA_DIR)/hosts + +# SQL +sql_DATA_DIR := $(eole_DIR)/mysql/$(SOURCE) +sql_gen_DATA_DIR := $(sql_DATA_DIR)/gen +sql_updates_DATA_DIR := $(sql_DATA_DIR)/updates + +sql_conf_gen_DATA_DIR := $(eole_DIR)/applications/gen +sql_conf_passwords_DATA_DIR := $(eole_DIR)/applications/passwords +sql_conf_updates_DATA_DIR := $(eole_DIR)/applications/updates/$(SOURCE) + +# Certifs +certs_DATA_DIR := $(eole_DIR)/certs + +# Logrotate +logrotate_DATA_DIR := $(DESTDIR)/etc/logrotate.d + + +# Python modules +ifneq ($(DESTDIR),) +PYTHON_OPTS := --root $(DESTDIR) +endif + +# Translation +TRANSLATION_SRC := translation +TRANSLATION_DEST := $(DESTDIR)/usr/share/locale +PO_FILES = $(wildcard $(TRANSLATION_SRC)/*/*.po) +MO_FOLDERS = $(addprefix $(TRANSLATION_DEST), $(addsuffix LC_MESSAGES,$(subst $(TRANSLATION_SRC),,$(dir $(PO_FILES))))) + +############################################# +# Common directories and files installation # +############################################# + +all: + +$(MO_FOLDERS): + $(INSTALL_DIRECTORY) $@ + +$(PO_FILES): $(MO_FOLDERS) + msgfmt -o $(TRANSLATION_DEST)$(subst $(TRANSLATION_SRC),,$(addsuffix LC_MESSAGES,$(dir $@)))/$(notdir $(@:.po=.mo)) $@ + +install-lang: $(PO_FILES) + +install:: install-dirs install-files install-lang + +# $1 = command to run +# $2 = source directory +# $3 = destination directory +define fc_install_file + if [ -d $2 ]; then \ + for file in `ls -1 $2/`; do \ + $1 $2/$$file $3 || true; \ + done; \ + fi +endef + +## +## Directory creation +## + +# use % to catch local name in $* +# data, program and recursive directory require a corresponding +# directory in local sources +%_DATA_DIR %_PROG_DIR %REC_DIR: + test ! -d $(subst _,/,$*) || $(INSTALL_DIRECTORY) $($@) + +# Create the directory referenced by the variable without a local one. +%_DIR: + $(INSTALL_DIRECTORY) $($@) + +## +## Install files present directly under data, program and recursive directories +## + +# $* : name of variable +# $($*): value of variable +%-instdata: + $(call fc_install_file, $(INSTALL_DATA), $(subst _,/,$(subst _DATA_DIR,,$*)), $($*)) + +%-instprog: + $(call fc_install_file, $(INSTALL_PROGRAM), $(subst _,/,$(subst _PROG_DIR,,$*)), $($*)) + +%-instrec: + $(call fc_install_file, $(INSTALL_RECURSIVE), $(subst _,/,$(subst _REC_DIR,,$*)), $($*)) + + +# Use second expansion as variables may be created in included +# Makefiles +.SECONDEXPANSION: + +# List of all directories +installdirs_LIST = $(foreach V, $(filter %_DIR, $(.VARIABLES)), \ + $(if $(filter file, $(origin $(V))), \ + $(V))) +# List of data directories +installdata_LIST = $(filter %_DATA_DIR, $(installdirs_LIST)) +# List of program directories +installprog_LIST = $(filter %_PROG_DIR, $(installdirs_LIST)) +# List of recursive directories +installrec_LIST = $(filter %_REC_DIR, $(installdirs_LIST)) + +# Expand directories to create as dependency +# Use double-colon to permit user to define additionnal install-dirs +install-dirs:: $$(installdirs_LIST) + +# Expand files to install as dependency +# Use double-colon to permit user to define additionnal install-files +install-files:: install-data-files install-prog-files install-rec-dirs + +install-data-files: $$(patsubst %,%-instdata,$$(installdata_LIST)) + +install-prog-files: $$(patsubst %,%-instprog,$$(installprog_LIST)) + +install-rec-dirs: $$(patsubst %,%-instrec,$$(installrec_LIST)) + +# Installation of python modules +ifeq ($(shell test -f setup.py && echo 0), 0) +install-files:: + python3 setup.py install --no-compile --install-layout=deb $(PYTHON_OPTS) +endif + +.PHONY: install install-dirs install-files install-data-files install-prog-files install-rec-dirs diff --git a/extra/schedule/00_schedule.xml b/extra/schedule/00_schedule.xml new file mode 100644 index 0000000..5446d0a --- /dev/null +++ b/extra/schedule/00_schedule.xml @@ -0,0 +1,64 @@ + + + + + + Programmer + ead_admin + ead + maj + schedule + + + + + + + + + + + + + [1, 2, 3, 4, 5, 6, 7] + + + [1, 2, 3, 4, 5, 6, 7] + + + [1, 2, 3, 4, 5] + + + range(0, 60) + + + 1 + 5 + + + 0 + 59 + + + 1 + 7 + + + 1 + 7 + schedule.schedule.weekday + + + schedule.schedule.weekday + + + + + diff --git a/extra/schedule/01_majauto.xml b/extra/schedule/01_majauto.xml new file mode 100644 index 0000000..9189d39 --- /dev/null +++ b/extra/schedule/01_majauto.xml @@ -0,0 +1,12 @@ + + + + + + + weekly + + + + diff --git a/extra/schedule/02_rebootauto.xml b/extra/schedule/02_rebootauto.xml new file mode 100644 index 0000000..4b1ed94 --- /dev/null +++ b/extra/schedule/02_rebootauto.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/extra/schedule/03_shutdownauto.xml b/extra/schedule/03_shutdownauto.xml new file mode 100644 index 0000000..aba37c8 --- /dev/null +++ b/extra/schedule/03_shutdownauto.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/extra/schedule/04_reconfigureauto.xml b/extra/schedule/04_reconfigureauto.xml new file mode 100644 index 0000000..866d61d --- /dev/null +++ b/extra/schedule/04_reconfigureauto.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/extra/schedule/sls/eole/cron.sls b/extra/schedule/sls/eole/cron.sls new file mode 100644 index 0000000..35b6338 --- /dev/null +++ b/extra/schedule/sls/eole/cron.sls @@ -0,0 +1,3 @@ +cron: + eole.file: + - name: /etc/cron.d/schedule diff --git a/extra/schedule/sls/eole/init.sls b/extra/schedule/sls/eole/init.sls new file mode 100644 index 0000000..a841134 --- /dev/null +++ b/extra/schedule/sls/eole/init.sls @@ -0,0 +1,3 @@ +include: + - schedule.cron + - schedule.manage diff --git a/extra/schedule/sls/eole/manage.sls b/extra/schedule/sls/eole/manage.sls new file mode 100644 index 0000000..aca63ae --- /dev/null +++ b/extra/schedule/sls/eole/manage.sls @@ -0,0 +1,3 @@ +schedule: + cmd.run: + - name: /usr/share/eole/sbin/manage_schedule --apply diff --git a/fr.man8/CreoleGet.8 b/fr.man8/CreoleGet.8 new file mode 100644 index 0000000..78c9302 --- /dev/null +++ b/fr.man8/CreoleGet.8 @@ -0,0 +1,109 @@ +.\" +.\" Page de manuel de la commande CreoleGet. +.\" +.TH CreoleGet 8 "04 Avril 2017" "Version 2.6.1" "Commande Creole - EOLE" + +.SH NOM +CreoleGet \- Récupération de la valeur d'une variable Creole + +.SH SYNOPSIS +.B CreoleGet +[ +.B OPTIONS +] +.B VARIABLE +[ +.B DEFAULT +] + +.br +.B CreoleGet +[ +.B OPTIONS +] +.B --groups + +.br +.B CreoleGet +[ +.B OPTIONS +] +.B --list + +.br +.B CreoleGet +[ +.B OPTIONS +] +.B --reload + +.br +.B CreoleGet +[ +.B OPTIONS +] +.B --reload-eol + +.br +.B CreoleGet +.B \-h + +.SH DESCRIPTION +.B CreoleGet +est un utilitaire très pratique pour récupérer la valeur d'une +variable Creole + +.SH ARGUMENTS +.TP +\fBVARIABLE\fP +nom de la variable à lire +.TP +\fBDEFAULT\fP +valeur à renvoyer en cas d'erreur (variable inconnue ou désactivée) + +.SH OPTIONS +Les options suivantes sont supportées: +.TP +\fB-d\fP +active le mode de débogage +.TP +\fB-l\fP +paramètrage du niveau de log (debug|info|warning|error|critical) +.TP +\fB-v\fP +active le mode verbeux +.TP +\fB-h\fP +Affiche de l'aide + +.SH ACTIONS +.TP +\fB--groups\fP +liste les groupes de conteneurs + +.TP +\fB--list\fP +liste l'ensemble des variables creole + +.TP +\fB--reload\fP +recharge toute la configuration creole (dictionnaires et valeurs) + +.TP +\fB--reload-eol\fP +recharge les valeurs de configuration creole + +.SH "BOGUES" +.PP +Pour signaler un bogue, consultez l'adresse suivante \fIhttp://dev-eole.ac-dijon.fr/projects/creole\fR + +.SH "AUTEURS" +.PP +.B Equipe EOLE +.br +\fIhttp://eole.orion.education.fr\fP + +.SH "VOIR AUSSI" +.B creole +(8). + diff --git a/fr.man8/CreoleLint.8 b/fr.man8/CreoleLint.8 new file mode 100644 index 0000000..32ddf34 --- /dev/null +++ b/fr.man8/CreoleLint.8 @@ -0,0 +1,57 @@ +.\" +.\" Page de manuel de la commande CreoleLint. +.\" +.TH CreoleLint 8 "11 octobre 2013" "Version 2.4" "Commande Creole - EOLE" + +.SH NOM +CreoleLint \- Outil de validation des dictionnaires et templates Creole + +.SH SYNOPSIS +.B CreoleLint +[ +.B \-t TMPL DIR +] [ +.B \-l info|warning|error +] [ +.B \-n LINT_NAME +] [ +.B \-d +] [ +.B \-h +] + +.SH DESCRIPTION +.B CreoleLint +est un utilitaire très pratique pour valider la syntaxe du dictionnaire et des templates. L'outil effectue une série de tests dans le but de détecter les erreurs les plus fréquentes. +.SH OPTIONS +Les options suivantes sont supportées: +.TP +\fB-t\fP +répertoire des templates +.TP +\fB-l\fP +niveau des messages (info, warning ou error) +.TP +\fB-n\fP +n'exécuter qu'un lint +.TP +\fB-d\fP +dico-only, ne lance le lint que sur les dictionnaires (et pas sur les templates, donc) +.TP +\fB-h\fP +Affiche de l'aide + +.SH "BOGUES" +.PP +Pour signaler un bogue, consultez l'adresse suivante \fIhttp://dev-eole.ac-dijon.fr/projects/creole\fR + +.SH "AUTEURS" +.PP +.B Equipe EOLE +.br +\fIhttp://eole.orion.education.fr\fP + +.SH "VOIR AUSSI" +.B creole +(8). +.\" Maj-Cd.8 1.0 diff --git a/fr.man8/CreoleService.8 b/fr.man8/CreoleService.8 new file mode 100644 index 0000000..4393854 --- /dev/null +++ b/fr.man8/CreoleService.8 @@ -0,0 +1,67 @@ +.\" +.\" Page de manuel de la commande CreoleService. +.\" +.TH CreoleService 8 "4 septembre 2013" "Version 1.0" "Commande Creole - EOLE" + +.SH NOM +CreoleService \- Outil de gestion des services définis dans Creole + +.SH SYNOPSIS +.B CreoleService +[ +.B \-c CONTAINER +] [ +.B \-d +] [ +.B \-l LEVEL +] [ +.B \-v +] +.B SERVICE +.B ACTION + +.br +.B CreoleService +.B \-h + +.SH DESCRIPTION +.B CreoleService +est un utilitaire très pratique pour démarrer, arrêter et redémarrer les services définis dans Creole. +.SH OPTIONS +Les options suivantes sont supportées: +.TP +\fB-c\fP +conteneur dans lequel se trouve le service +.TP +\fB-d\fP +active le mode de débogage +.TP +\fB-l\fP +paramètrage du niveau de log (debug|info|warning|error|critical) +.TP +\fB-v\fP +active le mode verbeux +.TP +\fBservice\fP +nom du service sur lequel effectuer l'action +.TP +\fBaction\fP +action à réaliser sur le service (start|stop|restart|reload|status) +.TP +\fB-h\fP +Affiche de l'aide + +.SH "BOGUES" +.PP +Pour signaler un bogue, consultez l'adresse suivante \fIhttp://dev-eole.ac-dijon.fr/projects/creole\fR + +.SH "AUTEURS" +.PP +.B Equipe EOLE +.br +\fIhttp://eole.orion.education.fr\fP + +.SH "VOIR AUSSI" +.B creole +(8). +.\" Maj-Cd.8 1.0 diff --git a/fr.man8/CreoleSet.8 b/fr.man8/CreoleSet.8 new file mode 100644 index 0000000..9e7da9d --- /dev/null +++ b/fr.man8/CreoleSet.8 @@ -0,0 +1,69 @@ +.\" +.\" Page de manuel de la commande CreoleSet. +.\" +.TH CreoleSet 8 "18 novembre 2013" "Version 1.0" "Commande Creole - EOLE" + +.SH NOM +CreoleSet \- Modification de la valeur d'une variable Creole + +.SH SYNOPSIS +.B CreoleSet +[ +.B \-d +] [ +.B \-l LEVEL +] [ +.B \-v +] [ +.B \-\-default +] +.B VARIABLE +[ +.B VALUE +] + +.br +.B CreoleSet +.B \-h + +.SH DESCRIPTION +.B CreoleSet +est un utilitaire très pratique pour modifier la valeur d'une variable Creole +.SH OPTIONS +Les options suivantes sont supportées: +.TP +\fB-d\fP +active le mode de débogage +.TP +\fB-l\fP +paramètrage du niveau de log (debug|info|warning|error|critical) +.TP +\fB-v\fP +active le mode verbeux +.TP +\fB--default\fP +réinitialiser la variable à sa valeur par défaut +.TP +\fBvariable\fP +nom de la variable à modifier +.TP +\fBvalue\fP +valeur à injecter +.TP +\fB-h\fP +Affiche de l'aide + +.SH "BOGUES" +.PP +Pour signaler un bogue, consultez l'adresse suivante \fIhttp://dev-eole.ac-dijon.fr/projects/creole\fR + +.SH "AUTEURS" +.PP +.B Equipe EOLE +.br +\fIhttp://eole.orion.education.fr\fP + +.SH "VOIR AUSSI" +.B creole +(8). +.\" CreoleSet.8 1.0 diff --git a/fr.man8/Maj-Auto.8 b/fr.man8/Maj-Auto.8 new file mode 100644 index 0000000..07dc9c0 --- /dev/null +++ b/fr.man8/Maj-Auto.8 @@ -0,0 +1,183 @@ +.\" +.\" Page de manuel de la commande Maj-Auto. +.\" +.TH Maj-Auto 8 "septembre 2016" "Version 2.6.0" "Commande Creole - EOLE" + +.SH NOM +Maj-Auto \- Mise à jour automatisée des modules EOLE + +.SH SYNOPSIS +.SY Maj-Auto +.OP \-l {debug,info,warning,error,critical} +.OP \-v +.OP \-d +.OP \-h] +.OP \-n +.OP \-f +.OP \-F +.OP \-s +.OP \-C\ |\ \-D [{eole,envole}\ [{eole,envole}\ ...]] +.OP \-r +.OP \-R +.OP \-\-download +.OP \-S \fIEOLE_MIRROR\fR +.OP \-U \fIUBUNTU_MIRROR\fR +.OP \-V \fIENVOLE_MIRROR\fR +.OP \-c +.OP \-W +.OP \-i +.YS +.SH DESCRIPTION +La commande +.B Maj-Auto +vous permet de lancer manuellement la mise à jour des paquets correctifs de la release actuelle du serveur. +.br +Vous profitez ainsi des mises à jour de sécurité et des corrections de bogues critiques, sans ajout de fonctionnalité. + +.P +Pour profiter des ajouts de fonctionnalité de la version actuelle du serveur, utilisez la commande \fBMaj-Release\fR. + +.SH OPTIONS +Les options suivantes sont supportées : +.TP +\fB-h\fR, \fB--help\fR +afficher ce message d'aide et quitter. +.TP +\fB\-n\fR, \fB\-\-dry\-run\fR +exécuter en mode simulation (option forcée en +invoquant Query\-Auto). +.TP +\fB\-f\fR, \fB\-\-force\fR +passer outre les autorisations Zéphir. + +.TP +\fB\-F\fR, \fB\-\-force\-update\fR +mettre à jour le serveur sans confirmation +.TP +\fB\-s\fR, \fB\-\-simulate\fR +demande à apt\-get de simuler l'installation des paquets +.TP +\fB\-C\fR [{eole,envole} [{eole,envole} ...]], \fB\-\-candidat\fR [{eole,envole} [{eole,envole} ...]] +utiliser les paquets candidats. +.TP +\fB\-D\fR [{eole,envole} [{eole,envole} ...]], \fB\-\-devel\fR [{eole,envole} [{eole,envole} ...]] +utiliser les paquets en développement. +.TP +\fB\-r\fR, \fB\-\-reconfigure\fR +exécuter reconfigure après une mise à jour réussie. +.TP +\fB\-R\fR, \fB\-\-reboot\fR +exécuter reconfigure après une mise à jour réussie et +redémarrer si nécessaire (implique l'option \fB\-r\fR). +.TP +\fB\-\-download\fR +procéder uniquement au téléchargement des paquets en +cache. +.TP +\fB\-S\fR \fIEOLE_MIRROR\fR, \fB\-\-eole\-mirror\fR \fIEOLE_MIRROR\fR +adresse des dépôts EOLE. +.TP +\fB\-U\fR \fIUBUNTU_MIRROR\fR, \fB\-\-ubuntu\-mirror\fR \fIUBUNTU_MIRROR\fR +adresse des dépôts Ubuntu. +.TP +\fB\-V\fR \fIENVOLE_MIRROR\fR, \fB\-\-envole\-mirror\fR \fIENVOLE_MIRROR\fR +adresse des dépôts Envole. +.TP +\fB\-c\fR, \fB\-\-cdrom\fR +utiliser une source de type CDROM +.TP +\fB\-W\fR +sortie formatée pour l'EAD. +.TP +\fB\-i\fR, \fB\-\-ignore\fR +ignore la configuration locale si creoled ne répond pas. +.SS "logging:" +.TP +\fB\-l\fR {debug,info,warning,error,critical}, \fB\-\-log\-level\fR {debug,info,warning,error,critical} +Niveau de log +.TP +\fB\-v\fR, \fB\-\-verbose\fR +Mode verbeux, équivalent à \fB\-l\fR info +.TP +\fB\-d\fR, \fB\-\-debug\fR +Mode debug, équivalent à \fB\-l\fR debug +.SH EXEMPLES +.TP +Pour utiliser le dépôt EOLE des paquets candidats et conserver les autres dépôts en stable : +.RS +.nf +\fBMaj-Auto -C eole\fP +.fi +.RE +.TP +Pour utiliser le dépôt Envole des paquets candidats et les autres en stable : +.RS +.nf +\fBMaj-Auto -C envole\fP +.fi +.RE +.TP +Pour utiliser les dépôts Envole et EOLE des paquets candidats : +.RS +.nf +\fBMaj-Auto -C eole envole\fP +.fi +.RE +.TP +Pour utiliser tous les dépôts de paquets candidats : +.RS +.nf +\fBMaj-Auto -C\fP +.fi +.RE +.TP +Pour utiliser le dépôt EOLE des paquets de développement et conserver les autres dépôts en stable : +.RS +.nf +\fBMaj-Auto -D eole\fP +.fi +.RE +.TP +Pour utiliser le dépôt Envole des paquets de développement et conserver les autres dépôts en stable : +.RS +.nf +\fBMaj-Auto -D envole\fP +.fi +.RE +.TP +Pour utiliser les dépôts Envole et EOLE des paquets de développement : +.RS +.nf +\fBMaj-Auto -D eole envole\fP +.fi +.RE +.TP +Pour utiliser tous les dépôts de paquets de développement : +.RS +.nf +\fBMaj-Auto -D\fP +.fi +.RE +.SH "VOIR AUSSI" +.B Maj-Cd +(8), +.B diagnose +(8), +.B Query-Auto +(8), +.B apt-eole +(8), +.B apt-get +(8), +.B creole +(8). +.SH "BOGUES" +.PP +Pour signaler un bogue, consultez l'adresse suivante \fIhttps://dev-eole.ac-dijon.fr/projects/eole/wiki/Accueil\fR + +.SH "AUTEURS" +.PP +.B Equipe EOLE +.br +\fIhttp://eole.orion.education.fr\fP +.\" Maj-Auto.8 2.5.2 diff --git a/fr.man8/Maj-Cd.8 b/fr.man8/Maj-Cd.8 new file mode 100644 index 0000000..b53e8ed --- /dev/null +++ b/fr.man8/Maj-Cd.8 @@ -0,0 +1,55 @@ +.\" +.\" Page de manuel de la commande Maj-Cd. +.\" +.TH Maj-Cd 8 "03 novembre 2009" "Version 1.0" "Commande Creole - EOLE" + +.SH NOM +Maj-Cd \- Mise à jour des modules EOLE + +.SH SYNOPSIS +.B Maj-Cd +[ +.B \-s +] + +.SH DESCRIPTION +La commande +.B Maj-Cd +vous permet de lancer manuellement la mise à jour de tous les paquets modifiés depuis la sortie de la dernière version stable. +.br +Vous profitez ainsi des dernières améliorations, des mises à jour de sécurité et des corrections de bogues. +.br +Pour cela le fichier des sources de apt-get doit être correctement configuré et le réseau fonctionnel (commande \fBdiagnose\fP). +.br +L'adresse du dépôt est \fIhttp://eoleng.ac-dijon.fr/eoleng\fP +.SH OPTIONS +Les options suivantes sont supportées: +.TP +\fB-s\fP +Equivalent à \fBapt-get -s\fP (simulation). + +.SH FICHIER +.PP +\fI/etc/apt/sources\&.list\fR +.RS 4 +Emplacements où aller chercher les paquets\&. Élément de configuration\ \&: +Dir::Etc::SourceList\&. + +.SH "BOGUES" +.PP +Pour signaler un bogue, consultez l'adresse suivante \fIhttp://eole.orion.education.fr/signalement/\fR + +.SH "AUTEURS" +.PP +.B Equipe EOLE +.br +\fIhttp://eole.orion.education.fr\fP + +.SH "VOIR AUSSI" +.B Maj-Auto +(8), +.B apt-get +(8), +.B creole +(8). +.\" Maj-Cd.8 1.0 diff --git a/fr.man8/Maj-Release.8 b/fr.man8/Maj-Release.8 new file mode 100644 index 0000000..5152ef9 --- /dev/null +++ b/fr.man8/Maj-Release.8 @@ -0,0 +1,64 @@ +.\" +.\" Page de manuel de la commande Maj-Release. +.\" +.TH Maj-Release 8 "Décembre 2015" "Version 2.5.0" "Commande Creole - EOLE" + +.SH NOM +Maj-Release \- Mise à jour automatisée de la version mineure des modules EOLE + +.SH SYNOPSIS +.B Upgrade-Auto +[\fB-h\fR] +[\fB\-\-release\fR \fIRELEASE\fR] +[\fB\-\-force\fR] + +.SH DESCRIPTION +La commande +.B Maj-Release +vous permet de lancer manuellement la mise à jour vers une version mineure plus récente. +.br +Il ne s'agit pas d'un changement de version majeure. + +.P +Vous profitez ainsi des dernières améliorations de la version actuelle +du serveur ainsi que des mises à jour de sécurité et des corrections +de bogues. + +.SH OPTIONS +.TP +\fB\-h | \-\-help\fR +afficher un message d’aide et quitter. + +.TP +\fB\-\-release\fR +numéro de version cible + +.TP +\fB\-\-force\fr +ne pas demander de confirmation. + +.SH "VOIR AUSSI" +.B Maj-Auto +(8), +.B diagnose +(8), +.B Query-Auto +(8), +.B Upgrade-Auto +(8), +.B apt-eole +(8), +.B apt-get +(8), +.B creole +(8). +.SH "BOGUES" +.PP +Pour signaler un bogue, consultez l'adresse suivante \fIhttps://dev-eole.ac-dijon.fr/projects/eole/wiki/Accueil\fR + +.SH "AUTEURS" +.PP +.B Equipe EOLE +.br +\fIhttp://eole.orion.education.fr\fP +.\" Maj-Release.8 2.5.0 diff --git a/fr.man8/Query-Auto.8 b/fr.man8/Query-Auto.8 new file mode 100644 index 0000000..d5268bf --- /dev/null +++ b/fr.man8/Query-Auto.8 @@ -0,0 +1,188 @@ +.\" +.\" Page de manuel de la commande Query-Auto. +.\" +.TH Query-Auto 8 "septembre 2016" "Version 2.6.0" "Commande Creole - EOLE" + +.SH NOM +Query-Auto \- Mise à jour automatisée des modules EOLE + +.SH SYNOPSIS +.SY Query-Auto +.OP \-l {debug,info,warning,error,critical} +.OP \-v +.OP \-d +.OP \-h] +.OP \-n +.OP \-f +.OP \-F +.OP \-s +.OP \-C\ |\ \-D [{eole,envole}\ [{eole,envole}\ ...]] +.OP \-r +.OP \-R +.OP \-\-download +.OP \-S \fIEOLE_MIRROR\fR +.OP \-U \fIUBUNTU_MIRROR\fR +.OP \-V \fIENVOLE_MIRROR\fR +.OP \-c +.OP \-W +.OP \-i +.YS +.SH DESCRIPTION +La commande +.B Query-Auto +vous permet de lancer manuellement la mise à jour de tous les paquets modifiés depuis la sortie de la dernière version stable. +.br +Vous profitez ainsi des dernières améliorations, des mises à jour de sécurité et des corrections de bogues. +.br +Pour cela le fichier des sources de apt-get doit être correctement configuré et le réseau fonctionnel (commande \fBdiagnose\fP). +.br +L'adresse du miroir EOLE est : +\fIhttp://eole.ac-dijon.fr\fP\fB/eole\fR : dépôt EOLE +.RS 54 +.br +\fB/ubuntu\fR : dépôt Ubuntu +.br +\fB/envole\fR : dépôt Envole +.SH OPTIONS +Les options suivantes sont supportées : +.TP +\fB-h\fR, \fB--help\fR +afficher ce message d'aide et quitter. +.TP +\fB\-n\fR, \fB\-\-dry\-run\fR +exécuter en mode simulation (option forcée en +invoquant Query\-Auto). +.TP +\fB\-f\fR, \fB\-\-force\fR +passer outre les autorisations Zéphir. +.TP +\fB\-F\fR, \fB\-\-force\-update\fR +mettre à jour le serveur sans confirmation +.TP +\fB\-s\fR, \fB\-\-simulate\fR +demande à apt\-get de simuler l'installation des paquets +.TP +\fB\-C\fR [{eole,envole} [{eole,envole} ...]], \fB\-\-candidat\fR [{eole,envole} [{eole,envole} ...]] +utiliser les paquets candidats. +.TP +\fB\-D\fR [{eole,envole} [{eole,envole} ...]], \fB\-\-devel\fR [{eole,envole} [{eole,envole} ...]] +utiliser les paquets en développement. +.TP +\fB\-r\fR, \fB\-\-reconfigure\fR +exécuter reconfigure après une mise à jour réussie. +.TP +\fB\-R\fR, \fB\-\-reboot\fR +exécuter reconfigure après une mise à jour réussie et +redémarrer si nécessaire (implique l'option \fB\-r\fR). +.TP +\fB\-\-download\fR +procéder uniquement au téléchargement des paquets en +cache. +.TP +\fB\-S\fR \fIEOLE_MIRROR\fR, \fB\-\-eole\-mirror\fR \fIEOLE_MIRROR\fR +adresse des dépôts EOLE. +.TP +\fB\-U\fR \fIUBUNTU_MIRROR\fR, \fB\-\-ubuntu\-mirror\fR \fIUBUNTU_MIRROR\fR +adresse des dépôts Ubuntu. +.TP +\fB\-V\fR \fIENVOLE_MIRROR\fR, \fB\-\-envole\-mirror\fR \fIENVOLE_MIRROR\fR +adresse des dépôts Envole. +.TP +\fB\-c\fR, \fB\-\-cdrom\fR +utiliser une source de type CDROM +.TP +\fB\-W\fR +sortie formatée pour l'EAD. +.TP +\fB\-i\fR, \fB\-\-ignore\fR +ignore la configuration locale si creoled ne répond pas. +.SS "logging:" +.TP +\fB\-l\fR {debug,info,warning,error,critical}, \fB\-\-log\-level\fR {debug,info,warning,error,critical} +Niveau de log +.TP +\fB\-v\fR, \fB\-\-verbose\fR +Mode verbeux, équivalent à \fB\-l\fR info +.TP +\fB\-d\fR, \fB\-\-debug\fR +Mode debug, équivalent à \fB\-l\fR debug +.SH EXEMPLES +.TP +Pour utiliser le dépôt EOLE des paquets candidats et conserver les autres dépôts en stable : +.RS +.nf +\fBQuery-Auto -C eole\fP +.fi +.RE +.TP +Pour utiliser le dépôt Envole des paquets candidats et les autres en stable : +.RS +.nf +\fBQuery-Auto -C envole\fP +.fi +.RE +.TP +Pour utiliser les dépôts Envole et EOLE des paquets candidats : +.RS +.nf +\fBQuery-Auto -C eole envole\fP +.fi +.RE +.TP +Pour utiliser tous les dépôts de paquets candidats : +.RS +.nf +\fBQuery-Auto -C\fP +.fi +.RE +.TP +Pour utiliser le dépôt EOLE des paquets de développement et conserver les autres dépôts en stable : +.RS +.nf +\fBQuery-Auto -D eole\fP +.fi +.RE +.TP +Pour utiliser le dépôt Envole des paquets de développement et conserver les autres dépôts en stable : +.RS +.nf +\fBQuery-Auto -D envole\fP +.fi +.RE +.TP +Pour utiliser les dépôts Envole et EOLE des paquets de développement : +.RS +.nf +\fBQuery-Auto -D eole envole\fP +.fi +.RE +.TP +Pour utiliser tous les dépôts de paquets de développement : +.RS +.nf +\fBQuery-Auto -D\fP +.fi +.RE +.SH "VOIR AUSSI" +.B Query-Cd +(8), +.B diagnose +(8), +.B Query-Auto +(8), +.B apt-eole +(8), +.B apt-get +(8), +.B creole +(8). +.SH "BOGUES" +.PP +Pour signaler un bogue, consultez l'adresse suivante \fIhttps://dev-eole.ac-dijon.fr/projects/eole/wiki/Accueil\fR + +.SH "AUTEURS" +.PP +.B Equipe EOLE +.br +\fIhttp://eole.orion.education.fr\fP +.\" Query-Auto.8 2.5.2 diff --git a/fr.man8/Upgrade-Auto.8 b/fr.man8/Upgrade-Auto.8 new file mode 100644 index 0000000..c3ed2b7 --- /dev/null +++ b/fr.man8/Upgrade-Auto.8 @@ -0,0 +1,110 @@ +.\" +.\" Page de manuel de la commande Maj-Release. +.\" +.TH Upgrade-Auto 8 "Décembre 2015" "Version 2.4.2" "Commande Creole - EOLE" + +.SH NOM +Upgrade-Auto \- Outil de montée de version majeure de la distribution EOLE + +.SH SYNOPSIS +.SY Upgrade-Auto +.OP \fB-h\fR +.OP \fB\-\-release\fR \fIRELEASE\fR +.OP \fB\-\-limit-rate\fR +.OP \fB\-\-download\fR +.OP \fB\-\-iso\fR \fIPATH\fR | \fB\-\-cdrom\fR +.OP \fB\-\-force\fR +.YS + +.SH DESCRIPTION +La commande +.B Upgrade-Auto +vous permet de lancer manuellement la migration d'un module vers les +dernières versions stables. + +.P +Vous profitez ainsi des dernières améliorations ainsi que des mises à +jour de sécurité et des corrections de bogues. + +.P +Pour cela le serveur doit être à jour dans la version courante +(\fBMaj-Auto\fR) et le réseau fonctionnel (commande \fBdiagnose\fP). + +.P +La procédure de mise à jour est la suivante : +.nr step 1 1 +.IP \n[step] 2 +demande le numéro de version cible et confirmation à l’utilisateur + +.IP \n+[step] +télécharge les fichiers \fISHA256SUMS\fR et \fISHA256SUMS.gpg\fR + +.IP \n+[step] +vérifie la signature GPG du fichier \fISHA256SUMS\fR + +.IP \n+[step] +télécharge l’image ISO + +.IP \n+[step] +valide la somme de contrôle de l’image ISO + +.IP \n+[step] +copie des paquets \fI.deb\fR de l’image ISO dans le cache APT ou +APT-CACHER-NG s’il est installé. + +.IP \n+[step] +exécute la procédure de mise à jour en réseau. + +.P +Vous pouvez limiter la taille du téléchargement en utilisant une image +ISO stockée sur une clef USB ou un cédérom. Dans ce cas, seul les +paquets plus récents que ceux présents sur l’image ISO seront +téléchargés. + +.SH OPTIONS +.TP +\fB\-h | \-\-help\fR +afficher un message d’aide et quitter. + +.TP +\fB\-\-release\fR +numéro de version cible + +.TP +\fB\-\-download\fR +ne procéder qu’au téléchargement de l’image ISO de la version +cible. La migration n’est pas effectuée. + +.TP +\fB\-\-limit\-rate\fR \fIBANDWIDTH\fR +limite de bande passante à utiliser pour le téléchargement. Cette +option est passée directement à wget. La valeur « 0 » désactive la +limitation. Par défaut \fI120k\fR. + +.TP +\fB\-\-iso\fR \fIPATH\fR +chemin vers l’image ISO. Cette option copie l’image ISO indiquée. + +.TP +\fB\-\-cdrom\fR +copie l’image ISO depuis un lecteur cédérom. + +.TP +\fB\-f | \-\-force\fr +ne pas demander de confirmation. + +.SH "VOIR AUSSI" +.B Maj-Auto +(8), +.B diagnose +(8), +.SH "BOGUES" +.PP +Pour signaler un bogue, consultez l'adresse suivante \fIhttps://dev-eole.ac-dijon.fr/projects/eole/wiki/Accueil\fR + +.SH "AUTEURS" +.PP +.B Equipe EOLE +.br +\fIhttp://eole.orion.education.fr\fP +.\" Upgrade-Auto.8 2.4.2 diff --git a/fr.man8/creole.8 b/fr.man8/creole.8 new file mode 100644 index 0000000..a2346b2 --- /dev/null +++ b/fr.man8/creole.8 @@ -0,0 +1,69 @@ +.\" +.\" Page de manuel de Creole. +.\" +.TH Creole 8 "03 novembre 2009" "Version 1.0" "Creole - EOLE" + +.SH NOM +Creole + +.SH DESCRIPTION +Creole est un ensemble de programmes, permettant la configuration et la mise à jour des serveurs. +Ce mécanisme automatisé inclut une procédure de patch ainsi que la possibilité de rajouter des spécifications : + + * ajout de variable + * modification de fichier templatisé + * templatisation de nouveau fichier + +Les modules EOLE sont livrés avec un ensemble de fichiers de configuration placés dans \fI/usr/share/eole/creole/distrib\fP et copiés vers leur emplacement de destination à chaque \fBinstance\fP/\fBreconfigure\fP (Ex.:\fI/usr/share/eole/creole/distrib/my.cnf\fP vers \fI/etc/mysql/my.cnf\fP). +.PP +Le compte rendu d'exécution des commandes Creole est dans le fichier \fI/var/log/creole.log\fR + +.SH "LISTE DES COMMANDES" +.TP +\fBMaj-Auto\fP +Lance les mises à jour du module à partir des dépôts. +.TP +\fBMaj-Cd\fP +Lance les mises à jour du module à partir d'un CD (pratique pour les connexion en bas débit). +.TP +\fBQuery-Auto\fP +Donne la liste des paquets disponibles sur les dépôts sans les installer. +.TP +\fBinstance\fP +Lance l'instanciation du module après l'avoir configuré avec \fBgen_config\fP. +.TP +\fBgen_config\fP +Application graphique et textuelle permettant de configurer et de reconfigurer votre module. +.TP +\fBreconfigure\fP +Applique les changements de configuration du module effectués dans \fBgen_config\fP. +.TP +\fBdiagnose\fP +Outil de diagnostic du réseau et de l'état des services. + +.SH "BOGUES" +.PP +Pour signaler un bogue, consultez l'adresse suivante \fIhttp://eole.orion.education.fr/signalement/\fR + +.SH "AUTEURS" +.PP +.B Equipe EOLE +.br +\fIhttp://eole.orion.education.fr\fP + +.SH "VOIR AUSSI" +.B instance +(8), +.B Maj-auto +(8), +.B Maj-Cd +(8), +.B reconfigure +(8), +.B gen_config +(8), +.B Query-Auto +(8), +.B diagnose +(8). +.\" Creole.8 1.0 diff --git a/fr.man8/diagnose.8 b/fr.man8/diagnose.8 new file mode 100644 index 0000000..0ecaa49 --- /dev/null +++ b/fr.man8/diagnose.8 @@ -0,0 +1,46 @@ +.\" +.\" Page de manuel de la commande diagnose. +.\" +.TH diagnose 8 "03 novembre 2009" "Version 1.0" "Commande Creole - EOLE" + +.SH NOM +diagnose \- Outil de diagnostic de la configuration d'un module EOLE + +.SH SYNOPSIS +.B diagnose +[ +.B \-L +] + +.SH DESCRIPTION +La commande +.B diagnose +permet de valider que la configuration injectée via les étapes d'adaptation et d'instanciation est correcte et fonctionnelle. +.br +Elle permet de tester rapidement l'état du réseau et des différents services de votre module EOLE. +.br +Si des erreurs apparaissent, il faut revoir le fichier de configuration \fI/etc/eole/config.eol\fR, et reconfigurer le serveur. +.SH OPTIONS +L'option suivante est supportée: +.TP +\fB-L\fP +Active le mode étendu qui permet d'obtenir plus d'informations (détail des disques, état des mises à jour, dernières actions réalisées sur le serveur). + +.SH "BOGUES" +.PP +Pour signaler un bogue, consultez l'adresse suivante \fIhttp://eole.orion.education.fr/signalement/\fR + +.SH "AUTEURS" +.PP +.B Equipe EOLE +.br +\fIhttp://eole.orion.education.fr\fP + +.SH "VOIR AUSSI" +.B gen_config +(8), +.B reconfigure +(8), +.B creole +(8). +.\" diagnose.8 1.0 diff --git a/fr.man8/instance.8 b/fr.man8/instance.8 new file mode 100644 index 0000000..15d19dd --- /dev/null +++ b/fr.man8/instance.8 @@ -0,0 +1,77 @@ +.\" +.\" Page de manuel de la commande instance. +.\" +.TH instance 8 "03 novembre 2009" "Version 1.0" "Commande Creole - EOLE" + +.SH NOM +instance \- Outil d'instanciation d'un module EOLE + +.SH SYNOPSIS +.B instance +[\fInomDeFichier.eol\fP] + +.SH DESCRIPTION +Les modules EOLE sont livrés avec un ensemble de templates. +.br +L'instanciation consiste à remplacer les variables par les valeurs renseignées dans le fichier \fI/root/zephir.eol\fR et +à copier les fichiers vers leur emplacement cible. +.br Vous devez donc d'abord renseigner le fichier zephir.eol à l'aide de la commande \fBgen_config\fP. + +.B Attention ! +.br +Cette opération n'est à réaliser qu'une seule fois sur un module après son installation. +.br +Pourquoi n'utiliser instance qu'une seule fois: + + * instance permet de le re-générer ce qui efface tous les comptes utilisateurs et les stations intégrés au domaine. + * les scripts pre/post instance/reconf sont différents + * risque de désynchronisation du SID + * valeurs par défaut non mises à jour + * reconfigure est automatique, il ne pose pas de question + +.br +Si des modifications sont apportées par la suite par \fBgen_config\fP dans le fichier de configuration il faut utiliser la commande \fBreconfigure\fP et non la commande \fBinstance\fP. + +.br +Voici les étapes gérées par la commande \fBinstance\fP: + + * initialise les mots de passe root, scribe et admin + * génère un nouveau SID + * génère l'annuaire et les bases MySql si inexistants + * lance les scripts pre/postinstance + * programme une mise à jour automatique hebdomadaire + * copie, patch et renseigne les templates + * (re)lance les services + +.br +Le compte rendu d'exécution est dans le fichier \fI/var/log/creole.log\fR + +.br +Une fois l'instanciation faite le fichier \fInomDeFichier.eol\fP peut être supprimé car c'est le fichier /etc/eole/config.eol qui servira lors des \fBreconfigure\fP. + +.SH OPTION +L'argument suivant est supporté: +.TP +\fBnomDeFichier.eol\fP +spécifier le chemin du \fIfichier.eol\fR nécessaire à l'instanciation. Par defaut le fichier utilisé est \fI/root/zephir.eol\fR + +.SH "BOGUES" +.PP +Pour signaler un bogue, consultez l'adresse suivante \fIhttp://eole.orion.education.fr/signalement/\fR + +.SH "AUTEURS" +.PP +.B Equipe EOLE +.br +\fIhttp://eole.orion.education.fr\fP + +.SH "VOIR AUSSI" +.B diagnose +(8), +.B gen_config +(8), +.B reconfigure +(8), +.B creole +(8). +.\" instance.8 1.0 diff --git a/fr.man8/maj-auto.8 b/fr.man8/maj-auto.8 new file mode 120000 index 0000000..66be74a --- /dev/null +++ b/fr.man8/maj-auto.8 @@ -0,0 +1 @@ +Maj-Auto.8 \ No newline at end of file diff --git a/fr.man8/maj-cd.8 b/fr.man8/maj-cd.8 new file mode 120000 index 0000000..66faf6f --- /dev/null +++ b/fr.man8/maj-cd.8 @@ -0,0 +1 @@ +Maj-Cd.8 \ No newline at end of file diff --git a/fr.man8/query-auto.8 b/fr.man8/query-auto.8 new file mode 120000 index 0000000..d6b575f --- /dev/null +++ b/fr.man8/query-auto.8 @@ -0,0 +1 @@ +Query-Auto.8 \ No newline at end of file diff --git a/fr.man8/reconfigure.8 b/fr.man8/reconfigure.8 new file mode 100644 index 0000000..fc36cfc --- /dev/null +++ b/fr.man8/reconfigure.8 @@ -0,0 +1,68 @@ +.\" +.\" Page de manuel de la commande reconfigure. +.\" +.TH reconfigure 8 "03 novembre 2009" "Version 1.0" "Commande Creole - EOLE" + +.SH NOM +reconfigure \- Ré-applique la configuration (après une mise à jour par exemple) ou des modifications de configuration (changement d'IP par ex.). + +.SH SYNOPSIS +.B reconfigure +[\fB-f\fP] +[\fB-a\fP] +[\fB-i\fP] + +.SH DESCRIPTION +La commande \fBreconfigure\fP sert à ré-appliquer la configuration sur une machine déjà configurée (instanciée). +.br +Elle est également utilisée lors de l'application de patch. \fBreconfigure\fP lit le fichier \fI/etc/eole/config.eol\fP. +.br +\fBreconfigure\fP doit être lancé après chaque modification effectuée par \fBgen_config\fP afin d'appliquer les changements. + +Voici les étapes gérées par la commande \fBreconfigure\fP: + + * ré-applique le SID trouvé dans l'annuaire + * installe/supprime des paquets (utilisé pour les noyaux) + * exécute les scripts pre/postreconf + * met à jour les valeurs par défaut des dictionnaires + * recrée "admin" s'il n'a pas été trouvé + * copie, patch et renseigne les templates + * contrôle la version du noyau en fonctionnement et demande un redémarrage si ce n'est pas la dernière version (reboot auto si Maj par EAD) + * relance les services + +Lors d'une mise à jour via l'EAD, \fBreconfigure\fP est lancé automatiquement. + +Si la mise à jour a été effectuée sur la console ou via SSH avec la commande \fBMaj-Auto\fP un message orange indique s'il est nécessaire de lancer \fBreconfigure\fP. + +.SH OPTIONS +Les arguments suivants sont supportés: +.TP +\fB-f\fP +outrepasser le blocage par Zéphir +.TP +\fB-a\fP +redémarrage automatique si nécessaire +.TP +\fB-i\fP +lancer le processus en mode interactif + +.SH "BOGUES" +.PP +Pour signaler un bogue, consultez l'adresse suivante \fIhttp://eole.orion.education.fr/signalement/\fR + +.SH "AUTEURS" +.PP +.B Equipe EOLE +.br +\fIhttp://eole.orion.education.fr\fP + +.SH "VOIR AUSSI" +.B instance +(8), +.B Maj-auto +(8), +.B gen_config +(8), +.B creole +(8). +.\" reconfigure.8 1.0 diff --git a/fr.man8/upgrade-auto.8 b/fr.man8/upgrade-auto.8 new file mode 120000 index 0000000..8d0c30f --- /dev/null +++ b/fr.man8/upgrade-auto.8 @@ -0,0 +1 @@ +Upgrade-Auto.8 \ No newline at end of file diff --git a/init/creoled.service b/init/creoled.service new file mode 100644 index 0000000..688e8ff --- /dev/null +++ b/init/creoled.service @@ -0,0 +1,12 @@ +[Unit] +Description=EOLE Creole server +After=local-fs.target network.target + +[Service] +Type=notify +EnvironmentFile=-/etc/default/locale +ExecStart=/usr/sbin/creoled --pidfile /run/creoled.pid +PIDFile=/run/creoled.pid + +[Install] +WantedBy=multi-user.target diff --git a/lib/eole/diagnose.sh b/lib/eole/diagnose.sh new file mode 100644 index 0000000..0de47d1 --- /dev/null +++ b/lib/eole/diagnose.sh @@ -0,0 +1,344 @@ +. /usr/lib/eole/ihm.sh + +len_pf=26 + +Inactif() { +printf ". %${len_pf}s => " "$1" +EchoOrange "Désactivé" +} + +NoConfig() { +printf ". %${len_pf}s => " "$1" +EchoOrange "Non configuré" +} + +TestIP() { +len=$((len_pf-7)) +printf "%-9s %${len}s => " "$2:" "$1" +/usr/bin/fping -t50 -r2 $1 > /dev/null 2>&1 +if [ $? -eq 0 ] +then + EchoVert "Ok" +else + EchoRouge "Erreur" +fi +} + +TestIP2() { +# présentation normale ;) +printf ". %${len_pf}s => " "$2" +/usr/bin/fping -t50 -r2 $1 > /dev/null 2>&1 +if [ $? -eq 0 ] +then + EchoVert "Ok" +else + EchoRouge "Erreur" +fi +} + +TestARP() { + if [ -z "$3" ]; then + # recherche de l'interface reseau + test + interface=`ip route get $1 2> /dev/null|sed -ne '/ via /! s/^.* dev \([^ ]\+\) \+src \+.*$/\\1/p;Q'` + [ "$interface" = "" ] && EchoRouge " Erreur interne impossible de determiner l'interface" + /sbin/ifconfig $interface > /dev/null 2>&1 + [ ! $? = 0 ] && EchoRouge " Erreur interne impossible de determiner l'interface" + else + interface=$3 + fi + + # utilisation d'arping + printf ". %${len_pf}s => " "$2" + /usr/bin/arping -w 1 -c 1 -f $1 -I $interface > /dev/null 2>&1 + if [ $? -eq 0 ] + then + EchoVert "Ok" + else + EchoRouge "Erreur" + fi +} + +TestService() { +printf ". %${len_pf}s => " "$1" +CMD="/usr/bin/tcpcheck 2 $2 2> /dev/null | grep -q \" alive\"" +if [ ! "$3" = "" ]; then + CreoleRun "$CMD" "$3" + ret=$? +else + CreoleRun "$CMD" + ret=$? +fi +if [ $ret -eq 0 ] +then + EchoVert "Ok" + return 0 +else + EchoRouge "Erreur" + return 1 +fi +} + +TestUDP() { +printf ". %${len_pf}s => " "$1" +CMD="netstat -unl | grep -q \":$2 \"" +if [ ! "$3" = "" ]; then + CreoleRun "$CMD" "$3" + ret=$? +else + CreoleRun "$CMD" + ret=$? +fi +if [ $ret -eq 0 ] +then + EchoVert "Ok" + return 0 +else + EchoRouge "Erreur" + return 1 +fi +} + +TestPid() { +printf ". %${len_pf}s => " "$1" +pidof "$2" > /dev/null +if [ $? -eq 0 ];then + EchoVert "Ok" + return 0 +else + EchoRouge "Erreur" + return 1 +fi +} + +TestDns() { +printf ". %${len_pf}s => " "DNS $1" +/usr/bin/host -W2 -tA $2 $1 > /dev/null 2>&1 +if [ $? -eq 0 ];then + EchoVert "Ok" + return 0 +else + EchoRouge "Erreur" + return 1 +fi +} + +TestNTP() { +printf ". %${len_pf}s => " "Statut NTP" +/usr/bin/ntpstat > /dev/null 2>&1 +if [ $? -eq 0 ] +then + EchoVert "Synchronisé" +elif [ $? -eq 1 ] +then + EchoRouge "Désynchronisé" + for ntp in $1;do + printf ". %${len_pf}s => " "NTP $ntp" + /usr/sbin/ntpdate -q $ntp > /dev/null 2>&1 + if [ $? -eq 0 ]; then + EchoVert "Ok" + else + EchoRouge "Erreur" + fi + done +else + EchoRouge "Erreur" +fi +} + +TestHTTPPage() { +printf ". %${len_pf}s => " "$1" +/usr/bin/httping -g $2 -c 1 > /dev/null 2>&1 +if [ $? -eq 0 ] +then + EchoVert "Ok" +else + EchoRouge "Erreur" +fi +} + +TestWeb() { +WGET_OPTIONS="-t2 --connect-timeout=3 --delete-after" +WARN_MSG="" +PROXIES_TESTS="PROXY:" +if [ "$(CreoleGet activer_proxy_client)" == "oui" ] +then + PROXIES_TESTS="PROXY:http://$(CreoleGet proxy_client_adresse):$(CreoleGet proxy_client_port)" +fi + +for PROXY_LOOP in $PROXIES_TESTS +do + PROXY=$(echo $PROXY_LOOP | sed -e 's/^PROXY://') + export http_proxy=$PROXY + if [ -n "$PROXY" ] + then + Proxy=` echo $http_proxy | sed -e 's!http://!!' ` + TestService "Serveur Proxy" $Proxy + if [ $? -ne 0 ] + then + #EchoRouge "Erreur" + #return 1 + export http_proxy= + fi + fi + # Test 1er site + wget -q $WGET_OPTIONS $2 + if [ $? -eq 0 ] + then + printf ". %${len_pf}s => " "$1" + EchoVert "Ok" + return 0 + fi + if [ "$3" != "" ] + then + # Test second site + msg=$(wget -nv $WGET_OPTIONS $3 2>&1) + ret=$? + if [ $ret -eq 0 ] + then + printf ". %${len_pf}s => " "$1" + EchoVert "Ok" + return 0 + elif [ $ret -eq 8 ] + then + WARN_MSG="$msg" + fi + fi +done + +printf ". %${len_pf}s => " "$1" +if [ -n "$WARN_MSG" ] +then + EchoOrange "$WARN_MSG" +else + EchoRouge "Erreur" +fi +return 1 +} + +TestCerts() { + CERTFILE=$1 + + # CODEERROR and MESSAGE not used now + # ref #22341 + #CODEERROR=$2 + #man verify for CODEERROR + #MESSAGE=$3 + # + + if [ -z "$4" ]; then + echo "$CERTFILE" | grep -q '^/etc/ipsec.d/' + [ $? = 0 ] && CAFILE=/etc/ipsec.d/cacerts/CertifCa.pem || CAFILE=/etc/ssl/certs/ca.crt + else + # Fichier de CA spécifié, on désactive l'utilisation + # des autres autorités installées sur le système. + CAFILE=$4 + fi + FAKE_CAPATH="/usr/lib/ssl/no_certs" + TMPFILE=$(mktemp) + mkdir -p "$FAKE_CAPATH" + if [[ -d ${CAFILE} ]] + then + cat ${CAFILE}/* > ${TMPFILE} + CAFILE=${TMPFILE} + fi + ssl_cmd="/usr/bin/openssl verify -CAfile $CAFILE -CApath $FAKE_CAPATH -purpose any $CERTFILE" + printf ". %${len_pf}s => " `basename $CERTFILE` + if [ -e $CAFILE ]; then + if [ -e $CERTFILE ]; then + if [ ! -s $CAFILE ] || [ ! -s $CERTFILE ]; then + EchoRouge "fichier vide" + else + sslmsg="`$ssl_cmd 2>&1`" + ERR_MSG=$(printf "$sslmsg" |grep "^error [0-9]* at ") + RETCODE=$? + # supression du répertoire temporaire + rm -rf "$FAKE_CAPATH" + if [ $RETCODE -eq 0 ]; then + #EchoRouge "Erreur openssl" + ERR_MSG=$(cut -d':' -f2 <<< $ERR_MSG) + EchoRouge "Erreur : $ERR_MSG" + return 1 + else + EchoVert "Ok" + printf ". %${len_pf}s => " "DNS reconnus" + openssl x509 -in $CERTFILE -noout -text \ + | sed -n -e '/X509v3 Subject Alternative Name/{n;p;}' \ + | sed -e 's/^ *//' -e 's/DNS://g' -e 's/,//g' \ + -e 's/IP Address:[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+//g' + return 0 + fi + fi + else + EchoRouge "$CERTFILE inexistant" + fi + else + EchoRouge "$CAFILE inexistant" + fi +} + +TestConnexion() { + connexions=( `/bin/netstat -a --$2 -p -n | grep $1 | grep $3` ) + retour=1 + if [ "$2" = "tcp" ]; then + sens=$4 + + if [ "$sens" = "reception" ]; then + pos=3 + incr=2 + cond='LISTEN' + elif [ "$sens" = "envoi" ]; then + pos=4 + incr=1 + cond='ESTABLISHED' + fi + for indice in `seq $pos 7 ${#connexions[*]}`; do + if [[ ${connexions[$indice]} == *$3* ]]; then + if [[ ${connexions[$(( $indice + $incr ))]} == $cond ]]; then + retour=0 + fi + fi + done + + elif [ "$2" = "udp" ]; then + if [ ${#connexions[*]} -gt 1 ]; then + retour=0 + fi + fi + + if [[ $retour == 0 ]]; then + return 0 + else + return 1 + fi +} + + +# +# @NAME : TestMailQ +# @AIM : Tester si la file d'attente du mailer a des messages "frozen" +# @PARAMS : None +# +function TestMailQ() +{ + ckqueue="exiqgrep -i" + # Nombre de messages "Frozen" + printf ". %${len_pf}s => " "File d'attente" + mailq=$(CreoleRun "${ckqueue} 2>&1 | wc -l" mail) + if [[ ${mailq} -eq 0 ]] + then + EchoVert "0 message" + else + EchoOrange "${mailq} message(s)" + fi + + frozen="exiqgrep -z -i" + # Nombre de messages "Frozen" + printf ". %${len_pf}s => " "Messages \"Frozen\"" + mailfrz=$(CreoleRun "${frozen} 2>&1 | wc -l" mail) + if [[ ${mailfrz} -eq 0 ]] + then + EchoVert "0 message" + else + EchoOrange "${mailfrz} message(s)" + fi +} diff --git a/lib/eole/ihm.sh b/lib/eole/ihm.sh new file mode 100644 index 0000000..ce8e6a1 --- /dev/null +++ b/lib/eole/ihm.sh @@ -0,0 +1,132 @@ +#!/bin/bash + +TPUT=/usr/bin/tput +#test si TPUT est utilisable +if [ ! "$TERM" = "" ] && $TPUT hpa 60 >/dev/null 2>&1 && $TPUT setaf 1 >/dev/null 2>&1; then + FANCYTTY=1 +else + FANCYTTY=0 +fi + +Pause() { +if [ "$ModeTxt" == "yes" ];then + echo +elif [ "$ModeEad" == "yes" ];then + echo "
" +else + [ $FANCYTTY = 1 ] && $TPUT setaf 6 + echo " Appuyez sur Entrée pour continuer ..." + [ $FANCYTTY = 1 ] && $TPUT sgr0 + read BiDon +fi +} + +Echo() { +if [ "$ModeEad" != "yes" ]; +then + echo "$1" +else + echo "$1
" +fi +} + +EchoColor() { +if [ "$ModeTxt" = "yes" ];then + echo "$1" +elif [ "$ModeEad" = "yes" ];then + echo " $1
" +else + [ "$FANCYTTY" = 1 ] && $TPUT setaf $2 + echo "$1" + [ "$FANCYTTY" = 1 ] && $TPUT sgr0 +fi +} + +EchoRouge() { + EchoColor "$1" "1" "red" +} + +EchoVert() { + EchoColor "$1" "2" "green" +} + +EchoOrange() { + EchoColor "$1" "3" "orange" +} + +EchoBleu() { + EchoColor "$1" "4" "blue" +} + +EchoMagenta() { + EchoColor "$1" "5" "magenta" +} + +EchoCyan() { + EchoColor "$1" "6" "cyan" +} + +EchoBlanc() { + EchoColor "$1" "7" "white" +} + +EchoGras() { +if [ "$ModeTxt" == "yes" ];then + echo "$1" +elif [ "$ModeEad" == "yes" ];then + echo " $1
" +else + [ $FANCYTTY = 1 ] && $TPUT bold + echo "$1" + [ $FANCYTTY = 1 ] && $TPUT sgr0 +fi +} + +Clear() { +if [ "$ModeEad" != "yes" -a "$ModeTxt" != "yes" ];then + clear +fi +} + +Question_ouinon() { + #attention, il faut synchroniser les modifications avec /usr/share/pyshared/pyeole/ihm.py + question=$1 + [ "$2" = "" ] && interactive='True' || interactive=$2 + [ "$3" = "" ] && default="non" || default=$3 + [ "$4" = "" ] && level="info" || level=$4 + [ "$5" = "" ] && default_uninteractive=$default || default_uninteractive=$5 + [ ! "$interactive" = "True" ] && [ ! "$interactive" = "False" ] && echo "Question_ouinon : interactive doit être True ou False" && exit 1 + [ ! "$default" = "oui" ] && [ ! "$default" = "non" ] && echo "Question_ouinon : default doit etre oui ou non" && exit 1 + [ ! "$default_uninteractive" = "oui" ] && [ ! "$default_uninteractive" = "non" ] && echo "Question_ouinon : default_uninteractive doit etre oui ou non" && exit 1 + [ ! "$level" = "info" ] && [ ! "$level" = "warn" ] && [ ! "$level" = "err" ] && echo "Question_ouinon : level doit etre info, warn ou err" && exit 1 + #non interactive + if [ "$interactive" = "False" ]; then + Rep=default_uninteractive + else + question="$question [oui/non]" + if [ $level = "info" ]; then + echo "$question" + elif [ $level = "warn" ]; then + EchoOrange "$question" + else + EchoRouge "$question" + fi + echo -n "[$default] : " + read Rep + #passe en minuscule + Rep=`echo $Rep | tr A-Z a-z` + fi + if [ "$default" = "non" ]; then + if [ "$Rep" = "oui" -o "$Rep" = "o" -o "$Rep" = "yes" -o "$Rep" = "y" ];then + return 0 + else + return 1 + fi + else + if [ "$Rep" = "non" -o "$Rep" = "n" -o "$Rep" = "no" ];then + return 1 + else + return 0 + fi + fi +} diff --git a/lib/eole/utils.sh b/lib/eole/utils.sh new file mode 100644 index 0000000..5ad3360 --- /dev/null +++ b/lib/eole/utils.sh @@ -0,0 +1,64 @@ +. /usr/lib/eole/ihm.sh + +TestFile() +{ + [ -f "$1" ] && return 0 + EchoRouge "* Erreur : fichier $1 absent" + echo + return 1 +} + +TestDir() +{ + [ -d "$1" ] && return 0 + EchoRouge "* Erreur : répertoire $1 absent" + echo + return 1 +} + +# +# @NAME : TestCreoled +# @AIM : Tester si Creoled fonctionne +# @PARAMS : None +# +function TestCreoled() +{ + var_name='eole_version' + if ! CreoleGet ${var_name} > /dev/null + then + EchoRouge "* Erreur : Creoled n'est pas actif" + return 1 + fi +} + +function wait_true_retcode() +{ +# teste une commande en boucle jusqu'à ret_code=0 +# ou $tries boucles +# exemple : wait_true_retcode "texte" "commande param1 param2" + tries=120 + ret_code=1 + i=0 + echo -n $1 + until [ $ret_code -eq 0 ] || [ $i -ge $tries ] + do + i=`expr $i + 1` + sleep 1 + eval $2 + ret_code=$? + echo -n "." + done + echo + if [ $i -eq $tries ] + then + EchoRouge "L'action '$1' n'a pas aboutie." + exit $ret_code + fi +} + +function only_root() +{ + [ ! $(id -u) = 0 ] && echo "$0 ne peut être exécuté qu'en root" && exit 1 +} + + diff --git a/lib/eole/zephir.sh b/lib/eole/zephir.sh new file mode 100644 index 0000000..6c8f3cb --- /dev/null +++ b/lib/eole/zephir.sh @@ -0,0 +1,28 @@ +# Les Fonctions Zephir +# Trois parametres +# Code Etat (ex INIT;FIN) +# Message (Libéllé) +# Type de procédure(ex MAj,RECONFIGURE, INSTANCE) + +ProgZephir=${RepZephir="/usr/share/zephir/scripts"} + +Zlog(){ +$RepZephir/Zlog.py "$1" "$2" "$3" +} + +Zephir() { +$RepZephir/Zephir.py "$1" "$2" "$3" +} + +# Verifie si une fonction est bloquée par Zephir +# Une erreur retourne OK pour ne pas bloquer la procédure +Init() { +ProgZephir=$RepZephir/Zinit.py +if [ -x $ProgZephir ];then + $ProgZephir $1 + return $? +else + echo "Avertissement : $ProgZephir non trouvé" + return 0 +fi +} diff --git a/local/XX_dico_exemple.xml.sample b/local/XX_dico_exemple.xml.sample new file mode 100644 index 0000000..7b56db8 --- /dev/null +++ b/local/XX_dico_exemple.xml.sample @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + nom-du-paquet-a-installer-dans-le-conteneur + + + + nom-du-service-a-lancer-dans-le-conteneur + + + + + + + + + + oui + + + + + + + + + + + je suis une chaine + + + + + + + + non + + + + + + + + + + + + + + + + + + + non + + + famille_demo + + + demo + + + demoservices + + + + + non + variablecachee + + + + + nom_machine + + + + + ma_slave + + + + + Message d'aide du type Activier un service type pour les besoins de démonstration + + diff --git a/logrotate/creole b/logrotate/creole new file mode 100644 index 0000000..298db32 --- /dev/null +++ b/logrotate/creole @@ -0,0 +1,10 @@ +/var/log/creole.log +/var/log/rsyslog/local/creoled/*.log +/var/log/reconfigure.log { + rotate 4 + weekly + missingok + notifempty + compress + delaycompress +} diff --git a/logrotate/schedule b/logrotate/schedule new file mode 100644 index 0000000..ccb00aa --- /dev/null +++ b/logrotate/schedule @@ -0,0 +1,5 @@ +/var/log/schedule.log { + rotate 10 + notifempty + weekly +} diff --git a/motd/91-eole-upgrade b/motd/91-eole-upgrade new file mode 100644 index 0000000..ac53f76 --- /dev/null +++ b/motd/91-eole-upgrade @@ -0,0 +1,4 @@ +#!/bin/bash + +printf " +" diff --git a/po_list b/po_list new file mode 100644 index 0000000..714d192 --- /dev/null +++ b/po_list @@ -0,0 +1,3 @@ +creole creole/*.py bin/Maj-Auto bin/Query-Auto bin/Maj-Release +update-manager upgrade/Upgrade-Auto +eole-schedule schedule/schedule diff --git a/po_update.sh b/po_update.sh new file mode 100755 index 0000000..0dc0df8 --- /dev/null +++ b/po_update.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# Création du fichier .pot et mise à jour des fichiers .po à partir des informations du fichier po_list +if [[ -e po_list ]]; then + while read p; do + project=$(echo $p |awk '{print $1}') + files=$(echo $p |cut -f 1 -d " " --complement) + if [[ ! -d translation/fr ]]; then + mkdir -p translation/fr + fi + if [[ ! -d translation/en ]]; then + mkdir -p translation/en + fi + # Création des fichiers po minimum (fr et en) si nécessaire. + xgettext -L Python --keyword=_:1,2 --from-code=UTF-8 --force-po -F --copyright-holder="projet EOLE" --package-name=$project --msgid-bugs-address=eole@ac-dijon.fr --foreign-user -d $project -o translation/$project.pot $files + sed -i -e 's/\("Content-Type: text\/plain; charset=\).*\(\\n"\)/\1UTF-8\2/g' translation/$project.pot + + # Mise à jour des fichiers po présents sous ./translation + for po_file in $(find translation -name $project.po); do + msgmerge -U $po_file translation/$project.pot + done + + if [[ ! -e translation/fr/${project}.po ]]; then + msginit -i translation/${project}.pot -o translation/fr/${project}.po -l fr_FR + sed -i -e "s/\\(\"PO-Revision-Date: \\).*\\(\\\\n\"\\)/\\1$(date '+%Y-%m-%d %H:%M%z')\\2/g" \ + -e 's/\("Language-Team: \).*\(\\n"\)/\1Équipe EOLE \2/g' \ + -e 's/\("Content-Type: text\/plain; charset=\).*\(\\n"\)/\1UTF-8\2/g' \ + translation/fr/${project}.po + fi + # Le fichier po "en" est écrasé. + msgen -o translation/en/$project.po translation/$project.pot + sed -i -e 's/\("Last-Translator: \).*\(\\n"\)/\1Équipe EOLE \2/g' \ + -e "s/\\(\"PO-Revision-Date: \\).*\\(\\\\n\"\\)/\\1$(date '+%Y-%m-%d %H:%M%z')\\2/g" \ + -e 's/\("Language-Team: \).*\(\\n"\)/\1Équipe EOLE \2/g' \ + -e 's/\("Language: \).*\(\\n"\)/\1en\2/g' \ + -e 's/\("Content-Type: text\/plain; charset=\).*\(\\n"\)/\1UTF-8\2/g' \ + -e 's/\("Plural-Forms: \).*/\1nplurals=2; plural=(n > 1);\\n"/' \ + -e '1,5 d' \ + translation/en/${project}.po + + done < po_list +fi + + diff --git a/sbin/creoled b/sbin/creoled new file mode 100755 index 0000000..0596bc1 --- /dev/null +++ b/sbin/creoled @@ -0,0 +1,9 @@ +#!/usr/bin/python + +from creole.server import CreoleDaemon +from pyeole.ihm import only_root + +only_root() + +d = CreoleDaemon() +d.run() diff --git a/schedule/config.sh b/schedule/config.sh new file mode 100755 index 0000000..4740886 --- /dev/null +++ b/schedule/config.sh @@ -0,0 +1,6 @@ +# Configuration commune aux scripts schedule + +SAVDIR=/home/backup +# pour que l'affichage de [ ok ] soit ok +export TERM='dumb' +umask 0077 diff --git a/schedule/schedule b/schedule/schedule new file mode 100755 index 0000000..139e11d --- /dev/null +++ b/schedule/schedule @@ -0,0 +1,217 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +utilitaire de lancement en fonction + +- cron +- bareos + +""" +import sys +import time +from os import readlink, unlink +from os.path import join +from glob import glob + +from pyeole.process import system_out +from pyeole.schedule import SCHEDULE_DIR +from pyeole.bareos import is_running_jobs, bareos_get_jobs_list +from creole.client import CreoleClient +from pyeole.i18n import i18n +from pyeole.log import init_logging + +_ = i18n('eole-schedule') + +log = init_logging(name=u'eole-schedule', level='info', syslog=True, + console=['stdout', 'stderr']) + +client = CreoleClient() + +NOW = time.strftime('%d/%m/%y %H:%M', time.localtime()) +# day in month +MONTH_DAY = int(time.strftime('%d', time.localtime())) +# day in week +WEEK_DAY = int(time.strftime('%w', time.localtime())) +HOUR = int(time.strftime('%H', time.localtime())) + +# night start at 12 +if HOUR > 12: + WEEK_DAY += 1 + +if WEEK_DAY == 0: + # sunday is 7 + WEEK_DAY = 7 +if WEEK_DAY == 8: + WEEK_DAY = 1 + + +def log_parts(func): + def split(msg): + shreds = msg.split('\n') + return [func(shred) for shred in shreds if len(shred) > 0] + return split + +log.info = log_parts(log.info) +log.error = log_parts(log.error) +log.warning = log_parts(log.warning) + + +def run_runparts(mode, bareos_type): + """ + run part script + test if weekly or monthly script must be launched this day + """ + if mode == 'weekly' and WEEK_DAY != client.get('/schedule/schedule/weekday'): + return + if mode == 'monthly' and ( WEEK_DAY != client.get('/schedule/schedule/monthday') or MONTH_DAY > 7 ): + return + part_str = u"{} schedule {}".format(bareos_type, mode) + log.info(_("Starting {}").format(part_str)) + dirname = join(SCHEDULE_DIR, mode, bareos_type) + env = {'PATH': '/sbin:/usr/sbin:/bin:/usr/bin:/usr/share/eole', + 'LC_ALL': 'fr_FR.UTF-8'} + if mode != 'once': + runparts_cmd = "/bin/run-parts --exit-on-error --report {} --arg {}" + wrapped_runparts_cmd = ['/bin/bash', + '-c', + runparts_cmd.format(dirname, mode)] + ret, out, err = system_out(wrapped_runparts_cmd, env=env) + else: + # unlink script before launch it + # (for example remove 'reboot' link before restart the machine) + names = glob(join(dirname, '*')) + names.sort() + ret = 0 + out = None + err = None + for name in names: + script = readlink(name) + unlink(name) + wrapped_runparts_cmd = ['/bin/bash', + '-c', script] + ret, out, err = system_out(wrapped_runparts_cmd, env=env) + if ret != 0: + break + if out: + log.info(out) + if err: + log.error(err) + if ret != 0: + # on affiche sur stderr pour que cron le récupère et le mail + # ce qui est printé sur stdout est envoyé dans les logs + if out: + sys.stderr.write(out) + if err: + sys.stderr.write(err) + sys.stderr.write(_("Error detected\n")) + log.error(_("{} exited with error return code").format(part_str)) + sys.exit(ret) + else: + log.info(_("{} finished").format(part_str)) + + +def schedule_pre(): + run_runparts('daily', 'pre') + run_runparts('weekly', 'pre') + run_runparts('monthly', 'pre') + run_runparts('once', 'pre') + + +def schedule_post(): + i = 0 + while is_running_jobs(): + time.sleep(1) + i += 1 + if i == 30: + log.info(_("Job already running, cancelling")) + sys.exit(1) + run_runparts('daily', 'post') + run_runparts('weekly', 'post') + run_runparts('monthly', 'post') + run_runparts('once', 'post') + + +def schedule_cron(): + """ + If schedule.py is launched by cron, try to run pre and post + cron file for daily, weekly and monthly if no backup is set this day + """ + def exit_not_cron(): + log.info(_("bareos is set for this day, cancelled")) + sys.exit(0) + try: + bareosjobs = bareos_get_jobs_list() + for job in bareosjobs: + day = int(job['day']) + if job['job'] == 'daily': + if day <= WEEK_DAY <= job['end_day']: + exit_not_cron() + elif job['job'] == 'weekly': + if WEEK_DAY == day: + exit_not_cron() + elif job['job'] == 'monthly': + if WEEK_DAY == day and MONTH_DAY < 8: + exit_not_cron() + else: + raise Exception(_('Unknown job: {0}').format(job['job'])) + except SystemExit: + raise + except: + pass + run_runparts('daily', 'pre') + run_runparts('daily', 'post') + + run_runparts('weekly', 'pre') + run_runparts('weekly', 'post') + + run_runparts('monthly', 'pre') + run_runparts('monthly', 'post') + + run_runparts('once', 'pre') + run_runparts('once', 'post') +# __________________________________________________ + + +if __name__ == '__main__': + + usage = """usage: +{0} bareos [pre|post] +{0} cron""".format(sys.argv[0]) + + if len(sys.argv) == 1: + print usage + sys.exit(1) + + if len(sys.argv) > 3: + log.error(_("Too many arguments: {0}").format(sys.argv)) + print usage + sys.exit(1) + + mode = sys.argv[1] + + if mode == 'bareos': + # pre|post + if len(sys.argv) == 2: + log.error(_("Not enough arguments: {0}").format(sys.argv)) + print usage + sys.exit(1) + if sys.argv[2] not in ['pre', 'post']: + log.error(_("Second argument must be pre or post: {0}").format(sys.argv)) + print usage + sys.exit(1) + bareos_type = sys.argv[2] + if bareos_type == 'pre': + schedule_pre() + elif bareos_type == 'post': + schedule_post() + + elif mode == 'cron': + if len(sys.argv) != 2: + log.error(_("Too many arguments for cron: {0}").format(sys.argv)) + print usage + sys.exit(1) + schedule_cron() + else: + log.error(_("Unknown schedule type : {0}").format(mode)) + print usage + sys.exit(1) diff --git a/schedule/schedule_bareos b/schedule/schedule_bareos new file mode 100755 index 0000000..9b75f3c --- /dev/null +++ b/schedule/schedule_bareos @@ -0,0 +1,15 @@ +#!/bin/bash +# script pour rediriger la sortie standard/erreur dans les logs + +OPT=$1 + +if [ "$OPT" = "pre" ]; then + /usr/share/eole/schedule/schedule bareos $OPT # faire apparaitre les run-parts dans le rapport de sauvegarde, ne pas rediriger >> /var/log/schedule.log 2>&1 + exit $? +elif [ "$OPT" = "post" ]; then + echo "/usr/share/eole/schedule/schedule bareos $OPT >> /var/lib/eole/reports/rapport-bareos.txt 2>&1" | at now + exit $? +else + echo Usage : $0 pre/post + exit 1 +fi diff --git a/schedule/scripts/majauto b/schedule/scripts/majauto new file mode 100755 index 0000000..3292ba6 --- /dev/null +++ b/schedule/scripts/majauto @@ -0,0 +1,8 @@ +#!/bin/bash + +DESC="Mise à jour du serveur" + +if [ "$1" == "once" ];then + rm -f /var/lib/eole/reports/maj-diff.txt +fi +/usr/bin/Maj-Auto -R diff --git a/schedule/scripts/y_reconfigureauto b/schedule/scripts/y_reconfigureauto new file mode 100755 index 0000000..b33b418 --- /dev/null +++ b/schedule/scripts/y_reconfigureauto @@ -0,0 +1,5 @@ +#!/bin/bash + +DESC="Reconfiguration du serveur" + +/usr/bin/reconfigure --auto >/var/lib/eole/reports/reconfigure-once.txt 2>&1 diff --git a/schedule/scripts/z_rebootauto b/schedule/scripts/z_rebootauto new file mode 100755 index 0000000..5ee4db8 --- /dev/null +++ b/schedule/scripts/z_rebootauto @@ -0,0 +1,5 @@ +#!/bin/bash + +DESC="Redémarrage du serveur" + +/sbin/reboot diff --git a/schedule/scripts/z_shutdownauto b/schedule/scripts/z_shutdownauto new file mode 100755 index 0000000..a3fc4c2 --- /dev/null +++ b/schedule/scripts/z_shutdownauto @@ -0,0 +1,5 @@ +#!/bin/bash + +DESC="Arrêt du serveur" + +/sbin/halt -p diff --git a/scripts/ParsePEM.py b/scripts/ParsePEM.py new file mode 100755 index 0000000..b5f3901 --- /dev/null +++ b/scripts/ParsePEM.py @@ -0,0 +1,112 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +##################### +# Parse pour Certificat +# Version Alpha +# LB 12/2002 +# $Id: ParsePEM.py,v 1.1.1.1 2004/01/05 10:50:56 eole Exp $ +##################### +import string,getopt,sys + + +def Usage(): + print "Usage : " + print "ParsePem -i FichierPem -o Repertoire de destination" + print """ +Fonction: + Recuperer les 2 Certificats (CA+Serveur) + contenus dans le fichier en entré et creer + deux fichiers CertifCa et CertifServeur + dans le Repertoire de destination + """ + sys.exit + +def Option(): + global Input , Output + try: + (opt, args) = getopt.getopt(sys.argv[1:], "hi:o:" ,["help","input=","output="]) + except: + getopt.GetoptError + Usage() + sys.exit(1) + #print "opt=%s" % opt + for (o , ch) in opt: + if o in ("-h", "--help"): + Usage() + sys.exit() + if o in ("-o","--output"): + if ch == "": + Usage() + Output = ch + if o in ("-i","--intput"): + if ch == "": + Usage() + Input = ch + +def CreFic(Nom): + + Fichier = Output+"/"+Nom + print "%s" % Fichier + try: + Desc= open(Fichier,"w") + except: + print "Fichier %s Non créé" % Fichier + sys.exit(2) + return(Desc) + +def Avance(Cherche): + global ligne + while ( ligne.find(Cherche)== -1 ): + #print "Ligne=%s" % ligne + ligne=Fic.readline() + if ligne=='': + print "Erreur Fichier %s Non conforme" % Input + print "Chaine %s non trouvéé" % Cherche + sys.exit(2) + +##################### MAIN ################ +Input=Output="" +Option() +print "In=%s Out=%s" % (Input , Output) +if (Input==""): + Fic=sys.stdin +else: + try: + Fic= open(Input,"r") + except: + print "Fichier %s Non trouvé" % Input + sys.exit(2) + +C1=CreFic("CertifCa.pem") + +ligne=Fic.readline() +Avance("-BEGIN CERTIF") +#Certif CA trouvé " +while (ligne.find("-END CERTIF")==-1): + C1.write(ligne) + ligne=Fic.readline() + if ligne=='': + print "Erreur Cerificat CA " + sys.exit(2) +C1.write(ligne) + +Avance("subject=") +(Bid,CN)=ligne.split("CN=") +outf="%s.pem" % CN.strip() +C2=CreFic(outf) +Avance("-BEGIN CERTIF") +#Certif Client trouvé " +while (ligne.find("-END CERTIF")==-1): + C2.write(ligne) + ligne=Fic.readline() + if ligne=='': + print "Erreur Cerificat Serveur " + sys.exit(2) +C2.write(ligne) + + + + + + diff --git a/scripts/Upgrade-Auto b/scripts/Upgrade-Auto new file mode 100755 index 0000000..7bf42f0 --- /dev/null +++ b/scripts/Upgrade-Auto @@ -0,0 +1,51 @@ +#!/bin/sh + +#------------------------------------------------------------------------ +# Upgrade-Auto - Wrapper to log upgrade of an EOLE server +# Copyright © 2016 Équipe EOLE +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +set -e + +#------------------------------------------------------------------------ +# Delegate help +# +if echo "$@" | grep -qse '-h\|--help' +then + /usr/share/eole/upgrade/Upgrade-Auto --help + exit 0 +fi + +#------------------------------------------------------------------------ +# Open log +# +LOG_FILE='/var/log/upgrade-auto.log' +PIPE="/run/upgrade-auto.fifo" + +[ ! -p "${PIPE}" ] || rm -f "${PIPE}" +mkfifo ${PIPE} + +# Use a function to strip ANSI colors from log +tee <${PIPE} "${LOG_FILE}" & +exec 1>&- +exec 2>&- + +exec 1> ${PIPE} +exec 2> ${PIPE} + +[ ! -p "${PIPE}" ] || rm -f "${PIPE}" + +/usr/share/eole/upgrade/Upgrade-Auto $@ diff --git a/scripts/manage_schedule b/scripts/manage_schedule new file mode 100755 index 0000000..87b675e --- /dev/null +++ b/scripts/manage_schedule @@ -0,0 +1,90 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys +from pyeole.schedule import display_schedules, ManageSchedule, \ + apply_schedules, add_schedule, del_schedule +from pyeole.ansiprint import print_orange +from optparse import OptionParser, OptionGroup + + +def main(): + parser = OptionParser() + parser.add_option("-l", "--list", dest="list", action="store_true", + default=False, help=u"Liste les scripts activés et désactivés") + parser.add_option("--apply", dest="apply", help=u"Active/désactive les scripts dans le schedule", + action='store_true', default=False) + group = OptionGroup(parser, u"Activer un script (ne pas oublier d'appliquer la configuration)") + group.add_option("-a", "--add", dest="add", help=u"Périodicité : une fois (once), tous les jours (daily), toutes les semaines (weekly) ou tous les mois (monthly)") + group.add_option("-s", "--script", dest="script", help=u"Nom du script") + group.add_option("-m", "--mode", dest="mode", help=u"Mode : avant la sauvegarde (pre) ou après la sauvegarde (post)") + parser.add_option_group(group) + parser.add_option("-d", "--del", dest="delete", help=u"Désactive le script en précisant son nom (ne pas oublier d'appliquer la configuration)") + (option, args) = parser.parse_args() + + if option.delete is None and option.add is None and option.list is False and option.apply is False: + parser.print_help() + sys.exit(0) + + if (option.delete is not None and option.add is not None) or \ + (option.list is True and option.add is not None) or \ + (option.delete is not None and option.list is True) or \ + (option.apply is True and option.add is not None) or \ + (option.apply is True and option.list is True) or \ + (option.apply is True and option.delete is True): + parser.print_help() + print "can't list, apply, add or delete together" + print + sys.exit(1) + + if option.add is not None and None in [option.script, option.mode]: + print "you should specified -s and -m with -a" + print + parser.print_help() + sys.exit(1) + + if option.delete == 'once' and None in [option.script, option.mode]: + print "you must specify mode if you want delete 'once' script" + print + parser.print_help() + sys.exit(1) + + if option.delete != 'once' and ((option.script is not None and option.add is None) or \ + (option.mode is not None and option.add is None)): + print "you should specified -s and -m only with -a" + print + parser.print_help() + sys.exit(1) + + if option.list: + display_schedules() + + if option.add is not None: + try: + if option.add == 'once': + add_schedule(option.add, option.mode, option.script) + else: + sch = ManageSchedule() + sch.add(option.script, option.add, option.mode) + sch.save() + except Exception, err: + print_orange(str(err)) + sys.exit(1) + + if option.delete is not None: + try: + if option.delete == 'once': + del_schedule(option.delete, option.mode, option.script) + else: + sch = ManageSchedule() + sch.delete(option.delete) + sch.save() + except Exception, err: + print_orange(str(err)) + sys.exit(1) + + if option.apply is not None: + apply_schedules() + +if __name__ == '__main__': + main() diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..7c2c961 --- /dev/null +++ b/setup.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from setuptools import setup +import os, glob + +BASE_DIR = 'share/' +DOC_DIR = os.path.join(BASE_DIR, 'doc/creole') + +# documentation +doc = [(DOC_DIR, glob.glob('doc/*.html') + glob.glob('doc/*.txt')), + (os.path.join(DOC_DIR, 'api'), glob.glob('doc/api/*.html') + glob.glob('doc/api/*.css')), +] + +setup( + author='Équipe EOLE', + author_email='eole@ac-dijon.fr', + name='creole', + version='2.7.0', + description='Eole configuration tools', + url='http://www.eole.orion.education.fr', + packages=['creole', 'creole.lint', 'creole.valid'], + data_files=doc +) diff --git a/tests/configs/amon23.eol b/tests/configs/amon23.eol new file mode 100644 index 0000000..3f89dc2 --- /dev/null +++ b/tests/configs/amon23.eol @@ -0,0 +1,4079 @@ +[activate_dansguardian_realtime] +valdefault = [] +valprec = [] +val = ['non'] + +[activate_squid_realtime] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_ad] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_agregation] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_ajaxplorer] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_ajout_hosts] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_antispoofing] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_apache] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_bacula] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_bacula_dir] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_bacula_sd] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_bash_completion] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_clam] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_clam_fichier] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_client_ldap] +valdefault = [] +valprec = [] +val = ['local'] + +[activer_cntlm] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_courier] +valdefault = [] +valprec = [] +val = ['imap'] + +[activer_ctrl_alt_suppr] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_cups] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_dhcp] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_dhcprelay] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_dns_eth0] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_ead_reverseproxy] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_ead_web] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_envoi_logs] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_envole] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_envole_infos] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_envolemobile] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_esu] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_filtrage_proxy] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_freeradius] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_ipv6] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_log_distant] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_log_martian] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_mysql] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_nut] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_phpmyadmin] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_piwik] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_plugin_cow] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_posh_profil] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_proftpd] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_proxy_client] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_reception_logs] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_reception_logs_relp] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_reception_logs_tcp] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_reception_logs_udp] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_revprox] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_revprox_rewrite] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_routage_ipv4] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_routage_ipv6] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_route] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_sap] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_spamassassin] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_squid2] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_squid_auth] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_squirrelmail] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_sso] +valdefault = [] +valprec = [] +val = ['local'] + +[activer_stats_nat] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_sympa] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_tftp] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_web_behind_revproxy] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_web_valider_ca] +valdefault = [] +valprec = [] +val = ['non'] + +[activer_xdesktop] +valdefault = [] +valprec = [] +val = ['oui'] + +[admin_eth0] +valdefault = [] +valprec = [] +val = ['oui'] + +[admin_eth1] +valdefault = [] +valprec = [] +val = ['oui'] + +[admin_eth2] +valdefault = [] +valprec = [] +val = ['non'] + +[admin_eth3] +valdefault = [] +valprec = [] +val = ['non'] + +[admin_eth4] +valdefault = [] +valprec = [] +val = ['non'] + +[adresse_bcast_eth0_proxy_link] +valdefault = [] +valprec = [] +val = [''] + +[adresse_bcast_eth1_proxy_link] +valdefault = [] +valprec = [] +val = ['10.3.2.255'] + +[adresse_bcast_eth2_proxy_link] +valdefault = [] +valprec = [] +val = ['10.3.1.255'] + +[adresse_bcast_eth3_proxy_link] +valdefault = [] +valprec = [] +val = [''] + +[adresse_bcast_fichier_link] +valdefault = [] +valprec = [] +val = ['10.3.2.255'] + +[adresse_broadcast_eth0] +valdefault = [] +valprec = [] +val = ['192.168.0.255'] + +[adresse_broadcast_eth1] +valdefault = [] +valprec = [] +val = ['10.3.2.255'] + +[adresse_broadcast_eth2] +valdefault = [] +valprec = [] +val = [''] + +[adresse_broadcast_eth3] +valdefault = [] +valprec = [] +val = [''] + +[adresse_broadcast_eth4] +valdefault = [] +valprec = [] +val = [''] + +[adresse_broadcast_vlan_eth0] +valdefault = [] +valprec = [] +val = [''] + +[adresse_broadcast_vlan_eth1] +valdefault = [] +valprec = [] +val = [''] + +[adresse_broadcast_vlan_eth2] +valdefault = [] +valprec = [] +val = [''] + +[adresse_broadcast_vlan_eth3] +valdefault = [] +valprec = [] +val = [''] + +[adresse_broadcast_vlan_eth4] +valdefault = [] +valprec = [] +val = [''] + +[adresse_dns_agriates] +valdefault = [] +valprec = [] +val = [''] + +[adresse_gw_vlan_eth0] +valdefault = [] +valprec = [] +val = ['aucun'] + +[adresse_ip_annuaire] +valdefault = [] +valprec = [] +val = ['192.0.2.50'] + +[adresse_ip_conteneur_dns] +valdefault = [] +valprec = [] +val = ['192.0.2.53'] + +[adresse_ip_dhcp] +valdefault = [] +valprec = [] +val = ['192.0.2.52'] + +[adresse_ip_dhcp_dhcrelay] +valdefault = [] +valprec = [] +val = [''] + +[adresse_ip_dns] +valdefault = [] +valprec = [] +val = ['192.168.232.2'] + +[adresse_ip_dns_dhcp] +valdefault = [] +valprec = [] +val = ['10.3.2.2'] + +[adresse_ip_eth0] +valdefault = [] +valprec = [] +val = ['192.168.0.33'] + +[adresse_ip_eth0_proxy_link] +valdefault = [] +valprec = [] +val = [''] + +[adresse_ip_eth1] +valdefault = [] +valprec = [] +val = ['10.3.2.1'] + +[adresse_ip_eth1_proxy_link] +valdefault = [] +valprec = [] +val = ['10.3.2.2'] + +[adresse_ip_eth2] +valdefault = [] +valprec = [] +val = [''] + +[adresse_ip_eth2_proxy_link] +valdefault = [] +valprec = [] +val = ['10.3.1.2'] + +[adresse_ip_eth3] +valdefault = [] +valprec = [] +val = [''] + +[adresse_ip_eth3_proxy_link] +valdefault = [] +valprec = [] +val = [''] + +[adresse_ip_eth4] +valdefault = [] +valprec = [] +val = [''] + +[adresse_ip_fichier] +valdefault = [] +valprec = [] +val = ['192.0.2.52'] + +[adresse_ip_fichier_link] +valdefault = [] +valprec = [] +val = ['10.3.2.3'] + +[adresse_ip_gw] +valdefault = [] +valprec = [] +val = ['192.168.0.1'] + +[adresse_ip_gw_dhcp] +valdefault = [] +valprec = [] +val = ['10.3.2.1'] + +[adresse_ip_hosts] +valdefault = [] +valprec = [] +val = [''] + +[adresse_ip_ldap] +valdefault = [] +valprec = [] +val = ['192.0.2.50'] + +[adresse_ip_ldap_exterieur] +valdefault = [] +valprec = [] +val = ['10.3.2.1'] + +[adresse_ip_mail] +valdefault = [] +valprec = [] +val = ['192.0.2.51'] + +[adresse_ip_mysql] +valdefault = [] +valprec = [] +val = ['192.0.2.50'] + +[adresse_ip_proxy] +valdefault = [] +valprec = [] +val = ['192.0.2.53'] + +[adresse_ip_serveur_logs] +valdefault = [] +valprec = [] +val = [''] + +[adresse_ip_tftp] +valdefault = [] +valprec = [] +val = ['10.3.2.3'] + +[adresse_ip_vlan_eth0] +valdefault = [] +valprec = [] +val = [''] + +[adresse_ip_vlan_eth1] +valdefault = [] +valprec = [] +val = [''] + +[adresse_ip_vlan_eth2] +valdefault = [] +valprec = [] +val = [''] + +[adresse_ip_vlan_eth3] +valdefault = [] +valprec = [] +val = [''] + +[adresse_ip_vlan_eth4] +valdefault = [] +valprec = [] +val = [''] + +[adresse_ip_web] +valdefault = [] +valprec = [] +val = ['192.0.2.51'] + +[adresse_ip_wpad_exclude] +valdefault = [] +valprec = [] +val = [''] + +[adresse_mask_eth0_proxy_link] +valdefault = [] +valprec = [] +val = [''] + +[adresse_mask_eth1_proxy_link] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[adresse_mask_eth2_proxy_link] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[adresse_mask_eth3_proxy_link] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[adresse_mask_fichier_link] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[adresse_netmask_dhcp] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[adresse_netmask_eth0] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[adresse_netmask_eth1] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[adresse_netmask_eth2] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[adresse_netmask_eth3] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[adresse_netmask_eth4] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[adresse_netmask_vlan_eth0] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[adresse_netmask_vlan_eth1] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[adresse_netmask_vlan_eth2] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[adresse_netmask_vlan_eth3] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[adresse_netmask_vlan_eth4] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[adresse_netmask_wpad_exclude] +valdefault = [] +valprec = [] +val = [''] + +[adresse_netmask_zone_rvp] +valdefault = [] +valprec = [] +val = [''] + +[adresse_network_dhcp] +valdefault = [] +valprec = [] +val = ['10.3.2.0'] + +[adresse_network_eth0] +valdefault = [] +valprec = [] +val = ['192.168.0.0'] + +[adresse_network_eth1] +valdefault = [] +valprec = [] +val = ['10.3.2.0'] + +[adresse_network_eth2] +valdefault = [] +valprec = [] +val = ['10.3.1.0'] + +[adresse_network_eth3] +valdefault = [] +valprec = [] +val = [''] + +[adresse_network_eth4] +valdefault = [] +valprec = [] +val = [''] + +[adresse_network_vlan_eth0] +valdefault = [] +valprec = [] +val = [''] + +[adresse_network_vlan_eth1] +valdefault = [] +valprec = [] +val = [''] + +[adresse_network_vlan_eth2] +valdefault = [] +valprec = [] +val = [''] + +[adresse_network_vlan_eth3] +valdefault = [] +valprec = [] +val = [''] + +[adresse_network_vlan_eth4] +valdefault = [] +valprec = [] +val = [''] + +[adresse_network_zone_rvp] +valdefault = [] +valprec = [] +val = [''] + +[adresse_postale] +valdefault = [] +valprec = [] +val = [''] + +[adresses_ip_clients_logs_relp] +valdefault = [] +valprec = [] +val = [''] + +[adresses_ip_clients_logs_tcp] +valdefault = [] +valprec = [] +val = [''] + +[adresses_ip_clients_logs_udp] +valdefault = [] +valprec = [] +val = [''] + +[adresses_ip_clients_nfs] +valdefault = [] +valprec = [] +val = [''] + +[ag_active_mail] +valdefault = [] +valprec = [] +val = ['non'] + +[ag_dns_eth0] +valdefault = [] +valprec = [] +val = [''] + +[ag_dns_eth0_0] +valdefault = [] +valprec = [] +val = [''] + +[ag_fo_etat_eth0] +valdefault = [] +valprec = [] +val = [''] + +[ag_fo_etat_eth0_0] +valdefault = [] +valprec = [] +val = [''] + +[ag_force_eth0] +valdefault = [] +valprec = [] +val = [''] + +[ag_force_eth0_0] +valdefault = [] +valprec = [] +val = [''] + +[ag_force_netmask_eth0] +valdefault = [] +valprec = [] +val = ['255.255.255.255'] + +[ag_force_netmask_eth0_0] +valdefault = [] +valprec = [] +val = ['255.255.255.255'] + +[ag_mail_dest] +valdefault = [] +valprec = [] +val = [''] + +[ag_mode] +valdefault = [] +valprec = [] +val = ['mode_lb'] + +[ag_nbechecs] +valdefault = [] +valprec = [] +val = ['1'] + +[ag_nbsucces] +valdefault = [] +valprec = [] +val = ['4'] + +[ag_pause] +valdefault = [] +valprec = [] +val = ['10'] + +[ag_testdns] +valdefault = [] +valprec = [] +val = ['www.google.com'] + +[ag_timeout] +valdefault = [] +valprec = [] +val = ['1'] + +[ag_weight_eth0] +valdefault = [] +valprec = [] +val = [''] + +[ag_weight_eth0_0] +valdefault = [] +valprec = [] +val = [''] + +[agriates_member] +valdefault = [] +valprec = [] +val = ['non'] + +[ajaxplorer_ftp] +valdefault = [] +valprec = [] +val = ['192.0.2.52'] + +[alias_broadcast_eth0] +valdefault = [] +valprec = [] +val = [''] + +[alias_broadcast_eth1] +valdefault = [] +valprec = [] +val = [''] + +[alias_broadcast_eth2] +valdefault = [] +valprec = [] +val = [''] + +[alias_broadcast_eth3] +valdefault = [] +valprec = [] +val = [''] + +[alias_broadcast_eth4] +valdefault = [] +valprec = [] +val = [''] + +[alias_envole] +valdefault = [] +valprec = [] +val = ['/envole'] + +[alias_eth0] +valdefault = [] +valprec = [] +val = ['non'] + +[alias_eth1] +valdefault = [] +valprec = [] +val = ['non'] + +[alias_eth2] +valdefault = [] +valprec = [] +val = ['non'] + +[alias_eth3] +valdefault = [] +valprec = [] +val = ['non'] + +[alias_eth4] +valdefault = [] +valprec = [] +val = ['non'] + +[alias_gw_eth0] +valdefault = [] +valprec = [] +val = ['aucun'] + +[alias_ip_eth0] +valdefault = [] +valprec = [] +val = [''] + +[alias_ip_eth1] +valdefault = [] +valprec = [] +val = [''] + +[alias_ip_eth2] +valdefault = [] +valprec = [] +val = [''] + +[alias_ip_eth3] +valdefault = [] +valprec = [] +val = [''] + +[alias_ip_eth4] +valdefault = [] +valprec = [] +val = [''] + +[alias_netmask_eth0] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[alias_netmask_eth1] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[alias_netmask_eth2] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[alias_netmask_eth3] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[alias_netmask_eth4] +valdefault = [] +valprec = [] +val = ['255.255.255.0'] + +[alias_network_eth0] +valdefault = [] +valprec = [] +val = [''] + +[alias_network_eth1] +valdefault = [] +valprec = [] +val = [''] + +[alias_network_eth2] +valdefault = [] +valprec = [] +val = [''] + +[alias_network_eth3] +valdefault = [] +valprec = [] +val = [''] + +[alias_network_eth4] +valdefault = [] +valprec = [] +val = [''] + +[allow_underscore] +valdefault = [] +valprec = [] +val = ['on'] + +[apache_alias] +valdefault = [] +valprec = [] +val = [''] + +[apache_dir] +valdefault = [] +valprec = [] +val = [''] + +[apache_plus] +valdefault = [] +valprec = [] +val = ['non'] + +[autoriser_proxy_autres] +valdefault = [] +valprec = [] +val = ['non'] + +[autoriser_rvp_autres] +valdefault = [] +valprec = [] +val = ['non'] + +[bacula_compression] +valdefault = [] +valprec = [] +val = ['GZIP6'] + +[bacula_diff_retention] +valdefault = [] +valprec = [] +val = ['5'] + +[bacula_diff_retention_unit] +valdefault = [] +valprec = [] +val = ['weeks'] + +[bacula_dir_name] +valdefault = [] +valprec = [] +val = ['amonecole-dir'] + +[bacula_dir_remote_ip] +valdefault = [] +valprec = [] +val = [''] + +[bacula_dir_remote_password] +valdefault = [] +valprec = [] +val = [''] + +[bacula_fd_name] +valdefault = [] +valprec = [] +val = ['127.0.0.1-fd'] + +[bacula_full_retention] +valdefault = [] +valprec = [] +val = ['6'] + +[bacula_full_retention_unit] +valdefault = [] +valprec = [] +val = ['months'] + +[bacula_inc_retention] +valdefault = [] +valprec = [] +val = ['10'] + +[bacula_inc_retention_unit] +valdefault = [] +valprec = [] +val = ['days'] + +[bacula_max_run_time] +valdefault = [] +valprec = [] +val = ['0'] + +[bacula_mon_password] +valdefault = [] +valprec = [] +val = [''] + +[bacula_sd_adresse] +valdefault = [] +valprec = [] +val = [''] + +[bacula_sd_name] +valdefault = [] +valprec = [] +val = ['127.0.0.1-sd'] + +[bacula_sd_password] +valdefault = [] +valprec = [] +val = [''] + +[bacula_sd_remote_dir_name] +valdefault = [] +valprec = [] +val = [''] + +[bacula_sd_remote_ip] +valdefault = [] +valprec = [] +val = [''] + +[bacula_sd_remote_password] +valdefault = [] +valprec = [] +val = [''] + +[bash_tmout] +valdefault = [] +valprec = [] +val = ['0'] + +[cache_dir] +valdefault = [] +valprec = [] +val = ['/var/spool/squid'] + +[cache_dir_2] +valdefault = [] +valprec = [] +val = ['/var/spool/squid2'] + +[cache_dir_disk_space] +valdefault = [] +valprec = [] +val = ['1000'] + +[cache_dir_disk_space_2] +valdefault = [] +valprec = [] +val = ['1000'] + +[cache_dir_firstLevel] +valdefault = [] +valprec = [] +val = ['16'] + +[cache_dir_firstLevel_2] +valdefault = [] +valprec = [] +val = ['16'] + +[cache_dir_secondLevel] +valdefault = [] +valprec = [] +val = ['256'] + +[cache_dir_secondLevel_2] +valdefault = [] +valprec = [] +val = ['256'] + +[cache_dir_type] +valdefault = [] +valprec = [] +val = ['ufs'] + +[cache_dir_type_2] +valdefault = [] +valprec = [] +val = ['ufs'] + +[cache_mem] +valdefault = [] +valprec = [] +val = ['16'] + +[cache_replacement_policy] +valdefault = [] +valprec = [] +val = ['lru'] + +[cache_swap_high] +valdefault = [] +valprec = [] +val = ['95'] + +[cache_swap_low] +valdefault = [] +valprec = [] +val = ['90'] + +[cas_send_logout] +valdefault = [] +valprec = [] +val = ['oui'] + +[cas_verify_service] +valdefault = [] +valprec = [] +val = ['non'] + +[check_hostname] +valdefault = [] +valprec = [] +val = ['on'] + +[check_passwd] +valdefault = [] +valprec = [] +val = ['non'] + +[check_passwd_max] +valdefault = [] +valprec = [] +val = ['40'] + +[check_passwd_min_len_four_type] +valdefault = [] +valprec = [] +val = ['8'] + +[check_passwd_min_len_one_type] +valdefault = [] +valprec = [] +val = ['0'] + +[check_passwd_min_len_three_type] +valdefault = [] +valprec = [] +val = ['8'] + +[check_passwd_min_len_two_type] +valdefault = [] +valprec = [] +val = ['9'] + +[chemin_fichier_pxe] +valdefault = [] +valprec = [] +val = ['/pxelinux.0'] + +[clam_broken_exe] +valdefault = [] +valprec = [] +val = ['no'] + +[clam_checks] +valdefault = [] +valprec = [] +val = ['24'] + +[clam_detect_pua] +valdefault = [] +valprec = [] +val = ['no'] + +[clam_dns_database_info] +valdefault = [] +valprec = [] +val = ['current.cvd.clamav.net'] + +[clam_exit_on_oom] +valdefault = [] +valprec = [] +val = ['no'] + +[clam_forcer_mirror_database] +valdefault = [] +valprec = [] +val = ['non'] + +[clam_iana] +valdefault = [] +valprec = [] +val = ['fr'] + +[clam_max_attempts] +valdefault = [] +valprec = [] +val = ['5'] + +[clam_max_file_size] +valdefault = [] +valprec = [] +val = ['5'] + +[clam_max_files] +valdefault = [] +valprec = [] +val = ['5000'] + +[clam_max_recursion] +valdefault = [] +valprec = [] +val = ['12'] + +[clam_max_scan_size] +valdefault = [] +valprec = [] +val = ['20'] + +[clam_mirror_database] +valdefault = [] +valprec = [] +val = [''] + +[clam_purge] +valdefault = [] +valprec = [] +val = ['20'] + +[clam_scan_elf] +valdefault = [] +valprec = [] +val = ['no'] + +[clam_scan_mail] +valdefault = [] +valprec = [] +val = ['no'] + +[clam_scan_pdf] +valdefault = [] +valprec = [] +val = ['yes'] + +[client_lifetime] +valdefault = [] +valprec = [] +val = ['120'] + +[client_netmask] +valdefault = [] +valprec = [] +val = ['255.255.255.255'] + +[cntlm_port] +valdefault = [] +valprec = [] +val = ['3127'] + +[code_ent] +valdefault = [] +valprec = [] +val = [''] + +[code_postal] +valdefault = [] +valprec = [] +val = [''] + +[connect_timeout] +valdefault = [] +valprec = [] +val = ['1'] + +[cups_autopurgejobs] +valdefault = [] +valprec = [] +val = ['No'] + +[cups_browsing] +valdefault = [] +valprec = [] +val = ['on'] + +[cups_loglevel] +valdefault = [] +valprec = [] +val = ['info'] + +[cups_lp] +valdefault = [] +valprec = [] +val = ['non'] + +[cups_maxclients] +valdefault = [] +valprec = [] +val = ['100'] + +[cups_maxcopies] +valdefault = [] +valprec = [] +val = ['100'] + +[cups_maxjobs] +valdefault = [] +valprec = [] +val = ['500'] + +[cups_preservejobfiles] +valdefault = [] +valprec = [] +val = ['No'] + +[cups_preservejobhistory] +valdefault = [] +valprec = [] +val = ['Yes'] + +[cups_printcap] +valdefault = [] +valprec = [] +val = ['non'] + +[dans_cachedir1] +valdefault = [] +valprec = [] +val = ['/tmp'] + +[dans_cachedir2] +valdefault = [] +valprec = [] +val = ['/tmp'] + +[dans_cachedir3] +valdefault = [] +valprec = [] +val = ['/tmp'] + +[dans_maxfilesize1] +valdefault = [] +valprec = [] +val = ['5000'] + +[dans_maxfilesize2] +valdefault = [] +valprec = [] +val = ['5000'] + +[dans_maxfilesize3] +valdefault = [] +valprec = [] +val = ['5000'] + +[dans_maxramsize1] +valdefault = [] +valprec = [] +val = ['5000'] + +[dans_maxramsize2] +valdefault = [] +valprec = [] +val = ['5000'] + +[dans_maxramsize3] +valdefault = [] +valprec = [] +val = ['5000'] + +[dans_num_opt_filters] +valdefault = [] +valprec = [] +val = ['3'] + +[dansguardian_clam] +valdefault = [] +valprec = [] +val = ['non'] + +[dansguardian_ead_filtre1] +valdefault = [] +valprec = [] +val = ['Filtre web 1'] + +[dansguardian_ead_filtre2] +valdefault = [] +valprec = [] +val = ['Filtre web 2'] + +[dansguardian_ead_filtre3] +valdefault = [] +valprec = [] +val = ['Filtre web 3'] + +[dansguardian_ead_log] +valdefault = [] +valprec = [] +val = ['non'] + +[dansguardian_eth0] +valdefault = [] +valprec = [] +val = ['1'] + +[dansguardian_eth1] +valdefault = [] +valprec = [] +val = ['1'] + +[dansguardian_eth2] +valdefault = [] +valprec = [] +val = ['1'] + +[dansguardian_eth3] +valdefault = [] +valprec = [] +val = ['1'] + +[dansguardian_eth4] +valdefault = [] +valprec = [] +val = ['1'] + +[dansguardian_heure_debut] +valdefault = [] +valprec = [] +val = [''] + +[dansguardian_heure_fin] +valdefault = [] +valprec = [] +val = [''] + +[dansguardian_port3] +valdefault = [] +valprec = [] +val = ['3129'] + +[dead_peer_timeout] +valdefault = [] +valprec = [] +val = ['10'] + +[debit_carte_eth0] +valdefault = [] +valprec = [] +val = [''] + +[debit_carte_eth1] +valdefault = [] +valprec = [] +val = [''] + +[debit_carte_eth2] +valdefault = [] +valprec = [] +val = [''] + +[debit_carte_eth3] +valdefault = [] +valprec = [] +val = [''] + +[debit_carte_eth4] +valdefault = [] +valprec = [] +val = [''] + +[dhcrelay_interfaces] +valdefault = [] +valprec = [] +val = ['all'] + +[dhcrelay_server_interface] +valdefault = [] +valprec = [] +val = ['eth3'] + +[dhcrelay_vlan] +valdefault = [] +valprec = [] +val = [''] + +[dns_defnames] +valdefault = [] +valprec = [] +val = ['off'] + +[dns_forward_alias_eth1] +valdefault = [] +valprec = [] +val = ['oui'] + +[dns_forward_alias_eth2] +valdefault = [] +valprec = [] +val = ['non'] + +[dns_forward_alias_eth3] +valdefault = [] +valprec = [] +val = ['non'] + +[dns_forward_alias_eth4] +valdefault = [] +valprec = [] +val = ['non'] + +[dns_forward_eth1] +valdefault = [] +valprec = [] +val = ['oui'] + +[dns_forward_eth2] +valdefault = [] +valprec = [] +val = ['oui'] + +[dns_forward_eth3] +valdefault = [] +valprec = [] +val = ['oui'] + +[dns_forward_eth4] +valdefault = [] +valprec = [] +val = ['oui'] + +[dns_forward_route] +valdefault = [] +valprec = [] +val = ['oui'] + +[dns_forward_vlan_eth1] +valdefault = [] +valprec = [] +val = ['oui'] + +[dns_forward_vlan_eth2] +valdefault = [] +valprec = [] +val = ['non'] + +[dns_forward_vlan_eth3] +valdefault = [] +valprec = [] +val = ['non'] + +[dns_forward_vlan_eth4] +valdefault = [] +valprec = [] +val = ['non'] + +[dns_master_eth0] +valdefault = [] +valprec = [] +val = ['non'] + +[dns_master_eth1] +valdefault = [] +valprec = [] +val = ['oui'] + +[dns_master_eth2] +valdefault = [] +valprec = [] +val = ['oui'] + +[dns_master_eth3] +valdefault = [] +valprec = [] +val = ['oui'] + +[dns_master_eth4] +valdefault = [] +valprec = [] +val = ['oui'] + +[dns_nameservers] +valdefault = [] +valprec = [] +val = [''] + +[dns_route] +valdefault = [] +valprec = [] +val = ['oui'] + +[dns_rvp_alias_eth1] +valdefault = [] +valprec = [] +val = ['oui'] + +[dns_rvp_alias_eth2] +valdefault = [] +valprec = [] +val = ['non'] + +[dns_rvp_alias_eth3] +valdefault = [] +valprec = [] +val = ['non'] + +[dns_rvp_alias_eth4] +valdefault = [] +valprec = [] +val = ['non'] + +[dns_rvp_eth1] +valdefault = [] +valprec = [] +val = ['oui'] + +[dns_rvp_eth2] +valdefault = [] +valprec = [] +val = ['non'] + +[dns_rvp_eth3] +valdefault = [] +valprec = [] +val = ['non'] + +[dns_rvp_eth4] +valdefault = [] +valprec = [] +val = ['non'] + +[dns_rvp_route] +valdefault = [] +valprec = [] +val = ['oui'] + +[dns_rvp_vlan_eth1] +valdefault = [] +valprec = [] +val = ['oui'] + +[dns_rvp_vlan_eth2] +valdefault = [] +valprec = [] +val = ['non'] + +[dns_rvp_vlan_eth3] +valdefault = [] +valprec = [] +val = ['non'] + +[dns_rvp_vlan_eth4] +valdefault = [] +valprec = [] +val = ['non'] + +[docbodytimeout] +valdefault = [] +valprec = [] +val = ['120'] + +[docheadertimeout] +valdefault = [] +valprec = [] +val = ['20'] + +[domaine_messagerie_etab] +valdefault = [] +valprec = [] +val = ['etb3.ac-test.fr'] + +[ead_sso] +valdefault = [] +valprec = [] +val = ['oui'] + +[ead_support_multietab] +valdefault = [] +valprec = [] +val = ['non'] + +[emulate_httpd_log] +valdefault = [] +valprec = [] +val = ['off'] + +[envoyer_logs_dansguardian] +valdefault = [] +valprec = [] +val = ['non'] + +[envoyer_logs_squid] +valdefault = [] +valprec = [] +val = ['non'] + +[envoyer_tous_logs] +valdefault = [] +valprec = [] +val = ['oui'] + +[eolesso_adresse] +valdefault = [] +valprec = [] +val = ['192.168.0.33'] + +[eolesso_adresse_parent] +valdefault = [] +valprec = [] +val = [''] + +[eolesso_base_ldap] +valdefault = [] +valprec = [] +val = ['o=gouv,c=fr'] + +[eolesso_ca_location] +valdefault = [] +valprec = [] +val = [''] + +[eolesso_cert] +valdefault = [] +valprec = [] +val = [''] + +[eolesso_css] +valdefault = [] +valprec = [] +val = [''] + +[eolesso_entity_name] +valdefault = [] +valprec = [] +val = [''] + +[eolesso_key] +valdefault = [] +valprec = [] +val = [''] + +[eolesso_ldap] +valdefault = [] +valprec = [] +val = ['localhost'] + +[eolesso_ldap_apps_params] +valdefault = [] +valprec = [] +val = ['non'] + +[eolesso_ldap_dntree_group] +valdefault = [] +valprec = [] +val = [''] + +[eolesso_ldap_dntree_user] +valdefault = [] +valprec = [] +val = [''] + +[eolesso_ldap_fill_categorie] +valdefault = [] +valprec = [] +val = [''] + +[eolesso_ldap_fill_displaygroup] +valdefault = [] +valprec = [] +val = ['cn'] + +[eolesso_ldap_fill_displayname] +valdefault = [] +valprec = [] +val = ['displayName'] + +[eolesso_ldap_fill_fonction] +valdefault = [] +valprec = [] +val = [''] + +[eolesso_ldap_fill_fredurne] +valdefault = [] +valprec = [] +val = [''] + +[eolesso_ldap_fill_mail] +valdefault = [] +valprec = [] +val = ['mail'] + +[eolesso_ldap_fill_rne] +valdefault = [] +valprec = [] +val = [''] + +[eolesso_ldap_filter_group] +valdefault = [] +valprec = [] +val = ['objectClass=posixGroup'] + +[eolesso_ldap_filter_user] +valdefault = [] +valprec = [] +val = ['objectClass=person'] + +[eolesso_ldap_infos] +valdefault = [] +valprec = [] +val = [''] + +[eolesso_ldap_label] +valdefault = [] +valprec = [] +val = ['Annuaire de amonecole.monreseau.lan'] + +[eolesso_ldap_login_otp] +valdefault = [] +valprec = [] +val = ['inactifs'] + +[eolesso_ldap_match_attribute] +valdefault = [] +valprec = [] +val = ['uid'] + +[eolesso_ldap_reader] +valdefault = [] +valprec = [] +val = ['cn=reader,o=gouv,c=fr'] + +[eolesso_ldap_reader_passfile] +valdefault = [] +valprec = [] +val = ['/root/.reader'] + +[eolesso_otp_portal] +valdefault = [] +valprec = [] +val = [''] + +[eolesso_otppass_maxsize] +valdefault = [] +valprec = [] +val = ['12'] + +[eolesso_otppass_minsize] +valdefault = [] +valprec = [] +val = ['10'] + +[eolesso_otppass_regx] +valdefault = [] +valprec = [] +val = ['^[0-9]{10,12}$'] + +[eolesso_pam_securid] +valdefault = [] +valprec = [] +val = ['non'] + +[eolesso_port] +valdefault = [] +valprec = [] +val = ['8443'] + +[eolesso_port_ldap] +valdefault = [] +valprec = [] +val = ['389'] + +[eolesso_port_parent] +valdefault = [] +valprec = [] +val = ['8443'] + +[eolesso_session_timeout] +valdefault = [] +valprec = [] +val = ['7200'] + +[era_proxy_bypass] +valdefault = [] +valprec = [] +val = [''] + +[era_proxy_bypass_eth2] +valdefault = [] +valprec = [] +val = [''] + +[esu_proxy] +valdefault = [] +valprec = [] +val = ['oui'] + +[esu_proxy_bypass] +valdefault = [] +valprec = [] +val = ['127.0.0.1', '10.3.2.0/24'] + +[esu_proxy_port] +valdefault = [] +valprec = [] +val = ['3128'] + +[esu_proxy_server] +valdefault = [] +valprec = [] +val = ['10.3.2.2'] + +[eth0_method] +valdefault = [] +valprec = [] +val = ['statique'] + +[eth1_method] +valdefault = [] +valprec = [] +val = ['statique'] + +[eth2_method] +valdefault = [] +valprec = [] +val = ['statique'] + +[eth3_method] +valdefault = [] +valprec = [] +val = ['statique'] + +[eth4_method] +valdefault = [] +valprec = [] +val = ['statique'] + +[exim_address_rewrite] +valdefault = [] +valprec = [] +val = ['non'] + +[exim_address_rewrite_flags] +valdefault = [] +valprec = [] +val = [''] + +[exim_address_rewrite_pattern] +valdefault = [] +valprec = [] +val = [''] + +[exim_address_rewrite_replacement] +valdefault = [] +valprec = [] +val = [''] + +[exim_clamav] +valdefault = [] +valprec = [] +val = ['oui'] + +[exim_mail_type] +valdefault = [] +valprec = [] +val = ['smarthost'] + +[exim_primary_hostname] +valdefault = [] +valprec = [] +val = ['automatique'] + +[exim_qualify_domain] +valdefault = [] +valprec = [] +val = ['nom de domaine local'] + +[exim_quota] +valdefault = [] +valprec = [] +val = ['20'] + +[exim_quota_warn] +valdefault = [] +valprec = [] +val = ['80'] + +[exim_relay] +valdefault = [] +valprec = [] +val = ['non'] + +[exim_relay_cidrv4] +valdefault = [] +valprec = [] +val = [''] + +[exim_relay_cidrv6] +valdefault = [] +valprec = [] +val = [''] + +[exim_relay_dhcp] +valdefault = [] +valprec = [] +val = ['non'] + +[exim_relay_domains] +valdefault = [] +valprec = [] +val = [''] + +[exim_spam_score] +valdefault = [] +valprec = [] +val = ['50'] + +[exim_use_log_files] +valdefault = [] +valprec = [] +val = ['non'] + +[exim_use_syslog] +valdefault = [] +valprec = [] +val = ['oui'] + +[federation_transparente] +valdefault = [] +valprec = [] +val = ['non'] + +[fichier_link_interface] +valdefault = [] +valprec = [] +val = ['eth1'] + +[fonction_serveur] +valdefault = [] +valprec = [] +val = ['ENT'] + +[force_envole] +valdefault = [] +valprec = [] +val = ['oui'] + +[forward_timeout] +valdefault = [] +valprec = [] +val = ['4'] + +[fqdncache_size] +valdefault = [] +valprec = [] +val = ['1024'] + +[freerad_cle_ldap_scribe] +valdefault = [] +valprec = [] +val = [''] + +[freerad_group_vlan] +valdefault = [] +valprec = [] +val = [''] + +[freerad_ldap_base_dn] +valdefault = [] +valprec = [] +val = ['o=gouv,c=fr'] + +[freerad_ldap_group] +valdefault = [] +valprec = [] +val = [''] + +[freerad_ldap_ip] +valdefault = [] +valprec = [] +val = [''] + +[freerad_listen_addr] +valdefault = [] +valprec = [] +val = [''] + +[freerad_listen_int] +valdefault = [] +valprec = [] +val = ['eth1'] + +[freerad_mode] +valdefault = [] +valprec = [] +val = ['802.1x'] + +[freerad_nas_cidr_netmask] +valdefault = [] +valprec = [] +val = [''] + +[freerad_nas_ip] +valdefault = [] +valprec = [] +val = [''] + +[freerad_nas_name] +valdefault = [] +valprec = [] +val = [''] + +[freerad_nas_passwd] +valdefault = [] +valprec = [] +val = [''] + +[freerad_nas_type] +valdefault = [] +valprec = [] +val = ['other'] + +[fs_inotify_max_queued_events] +valdefault = [] +valprec = [] +val = ['16384'] + +[fs_inotify_max_user_instances] +valdefault = [] +valprec = [] +val = ['128'] + +[fs_inotify_max_user_watches] +valdefault = [] +valprec = [] +val = ['8192'] + +[ftp_passive] +valdefault = [] +valprec = [] +val = ['on'] + +[ftp_perso_ele] +valdefault = [] +valprec = [] +val = ['non'] + +[ftp_sanitycheck] +valdefault = [] +valprec = [] +val = ['on'] + +[ftp_scan] +valdefault = [] +valprec = [] +val = ['oui'] + +[ftp_servername] +valdefault = [] +valprec = [] +val = ['etb3'] + +[ftp_telnet_protocol] +valdefault = [] +valprec = [] +val = ['on'] + +[ftp_tls] +valdefault = [] +valprec = [] +val = ['non'] + +[ftp_user] +valdefault = [] +valprec = [] +val = ['ftp'] + +[half_closed_clients] +valdefault = [] +valprec = [] +val = ['on'] + +[headertimeout] +valdefault = [] +valprec = [] +val = ['14'] + +[hierarchy_stoplist] +valdefault = [] +valprec = [] +val = ['cgi-bin ?'] + +[home_path] +valdefault = [] +valprec = [] +val = ['/home'] + +[hosts_file] +valdefault = [] +valprec = [] +val = ['/etc/hosts'] + +[htcp_port] +valdefault = [] +valprec = [] +val = ['4827'] + +[http_port] +valdefault = [] +valprec = [] +val = ['127.0.0.1:8080'] + +[http_port_2] +valdefault = [] +valprec = [] +val = ['127.0.0.1:8081'] + +[https_port] +valdefault = [] +valprec = [] +val = [''] + +[icp_port] +valdefault = [] +valprec = [] +val = ['3130'] + +[icp_query_timeout] +valdefault = [] +valprec = [] +val = ['0'] + +[id_vlan_eth0] +valdefault = [] +valprec = [] +val = [''] + +[id_vlan_eth1] +valdefault = [] +valprec = [] +val = [''] + +[id_vlan_eth2] +valdefault = [] +valprec = [] +val = [''] + +[id_vlan_eth3] +valdefault = [] +valprec = [] +val = [''] + +[id_vlan_eth4] +valdefault = [] +valprec = [] +val = [''] + +[ident_timeout] +valdefault = [] +valprec = [] +val = ['10'] + +[ignore_expect_100] +valdefault = [] +valprec = [] +val = ['off'] + +[install_rvp] +valdefault = [] +valprec = [] +val = ['oui'] + +[install_scribe_dmz] +valdefault = [] +valprec = [] +val = ['non'] + +[interface_gw] +valdefault = [] +valprec = [] +val = ['eth0'] + +[interface_wpad_exclude] +valdefault = [] +valprec = [] +val = [''] + +[ip_admin_eth0] +valdefault = [] +valprec = [] +val = ['0.0.0.0'] + +[ip_admin_eth1] +valdefault = [] +valprec = [] +val = ['0.0.0.0'] + +[ip_admin_eth2] +valdefault = [] +valprec = [] +val = [''] + +[ip_admin_eth3] +valdefault = [] +valprec = [] +val = [''] + +[ip_admin_eth4] +valdefault = [] +valprec = [] +val = [''] + +[ip_basse_dhcp] +valdefault = [] +valprec = [] +val = [''] + +[ip_client_logs_udp] +valdefault = [] +valprec = [] +val = [''] + +[ip_dns_zone_forward] +valdefault = [] +valprec = [] +val = [''] + +[ip_haute_dhcp] +valdefault = [] +valprec = [] +val = [''] + +[ip_host_dns] +valdefault = [] +valprec = [] +val = [''] + +[ip_no_pmtu_disc] +valdefault = [] +valprec = [] +val = ['non'] + +[ip_serveur_krb] +valdefault = [] +valprec = [] +val = [''] + +[ip_serveur_ldap1] +valdefault = [] +valprec = [] +val = ['192.0.2.50'] + +[ip_serveur_ldap1_2] +valdefault = [] +valprec = [] +val = ['192.0.2.50'] + +[ip_serveur_ldap2] +valdefault = [] +valprec = [] +val = [''] + +[ip_serveur_ldap2_2] +valdefault = [] +valprec = [] +val = [''] + +[ip_serveur_ldapad] +valdefault = [] +valprec = [] +val = [''] + +[ip_serveur_ldapad_2] +valdefault = [] +valprec = [] +val = [''] + +[ip_serveur_scribe_dmz] +valdefault = [] +valprec = [] +val = [''] + +[ip_serveur_smb] +valdefault = [] +valprec = [] +val = ['192.0.2.52'] + +[ip_serveur_smb_2] +valdefault = [] +valprec = [] +val = [''] + +[ip_ssh_eth0] +valdefault = [] +valprec = [] +val = ['0.0.0.0'] + +[ip_ssh_eth1] +valdefault = [] +valprec = [] +val = ['0.0.0.0'] + +[ip_ssh_eth2] +valdefault = [] +valprec = [] +val = [''] + +[ip_ssh_eth3] +valdefault = [] +valprec = [] +val = [''] + +[ip_ssh_eth4] +valdefault = [] +valprec = [] +val = [''] + +[ip_test_rvp] +valdefault = [] +valprec = [] +val = [''] + +[ipcache_high] +valdefault = [] +valprec = [] +val = ['95'] + +[ipcache_low] +valdefault = [] +valprec = [] +val = ['90'] + +[ipcache_size] +valdefault = [] +valprec = [] +val = ['1024'] + +[ipv4_neigh_default_gc_thresh1] +valdefault = [] +valprec = [] +val = ['128'] + +[ipv4_neigh_default_gc_thresh2] +valdefault = [] +valprec = [] +val = ['512'] + +[ipv4_neigh_default_gc_thresh3] +valdefault = [] +valprec = [] +val = ['1024'] + +[ldap_base_dn] +valdefault = [] +valprec = [] +val = ['o=gouv,c=fr'] + +[ldap_cachesize] +valdefault = [] +valprec = [] +val = ['1000'] + +[ldap_loglevel] +valdefault = [] +valprec = [] +val = ['0'] + +[ldap_nss] +valdefault = [] +valprec = [] +val = ['oui'] + +[ldap_replication] +valdefault = [] +valprec = [] +val = ['non'] + +[ldap_replication_client] +valdefault = [] +valprec = [] +val = ['non'] + +[ldap_restrict_access] +valdefault = [] +valprec = [] +val = ['tous'] + +[ldap_sizelimit] +valdefault = [] +valprec = [] +val = ['5000'] + +[ldap_ssl] +valdefault = [] +valprec = [] +val = ['non'] + +[ldap_timelimit] +valdefault = [] +valprec = [] +val = ['3600'] + +[ldap_tls] +valdefault = [] +valprec = [] +val = ['non'] + +[ldapad_base_dn] +valdefault = [] +valprec = [] +val = [''] + +[ldapad_base_dn_2] +valdefault = [] +valprec = [] +val = [''] + +[ldapad_passwd] +valdefault = [] +valprec = [] +val = [''] + +[ldapad_passwd_2] +valdefault = [] +valprec = [] +val = [''] + +[ldapad_user] +valdefault = [] +valprec = [] +val = [''] + +[ldapad_user_2] +valdefault = [] +valprec = [] +val = [''] + +[libelle_etab] +valdefault = [] +valprec = [] +val = ['etb3'] + +[lightsquid_anon_mode] +valdefault = [] +valprec = [] +val = ['aucune'] + +[lightsquid_auto] +valdefault = [] +valprec = [] +val = ['non'] + +[lightsquid_port] +valdefault = [] +valprec = [] +val = ['8062'] + +[log_fqdn] +valdefault = [] +valprec = [] +val = ['off'] + +[log_ip_on_direct] +valdefault = [] +valprec = [] +val = ['on'] + +[log_mime_hdrs] +valdefault = [] +valprec = [] +val = ['off'] + +[maxagechildren1] +valdefault = [] +valprec = [] +val = ['500'] + +[maxagechildren2] +valdefault = [] +valprec = [] +val = ['500'] + +[maxagechildren3] +valdefault = [] +valprec = [] +val = ['500'] + +[maxchildren1] +valdefault = [] +valprec = [] +val = ['80'] + +[maxchildren2] +valdefault = [] +valprec = [] +val = ['80'] + +[maxchildren3] +valdefault = [] +valprec = [] +val = ['80'] + +[maximum_icp_query_timeout] +valdefault = [] +valprec = [] +val = ['2000'] + +[maximum_object_size] +valdefault = [] +valprec = [] +val = ['32768'] + +[maximum_object_size_in_memory] +valdefault = [] +valprec = [] +val = ['16'] + +[maxsparechildren1] +valdefault = [] +valprec = [] +val = ['32'] + +[maxsparechildren2] +valdefault = [] +valprec = [] +val = ['32'] + +[maxsparechildren3] +valdefault = [] +valprec = [] +val = ['32'] + +[mcast_groups] +valdefault = [] +valprec = [] +val = [''] + +[mcast_icp_query_timeout] +valdefault = [] +valprec = [] +val = ['2000'] + +[memory_replacement_policy] +valdefault = [] +valprec = [] +val = ['lru'] + +[minchildren1] +valdefault = [] +valprec = [] +val = ['8'] + +[minchildren2] +valdefault = [] +valprec = [] +val = ['8'] + +[minchildren3] +valdefault = [] +valprec = [] +val = ['8'] + +[minimum_object_size] +valdefault = [] +valprec = [] +val = ['0'] + +[minsparechildren1] +valdefault = [] +valprec = [] +val = ['4'] + +[minsparechildren2] +valdefault = [] +valprec = [] +val = ['4'] + +[minsparechildren3] +valdefault = [] +valprec = [] +val = ['4'] + +[mode_conteneur_actif] +valdefault = [] +valprec = [] +val = ['oui'] + +[mysql_max_connexions] +valdefault = [] +valprec = [] +val = ['200'] + +[nature_etab] +valdefault = [] +valprec = [] +val = ['\xc3\xa9cole'] + +[nature_serveur] +valdefault = [] +valprec = [] +val = ['production'] + +[negative_dns_ttl] +valdefault = [] +valprec = [] +val = ['1'] + +[negative_ttl] +valdefault = [] +valprec = [] +val = ['5'] + +[netmask_admin_eth0] +valdefault = [] +valprec = [] +val = ['0.0.0.0'] + +[netmask_admin_eth1] +valdefault = [] +valprec = [] +val = ['0.0.0.0'] + +[netmask_admin_eth2] +valdefault = [] +valprec = [] +val = [''] + +[netmask_admin_eth3] +valdefault = [] +valprec = [] +val = [''] + +[netmask_admin_eth4] +valdefault = [] +valprec = [] +val = [''] + +[netmask_client_logs_relp] +valdefault = [] +valprec = [] +val = [''] + +[netmask_client_logs_tcp] +valdefault = [] +valprec = [] +val = [''] + +[netmask_client_logs_udp] +valdefault = [] +valprec = [] +val = [''] + +[netmask_ssh_eth0] +valdefault = [] +valprec = [] +val = ['0.0.0.0'] + +[netmask_ssh_eth1] +valdefault = [] +valprec = [] +val = ['0.0.0.0'] + +[netmask_ssh_eth2] +valdefault = [] +valprec = [] +val = [''] + +[netmask_ssh_eth3] +valdefault = [] +valprec = [] +val = [''] + +[netmask_ssh_eth4] +valdefault = [] +valprec = [] +val = [''] + +[nom_academie] +valdefault = [] +valprec = [] +val = ['ac-test'] + +[nom_cache_pere] +valdefault = [] +valprec = [] +val = [''] + +[nom_cache_pere_zone] +valdefault = [] +valprec = [] +val = [''] + +[nom_court_hosts] +valdefault = [] +valprec = [] +val = [''] + +[nom_domaine_dhcp] +valdefault = [] +valprec = [] +val = ['monreseau.lan'] + +[nom_domaine_krb] +valdefault = [] +valprec = [] +val = [''] + +[nom_domaine_local] +valdefault = [] +valprec = [] +val = ['etb3.lan'] + +[nom_domaine_local_supp] +valdefault = [] +valprec = [] +val = [''] + +[nom_domaine_smb] +valdefault = [] +valprec = [] +val = ['dometb3'] + +[nom_domaine_smb_2] +valdefault = [] +valprec = [] +val = [''] + +[nom_domaine_windows] +valdefault = [] +valprec = [] +val = [''] + +[nom_domaine_wpad_exclude] +valdefault = [] +valprec = [] +val = [''] + +[nom_host_dns] +valdefault = [] +valprec = [] +val = [''] + +[nom_host_interface_wpad_exclude] +valdefault = [] +valprec = [] +val = [''] + +[nom_host_wpad_exclude] +valdefault = [] +valprec = [] +val = [''] + +[nom_interface1] +valdefault = [] +valprec = [] +val = ['eth1'] + +[nom_interface_wpad_exclude] +valdefault = [] +valprec = [] +val = [''] + +[nom_long_hosts] +valdefault = [] +valprec = [] +val = [''] + +[nom_machine] +valdefault = [] +valprec = [] +val = ['amonecole'] + +[nom_machine_eth1] +valdefault = [] +valprec = [] +val = ['admin'] + +[nom_machine_eth2] +valdefault = [] +valprec = [] +val = ['pedago'] + +[nom_machine_eth3] +valdefault = [] +valprec = [] +val = ['dmz-priv'] + +[nom_machine_eth4] +valdefault = [] +valprec = [] +val = ['dmz-pub'] + +[nom_serveur_krb] +valdefault = [] +valprec = [] +val = [''] + +[nom_serveur_scribe_dmz] +valdefault = [] +valprec = [] +val = [''] + +[nom_serveur_smb] +valdefault = [] +valprec = [] +val = ['srvetb3'] + +[nom_serveur_smb_2] +valdefault = [] +valprec = [] +val = [''] + +[nom_zone_dns_cache] +valdefault = [] +valprec = [] +val = [''] + +[nom_zone_forward] +valdefault = [] +valprec = [] +val = [''] + +[nom_zone_forward_rvp] +valdefault = [] +valprec = [] +val = [''] + +[nombre_interfaces] +valdefault = [] +valprec = [] +val = ['2'] + +[num_dansguardian_instance] +valdefault = [] +valprec = [] +val = ['2'] + +[number_of_basic_children] +valdefault = [] +valprec = [] +val = ['20'] + +[number_of_ntlm_children] +valdefault = [] +valprec = [] +val = ['20'] + +[numero_etab] +valdefault = [] +valprec = [] +val = ['00000003'] + +[nut_monitor_foreign_host] +valdefault = [] +valprec = [] +val = [''] + +[nut_monitor_foreign_name] +valdefault = [] +valprec = [] +val = [''] + +[nut_monitor_foreign_password] +valdefault = [] +valprec = [] +val = [''] + +[nut_monitor_foreign_user] +valdefault = [] +valprec = [] +val = [''] + +[nut_monitor_host] +valdefault = [] +valprec = [] +val = [''] + +[nut_monitor_netmask] +valdefault = [] +valprec = [] +val = [''] + +[nut_monitor_password] +valdefault = [] +valprec = [] +val = [''] + +[nut_monitor_user] +valdefault = [] +valprec = [] +val = [''] + +[nut_ups_daemon] +valdefault = [] +valprec = [] +val = ['oui'] + +[nut_ups_driver] +valdefault = [] +valprec = [] +val = ['usbhid-ups'] + +[nut_ups_name] +valdefault = [] +valprec = [] +val = [''] + +[nut_ups_password] +valdefault = [] +valprec = [] +val = ['f5f352132877a4ae2360dec086aca9184d9efe8ce36dd6d6771ee117'] + +[nut_ups_port] +valdefault = [] +valprec = [] +val = ['auto'] + +[nut_ups_productid] +valdefault = [] +valprec = [] +val = [''] + +[nut_ups_serial] +valdefault = [] +valprec = [] +val = [''] + +[nut_ups_upstype] +valdefault = [] +valprec = [] +val = [''] + +[options_cache_pere] +valdefault = [] +valprec = [] +val = ['no-query'] + +[options_cache_pere_zone] +valdefault = [] +valprec = [] +val = ['proxy-only no-query'] + +[passerelle_smtp] +valdefault = [] +valprec = [] +val = ['smtp.ac-dijon.fr'] + +[pays] +valdefault = [] +valprec = [] +val = ['France'] + +[pconn_timeout] +valdefault = [] +valprec = [] +val = ['120'] + +[peer_connect_timeout] +valdefault = [] +valprec = [] +val = ['30'] + +[persistent_request_timeout] +valdefault = [] +valprec = [] +val = ['1'] + +[php_display_errors] +valdefault = [] +valprec = [] +val = ['Off'] + +[php_max_execution_time] +valdefault = [] +valprec = [] +val = ['30'] + +[php_max_input_time] +valdefault = [] +valprec = [] +val = ['60'] + +[php_memory_limit] +valdefault = [] +valprec = [] +val = ['128'] + +[php_post_max_size] +valdefault = [] +valprec = [] +val = ['32'] + +[php_session_gc_maxlifetime] +valdefault = [] +valprec = [] +val = ['3600'] + +[php_upload_max_filesize] +valdefault = [] +valprec = [] +val = ['16'] + +[plugin_cow_id_server] +valdefault = [] +valprec = [] +val = [''] + +[plugin_cow_key_server] +valdefault = [] +valprec = [] +val = [''] + +[plugin_cow_local_server] +valdefault = [] +valprec = [] +val = [''] + +[plugin_cow_url_server] +valdefault = [] +valprec = [] +val = [''] + +[port_cache_pere] +valdefault = [] +valprec = [] +val = [''] + +[port_cache_pere_zone] +valdefault = [] +valprec = [] +val = [''] + +[port_ead_reverseproxy] +valdefault = [] +valprec = [] +val = ['4203'] + +[positive_dns_ttl] +valdefault = [] +valprec = [] +val = ['6'] + +[pppoe_interface] +valdefault = [] +valprec = [] +val = ['eth0'] + +[pppoe_passwd] +valdefault = [] +valprec = [] +val = [''] + +[pppoe_user] +valdefault = [] +valprec = [] +val = [''] + +[preforkchildren1] +valdefault = [] +valprec = [] +val = ['6'] + +[preforkchildren2] +valdefault = [] +valprec = [] +val = ['6'] + +[preforkchildren3] +valdefault = [] +valprec = [] +val = ['6'] + +[proxy_cachemaster] +valdefault = [] +valprec = [] +val = ['cachemaster@ac-test.fr'] + +[proxy_client_adresse] +valdefault = [] +valprec = [] +val = [''] + +[proxy_client_port] +valdefault = [] +valprec = [] +val = ['3128'] + +[proxy_eth0_adresse] +valdefault = [] +valprec = [] +val = [''] + +[proxy_eth0_network] +valdefault = [] +valprec = [] +val = [''] + +[proxy_ldap_base_dn] +valdefault = [] +valprec = [] +val = ['o=gouv,c=fr'] + +[proxy_ldap_base_dn_2] +valdefault = [] +valprec = [] +val = ['o=gouv,c=fr'] + +[proxy_pere_rvp] +valdefault = [] +valprec = [] +val = ['non'] + +[proxy_sibling_ip] +valdefault = [] +valprec = [] +val = [''] + +[proxy_sibling_port] +valdefault = [] +valprec = [] +val = [''] + +[quick_abort_max] +valdefault = [] +valprec = [] +val = ['16'] + +[quick_abort_min] +valdefault = [] +valprec = [] +val = ['16'] + +[quick_abort_pct] +valdefault = [] +valprec = [] +val = ['95'] + +[range_offset_limit] +valdefault = [] +valprec = [] +val = ['0'] + +[read_ahead_gap] +valdefault = [] +valprec = [] +val = ['16'] + +[read_timeout] +valdefault = [] +valprec = [] +val = ['15'] + +[repertoire_tftp] +valdefault = [] +valprec = [] +val = ['/var/lib/tftpboot/'] + +[request_body_max_size] +valdefault = [] +valprec = [] +val = ['10'] + +[request_header_max_size] +valdefault = [] +valprec = [] +val = ['20'] + +[request_timeout] +valdefault = [] +valprec = [] +val = ['5'] + +[revprox_activate_http] +valdefault = [] +valprec = [] +val = ['non'] + +[revprox_auto_config_local_web] +valdefault = [] +valprec = [] +val = ['non'] + +[revprox_default] +valdefault = [] +valprec = [] +val = [''] + +[revprox_domainname] +valdefault = [] +valprec = [] +val = [''] + +[revprox_ead] +valdefault = [] +valprec = [] +val = ['192.0.2.51'] + +[revprox_ead_port] +valdefault = [] +valprec = [] +val = [''] + +[revprox_hash_bucket_size] +valdefault = [] +valprec = [] +val = ['128'] + +[revprox_http] +valdefault = [] +valprec = [] +val = ['redirige vers https'] + +[revprox_https] +valdefault = [] +valprec = [] +val = ['oui'] + +[revprox_poshadmin] +valdefault = [] +valprec = [] +val = ['192.0.2.51'] + +[revprox_rep] +valdefault = [] +valprec = [] +val = ['/'] + +[revprox_rewrite_domaine] +valdefault = [] +valprec = [] +val = [''] + +[revprox_rewrite_location] +valdefault = [] +valprec = [] +val = [''] + +[revprox_rewrite_proto] +valdefault = [] +valprec = [] +val = ['http/https'] + +[revprox_rewrite_regex] +valdefault = [] +valprec = [] +val = [''] + +[revprox_rewrite_replacement] +valdefault = [] +valprec = [] +val = [''] + +[revprox_sso] +valdefault = [] +valprec = [] +val = [''] + +[revprox_url] +valdefault = [] +valprec = [] +val = [''] + +[route_adresse] +valdefault = [] +valprec = [] +val = [''] + +[route_gw] +valdefault = [] +valprec = [] +val = [''] + +[route_int] +valdefault = [] +valprec = [] +val = [''] + +[route_netmask] +valdefault = [] +valprec = [] +val = [''] + +[rsyslog_ca_file] +valdefault = [] +valprec = [] +val = ['/etc/rsyslog.d/ssl/certs/zephirlog_ca.pem'] + +[rsyslog_cert_file] +valdefault = [] +valprec = [] +val = ['/etc/rsyslog.d/ssl/certs/rsyslog_cert.pem'] + +[rsyslog_envoi_tls] +valdefault = [] +valprec = [] +val = ['non'] + +[rsyslog_plage_globale_heure_debut] +valdefault = [] +valprec = [] +val = [''] + +[rsyslog_plage_globale_heure_fin] +valdefault = [] +valprec = [] +val = [''] + +[rsyslog_privkey_file] +valdefault = [] +valprec = [] +val = ['/etc/rsyslog.d/ssl/private/rsyslog_privkey.pem'] + +[rsyslog_reception_tls] +valdefault = [] +valprec = [] +val = ['non'] + +[safe_ports] +valdefault = [] +valprec = [] +val = [''] + +[scribe_piwik_distant] +valdefault = [] +valprec = [] +val = ['non'] + +[scribe_posh_adresse_aca] +valdefault = [] +valprec = [] +val = [''] + +[scribe_posh_piwikbase_aca] +valdefault = [] +valprec = [] +val = ['/piwik'] + +[scribe_posh_piwikid_aca] +valdefault = [] +valprec = [] +val = ['1'] + +[server_cert] +valdefault = [] +valprec = [] +val = ['/etc/ssl/certs/eole.crt'] + +[server_key] +valdefault = [] +valprec = [] +val = ['/etc/ssl/certs/eole.key'] + +[server_pem] +valdefault = [] +valprec = [] +val = ['/etc/ssl/certs/eole.pem'] + +[serveur_maj] +valdefault = [] +valprec = [] +val = ['eoleng.ac-dijon.fr', 'ftp.crihan.fr'] + +[serveur_ntp] +valdefault = [] +valprec = [] +val = ['pool.ntp.org'] + +[serveur_stats_nat] +valdefault = [] +valprec = [] +val = ['https://statenvole.ac-creteil.fr/piwik'] + +[shutdown_lifetime] +valdefault = [] +valprec = [] +val = ['30'] + +[smb_activer_partages] +valdefault = [] +valprec = [] +val = ['non'] + +[smb_dns_proxy] +valdefault = [] +valprec = [] +val = ['no'] + +[smb_dos_attributes] +valdefault = [] +valprec = [] +val = ['no'] + +[smb_guest] +valdefault = [] +valprec = [] +val = ['oui'] + +[smb_log_level] +valdefault = [] +valprec = [] +val = ['0'] + +[smb_min_password_class] +valdefault = [] +valprec = [] +val = ['2'] + +[smb_min_password_length] +valdefault = [] +valprec = [] +val = ['5'] + +[smb_netbios_name] +valdefault = [] +valprec = [] +val = ['srvetb3'] + +[smb_oplocks] +valdefault = [] +valprec = [] +val = ['no'] + +[smb_os_level] +valdefault = [] +valprec = [] +val = ['99'] + +[smb_partage_ecriture] +valdefault = [] +valprec = [] +val = ['non'] + +[smb_partage_nom] +valdefault = [] +valprec = [] +val = [''] + +[smb_partage_path] +valdefault = [] +valprec = [] +val = [''] + +[smb_partage_visibilite] +valdefault = [] +valprec = [] +val = ['non'] + +[smb_quotawarn] +valdefault = [] +valprec = [] +val = ['non'] + +[smb_server_string] +valdefault = [] +valprec = [] +val = ['etb3'] + +[smb_share_model] +valdefault = [] +valprec = [] +val = ['standard'] + +[smb_trash] +valdefault = [] +valprec = [] +val = ['non'] + +[smb_trash_dir] +valdefault = [] +valprec = [] +val = ['.corbeille'] + +[smb_trash_purge] +valdefault = [] +valprec = [] +val = ['8'] + +[smb_unixextensions] +valdefault = [] +valprec = [] +val = ['no'] + +[smb_vscan] +valdefault = [] +valprec = [] +val = ['oui'] + +[smb_wins_support] +valdefault = [] +valprec = [] +val = ['yes'] + +[smb_workgroup] +valdefault = [] +valprec = [] +val = ['dometb3'] + +[squid_auth_eth1] +valdefault = [] +valprec = [] +val = ['oui'] + +[squid_auth_eth2] +valdefault = [] +valprec = [] +val = ['oui'] + +[squid_auth_eth3] +valdefault = [] +valprec = [] +val = ['oui'] + +[squid_auth_eth4] +valdefault = [] +valprec = [] +val = ['oui'] + +[squid_heure_debut] +valdefault = [] +valprec = [] +val = [''] + +[squid_heure_fin] +valdefault = [] +valprec = [] +val = [''] + +[ssh_allow_groups] +valdefault = [] +valprec = [] +val = [''] + +[ssh_allow_passwd] +valdefault = [] +valprec = [] +val = ['oui'] + +[ssh_eth0] +valdefault = [] +valprec = [] +val = ['oui'] + +[ssh_eth1] +valdefault = [] +valprec = [] +val = ['oui'] + +[ssh_eth2] +valdefault = [] +valprec = [] +val = ['non'] + +[ssh_eth3] +valdefault = [] +valprec = [] +val = ['non'] + +[ssh_eth4] +valdefault = [] +valprec = [] +val = ['non'] + +[ssh_permit_root] +valdefault = [] +valprec = [] +val = ['oui'] + +[ssl_country_name] +valdefault = [] +valprec = [] +val = ['fr'] + +[ssl_default_cert_time] +valdefault = [] +valprec = [] +val = ['1096'] + +[ssl_default_key_bits] +valdefault = [] +valprec = [] +val = ['2048'] + +[ssl_organization_name] +valdefault = [] +valprec = [] +val = ['Ministere Education Nationale (MENESR)'] + +[ssl_organization_unit_name] +valdefault = [] +valprec = [] +val = ['110 043 015', 'ac-test'] + +[ssl_ports] +valdefault = [] +valprec = [] +val = [''] + +[ssl_server_name] +valdefault = [] +valprec = [] +val = [''] + +[ssl_subjectaltname_ip] +valdefault = [] +valprec = [] +val = ['192.168.0.33'] + +[ssl_subjectaltname_ns] +valdefault = [] +valprec = [] +val = ['amonecole.etb3.ac-test.fr'] + +[sso_saml_time_adjust] +valdefault = [] +valprec = [] +val = ['-300'] + +[strip_query_terms] +valdefault = [] +valprec = [] +val = ['off'] + +[suffixe_domaine_academique] +valdefault = [] +valprec = [] +val = ['fr'] + +[sw_crl_check] +valdefault = [] +valprec = [] +val = ['oui'] + +[sw_database_mode] +valdefault = [] +valprec = [] +val = ['oui'] + +[sw_force_ip_src] +valdefault = [] +valprec = [] +val = ['eth1'] + +[sw_high_priority_threads] +valdefault = [] +valprec = [] +val = ['2'] + +[sw_install_vpn_route] +valdefault = [] +valprec = [] +val = ['non'] + +[sw_medium_priority_threads] +valdefault = [] +valprec = [] +val = ['4'] + +[sw_retransmit_tries] +valdefault = [] +valprec = [] +val = ['11'] + +[sw_threads] +valdefault = [] +valprec = [] +val = ['32'] + +[synchro_aaf] +valdefault = [] +valprec = [] +val = ['manuel'] + +[system_mail_from] +valdefault = [] +valprec = [] +val = ['fromuser@ac-test.fr'] + +[system_mail_to] +valdefault = [] +valprec = [] +val = ['touser@ac-test.fr'] + +[test_activer_bacula_dir] +valdefault = [] +valprec = [] +val = ['oui'] + +[test_activer_bacula_sd] +valdefault = [] +valprec = [] +val = ['oui'] + +[test_activer_clam_fichier] +valdefault = [] +valprec = [] +val = ['oui'] + +[test_activer_clam_mail] +valdefault = [] +valprec = [] +val = ['oui'] + +[test_activer_clam_proxy] +valdefault = [] +valprec = [] +val = ['non'] + +[test_activer_envole_infos] +valdefault = [] +valprec = [] +val = ['non'] + +[test_activer_kerberos] +valdefault = [] +valprec = [] +val = ['non'] + +[test_activer_proxy_eth0] +valdefault = [] +valprec = [] +val = ['non'] + +[test_activer_routage_ipv6] +valdefault = [] +valprec = [] +val = ['non'] + +[test_distant_domaine1] +valdefault = [] +valprec = [] +val = ['bp-eole.ac-dijon.fr'] + +[test_distant_domaine2] +valdefault = [] +valprec = [] +val = ['google.fr'] + +[test_force_envole] +valdefault = [] +valprec = [] +val = ['non'] + +[test_myadmin] +valdefault = [] +valprec = [] +val = ['non'] + +[test_nutmaster] +valdefault = [] +valprec = [] +val = ['non'] + +[test_smb_vscan] +valdefault = [] +valprec = [] +val = ['oui'] + +[time_zone] +valdefault = [] +valprec = [] +val = ['Europe/Paris'] + +[tls_smtp] +valdefault = [] +valprec = [] +val = ['non'] + +[tmp_esu_proxy_bypass] +valdefault = [] +valprec = [] +val = ['24'] + +[tmp_esu_proxy_bypass2] +valdefault = [] +valprec = [] +val = ['10.3.2.0/24'] + +[type_amon] +valdefault = [] +valprec = [] +val = ['2zones-amonecole'] + +[type_maj] +valdefault = [] +valprec = [] +val = ['complete'] + +[type_squid_auth] +valdefault = [] +valprec = [] +val = ['NTLM/SMB'] + +[type_squid_auth_2] +valdefault = [] +valprec = [] +val = ['Ldap'] + +[unactive_dansguardian_auth1] +valdefault = [] +valprec = [] +val = ['---'] + +[unactive_dansguardian_auth2] +valdefault = [] +valprec = [] +val = ['---'] + +[unactive_dansguardian_auth3] +valdefault = [] +valprec = [] +val = ['---'] + +[url_maj_blacklist] +valdefault = [] +valprec = [] +val = ['http://eole.orion.education.fr/maj/blacklists'] + +[utiliser_rsyslog_plage_envoi_globale] +valdefault = [] +valprec = [] +val = ['non'] + +[valeur_mtu_eth0] +valdefault = [] +valprec = [] +val = [''] + +[valeur_mtu_ppp0] +valdefault = [] +valprec = [] +val = [''] + +[version_envole] +valdefault = [] +valprec = [] +val = ['3.3.8'] + +[ville] +valdefault = [] +valprec = [] +val = [''] + +[vlan_eth0] +valdefault = [] +valprec = [] +val = ['non'] + +[vlan_eth1] +valdefault = [] +valprec = [] +val = ['non'] + +[vlan_eth2] +valdefault = [] +valprec = [] +val = ['non'] + +[vlan_eth3] +valdefault = [] +valprec = [] +val = ['non'] + +[vlan_eth4] +valdefault = [] +valprec = [] +val = ['non'] + +[web_behind_revproxy_ip] +valdefault = [] +valprec = [] +val = ['192.0.2.1'] + +[web_redirection] +valdefault = [] +valprec = [] +val = ['/webmail'] + +[web_url] +valdefault = [] +valprec = [] +val = ['amonecole.etb3.ac-test.fr'] + +[zephir_client_noaction] +valdefault = [] +valprec = [] +val = ['non'] diff --git a/tests/configs/bacula23.eol b/tests/configs/bacula23.eol new file mode 100644 index 0000000..a79295b --- /dev/null +++ b/tests/configs/bacula23.eol @@ -0,0 +1,4 @@ +[bacula_full_retention] +valdefault = [] +valprec = [] +val = ['13'] diff --git a/tests/configs/cert_261.eol b/tests/configs/cert_261.eol new file mode 100644 index 0000000..b3ccdd9 --- /dev/null +++ b/tests/configs/cert_261.eol @@ -0,0 +1,4 @@ +{ + "___version___":"2.6.1", + "server_key":{"owner":"gen_config","val":"/etc/ssl/certs/eole.key"} +} diff --git a/tests/configs/certempty_261.eol b/tests/configs/certempty_261.eol new file mode 100644 index 0000000..53491ec --- /dev/null +++ b/tests/configs/certempty_261.eol @@ -0,0 +1,4 @@ +{ + "___version___":"2.6.1" +} + diff --git a/tests/configs/config_261.eol b/tests/configs/config_261.eol new file mode 100644 index 0000000..e3c3bff --- /dev/null +++ b/tests/configs/config_261.eol @@ -0,0 +1,3 @@ +{ + "___version___":"2.6.1" +} diff --git a/tests/configs/envole.eol b/tests/configs/envole.eol new file mode 100644 index 0000000..94a53ef --- /dev/null +++ b/tests/configs/envole.eol @@ -0,0 +1,24 @@ +[activer_apache] +valdefault = [] +valprec = [] +val = ['oui'] + +[activer_envole] +valdefault = [] +valprec = [] +val = ['oui'] + +[force_envole] +valdefault = [] +valprec = [] +val = ['oui'] + +[alias_envole] +valdefault = [] +valprec = [] +val = ['/testenvole'] + +[web_redirection] +valdefault = [] +valprec = [] +val = ['/pasenvole'] diff --git a/tests/configs/exim_relay_261.eol b/tests/configs/exim_relay_261.eol new file mode 100644 index 0000000..805f709 --- /dev/null +++ b/tests/configs/exim_relay_261.eol @@ -0,0 +1,4 @@ +{ + "___version___":"2.6.1", + "activer_dhcp":{"owner":"gen_config","val":"oui"} +} diff --git a/tests/configs/hamaster241.eol b/tests/configs/hamaster241.eol new file mode 100644 index 0000000..f36f2ee --- /dev/null +++ b/tests/configs/hamaster241.eol @@ -0,0 +1,38 @@ +{ + "___version___":"2.4.1", + "activer_haute_dispo":{"owner":"gen_config","val":"maitre"}, + "admin_eth0":{"owner":"gen_config","val":"oui"}, + "adresse_ip_dns":{"owner":"gen_config","val":["192.168.232.2"]}, + "adresse_ip_eth0":{"owner":"gen_config","val":"192.168.0.11"}, + "adresse_ip_eth1":{"owner":"gen_config","val":"172.30.101.11"}, + "adresse_ip_eth2":{"owner":"gen_config","val":"10.0.254.11"}, + "adresse_ip_gw":{"owner":"gen_config","val":"192.168.0.1"}, + "arv_allow_user":{"owner":"gen_config","val":["root","eole","arv"]}, + "bash_tmout":{"owner":"gen_config","val":0}, + "check_passwd":{"owner":"gen_config","val":"non"}, + "domaine_messagerie_etab":{"owner":"gen_config","val":"rectorat.ac-test.fr"}, + "exim_relay_smtp":{"owner":"gen_config","val":"smtp.in.ac-dijon.fr"}, + "ip_admin_eth0":{"owner":"gen_config","val":["0.0.0.0"]}, + "ip_admin_eth1":{"owner":"gen_config","val":["0.0.0.0"]}, + "ip_machine_esclave":{"owner":"gen_config","val":"10.0.254.12"}, + "ip_ssh_eth0":{"owner":"gen_config","val":["0.0.0.0"]}, + "ip_ssh_eth1":{"owner":"gen_config","val":["172.30.101.0"]}, + "ip_ssh_eth2":{"owner":"gen_config","val":["10.0.254.0"]}, + "libelle_etab":{"owner":"gen_config","val":"aca"}, + "netmask_admin_eth0":{"owner":"gen_config","val":["0.0.0.0"]}, + "netmask_admin_eth1":{"owner":"gen_config","val":["0.0.0.0"]}, + "netmask_ssh_eth0":{"owner":"gen_config","val":["0.0.0.0"]}, + "netmask_ssh_eth1":{"owner":"gen_config","val":["255.255.255.0"]}, + "netmask_ssh_eth2":{"owner":"gen_config","val":["255.255.255.0"]}, + "nom_academie":{"owner":"gen_config","val":"ac-test"}, + "nom_domaine_local":{"owner":"gen_config","val":"ac-test.lan"}, + "nom_machine_esclave":{"owner":"gen_config","val":"sphynxb"}, + "numero_etab":{"owner":"gen_config","val":"0000000A"}, + "service_resource_interval":{"owner":"gen_config","val":[20,60]}, + "service_resource_timeout":{"owner":"gen_config","val":[40,60]}, + "ssh_eth0":{"owner":"gen_config","val":"oui"}, + "ssh_eth2":{"owner":"gen_config","val":"oui"}, + "system_mail_to":{"owner":"gen_config","val":null}, + "vip_resource_adresseip":{"owner":"gen_config","val":["192.168.0.10","172.30.101.10"]}, + "vip_resource_if":{"owner":"gen_config","val":["eth0","eth1"]} +} diff --git a/tests/configs/hosts23.eol b/tests/configs/hosts23.eol new file mode 100644 index 0000000..4f6a181 --- /dev/null +++ b/tests/configs/hosts23.eol @@ -0,0 +1,19 @@ +[activer_ajout_hosts] +valdefault = [] +valprec = [] +val = ['oui'] + +[adresse_ip_hosts] +valdefault = [] +valprec = [] +val = ['1.1.1.1', '2.2.2.2', '3.3.3.3', '4.4.4.4'] + +[nom_court_hosts] +valdefault = [] +valprec = [] +val = ['min', 'Maj', 'wpad', 'wpad'] + +[nom_long_hosts] +valdefault = [] +valprec = [] +val = ['min.min', 'Maj.MAJ', 'wpad.admin.lan', 'wpad.pedago.lan'] diff --git a/tests/configs/maj23.eol b/tests/configs/maj23.eol new file mode 100644 index 0000000..c379297 --- /dev/null +++ b/tests/configs/maj23.eol @@ -0,0 +1,4 @@ +[serveur_maj] +valdefault = [] +valprec = [] +val = ['test-eoleng.ac-dijon.fr', 'eoleng.ac-dijon.fr', 'eoleng.ac-test.fr', 'ftp.crihan.fr'] diff --git a/tests/configs/nom_carte.eol b/tests/configs/nom_carte.eol new file mode 100644 index 0000000..31cd3b7 --- /dev/null +++ b/tests/configs/nom_carte.eol @@ -0,0 +1,5 @@ +{ + "___version___":"2.6.0", + "nombre_interfaces":{"owner":"basique","val":"2"}, + "nom_carte_eth1":{"owner":"basique","val":"carte1"} +} diff --git a/tests/configs/ntlm.eol b/tests/configs/ntlm.eol new file mode 100644 index 0000000..3cd7315 --- /dev/null +++ b/tests/configs/ntlm.eol @@ -0,0 +1,8 @@ +{ + "___version___":"2.5.2", + "activer_squid_auth":{"owner":"gen_config","val":"oui"}, + "type_squid_auth":{"owner":"gen_config","val":"NTLM/SMB"}, + "ip_serveur_smb":{"owner":"gen_config","val":["10.1.3.5","10.1.1.10"]}, + "nom_domaine_smb":{"owner":"gen_config","val":["dompedago","domadmin"]}, + "nom_serveur_smb":{"owner":"gen_config","val":["scribe","horus"]} +} diff --git a/tests/configs/onduleur24.eol b/tests/configs/onduleur24.eol new file mode 100644 index 0000000..dce1be4 --- /dev/null +++ b/tests/configs/onduleur24.eol @@ -0,0 +1,9 @@ +{ + "___version___":"2.4.2", + "activer_nut":{"owner":"gen_config","val":"oui"}, + "nut_ups_name":{"owner":"gen_config","val":["eole"]}, + "nut_monitor_user":{"owner":"gen_config","val":["slave"]}, + "nut_monitor_password":{"owner":"gen_config","val":["password"]}, + "nut_monitor_host":{"owner":"gen_config","val":["10.1.1.1"]}, + "nut_monitor_netmask":{"owner":"gen_config","val":["255.255.255.255"]} +} diff --git a/tests/configs/plagedhcp.eol b/tests/configs/plagedhcp.eol new file mode 100644 index 0000000..3e394f7 --- /dev/null +++ b/tests/configs/plagedhcp.eol @@ -0,0 +1,8 @@ +{ + "adresse_network_dhcp": {"owner": "gen_config", "val": ["192.168.0.0", "192.168.1.0"]}, + "adresse_netmask_dhcp": {"owner": {"1": "gen_config", "0": "gen_config"}, "val": {"1": "255.255.255.0", "0": "255.255.255.0"}}, + "ip_haute_dhcp": {"owner": {"1": "gen_config", "0": "gen_config"}, "val": {"1": "192.168.1.20", "0": "192.168.0.20"}}, + "ip_basse_dhcp": {"owner": {"1": "gen_config", "0": "gen_config"}, "val": {"1": "192.168.1.10", "0": "192.168.0.10"}}, + "bash_tmout": {"owner": "genconfig", "val": 0}, "nom_machine": {"owner": "genconfig", "val": "scribe"}, + "___version___": "2.6.1" +} diff --git a/tests/configs/postgres23_default.eol b/tests/configs/postgres23_default.eol new file mode 100644 index 0000000..fbfc8dc --- /dev/null +++ b/tests/configs/postgres23_default.eol @@ -0,0 +1,4 @@ +[pg_shared_buffers] +valdefault = [] +valprec = [] +val = ['3072'] diff --git a/tests/configs/postgres23_modif.eol b/tests/configs/postgres23_modif.eol new file mode 100644 index 0000000..0e059df --- /dev/null +++ b/tests/configs/postgres23_modif.eol @@ -0,0 +1,4 @@ +[pg_shared_buffers] +valdefault = [] +valprec = [] +val = ['6000'] diff --git a/tests/configs/scribe_dmz_ko.eol b/tests/configs/scribe_dmz_ko.eol new file mode 100644 index 0000000..25d49c6 --- /dev/null +++ b/tests/configs/scribe_dmz_ko.eol @@ -0,0 +1,14 @@ +[install_scribe_dmz] +valdefault = [] +valprec = [] +val = ['oui'] + +[ip_serveur_scribe_dmz] +valdefault = [] +valprec = [] +val = [] + +[nom_serveur_scribe_dmz] +valdefault = [] +valprec = [] +val = [] diff --git a/tests/configs/scribe_dmz_ok.eol b/tests/configs/scribe_dmz_ok.eol new file mode 100644 index 0000000..e5df349 --- /dev/null +++ b/tests/configs/scribe_dmz_ok.eol @@ -0,0 +1,14 @@ +[install_scribe_dmz] +valdefault = [] +valprec = [] +val = ['oui'] + +[ip_serveur_scribe_dmz] +valdefault = [] +valprec = [] +val = ['1.1.1.1'] + +[nom_serveur_scribe_dmz] +valdefault = [] +valprec = [] +val = ['scribe'] diff --git a/tests/configs/seth261.eol b/tests/configs/seth261.eol new file mode 100644 index 0000000..a55114d --- /dev/null +++ b/tests/configs/seth261.eol @@ -0,0 +1,8 @@ +{ + "ad_domain_sid": {"owner": "gen_config", "val": "S-1234"}, + "ad_servers_ip": {"owner": "gen_config", "val": ["1.1.1.1", "2.2.2.2"]}, + "ad_servers_netmask": {"owner": {"1": "gen_config", "0": "gen_config"}, "val": {"1": "255.255.255.255", "0": "255.255.255.255"}}, + "ad_clients_ip": {"owner": "gen_config", "val": ["1.1.1.1", "3.3.3.0"]}, + "ad_clients_netmask": {"owner": {"1": "gen_config", "0": "gen_config"}, "val": {"1": "255.255.255.0", "0": "255.255.255.255"}}, + "___version___":"2.6.1" +} diff --git a/tests/configs/squid261.eol b/tests/configs/squid261.eol new file mode 100644 index 0000000..ec6f1fc --- /dev/null +++ b/tests/configs/squid261.eol @@ -0,0 +1,8 @@ +{ + "forward_timeout": {"owner": "creoleset", "val": 1}, + "peer_connect_timeout": {"owner": "creoleset", "val": 60}, + "read_timeout": {"owner": "creoleset", "val": 1}, + "request_timeout": {"owner": "creoleset", "val": 1}, + "persistent_request_timeout": {"owner": "creoleset", "val": 1}, + "___version___":"2.6.1" +} diff --git a/tests/configs/upgrade_eth_name252.eol b/tests/configs/upgrade_eth_name252.eol new file mode 100644 index 0000000..5728feb --- /dev/null +++ b/tests/configs/upgrade_eth_name252.eol @@ -0,0 +1,20 @@ +{ + "___version___":"2.5.2", + "activer_route":{"owner":"gen_config","val":"oui"}, + "install_rvp":{"owner":"gen_config","val":"oui"}, + "activer_dhcprelay":{"owner":"gen_config","val":"oui"}, + "route_int":{"owner":"gen_config","val":["eth0", "eth1", "eth2", "eth3", "eth4"]}, + "route_gw": {"owner": "gen_config", "val": ["192.168.0.99", "10.1.1.99", "10.1.2.99", "10.1.3.99", "10.1.4.99"]}, + "route_adresse": {"owner": "gen_config", "val": ["192.168.1.0", "10.1.11.0", "10.1.12.0", "10.1.13.0", "10.1.14.0"]}, + "route_netmask": {"owner": "gen_config", "val": ["255.255.255.0", "255.255.255.0", "255.255.255.0", "255.255.255.0", "255.255.255.0"]}, + "dhcrelay_interfaces":{"owner":"gen_config","val":["eth1", "eth2"]}, + "dhcrelay_server_interface":{"owner":"gen_config","val":"eth3"}, + "activer_freeradius":{"owner":"gen_config","val":"oui"}, + "freerad_mode":{"owner":"gen_config","val":"802.1x"}, + "freerad_listen_int":{"owner":"gen_config","val":"eth2"}, + "sw_install_vpn_route":{"owner":"gen_config","val":"non"}, + "sw_force_ip_src":{"owner":"gen_config","val":"eth1"}, + "activer_haute_dispo":{"owner":"gen_config","val":"maitre"}, + "vip_resource_if":{"owner":"gen_config","val":["eth0", "eth1"]}, + "corosync_dial_if":{"owner":"gen_config","val":"eth2"} +} diff --git a/tests/configs/zone_forward24.eol b/tests/configs/zone_forward24.eol new file mode 100644 index 0000000..bce2603 --- /dev/null +++ b/tests/configs/zone_forward24.eol @@ -0,0 +1,5 @@ +{ + "___version___":"2.4.2", + "nom_zone_forward":{"owner":"gen_config","val":["toto.lan"]}, + "ip_dns_zone_forward":{"owner":"gen_config","val":["10.1.1.1"]} +} diff --git a/tests/dicos/00_base.xml b/tests/dicos/00_base.xml new file mode 100644 index 0000000..cd81e1f --- /dev/null +++ b/tests/dicos/00_base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/dicos/autofreeze/00_base.xml b/tests/dicos/autofreeze/00_base.xml new file mode 120000 index 0000000..ed202ee --- /dev/null +++ b/tests/dicos/autofreeze/00_base.xml @@ -0,0 +1 @@ +../00_base.xml \ No newline at end of file diff --git a/tests/dicos/autofreeze/99_autofreeze.xml b/tests/dicos/autofreeze/99_autofreeze.xml new file mode 100644 index 0000000..744ae3a --- /dev/null +++ b/tests/dicos/autofreeze/99_autofreeze.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + fixedvariable + + + + + + + diff --git a/tests/dicos/autosave/00_base.xml b/tests/dicos/autosave/00_base.xml new file mode 120000 index 0000000..ed202ee --- /dev/null +++ b/tests/dicos/autosave/00_base.xml @@ -0,0 +1 @@ +../00_base.xml \ No newline at end of file diff --git a/tests/dicos/autosave/99_autosave.xml b/tests/dicos/autosave/99_autosave.xml new file mode 100644 index 0000000..df08e48 --- /dev/null +++ b/tests/dicos/autosave/99_autosave.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + a + b + + + + + + + + + + + + + diff --git a/tests/dicos/badips/00_base.xml b/tests/dicos/badips/00_base.xml new file mode 120000 index 0000000..ed202ee --- /dev/null +++ b/tests/dicos/badips/00_base.xml @@ -0,0 +1 @@ +../00_base.xml \ No newline at end of file diff --git a/tests/dicos/badips/01_badips.xml b/tests/dicos/badips/01_badips.xml new file mode 100644 index 0000000..5f18e6c --- /dev/null +++ b/tests/dicos/badips/01_badips.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/dicos/basic/00_base.xml b/tests/dicos/basic/00_base.xml new file mode 120000 index 0000000..ed202ee --- /dev/null +++ b/tests/dicos/basic/00_base.xml @@ -0,0 +1 @@ +../00_base.xml \ No newline at end of file diff --git a/tests/dicos/basic/99_basic.xml b/tests/dicos/basic/99_basic.xml new file mode 100644 index 0000000..c17ad4e --- /dev/null +++ b/tests/dicos/basic/99_basic.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + avec valeur + + + + + + + + + + + + + + + + diff --git a/tests/dicos/check/00_base.xml b/tests/dicos/check/00_base.xml new file mode 120000 index 0000000..ed202ee --- /dev/null +++ b/tests/dicos/check/00_base.xml @@ -0,0 +1 @@ +../00_base.xml \ No newline at end of file diff --git a/tests/dicos/check/99_check.xml b/tests/dicos/check/99_check.xml new file mode 100644 index 0000000..07e9cf7 --- /dev/null +++ b/tests/dicos/check/99_check.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + sample + + + non + + + + + + + + + + + unknown + + + sample + + + oui + sample + + + + + + + diff --git a/tests/dicos/disabled/00_base.xml b/tests/dicos/disabled/00_base.xml new file mode 120000 index 0000000..ed202ee --- /dev/null +++ b/tests/dicos/disabled/00_base.xml @@ -0,0 +1 @@ +../00_base.xml \ No newline at end of file diff --git a/tests/dicos/disabled/99_disabled.xml b/tests/dicos/disabled/99_disabled.xml new file mode 100644 index 0000000..fe216a8 --- /dev/null +++ b/tests/dicos/disabled/99_disabled.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + oui + + + oui + + + oui + + + + + + + + + non + cible + + + oui + cible + + + + + + + diff --git a/tests/dicos/disabled/99_disabled_slave.xml b/tests/dicos/disabled/99_disabled_slave.xml new file mode 100644 index 0000000..c253aab --- /dev/null +++ b/tests/dicos/disabled/99_disabled_slave.xml @@ -0,0 +1,30 @@ + + + + + + + + oui + + + + + + + + ma_slave1 + ma_slave2 + ma_slave3 + + + non + ma_slave2 + + + oui + ma_slave3 + + + + diff --git a/tests/dicos/mandatory/00_base.xml b/tests/dicos/mandatory/00_base.xml new file mode 120000 index 0000000..ed202ee --- /dev/null +++ b/tests/dicos/mandatory/00_base.xml @@ -0,0 +1 @@ +../00_base.xml \ No newline at end of file diff --git a/tests/dicos/mandatory/01_mandatory.xml b/tests/dicos/mandatory/01_mandatory.xml new file mode 100644 index 0000000..5a3dea2 --- /dev/null +++ b/tests/dicos/mandatory/01_mandatory.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + non + + + + + + + + + oui + mandatory_if + + + non + mandatory_ifnot + + + + + + + diff --git a/tests/dicos/multicondition/00_base.xml b/tests/dicos/multicondition/00_base.xml new file mode 120000 index 0000000..ed202ee --- /dev/null +++ b/tests/dicos/multicondition/00_base.xml @@ -0,0 +1 @@ +../00_base.xml \ No newline at end of file diff --git a/tests/dicos/multicondition/99_multicondition.xml b/tests/dicos/multicondition/99_multicondition.xml new file mode 100644 index 0000000..ecd09f1 --- /dev/null +++ b/tests/dicos/multicondition/99_multicondition.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + oui + + + non + + + resultat1 + + + resultat2 + + + + + + + + + + + + non + condition + resultat1 + resultat2 + + + oui + condition + resultat1 + resultat2 + mismatch + + + ['oui', 'non'] + condition + condition2 + oui + non + + + non + resultat2 + + + + + + + diff --git a/tests/dicos/multival/00_base.xml b/tests/dicos/multival/00_base.xml new file mode 120000 index 0000000..ed202ee --- /dev/null +++ b/tests/dicos/multival/00_base.xml @@ -0,0 +1 @@ +../00_base.xml \ No newline at end of file diff --git a/tests/dicos/multival/99_multival.xml b/tests/dicos/multival/99_multival.xml new file mode 100644 index 0000000..0d2f7bd --- /dev/null +++ b/tests/dicos/multival/99_multival.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + oui + + + + + + + + + mail_src + + + non + mail_dest + + + + + + + diff --git a/tests/dicos/obligatoire/00_base.xml b/tests/dicos/obligatoire/00_base.xml new file mode 120000 index 0000000..ed202ee --- /dev/null +++ b/tests/dicos/obligatoire/00_base.xml @@ -0,0 +1 @@ +../00_base.xml \ No newline at end of file diff --git a/tests/dicos/obligatoire/99_obligatoire.xml b/tests/dicos/obligatoire/99_obligatoire.xml new file mode 100644 index 0000000..b3b1b2d --- /dev/null +++ b/tests/dicos/obligatoire/99_obligatoire.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + valdef + + + + + + + + valfill + + + vslave1 + vslave2 + vslave3 + vslave4 + + + + + diff --git a/tests/dicos/redefine/00_base.xml b/tests/dicos/redefine/00_base.xml new file mode 120000 index 0000000..ed202ee --- /dev/null +++ b/tests/dicos/redefine/00_base.xml @@ -0,0 +1 @@ +../00_base.xml \ No newline at end of file diff --git a/tests/dicos/redefine/01_variables.xml b/tests/dicos/redefine/01_variables.xml new file mode 100644 index 0000000..8cafed6 --- /dev/null +++ b/tests/dicos/redefine/01_variables.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + a + + + a + + + a + + + + + + + + + + + oui + + + + + + + + + ['a','b','c'] + + + ['a','b','c'] + + + ['a','b','c'] + + + valeur + + + valeur1 + valeur2 + + + oui + disabled_if + disabled_if_redefine + + + non + enabled_if + enabled_if_redefine + + + oui + frozen_if + frozen_if_redefine + + + + + + + + diff --git a/tests/dicos/redefine/02_redefine.xml b/tests/dicos/redefine/02_redefine.xml new file mode 100644 index 0000000..08b1d66 --- /dev/null +++ b/tests/dicos/redefine/02_redefine.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + b + + + b + + + + + + + + + + + + + valeur1 + valeur2 + + + valeur + + + + + + + diff --git a/tests/dicos/types/00_base.xml b/tests/dicos/types/00_base.xml new file mode 120000 index 0000000..ed202ee --- /dev/null +++ b/tests/dicos/types/00_base.xml @@ -0,0 +1 @@ +../00_base.xml \ No newline at end of file diff --git a/tests/dicos/types/01_types.xml b/tests/dicos/types/01_types.xml new file mode 100644 index 0000000..cad4386 --- /dev/null +++ b/tests/dicos/types/01_types.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/dicos/wrong_calc/00_base.xml b/tests/dicos/wrong_calc/00_base.xml new file mode 120000 index 0000000..ed202ee --- /dev/null +++ b/tests/dicos/wrong_calc/00_base.xml @@ -0,0 +1 @@ +../00_base.xml \ No newline at end of file diff --git a/tests/dicos/wrong_calc/00_test.xml b/tests/dicos/wrong_calc/00_test.xml new file mode 100644 index 0000000..fc5a496 --- /dev/null +++ b/tests/dicos/wrong_calc/00_test.xml @@ -0,0 +1,30 @@ + + + + + + + + + + FR + + + + + + + + + + + test_value + + + test_value + + + + + + diff --git a/tests/flattener_dicos/00load_autofreeze/00-base.xml b/tests/flattener_dicos/00load_autofreeze/00-base.xml new file mode 100644 index 0000000..312fca3 --- /dev/null +++ b/tests/flattener_dicos/00load_autofreeze/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + non + + + + + + + + + + + + diff --git a/tests/flattener_dicos/00load_autofreeze/result/00-base.xml b/tests/flattener_dicos/00load_autofreeze/result/00-base.xml new file mode 100644 index 0000000..391f74a --- /dev/null +++ b/tests/flattener_dicos/00load_autofreeze/result/00-base.xml @@ -0,0 +1,92 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/00load_autofreezeexpert/00-base.xml b/tests/flattener_dicos/00load_autofreezeexpert/00-base.xml new file mode 100644 index 0000000..369f7ab --- /dev/null +++ b/tests/flattener_dicos/00load_autofreezeexpert/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + non + + + + + + + + + + + + diff --git a/tests/flattener_dicos/00load_autofreezeexpert/result/00-base.xml b/tests/flattener_dicos/00load_autofreezeexpert/result/00-base.xml new file mode 100644 index 0000000..babb345 --- /dev/null +++ b/tests/flattener_dicos/00load_autofreezeexpert/result/00-base.xml @@ -0,0 +1,92 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/00load_autosave/00-base.xml b/tests/flattener_dicos/00load_autosave/00-base.xml new file mode 100644 index 0000000..4bcc88a --- /dev/null +++ b/tests/flattener_dicos/00load_autosave/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + non + + + + + + + + + + + + diff --git a/tests/flattener_dicos/00load_autosave/result/00-base.xml b/tests/flattener_dicos/00load_autosave/result/00-base.xml new file mode 100644 index 0000000..51ffa6c --- /dev/null +++ b/tests/flattener_dicos/00load_autosave/result/00-base.xml @@ -0,0 +1,92 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/00load_autosaveexpert/00-base.xml b/tests/flattener_dicos/00load_autosaveexpert/00-base.xml new file mode 100644 index 0000000..0d703ff --- /dev/null +++ b/tests/flattener_dicos/00load_autosaveexpert/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + non + + + + + + + + + + + + diff --git a/tests/flattener_dicos/00load_autosaveexpert/result/00-base.xml b/tests/flattener_dicos/00load_autosaveexpert/result/00-base.xml new file mode 100644 index 0000000..67f99c3 --- /dev/null +++ b/tests/flattener_dicos/00load_autosaveexpert/result/00-base.xml @@ -0,0 +1,92 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/00load_comment/00-base.xml b/tests/flattener_dicos/00load_comment/00-base.xml new file mode 100644 index 0000000..9dbdb35 --- /dev/null +++ b/tests/flattener_dicos/00load_comment/00-base.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/00load_comment/result/00-base.xml b/tests/flattener_dicos/00load_comment/result/00-base.xml new file mode 100644 index 0000000..defb393 --- /dev/null +++ b/tests/flattener_dicos/00load_comment/result/00-base.xml @@ -0,0 +1,94 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/00load_notype/00-base.xml b/tests/flattener_dicos/00load_notype/00-base.xml new file mode 100644 index 0000000..a90d0cc --- /dev/null +++ b/tests/flattener_dicos/00load_notype/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + non + + + + + + + + + + + + diff --git a/tests/flattener_dicos/00load_notype/result/00-base.xml b/tests/flattener_dicos/00load_notype/result/00-base.xml new file mode 100644 index 0000000..42387ec --- /dev/null +++ b/tests/flattener_dicos/00load_notype/result/00-base.xml @@ -0,0 +1,99 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/00load_save/00-base.xml b/tests/flattener_dicos/00load_save/00-base.xml new file mode 100644 index 0000000..aa3b2ed --- /dev/null +++ b/tests/flattener_dicos/00load_save/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/00load_save/result/00-base.xml b/tests/flattener_dicos/00load_save/result/00-base.xml new file mode 100644 index 0000000..defb393 --- /dev/null +++ b/tests/flattener_dicos/00load_save/result/00-base.xml @@ -0,0 +1,94 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/00load_subfolder/99-base.xml b/tests/flattener_dicos/00load_subfolder/99-base.xml new file mode 100644 index 0000000..aa3b2ed --- /dev/null +++ b/tests/flattener_dicos/00load_subfolder/99-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/00load_subfolder/result/00-base.xml b/tests/flattener_dicos/00load_subfolder/result/00-base.xml new file mode 100644 index 0000000..d7ac477 --- /dev/null +++ b/tests/flattener_dicos/00load_subfolder/result/00-base.xml @@ -0,0 +1,104 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/00load_subfolder/subfolder/00-base.xml b/tests/flattener_dicos/00load_subfolder/subfolder/00-base.xml new file mode 100644 index 0000000..3306ffa --- /dev/null +++ b/tests/flattener_dicos/00load_subfolder/subfolder/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/01auto_base/00-base.xml b/tests/flattener_dicos/01auto_base/00-base.xml new file mode 100644 index 0000000..c1704a4 --- /dev/null +++ b/tests/flattener_dicos/01auto_base/00-base.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + non + + + + + + + + mode_conteneur_actif1 + + + + + + + diff --git a/tests/flattener_dicos/01auto_base/result/00-base.xml b/tests/flattener_dicos/01auto_base/result/00-base.xml new file mode 100644 index 0000000..684f163 --- /dev/null +++ b/tests/flattener_dicos/01auto_base/result/00-base.xml @@ -0,0 +1,103 @@ + + + + + creole.general.mode_conteneur_actif1 + + + + + + + + diff --git a/tests/flattener_dicos/01auto_withoutparam/00-base.xml b/tests/flattener_dicos/01auto_withoutparam/00-base.xml new file mode 100644 index 0000000..b44d1b1 --- /dev/null +++ b/tests/flattener_dicos/01auto_withoutparam/00-base.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + non + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/01auto_withoutparam/result/00-base.xml b/tests/flattener_dicos/01auto_withoutparam/result/00-base.xml new file mode 100644 index 0000000..8893e6b --- /dev/null +++ b/tests/flattener_dicos/01auto_withoutparam/result/00-base.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + diff --git a/tests/flattener_dicos/01fill_autofreeze/00-base.xml b/tests/flattener_dicos/01fill_autofreeze/00-base.xml new file mode 100644 index 0000000..bc781d2 --- /dev/null +++ b/tests/flattener_dicos/01fill_autofreeze/00-base.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + non + + + non + + + + + + + + mode_conteneur_actif1 + + + + + + + diff --git a/tests/flattener_dicos/01fill_autofreeze/result/00-base.xml b/tests/flattener_dicos/01fill_autofreeze/result/00-base.xml new file mode 100644 index 0000000..0ba30b4 --- /dev/null +++ b/tests/flattener_dicos/01fill_autofreeze/result/00-base.xml @@ -0,0 +1,101 @@ + + + + + creole.general.mode_conteneur_actif1 + + + + + + + + diff --git a/tests/flattener_dicos/01fill_autosave/00-base.xml b/tests/flattener_dicos/01fill_autosave/00-base.xml new file mode 100644 index 0000000..56e6c85 --- /dev/null +++ b/tests/flattener_dicos/01fill_autosave/00-base.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + non + + + non + + + + + + + + mode_conteneur_actif1 + + + + + + + diff --git a/tests/flattener_dicos/01fill_autosave/result/00-base.xml b/tests/flattener_dicos/01fill_autosave/result/00-base.xml new file mode 100644 index 0000000..2ff054e --- /dev/null +++ b/tests/flattener_dicos/01fill_autosave/result/00-base.xml @@ -0,0 +1,101 @@ + + + + + creole.general.mode_conteneur_actif1 + + + + + + + + diff --git a/tests/flattener_dicos/01fill_base/00-base.xml b/tests/flattener_dicos/01fill_base/00-base.xml new file mode 100644 index 0000000..2f600a3 --- /dev/null +++ b/tests/flattener_dicos/01fill_base/00-base.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + non + + + + + + + + mode_conteneur_actif1 + + + + + + + diff --git a/tests/flattener_dicos/01fill_base/result/00-base.xml b/tests/flattener_dicos/01fill_base/result/00-base.xml new file mode 100644 index 0000000..684f163 --- /dev/null +++ b/tests/flattener_dicos/01fill_base/result/00-base.xml @@ -0,0 +1,103 @@ + + + + + creole.general.mode_conteneur_actif1 + + + + + + + + diff --git a/tests/flattener_dicos/01fill_baseaccent/00-base.xml b/tests/flattener_dicos/01fill_baseaccent/00-base.xml new file mode 100644 index 0000000..89ca785 --- /dev/null +++ b/tests/flattener_dicos/01fill_baseaccent/00-base.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + non + + + + + + + + mode_conteneur_actif1 + + + + + + + diff --git a/tests/flattener_dicos/01fill_baseaccent/result/00-base.xml b/tests/flattener_dicos/01fill_baseaccent/result/00-base.xml new file mode 100644 index 0000000..b1b0d2f --- /dev/null +++ b/tests/flattener_dicos/01fill_baseaccent/result/00-base.xml @@ -0,0 +1,103 @@ + + + + + creole.general.mode_conteneur_actif1 + + + + + + + + diff --git a/tests/flattener_dicos/01fill_container/00-base.xml b/tests/flattener_dicos/01fill_container/00-base.xml new file mode 100644 index 0000000..5884367 --- /dev/null +++ b/tests/flattener_dicos/01fill_container/00-base.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + test + + + + + + + diff --git a/tests/flattener_dicos/01fill_container/result/00-base.xml b/tests/flattener_dicos/01fill_container/result/00-base.xml new file mode 100644 index 0000000..ed53a3a --- /dev/null +++ b/tests/flattener_dicos/01fill_container/result/00-base.xml @@ -0,0 +1,134 @@ + + + + + creole.containers.container_ip_test + + + + + + + + + diff --git a/tests/flattener_dicos/01fill_context/00-base.xml b/tests/flattener_dicos/01fill_context/00-base.xml new file mode 100644 index 0000000..05a6106 --- /dev/null +++ b/tests/flattener_dicos/01fill_context/00-base.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + non + + + + + + + + mode_conteneur_actif + + + + + + + + diff --git a/tests/flattener_dicos/01fill_context/result/00-base.xml b/tests/flattener_dicos/01fill_context/result/00-base.xml new file mode 100644 index 0000000..452d1ed --- /dev/null +++ b/tests/flattener_dicos/01fill_context/result/00-base.xml @@ -0,0 +1,104 @@ + + + + + creole.general.mode_conteneur_actif + + + + + + + + + diff --git a/tests/flattener_dicos/01fill_mandatory/00-base.xml b/tests/flattener_dicos/01fill_mandatory/00-base.xml new file mode 100644 index 0000000..cbaa9a0 --- /dev/null +++ b/tests/flattener_dicos/01fill_mandatory/00-base.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + non + + + + + + + + mode_conteneur_actif1 + + + + + + + diff --git a/tests/flattener_dicos/01fill_mandatory/result/00-base.xml b/tests/flattener_dicos/01fill_mandatory/result/00-base.xml new file mode 100644 index 0000000..5bd8491 --- /dev/null +++ b/tests/flattener_dicos/01fill_mandatory/result/00-base.xml @@ -0,0 +1,99 @@ + + + + + creole.general.mode_conteneur_actif1 + + + + + + + + diff --git a/tests/flattener_dicos/01fill_number/00-base.xml b/tests/flattener_dicos/01fill_number/00-base.xml new file mode 100644 index 0000000..d57fe9e --- /dev/null +++ b/tests/flattener_dicos/01fill_number/00-base.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + 3 + + + + + + + diff --git a/tests/flattener_dicos/01fill_number/result/00-base.xml b/tests/flattener_dicos/01fill_number/result/00-base.xml new file mode 100644 index 0000000..f91e6b7 --- /dev/null +++ b/tests/flattener_dicos/01fill_number/result/00-base.xml @@ -0,0 +1,101 @@ + + + + + 3 + + + + + + + + diff --git a/tests/flattener_dicos/01fill_optional/00-base.xml b/tests/flattener_dicos/01fill_optional/00-base.xml new file mode 100644 index 0000000..2155b4d --- /dev/null +++ b/tests/flattener_dicos/01fill_optional/00-base.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + non + + + + + + + + mode_conteneur_actif4 + mode_conteneur_actif1 + mode_conteneur_actif3 + + + + + + + diff --git a/tests/flattener_dicos/01fill_optional/result/00-base.xml b/tests/flattener_dicos/01fill_optional/result/00-base.xml new file mode 100644 index 0000000..684f163 --- /dev/null +++ b/tests/flattener_dicos/01fill_optional/result/00-base.xml @@ -0,0 +1,103 @@ + + + + + creole.general.mode_conteneur_actif1 + + + + + + + + diff --git a/tests/flattener_dicos/01separator_base/00-base.xml b/tests/flattener_dicos/01separator_base/00-base.xml new file mode 100644 index 0000000..711c533 --- /dev/null +++ b/tests/flattener_dicos/01separator_base/00-base.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + Établissement + + + + + + + + + + diff --git a/tests/flattener_dicos/01separator_base/result/00-base.xml b/tests/flattener_dicos/01separator_base/result/00-base.xml new file mode 100644 index 0000000..b044f8d --- /dev/null +++ b/tests/flattener_dicos/01separator_base/result/00-base.xml @@ -0,0 +1,96 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/01separator_neverhidden/00-base.xml b/tests/flattener_dicos/01separator_neverhidden/00-base.xml new file mode 100644 index 0000000..50edc69 --- /dev/null +++ b/tests/flattener_dicos/01separator_neverhidden/00-base.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + Établissement + + + + + + + + + + diff --git a/tests/flattener_dicos/01separator_neverhidden/result/00-base.xml b/tests/flattener_dicos/01separator_neverhidden/result/00-base.xml new file mode 100644 index 0000000..8ce3e77 --- /dev/null +++ b/tests/flattener_dicos/01separator_neverhidden/result/00-base.xml @@ -0,0 +1,96 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/01separator_nonexists/00-base.xml b/tests/flattener_dicos/01separator_nonexists/00-base.xml new file mode 100644 index 0000000..4dde9f0 --- /dev/null +++ b/tests/flattener_dicos/01separator_nonexists/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + Établissement + separator + + + + + + + + + + diff --git a/tests/flattener_dicos/01separator_nonexists/result/00-base.xml b/tests/flattener_dicos/01separator_nonexists/result/00-base.xml new file mode 100644 index 0000000..b044f8d --- /dev/null +++ b/tests/flattener_dicos/01separator_nonexists/result/00-base.xml @@ -0,0 +1,96 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/02auto_probe/00-base.xml b/tests/flattener_dicos/02auto_probe/00-base.xml new file mode 100644 index 0000000..e9f0ebe --- /dev/null +++ b/tests/flattener_dicos/02auto_probe/00-base.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + non + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/02auto_probe/result/00-base.xml b/tests/flattener_dicos/02auto_probe/result/00-base.xml new file mode 100644 index 0000000..b78e069 --- /dev/null +++ b/tests/flattener_dicos/02auto_probe/result/00-base.xml @@ -0,0 +1,91 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/02auto_probe/result/probe.json b/tests/flattener_dicos/02auto_probe/result/probe.json new file mode 100644 index 0000000..d833a68 --- /dev/null +++ b/tests/flattener_dicos/02auto_probe/result/probe.json @@ -0,0 +1 @@ +{"creole.general.mode_conteneur_actif": {"args": [], "function": "get_devices", "kwargs": {}}} diff --git a/tests/flattener_dicos/02auto_probe_namedparam/00-base.xml b/tests/flattener_dicos/02auto_probe_namedparam/00-base.xml new file mode 100644 index 0000000..3490b87 --- /dev/null +++ b/tests/flattener_dicos/02auto_probe_namedparam/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + non + + + + + + + + /tmp + + + + + + + diff --git a/tests/flattener_dicos/02auto_probe_namedparam/result/00-base.xml b/tests/flattener_dicos/02auto_probe_namedparam/result/00-base.xml new file mode 100644 index 0000000..b78e069 --- /dev/null +++ b/tests/flattener_dicos/02auto_probe_namedparam/result/00-base.xml @@ -0,0 +1,91 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/02auto_probe_namedparam/result/probe.json b/tests/flattener_dicos/02auto_probe_namedparam/result/probe.json new file mode 100644 index 0000000..600fc87 --- /dev/null +++ b/tests/flattener_dicos/02auto_probe_namedparam/result/probe.json @@ -0,0 +1 @@ +{"creole.general.mode_conteneur_actif": {"args": [], "function": "get_mount_point_device", "kwargs": {"mount_point": "/tmp"}}} diff --git a/tests/flattener_dicos/02auto_probe_param/00-base.xml b/tests/flattener_dicos/02auto_probe_param/00-base.xml new file mode 100644 index 0000000..40d0d5a --- /dev/null +++ b/tests/flattener_dicos/02auto_probe_param/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + non + + + + + + + + /tmp + + + + + + + diff --git a/tests/flattener_dicos/02auto_probe_param/result/00-base.xml b/tests/flattener_dicos/02auto_probe_param/result/00-base.xml new file mode 100644 index 0000000..b78e069 --- /dev/null +++ b/tests/flattener_dicos/02auto_probe_param/result/00-base.xml @@ -0,0 +1,91 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/02auto_probe_param/result/probe.json b/tests/flattener_dicos/02auto_probe_param/result/probe.json new file mode 100644 index 0000000..fa1bf6e --- /dev/null +++ b/tests/flattener_dicos/02auto_probe_param/result/probe.json @@ -0,0 +1 @@ +{"creole.general.mode_conteneur_actif": {"args": ["/tmp"], "function": "get_mount_point_device", "kwargs": {}}} diff --git a/tests/flattener_dicos/02fill_probe/00-base.xml b/tests/flattener_dicos/02fill_probe/00-base.xml new file mode 100644 index 0000000..db60c4d --- /dev/null +++ b/tests/flattener_dicos/02fill_probe/00-base.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + non + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/02fill_probe/result/00-base.xml b/tests/flattener_dicos/02fill_probe/result/00-base.xml new file mode 100644 index 0000000..8c46cb6 --- /dev/null +++ b/tests/flattener_dicos/02fill_probe/result/00-base.xml @@ -0,0 +1,89 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/02fill_probe/result/probe.json b/tests/flattener_dicos/02fill_probe/result/probe.json new file mode 100644 index 0000000..d833a68 --- /dev/null +++ b/tests/flattener_dicos/02fill_probe/result/probe.json @@ -0,0 +1 @@ +{"creole.general.mode_conteneur_actif": {"args": [], "function": "get_devices", "kwargs": {}}} diff --git a/tests/flattener_dicos/02fill_probe_error/00-base.xml b/tests/flattener_dicos/02fill_probe_error/00-base.xml new file mode 100644 index 0000000..ccb9aa1 --- /dev/null +++ b/tests/flattener_dicos/02fill_probe_error/00-base.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + non + + + + + + + + mode_conteneur_actif1 + + + + + + + diff --git a/tests/flattener_dicos/10autosave_hidden/00-base.xml b/tests/flattener_dicos/10autosave_hidden/00-base.xml new file mode 100644 index 0000000..8cf2555 --- /dev/null +++ b/tests/flattener_dicos/10autosave_hidden/00-base.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + oui + + + + + + + + diff --git a/tests/flattener_dicos/10autosave_hidden/result/00-base.xml b/tests/flattener_dicos/10autosave_hidden/result/00-base.xml new file mode 100644 index 0000000..8aa5fcb --- /dev/null +++ b/tests/flattener_dicos/10autosave_hidden/result/00-base.xml @@ -0,0 +1,104 @@ + + + + + oui + + + + + + + + diff --git a/tests/flattener_dicos/10autosave_hidden_frozenifin/00-base.xml b/tests/flattener_dicos/10autosave_hidden_frozenifin/00-base.xml new file mode 100644 index 0000000..7623e97 --- /dev/null +++ b/tests/flattener_dicos/10autosave_hidden_frozenifin/00-base.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + oui + + + oui + autosavevar + + + + + + + + diff --git a/tests/flattener_dicos/10autosave_hidden_frozenifin/result/00-base.xml b/tests/flattener_dicos/10autosave_hidden_frozenifin/result/00-base.xml new file mode 100644 index 0000000..c172bb7 --- /dev/null +++ b/tests/flattener_dicos/10autosave_hidden_frozenifin/result/00-base.xml @@ -0,0 +1,106 @@ + + + + + oui + creole.general.autosavevar + + + oui + + + + + + + + diff --git a/tests/flattener_dicos/10check_base/00-base.xml b/tests/flattener_dicos/10check_base/00-base.xml new file mode 100644 index 0000000..5966d49 --- /dev/null +++ b/tests/flattener_dicos/10check_base/00-base.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + b + + + + + + + + + 0 + 100 + + + + + + + diff --git a/tests/flattener_dicos/10check_base/result/00-base.xml b/tests/flattener_dicos/10check_base/result/00-base.xml new file mode 100644 index 0000000..3e5d33a --- /dev/null +++ b/tests/flattener_dicos/10check_base/result/00-base.xml @@ -0,0 +1,97 @@ + + + + + 0 + 100 + + + + + + + + diff --git a/tests/flattener_dicos/10check_option/00-base.xml b/tests/flattener_dicos/10check_option/00-base.xml new file mode 100644 index 0000000..0e8d455 --- /dev/null +++ b/tests/flattener_dicos/10check_option/00-base.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + b + + + 100 + + + + + + + + + 0 + int2 + + + + + + + diff --git a/tests/flattener_dicos/10check_option/result/00-base.xml b/tests/flattener_dicos/10check_option/result/00-base.xml new file mode 100644 index 0000000..3639846 --- /dev/null +++ b/tests/flattener_dicos/10check_option/result/00-base.xml @@ -0,0 +1,102 @@ + + + + + 0 + creole.general.int2 + + + + + + + + diff --git a/tests/flattener_dicos/10check_optional/00-base.xml b/tests/flattener_dicos/10check_optional/00-base.xml new file mode 100644 index 0000000..191481c --- /dev/null +++ b/tests/flattener_dicos/10check_optional/00-base.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + b + + + + + + + + + + int2 + + + int3 + + + + + + + + diff --git a/tests/flattener_dicos/10check_optional/result/00-base.xml b/tests/flattener_dicos/10check_optional/result/00-base.xml new file mode 100644 index 0000000..6d396a9 --- /dev/null +++ b/tests/flattener_dicos/10check_optional/result/00-base.xml @@ -0,0 +1,100 @@ + + + + + creole.general.int2 + + + + + + + + + diff --git a/tests/flattener_dicos/10check_valid_differ/00-base.xml b/tests/flattener_dicos/10check_valid_differ/00-base.xml new file mode 100644 index 0000000..936fa7a --- /dev/null +++ b/tests/flattener_dicos/10check_valid_differ/00-base.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + oui + + + non + + + + + + + + mode_conteneur_actif1 + + + + + + + diff --git a/tests/flattener_dicos/10check_valid_differ/result/00-base.xml b/tests/flattener_dicos/10check_valid_differ/result/00-base.xml new file mode 100644 index 0000000..0d24185 --- /dev/null +++ b/tests/flattener_dicos/10check_valid_differ/result/00-base.xml @@ -0,0 +1,100 @@ + + + + + creole.general.mode_conteneur_actif1 + + + + + + + + diff --git a/tests/flattener_dicos/10check_valid_differ_add/00-base.xml b/tests/flattener_dicos/10check_valid_differ_add/00-base.xml new file mode 100644 index 0000000..1293c06 --- /dev/null +++ b/tests/flattener_dicos/10check_valid_differ_add/00-base.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + oui + + + non + + + non + + + oui + + + + + + + + mode_conteneur_actif1 + + + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos/10check_valid_differ_add/01-base.xml b/tests/flattener_dicos/10check_valid_differ_add/01-base.xml new file mode 100644 index 0000000..45232d3 --- /dev/null +++ b/tests/flattener_dicos/10check_valid_differ_add/01-base.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + oui + + + + + + + + mode_conteneur_actif1 + + + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos/10check_valid_differ_add/result/00-base.xml b/tests/flattener_dicos/10check_valid_differ_add/result/00-base.xml new file mode 100644 index 0000000..4073be9 --- /dev/null +++ b/tests/flattener_dicos/10check_valid_differ_add/result/00-base.xml @@ -0,0 +1,121 @@ + + + + + creole.general.mode_conteneur_actif1 + + + creole.general.mode_conteneur_actif2 + + + creole.general.mode_conteneur_actif1 + + + creole.general.mode_conteneur_actif2 + + + + + + + + diff --git a/tests/flattener_dicos/10check_valid_differ_removecheck/00-base.xml b/tests/flattener_dicos/10check_valid_differ_removecheck/00-base.xml new file mode 100644 index 0000000..1293c06 --- /dev/null +++ b/tests/flattener_dicos/10check_valid_differ_removecheck/00-base.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + oui + + + non + + + non + + + oui + + + + + + + + mode_conteneur_actif1 + + + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos/10check_valid_differ_removecheck/01-base.xml b/tests/flattener_dicos/10check_valid_differ_removecheck/01-base.xml new file mode 100644 index 0000000..4ce6add --- /dev/null +++ b/tests/flattener_dicos/10check_valid_differ_removecheck/01-base.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + oui + + + + + + + + mode_conteneur_actif1 + + + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos/10check_valid_differ_removecheck/result/00-base.xml b/tests/flattener_dicos/10check_valid_differ_removecheck/result/00-base.xml new file mode 100644 index 0000000..7c89116 --- /dev/null +++ b/tests/flattener_dicos/10check_valid_differ_removecheck/result/00-base.xml @@ -0,0 +1,115 @@ + + + + + creole.general.mode_conteneur_actif1 + + + creole.general.mode_conteneur_actif2 + + + + + + + + diff --git a/tests/flattener_dicos/10check_valid_ipnetmask/00-base.xml b/tests/flattener_dicos/10check_valid_ipnetmask/00-base.xml new file mode 100644 index 0000000..ecbbb40 --- /dev/null +++ b/tests/flattener_dicos/10check_valid_ipnetmask/00-base.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + oui + + + + + + + + + + adresse_ip_eth0 + + + + + + + diff --git a/tests/flattener_dicos/10check_valid_ipnetmask/result/00-base.xml b/tests/flattener_dicos/10check_valid_ipnetmask/result/00-base.xml new file mode 100644 index 0000000..ec51fbb --- /dev/null +++ b/tests/flattener_dicos/10check_valid_ipnetmask/result/00-base.xml @@ -0,0 +1,101 @@ + + + + + creole.general.adresse_ip_eth0 + + + + + + + + diff --git a/tests/flattener_dicos/10load_disabled_if_in/00-base.xml b/tests/flattener_dicos/10load_disabled_if_in/00-base.xml new file mode 100644 index 0000000..30bd4bd --- /dev/null +++ b/tests/flattener_dicos/10load_disabled_if_in/00-base.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + non + + + + + + + + + + oui + mode_conteneur_actif + mode_conteneur_actif2 + afilllist + + + + + + + diff --git a/tests/flattener_dicos/10load_disabled_if_in/result/00-base.xml b/tests/flattener_dicos/10load_disabled_if_in/result/00-base.xml new file mode 100644 index 0000000..f38e111 --- /dev/null +++ b/tests/flattener_dicos/10load_disabled_if_in/result/00-base.xml @@ -0,0 +1,111 @@ + + + + + oui + creole.general.mode_conteneur_actif + creole.general.mode_conteneur_actif2 + + + + + + + + diff --git a/tests/flattener_dicos/10load_disabled_if_in_none/00-base.xml b/tests/flattener_dicos/10load_disabled_if_in_none/00-base.xml new file mode 100644 index 0000000..2708976 --- /dev/null +++ b/tests/flattener_dicos/10load_disabled_if_in_none/00-base.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + non + + + + + + + + + + + mode_conteneur_actif + mode_conteneur_actif2 + afilllist + + + + + + + diff --git a/tests/flattener_dicos/10load_disabled_if_in_none/result/00-base.xml b/tests/flattener_dicos/10load_disabled_if_in_none/result/00-base.xml new file mode 100644 index 0000000..03ceed5 --- /dev/null +++ b/tests/flattener_dicos/10load_disabled_if_in_none/result/00-base.xml @@ -0,0 +1,109 @@ + + + + + + creole.general.mode_conteneur_actif + creole.general.mode_conteneur_actif2 + + + + + + + + diff --git a/tests/flattener_dicos/10load_disabled_if_inaccent/00-base.xml b/tests/flattener_dicos/10load_disabled_if_inaccent/00-base.xml new file mode 100644 index 0000000..4eaf97c --- /dev/null +++ b/tests/flattener_dicos/10load_disabled_if_inaccent/00-base.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + non + + + + + + + + + + + + + oui + mode_conteneur_actif + mode_conteneur_actif2 + Général2 + + + + + + + diff --git a/tests/flattener_dicos/10load_disabled_if_inaccent/result/00-base.xml b/tests/flattener_dicos/10load_disabled_if_inaccent/result/00-base.xml new file mode 100644 index 0000000..b8ac89b --- /dev/null +++ b/tests/flattener_dicos/10load_disabled_if_inaccent/result/00-base.xml @@ -0,0 +1,124 @@ + + + + + oui + creole.general.mode_conteneur_actif + creole.general.mode_conteneur_actif2 + creole.general2 + + + + + + + + diff --git a/tests/flattener_dicos/10load_disabledifin_fallback/00-base.xml b/tests/flattener_dicos/10load_disabledifin_fallback/00-base.xml new file mode 100644 index 0000000..2a5aa7d --- /dev/null +++ b/tests/flattener_dicos/10load_disabledifin_fallback/00-base.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + non + + + + + + + + + + oui + mode_conteneur_actif + mode_conteneur_actif2 + afilllist + + + non + mode_conteneur_actif + + + + + + + diff --git a/tests/flattener_dicos/10load_disabledifin_fallback/result/00-base.xml b/tests/flattener_dicos/10load_disabledifin_fallback/result/00-base.xml new file mode 100644 index 0000000..c06cab9 --- /dev/null +++ b/tests/flattener_dicos/10load_disabledifin_fallback/result/00-base.xml @@ -0,0 +1,111 @@ + + + + + oui + creole.general.mode_conteneur_actif2 + + + + + + + + diff --git a/tests/flattener_dicos/10load_disabledifin_whithouttype/00-base.xml b/tests/flattener_dicos/10load_disabledifin_whithouttype/00-base.xml new file mode 100644 index 0000000..5969346 --- /dev/null +++ b/tests/flattener_dicos/10load_disabledifin_whithouttype/00-base.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + non + + + + + + + + + + oui + mode_conteneur_actif + mode_conteneur_actif2 + afilllist + + + + + + + diff --git a/tests/flattener_dicos/10load_disabledifin_whithouttype/result/00-base.xml b/tests/flattener_dicos/10load_disabledifin_whithouttype/result/00-base.xml new file mode 100644 index 0000000..f38e111 --- /dev/null +++ b/tests/flattener_dicos/10load_disabledifin_whithouttype/result/00-base.xml @@ -0,0 +1,111 @@ + + + + + oui + creole.general.mode_conteneur_actif + creole.general.mode_conteneur_actif2 + + + + + + + + diff --git a/tests/flattener_dicos/10load_frozenifin/00-base.xml b/tests/flattener_dicos/10load_frozenifin/00-base.xml new file mode 100644 index 0000000..1cb18a8 --- /dev/null +++ b/tests/flattener_dicos/10load_frozenifin/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + non + + + + + + + + + + oui + mode_conteneur_actif + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos/10load_frozenifin/result/00-base.xml b/tests/flattener_dicos/10load_frozenifin/result/00-base.xml new file mode 100644 index 0000000..78a66c3 --- /dev/null +++ b/tests/flattener_dicos/10load_frozenifin/result/00-base.xml @@ -0,0 +1,111 @@ + + + + + oui + creole.general.mode_conteneur_actif + creole.general.mode_conteneur_actif2 + + + + + + + + diff --git a/tests/flattener_dicos/10load_frozenifin_auto/00-base.xml b/tests/flattener_dicos/10load_frozenifin_auto/00-base.xml new file mode 100644 index 0000000..f4d22c8 --- /dev/null +++ b/tests/flattener_dicos/10load_frozenifin_auto/00-base.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + non + + + + + + + + + + oui + mode_conteneur_actif + mode_conteneur_actif2 + + + non + + + + + + + diff --git a/tests/flattener_dicos/10load_frozenifin_auto/result/00-base.xml b/tests/flattener_dicos/10load_frozenifin_auto/result/00-base.xml new file mode 100644 index 0000000..7a5ef47 --- /dev/null +++ b/tests/flattener_dicos/10load_frozenifin_auto/result/00-base.xml @@ -0,0 +1,112 @@ + + + + + oui + creole.general.mode_conteneur_actif + creole.general.mode_conteneur_actif2 + + + non + + + + + + + + diff --git a/tests/flattener_dicos/10load_frozenifin_multiparam/00-base.xml b/tests/flattener_dicos/10load_frozenifin_multiparam/00-base.xml new file mode 100644 index 0000000..7d60140 --- /dev/null +++ b/tests/flattener_dicos/10load_frozenifin_multiparam/00-base.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + tous + + + + + + + + + + ['tous', 'authentifié', 'aucun'] + + + tous + authentifié + mode_conteneur_actif + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos/10load_frozenifin_multiparam/result/00-base.xml b/tests/flattener_dicos/10load_frozenifin_multiparam/result/00-base.xml new file mode 100644 index 0000000..54c698b --- /dev/null +++ b/tests/flattener_dicos/10load_frozenifin_multiparam/result/00-base.xml @@ -0,0 +1,113 @@ + + + + + tous + authentifié + creole.general.mode_conteneur_actif + creole.general.mode_conteneur_actif2 + + + + + + + + diff --git a/tests/flattener_dicos/10load_hidden_if_in/00-base.xml b/tests/flattener_dicos/10load_hidden_if_in/00-base.xml new file mode 100644 index 0000000..ce0702f --- /dev/null +++ b/tests/flattener_dicos/10load_hidden_if_in/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + non + + + + + + + + + + oui + mode_conteneur_actif + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos/10load_hidden_if_in/result/00-base.xml b/tests/flattener_dicos/10load_hidden_if_in/result/00-base.xml new file mode 100644 index 0000000..f38e111 --- /dev/null +++ b/tests/flattener_dicos/10load_hidden_if_in/result/00-base.xml @@ -0,0 +1,111 @@ + + + + + oui + creole.general.mode_conteneur_actif + creole.general.mode_conteneur_actif2 + + + + + + + + diff --git a/tests/flattener_dicos/10load_hidden_if_not_in/00-base.xml b/tests/flattener_dicos/10load_hidden_if_not_in/00-base.xml new file mode 100644 index 0000000..f1472fa --- /dev/null +++ b/tests/flattener_dicos/10load_hidden_if_not_in/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + non + + + + + + + + + + oui + mode_conteneur_actif + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos/10load_hidden_if_not_in/result/00-base.xml b/tests/flattener_dicos/10load_hidden_if_not_in/result/00-base.xml new file mode 100644 index 0000000..b9f3b11 --- /dev/null +++ b/tests/flattener_dicos/10load_hidden_if_not_in/result/00-base.xml @@ -0,0 +1,111 @@ + + + + + oui + creole.general.mode_conteneur_actif + creole.general.mode_conteneur_actif2 + + + + + + + + diff --git a/tests/flattener_dicos/10load_mandatoryifin/00-base.xml b/tests/flattener_dicos/10load_mandatoryifin/00-base.xml new file mode 100644 index 0000000..85db702 --- /dev/null +++ b/tests/flattener_dicos/10load_mandatoryifin/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + non + + + non + + + non + + + + + + + + oui + mode_conteneur_actif + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos/10load_mandatoryifin/result/00-base.xml b/tests/flattener_dicos/10load_mandatoryifin/result/00-base.xml new file mode 100644 index 0000000..d46d120 --- /dev/null +++ b/tests/flattener_dicos/10load_mandatoryifin/result/00-base.xml @@ -0,0 +1,109 @@ + + + + + oui + creole.general.mode_conteneur_actif + creole.general.mode_conteneur_actif2 + + + + + + + + diff --git a/tests/flattener_dicos/10load_masterslaves/00-base.xml b/tests/flattener_dicos/10load_masterslaves/00-base.xml new file mode 100644 index 0000000..7caaeb4 --- /dev/null +++ b/tests/flattener_dicos/10load_masterslaves/00-base.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + non + + + + + + + + + + + + valfill + + + slave1 + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/10load_masterslaves/result/00-base.xml b/tests/flattener_dicos/10load_masterslaves/result/00-base.xml new file mode 100644 index 0000000..925cb59 --- /dev/null +++ b/tests/flattener_dicos/10load_masterslaves/result/00-base.xml @@ -0,0 +1,110 @@ + + + + + valfill + + + creole.general1.master.slave1 + + + + + + + + diff --git a/tests/flattener_dicos/10load_masterslaves_default_multi/00-base.xml b/tests/flattener_dicos/10load_masterslaves_default_multi/00-base.xml new file mode 100644 index 0000000..60f664f --- /dev/null +++ b/tests/flattener_dicos/10load_masterslaves_default_multi/00-base.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + non + + + + value + + + + + + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/10load_masterslaves_default_multi/result/00-base.xml b/tests/flattener_dicos/10load_masterslaves_default_multi/result/00-base.xml new file mode 100644 index 0000000..77fbf74 --- /dev/null +++ b/tests/flattener_dicos/10load_masterslaves_default_multi/result/00-base.xml @@ -0,0 +1,103 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/10load_masterslaves_defaultmulti_master/00-base.xml b/tests/flattener_dicos/10load_masterslaves_defaultmulti_master/00-base.xml new file mode 100644 index 0000000..2b344c6 --- /dev/null +++ b/tests/flattener_dicos/10load_masterslaves_defaultmulti_master/00-base.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + non + + + value + + + + + + + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/10load_masterslaves_defaultmulti_master/result/00-base.xml b/tests/flattener_dicos/10load_masterslaves_defaultmulti_master/result/00-base.xml new file mode 100644 index 0000000..bb45995 --- /dev/null +++ b/tests/flattener_dicos/10load_masterslaves_defaultmulti_master/result/00-base.xml @@ -0,0 +1,103 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/10load_masterslaves_normalize_family/00-base.xml b/tests/flattener_dicos/10load_masterslaves_normalize_family/00-base.xml new file mode 100644 index 0000000..fe33919 --- /dev/null +++ b/tests/flattener_dicos/10load_masterslaves_normalize_family/00-base.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + non + + + + + + + + + + + + slave1 + slave2 + + + + + + diff --git a/tests/flattener_dicos/10load_masterslaves_normalize_family/01-base.xml b/tests/flattener_dicos/10load_masterslaves_normalize_family/01-base.xml new file mode 100644 index 0000000..e1adb6a --- /dev/null +++ b/tests/flattener_dicos/10load_masterslaves_normalize_family/01-base.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/10load_masterslaves_normalize_family/result/00-base.xml b/tests/flattener_dicos/10load_masterslaves_normalize_family/result/00-base.xml new file mode 100644 index 0000000..5289793 --- /dev/null +++ b/tests/flattener_dicos/10load_masterslaves_normalize_family/result/00-base.xml @@ -0,0 +1,104 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/10load_multivalue/00-base.xml b/tests/flattener_dicos/10load_multivalue/00-base.xml new file mode 100644 index 0000000..9b64851 --- /dev/null +++ b/tests/flattener_dicos/10load_multivalue/00-base.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/10load_multivalue/result/00-base.xml b/tests/flattener_dicos/10load_multivalue/result/00-base.xml new file mode 100644 index 0000000..346a5c3 --- /dev/null +++ b/tests/flattener_dicos/10load_multivalue/result/00-base.xml @@ -0,0 +1,95 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/10masterslave_autosaveexpert/00-base.xml b/tests/flattener_dicos/10masterslave_autosaveexpert/00-base.xml new file mode 100644 index 0000000..79bd14f --- /dev/null +++ b/tests/flattener_dicos/10masterslave_autosaveexpert/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + non + + + + + + + + + + valfill + + + slave1 + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/10masterslave_autosaveexpert/result/00-base.xml b/tests/flattener_dicos/10masterslave_autosaveexpert/result/00-base.xml new file mode 100644 index 0000000..2117fe1 --- /dev/null +++ b/tests/flattener_dicos/10masterslave_autosaveexpert/result/00-base.xml @@ -0,0 +1,108 @@ + + + + + valfill + + + creole.general.master.slave1 + + + + + + + + diff --git a/tests/flattener_dicos/10masterslave_mandatory/00-base.xml b/tests/flattener_dicos/10masterslave_mandatory/00-base.xml new file mode 100644 index 0000000..04a8804 --- /dev/null +++ b/tests/flattener_dicos/10masterslave_mandatory/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + non + + + + + + + + + + valfill + + + slave1 + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/10masterslave_mandatory/result/00-base.xml b/tests/flattener_dicos/10masterslave_mandatory/result/00-base.xml new file mode 100644 index 0000000..19563e7 --- /dev/null +++ b/tests/flattener_dicos/10masterslave_mandatory/result/00-base.xml @@ -0,0 +1,109 @@ + + + + + valfill + + + creole.general.master.slave1 + + + + + + + + diff --git a/tests/flattener_dicos/10masterslave_mandatoryslave/00-base.xml b/tests/flattener_dicos/10masterslave_mandatoryslave/00-base.xml new file mode 100644 index 0000000..cd90add --- /dev/null +++ b/tests/flattener_dicos/10masterslave_mandatoryslave/00-base.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + nut_monitor_host + + + + + + + diff --git a/tests/flattener_dicos/10masterslave_mandatoryslave/result/00-base.xml b/tests/flattener_dicos/10masterslave_mandatoryslave/result/00-base.xml new file mode 100644 index 0000000..925e8bc --- /dev/null +++ b/tests/flattener_dicos/10masterslave_mandatoryslave/result/00-base.xml @@ -0,0 +1,101 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/10masterslave_mastermandatory/00-base.xml b/tests/flattener_dicos/10masterslave_mastermandatory/00-base.xml new file mode 100644 index 0000000..30932e0 --- /dev/null +++ b/tests/flattener_dicos/10masterslave_mastermandatory/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + non + + + + + + + + + + valfill + + + slave1 + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/10masterslave_mastermandatory/result/00-base.xml b/tests/flattener_dicos/10masterslave_mastermandatory/result/00-base.xml new file mode 100644 index 0000000..a80cd8f --- /dev/null +++ b/tests/flattener_dicos/10masterslave_mastermandatory/result/00-base.xml @@ -0,0 +1,109 @@ + + + + + valfill + + + creole.general.master.slave1 + + + + + + + + diff --git a/tests/flattener_dicos/10masterslave_multi/00-base.xml b/tests/flattener_dicos/10masterslave_multi/00-base.xml new file mode 100644 index 0000000..39d46f4 --- /dev/null +++ b/tests/flattener_dicos/10masterslave_multi/00-base.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + non + + + + + + + + + + + + + + + valfill + + + slave1 + + + slave1 + slave2 + + + slave11 + slave21 + + + + + + + diff --git a/tests/flattener_dicos/10masterslave_multi/result/00-base.xml b/tests/flattener_dicos/10masterslave_multi/result/00-base.xml new file mode 100644 index 0000000..5574350 --- /dev/null +++ b/tests/flattener_dicos/10masterslave_multi/result/00-base.xml @@ -0,0 +1,121 @@ + + + + + valfill + + + creole.general1.master.slave1 + + + + + + + + diff --git a/tests/flattener_dicos/10masterslaves_append/00-base.xml b/tests/flattener_dicos/10masterslaves_append/00-base.xml new file mode 100644 index 0000000..7caaeb4 --- /dev/null +++ b/tests/flattener_dicos/10masterslaves_append/00-base.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + non + + + + + + + + + + + + valfill + + + slave1 + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/10masterslaves_append/01-base.xml b/tests/flattener_dicos/10masterslaves_append/01-base.xml new file mode 100644 index 0000000..5a4f9e5 --- /dev/null +++ b/tests/flattener_dicos/10masterslaves_append/01-base.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + slave3 + + + + + + + diff --git a/tests/flattener_dicos/10masterslaves_append/result/00-base.xml b/tests/flattener_dicos/10masterslaves_append/result/00-base.xml new file mode 100644 index 0000000..65994e8 --- /dev/null +++ b/tests/flattener_dicos/10masterslaves_append/result/00-base.xml @@ -0,0 +1,113 @@ + + + + + valfill + + + creole.general1.master.slave1 + + + + + + + + diff --git a/tests/flattener_dicos/10masterslaves_auto/00-base.xml b/tests/flattener_dicos/10masterslaves_auto/00-base.xml new file mode 100644 index 0000000..d6f69d1 --- /dev/null +++ b/tests/flattener_dicos/10masterslaves_auto/00-base.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + non + + + + + + + + + + + valfill + + + slave1 + + + master + + + slave1 + slave2 + slave3 + + + + + + + diff --git a/tests/flattener_dicos/10masterslaves_auto/result/00-base.xml b/tests/flattener_dicos/10masterslaves_auto/result/00-base.xml new file mode 100644 index 0000000..ccee91a --- /dev/null +++ b/tests/flattener_dicos/10masterslaves_auto/result/00-base.xml @@ -0,0 +1,123 @@ + + + + + valfill + + + creole.general.master.slave1 + + + creole.general.master.master + + + + + + + + diff --git a/tests/flattener_dicos/10masterslaves_automaster/00-base.xml b/tests/flattener_dicos/10masterslaves_automaster/00-base.xml new file mode 100644 index 0000000..fb12ff7 --- /dev/null +++ b/tests/flattener_dicos/10masterslaves_automaster/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + non + + + + + + + + + + valfill + + + master + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/10masterslaves_automaster/result/00-base.xml b/tests/flattener_dicos/10masterslaves_automaster/result/00-base.xml new file mode 100644 index 0000000..1b3366b --- /dev/null +++ b/tests/flattener_dicos/10masterslaves_automaster/result/00-base.xml @@ -0,0 +1,114 @@ + + + + + valfill + + + creole.general.master.master + + + + + + + + diff --git a/tests/flattener_dicos/10masterslaves_automaster_expert/00-base.xml b/tests/flattener_dicos/10masterslaves_automaster_expert/00-base.xml new file mode 100644 index 0000000..d75c30d --- /dev/null +++ b/tests/flattener_dicos/10masterslaves_automaster_expert/00-base.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + non + + + + + + + + + + + + valfill + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/10masterslaves_automaster_expert/result/00-base.xml b/tests/flattener_dicos/10masterslaves_automaster_expert/result/00-base.xml new file mode 100644 index 0000000..7726d23 --- /dev/null +++ b/tests/flattener_dicos/10masterslaves_automaster_expert/result/00-base.xml @@ -0,0 +1,110 @@ + + + + + valfill + + + + + + + + diff --git a/tests/flattener_dicos/10masterslaves_familyaccent/00-base.xml b/tests/flattener_dicos/10masterslaves_familyaccent/00-base.xml new file mode 100644 index 0000000..509565e --- /dev/null +++ b/tests/flattener_dicos/10masterslaves_familyaccent/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + non + + + + + + + + + + valfill + + + slave1 + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/10masterslaves_familyaccent/result/00-base.xml b/tests/flattener_dicos/10masterslaves_familyaccent/result/00-base.xml new file mode 100644 index 0000000..a9b8556 --- /dev/null +++ b/tests/flattener_dicos/10masterslaves_familyaccent/result/00-base.xml @@ -0,0 +1,108 @@ + + + + + valfill + + + creole.general.master.slave1 + + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_accent/00-base.xml b/tests/flattener_dicos/10valid_enum_accent/00-base.xml new file mode 100644 index 0000000..cacda03 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_accent/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + non + + + + + c + + + + + + + + ['a', 'b', 'c', 'é'] + False + + + + + bla bla bla + + + + diff --git a/tests/flattener_dicos/10valid_enum_accent/result/00-base.xml b/tests/flattener_dicos/10valid_enum_accent/result/00-base.xml new file mode 100644 index 0000000..fcf0a7a --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_accent/result/00-base.xml @@ -0,0 +1,104 @@ + + + + + ['a', 'b', 'c', 'é'] + + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_base/00-base.xml b/tests/flattener_dicos/10valid_enum_base/00-base.xml new file mode 100644 index 0000000..5e60752 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_base/00-base.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + non + + + + + c + + + + + + + + ['a','b','c'] + + + + + bla bla bla + + + + diff --git a/tests/flattener_dicos/10valid_enum_base/result/00-base.xml b/tests/flattener_dicos/10valid_enum_base/result/00-base.xml new file mode 100644 index 0000000..da9bd83 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_base/result/00-base.xml @@ -0,0 +1,103 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_base_redefine/00-base.xml b/tests/flattener_dicos/10valid_enum_base_redefine/00-base.xml new file mode 100644 index 0000000..1ac4855 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_base_redefine/00-base.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + non + + + + + c + + + c + + + + + + + + ['a','b','c'] + + + ['a','b','c'] + + + + + bla bla bla + + + + diff --git a/tests/flattener_dicos/10valid_enum_base_redefine/01-base.xml b/tests/flattener_dicos/10valid_enum_base_redefine/01-base.xml new file mode 100644 index 0000000..da072f5 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_base_redefine/01-base.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + c + + + + + + + + ['a','c'] + + + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_base_redefine/result/00-base.xml b/tests/flattener_dicos/10valid_enum_base_redefine/result/00-base.xml new file mode 100644 index 0000000..53af4e6 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_base_redefine/result/00-base.xml @@ -0,0 +1,110 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_checkval/00-base.xml b/tests/flattener_dicos/10valid_enum_checkval/00-base.xml new file mode 100644 index 0000000..96a0638 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_checkval/00-base.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + ['a','b','c'] + False + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_checkval/result/00-base.xml b/tests/flattener_dicos/10valid_enum_checkval/result/00-base.xml new file mode 100644 index 0000000..3e49304 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_checkval/result/00-base.xml @@ -0,0 +1,92 @@ + + + + + ['a','b','c'] + + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_checkval_true/00-base.xml b/tests/flattener_dicos/10valid_enum_checkval_true/00-base.xml new file mode 100644 index 0000000..cc61006 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_checkval_true/00-base.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + ['a','b','c'] + True + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_checkval_true/result/00-base.xml b/tests/flattener_dicos/10valid_enum_checkval_true/result/00-base.xml new file mode 100644 index 0000000..c8d51c5 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_checkval_true/result/00-base.xml @@ -0,0 +1,91 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_eosfunc/00-base.xml b/tests/flattener_dicos/10valid_enum_eosfunc/00-base.xml new file mode 100644 index 0000000..20e3017 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_eosfunc/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + non + + + + + + + + eosfunc.list_files('/notexists', default=['oui', 'non']) + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_eosfunc/result/00-base.xml b/tests/flattener_dicos/10valid_enum_eosfunc/result/00-base.xml new file mode 100644 index 0000000..cb605a3 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_eosfunc/result/00-base.xml @@ -0,0 +1,91 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_eosfunc_probe/00-base.xml b/tests/flattener_dicos/10valid_enum_eosfunc_probe/00-base.xml new file mode 100644 index 0000000..5d38304 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_eosfunc_probe/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + non + + + + + + + + get_net_devices + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_eosfunc_probe/result/00-base.xml b/tests/flattener_dicos/10valid_enum_eosfunc_probe/result/00-base.xml new file mode 100644 index 0000000..c82e400 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_eosfunc_probe/result/00-base.xml @@ -0,0 +1,89 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_eosfunc_probe_checkval/00-base.xml b/tests/flattener_dicos/10valid_enum_eosfunc_probe_checkval/00-base.xml new file mode 100644 index 0000000..c5376d2 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_eosfunc_probe_checkval/00-base.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + non + + + + + + + + get_net_devices + False + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_eosfunc_probe_checkval/result/00-base.xml b/tests/flattener_dicos/10valid_enum_eosfunc_probe_checkval/result/00-base.xml new file mode 100644 index 0000000..0c0d1cb --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_eosfunc_probe_checkval/result/00-base.xml @@ -0,0 +1,93 @@ + + + + + get_net_devices + + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_mandatory/00-base.xml b/tests/flattener_dicos/10valid_enum_mandatory/00-base.xml new file mode 100644 index 0000000..69229c0 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_mandatory/00-base.xml @@ -0,0 +1,25 @@ + + + + + + + + + non + + + + + + + + + + + ['a','b','c'] + + + + diff --git a/tests/flattener_dicos/10valid_enum_mandatory/result/00-base.xml b/tests/flattener_dicos/10valid_enum_mandatory/result/00-base.xml new file mode 100644 index 0000000..7779a5f --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_mandatory/result/00-base.xml @@ -0,0 +1,100 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_master/00-base.xml b/tests/flattener_dicos/10valid_enum_master/00-base.xml new file mode 100644 index 0000000..61d177a --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_master/00-base.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + non + + + + + + + + + + + ['a','b','c'] + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_master/result/00-base.xml b/tests/flattener_dicos/10valid_enum_master/result/00-base.xml new file mode 100644 index 0000000..f68d1f7 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_master/result/00-base.xml @@ -0,0 +1,105 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_multi/00-base.xml b/tests/flattener_dicos/10valid_enum_multi/00-base.xml new file mode 100644 index 0000000..b037d27 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_multi/00-base.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + non + + + + + + + + + ['a','b','c'] + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_multi/result/00-base.xml b/tests/flattener_dicos/10valid_enum_multi/result/00-base.xml new file mode 100644 index 0000000..2d3e8d4 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_multi/result/00-base.xml @@ -0,0 +1,97 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_number/00-base.xml b/tests/flattener_dicos/10valid_enum_number/00-base.xml new file mode 100644 index 0000000..19a73d9 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_number/00-base.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + non + + + + + + + + + + + [1, 2, 3] + + + + + bla bla bla + + + + diff --git a/tests/flattener_dicos/10valid_enum_number/result/00-base.xml b/tests/flattener_dicos/10valid_enum_number/result/00-base.xml new file mode 100644 index 0000000..aade7e1 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_number/result/00-base.xml @@ -0,0 +1,102 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_numberdefault/00-base.xml b/tests/flattener_dicos/10valid_enum_numberdefault/00-base.xml new file mode 100644 index 0000000..96137ae --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_numberdefault/00-base.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + non + + + + + 3 + + + + + + + + [1, 2, 3] + + + + + bla bla bla + + + + diff --git a/tests/flattener_dicos/10valid_enum_numberdefault/result/00-base.xml b/tests/flattener_dicos/10valid_enum_numberdefault/result/00-base.xml new file mode 100644 index 0000000..114cfec --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_numberdefault/result/00-base.xml @@ -0,0 +1,103 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_python/00-base.xml b/tests/flattener_dicos/10valid_enum_python/00-base.xml new file mode 100644 index 0000000..5b5bf6b --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_python/00-base.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + non + + + + + test + + + + + + + + eosfunc.calc_multi_val(['test']) + + + + + bla bla bla + + + + diff --git a/tests/flattener_dicos/10valid_enum_python/result/00-base.xml b/tests/flattener_dicos/10valid_enum_python/result/00-base.xml new file mode 100644 index 0000000..69f1bbd --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_python/result/00-base.xml @@ -0,0 +1,101 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_value/00-base.xml b/tests/flattener_dicos/10valid_enum_value/00-base.xml new file mode 100644 index 0000000..f9654e9 --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_value/00-base.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + b + + + + + + + + ['a','b','c'] + False + + + + + + + diff --git a/tests/flattener_dicos/10valid_enum_value/result/00-base.xml b/tests/flattener_dicos/10valid_enum_value/result/00-base.xml new file mode 100644 index 0000000..c9a06fc --- /dev/null +++ b/tests/flattener_dicos/10valid_enum_value/result/00-base.xml @@ -0,0 +1,93 @@ + + + + + ['a','b','c'] + + + + + + + + diff --git a/tests/flattener_dicos/11disabled_if_in_filelist/00-base.xml b/tests/flattener_dicos/11disabled_if_in_filelist/00-base.xml new file mode 100644 index 0000000..7140e1d --- /dev/null +++ b/tests/flattener_dicos/11disabled_if_in_filelist/00-base.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + non + + + + + + + + + + oui + mode_conteneur_actif + mode_conteneur_actif2 + afilllist + + + + + + + diff --git a/tests/flattener_dicos/11disabled_if_in_filelist/result/00-base.xml b/tests/flattener_dicos/11disabled_if_in_filelist/result/00-base.xml new file mode 100644 index 0000000..27b9796 --- /dev/null +++ b/tests/flattener_dicos/11disabled_if_in_filelist/result/00-base.xml @@ -0,0 +1,145 @@ + + + + + oui + creole.general.mode_conteneur_actif + creole.general.mode_conteneur_actif2 + containers.files.file0.activate + + + + + + + + diff --git a/tests/flattener_dicos/11disabled_if_in_filelist_multi/00-base.xml b/tests/flattener_dicos/11disabled_if_in_filelist_multi/00-base.xml new file mode 100644 index 0000000..fbe695e --- /dev/null +++ b/tests/flattener_dicos/11disabled_if_in_filelist_multi/00-base.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + non + + + + + + + + + + oui + mode_conteneur_actif + mode_conteneur_actif2 + afilllist + + + + + + + diff --git a/tests/flattener_dicos/11disabled_if_in_filelist_multi/result/00-base.xml b/tests/flattener_dicos/11disabled_if_in_filelist_multi/result/00-base.xml new file mode 100644 index 0000000..4a9afae --- /dev/null +++ b/tests/flattener_dicos/11disabled_if_in_filelist_multi/result/00-base.xml @@ -0,0 +1,178 @@ + + + + + oui + creole.general.mode_conteneur_actif + creole.general.mode_conteneur_actif2 + containers.files.file0.activate + containers.files.file1.activate + + + + + + + + diff --git a/tests/flattener_dicos/11disabledifin_filelist_notexist/00-base.xml b/tests/flattener_dicos/11disabledifin_filelist_notexist/00-base.xml new file mode 100644 index 0000000..3cb2a58 --- /dev/null +++ b/tests/flattener_dicos/11disabledifin_filelist_notexist/00-base.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + non + + + + + + + + + + unpossible + afilllist + + + + + + + diff --git a/tests/flattener_dicos/11disabledifin_filelist_notexist/result/00-base.xml b/tests/flattener_dicos/11disabledifin_filelist_notexist/result/00-base.xml new file mode 100644 index 0000000..d120c6c --- /dev/null +++ b/tests/flattener_dicos/11disabledifin_filelist_notexist/result/00-base.xml @@ -0,0 +1,145 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/11disabledifnotin_filelist_notexist/00-base.xml b/tests/flattener_dicos/11disabledifnotin_filelist_notexist/00-base.xml new file mode 100644 index 0000000..3cb2a58 --- /dev/null +++ b/tests/flattener_dicos/11disabledifnotin_filelist_notexist/00-base.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + non + + + + + + + + + + unpossible + afilllist + + + + + + + diff --git a/tests/flattener_dicos/11disabledifnotin_filelist_notexist/result/00-base.xml b/tests/flattener_dicos/11disabledifnotin_filelist_notexist/result/00-base.xml new file mode 100644 index 0000000..d120c6c --- /dev/null +++ b/tests/flattener_dicos/11disabledifnotin_filelist_notexist/result/00-base.xml @@ -0,0 +1,145 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/11disabledifnotin_filelist_notexist_multi/00-base.xml b/tests/flattener_dicos/11disabledifnotin_filelist_notexist_multi/00-base.xml new file mode 100644 index 0000000..7a0ffda --- /dev/null +++ b/tests/flattener_dicos/11disabledifnotin_filelist_notexist_multi/00-base.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + non + + + + + + + + + + unpossible + afilllist + + + oui + afilllist + + + + + + + diff --git a/tests/flattener_dicos/11disabledifnotin_filelist_notexist_multi/result/00-base.xml b/tests/flattener_dicos/11disabledifnotin_filelist_notexist_multi/result/00-base.xml new file mode 100644 index 0000000..6dd38ea --- /dev/null +++ b/tests/flattener_dicos/11disabledifnotin_filelist_notexist_multi/result/00-base.xml @@ -0,0 +1,149 @@ + + + + + oui + + + + + + + + diff --git a/tests/flattener_dicos/11disabledifnotin_filelist_notexist_validenum/00-base.xml b/tests/flattener_dicos/11disabledifnotin_filelist_notexist_validenum/00-base.xml new file mode 100644 index 0000000..c079eda --- /dev/null +++ b/tests/flattener_dicos/11disabledifnotin_filelist_notexist_validenum/00-base.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + non + + + + + + + + + + ['non','statique'] + + + statique + afilllist + + + + + + + diff --git a/tests/flattener_dicos/11disabledifnotin_filelist_notexist_validenum/result/00-base.xml b/tests/flattener_dicos/11disabledifnotin_filelist_notexist_validenum/result/00-base.xml new file mode 100644 index 0000000..aa5e9c5 --- /dev/null +++ b/tests/flattener_dicos/11disabledifnotin_filelist_notexist_validenum/result/00-base.xml @@ -0,0 +1,149 @@ + + + + + statique + containers.files.file0.activate + + + + + + + + diff --git a/tests/flattener_dicos/11multi_disabled_if_in_filelist/00-base.xml b/tests/flattener_dicos/11multi_disabled_if_in_filelist/00-base.xml new file mode 100644 index 0000000..d62e1dc --- /dev/null +++ b/tests/flattener_dicos/11multi_disabled_if_in_filelist/00-base.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + non + + + + + + + + non + afilllist + + + non + afilllist + + + + + + + diff --git a/tests/flattener_dicos/11multi_disabled_if_in_filelist/result/00-base.xml b/tests/flattener_dicos/11multi_disabled_if_in_filelist/result/00-base.xml new file mode 100644 index 0000000..f7073b1 --- /dev/null +++ b/tests/flattener_dicos/11multi_disabled_if_in_filelist/result/00-base.xml @@ -0,0 +1,139 @@ + + + + + non + + + + + + + + diff --git a/tests/flattener_dicos/20family_append/00-base.xml b/tests/flattener_dicos/20family_append/00-base.xml new file mode 100644 index 0000000..79051f1 --- /dev/null +++ b/tests/flattener_dicos/20family_append/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/20family_append/01-base.xml b/tests/flattener_dicos/20family_append/01-base.xml new file mode 100644 index 0000000..81d2265 --- /dev/null +++ b/tests/flattener_dicos/20family_append/01-base.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/20family_append/result/00-base.xml b/tests/flattener_dicos/20family_append/result/00-base.xml new file mode 100644 index 0000000..4c8167a --- /dev/null +++ b/tests/flattener_dicos/20family_append/result/00-base.xml @@ -0,0 +1,104 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/20family_appendaccent/00-base.xml b/tests/flattener_dicos/20family_appendaccent/00-base.xml new file mode 100644 index 0000000..32ed496 --- /dev/null +++ b/tests/flattener_dicos/20family_appendaccent/00-base.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + non + mode_conteneur_actif + + + + + + + diff --git a/tests/flattener_dicos/20family_appendaccent/01-base.xml b/tests/flattener_dicos/20family_appendaccent/01-base.xml new file mode 100644 index 0000000..97bc2a3 --- /dev/null +++ b/tests/flattener_dicos/20family_appendaccent/01-base.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/20family_appendaccent/02-base.xml b/tests/flattener_dicos/20family_appendaccent/02-base.xml new file mode 100644 index 0000000..edd324f --- /dev/null +++ b/tests/flattener_dicos/20family_appendaccent/02-base.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/20family_appendaccent/result/00-base.xml b/tests/flattener_dicos/20family_appendaccent/result/00-base.xml new file mode 100644 index 0000000..d73c22d --- /dev/null +++ b/tests/flattener_dicos/20family_appendaccent/result/00-base.xml @@ -0,0 +1,128 @@ + + + + + non + creole.general.mode_conteneur_actif + + + + + + + + diff --git a/tests/flattener_dicos/20family_empty/00-base.xml b/tests/flattener_dicos/20family_empty/00-base.xml new file mode 100644 index 0000000..ce0a7f2 --- /dev/null +++ b/tests/flattener_dicos/20family_empty/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + non + + + + + + + + + + + redefine help family + + + + diff --git a/tests/flattener_dicos/20family_empty/result/00-base.xml b/tests/flattener_dicos/20family_empty/result/00-base.xml new file mode 100644 index 0000000..0244c74 --- /dev/null +++ b/tests/flattener_dicos/20family_empty/result/00-base.xml @@ -0,0 +1,94 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/20family_hidden/00-base.xml b/tests/flattener_dicos/20family_hidden/00-base.xml new file mode 100644 index 0000000..79051f1 --- /dev/null +++ b/tests/flattener_dicos/20family_hidden/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/20family_hidden/01-base.xml b/tests/flattener_dicos/20family_hidden/01-base.xml new file mode 100644 index 0000000..29b7e45 --- /dev/null +++ b/tests/flattener_dicos/20family_hidden/01-base.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/20family_hidden/result/00-base.xml b/tests/flattener_dicos/20family_hidden/result/00-base.xml new file mode 100644 index 0000000..f14b86d --- /dev/null +++ b/tests/flattener_dicos/20family_hidden/result/00-base.xml @@ -0,0 +1,94 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/20family_mode/00-base.xml b/tests/flattener_dicos/20family_mode/00-base.xml new file mode 100644 index 0000000..c7f4e47 --- /dev/null +++ b/tests/flattener_dicos/20family_mode/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + non + + + + + + + + + + + + diff --git a/tests/flattener_dicos/20family_mode/result/00-base.xml b/tests/flattener_dicos/20family_mode/result/00-base.xml new file mode 100644 index 0000000..1846afc --- /dev/null +++ b/tests/flattener_dicos/20family_mode/result/00-base.xml @@ -0,0 +1,91 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/20family_modemasterslaves/00-base.xml b/tests/flattener_dicos/20family_modemasterslaves/00-base.xml new file mode 100644 index 0000000..1f9b5d8 --- /dev/null +++ b/tests/flattener_dicos/20family_modemasterslaves/00-base.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + non + + + + + + + + + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/20family_modemasterslaves/result/00-base.xml b/tests/flattener_dicos/20family_modemasterslaves/result/00-base.xml new file mode 100644 index 0000000..66a6889 --- /dev/null +++ b/tests/flattener_dicos/20family_modemasterslaves/result/00-base.xml @@ -0,0 +1,102 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/20family_slavenotmulti/00-base.xml b/tests/flattener_dicos/20family_slavenotmulti/00-base.xml new file mode 100644 index 0000000..feb1224 --- /dev/null +++ b/tests/flattener_dicos/20family_slavenotmulti/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + non + + + + + + + + + + valfill + + + slave1 + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/20family_slavenotmulti/result/00-base.xml b/tests/flattener_dicos/20family_slavenotmulti/result/00-base.xml new file mode 100644 index 0000000..b9f50ca --- /dev/null +++ b/tests/flattener_dicos/20family_slavenotmulti/result/00-base.xml @@ -0,0 +1,108 @@ + + + + + valfill + + + creole.general.master.slave1 + + + + + + + + diff --git a/tests/flattener_dicos/21family_change/00-base.xml b/tests/flattener_dicos/21family_change/00-base.xml new file mode 100644 index 0000000..fc142a9 --- /dev/null +++ b/tests/flattener_dicos/21family_change/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/21family_change/01-base.xml b/tests/flattener_dicos/21family_change/01-base.xml new file mode 100644 index 0000000..b706723 --- /dev/null +++ b/tests/flattener_dicos/21family_change/01-base.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + non + + + + + + + + + + + + diff --git a/tests/flattener_dicos/21family_change/result/00-base.xml b/tests/flattener_dicos/21family_change/result/00-base.xml new file mode 100644 index 0000000..adbf3ae --- /dev/null +++ b/tests/flattener_dicos/21family_change/result/00-base.xml @@ -0,0 +1,106 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/21family_changeaccent/00-base.xml b/tests/flattener_dicos/21family_changeaccent/00-base.xml new file mode 100644 index 0000000..fe3fc4d --- /dev/null +++ b/tests/flattener_dicos/21family_changeaccent/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/21family_changeaccent/01-base.xml b/tests/flattener_dicos/21family_changeaccent/01-base.xml new file mode 100644 index 0000000..daa109f --- /dev/null +++ b/tests/flattener_dicos/21family_changeaccent/01-base.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + non + + + + + + + + + + + + diff --git a/tests/flattener_dicos/21family_changeaccent/result/00-base.xml b/tests/flattener_dicos/21family_changeaccent/result/00-base.xml new file mode 100644 index 0000000..7bac5fc --- /dev/null +++ b/tests/flattener_dicos/21family_changeaccent/result/00-base.xml @@ -0,0 +1,106 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/21family_empty/00-base.xml b/tests/flattener_dicos/21family_empty/00-base.xml new file mode 100644 index 0000000..8874d99 --- /dev/null +++ b/tests/flattener_dicos/21family_empty/00-base.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + non + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/21family_empty/result/00-base.xml b/tests/flattener_dicos/21family_empty/result/00-base.xml new file mode 100644 index 0000000..2801e67 --- /dev/null +++ b/tests/flattener_dicos/21family_empty/result/00-base.xml @@ -0,0 +1,92 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/30mandatory_withoutvalue/00-base.xml b/tests/flattener_dicos/30mandatory_withoutvalue/00-base.xml new file mode 100644 index 0000000..0559531 --- /dev/null +++ b/tests/flattener_dicos/30mandatory_withoutvalue/00-base.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/30mandatory_withoutvalue/result/00-base.xml b/tests/flattener_dicos/30mandatory_withoutvalue/result/00-base.xml new file mode 100644 index 0000000..e330008 --- /dev/null +++ b/tests/flattener_dicos/30mandatory_withoutvalue/result/00-base.xml @@ -0,0 +1,88 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/30mandatory_withoutvaluecalc/00-base.xml b/tests/flattener_dicos/30mandatory_withoutvaluecalc/00-base.xml new file mode 100644 index 0000000..9cf610e --- /dev/null +++ b/tests/flattener_dicos/30mandatory_withoutvaluecalc/00-base.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + value + + + + + + + diff --git a/tests/flattener_dicos/30mandatory_withoutvaluecalc/result/00-base.xml b/tests/flattener_dicos/30mandatory_withoutvaluecalc/result/00-base.xml new file mode 100644 index 0000000..b80f38d --- /dev/null +++ b/tests/flattener_dicos/30mandatory_withoutvaluecalc/result/00-base.xml @@ -0,0 +1,94 @@ + + + + + value + + + + + + + + diff --git a/tests/flattener_dicos/30mandatory_withvalue/00-base.xml b/tests/flattener_dicos/30mandatory_withvalue/00-base.xml new file mode 100644 index 0000000..9ede15b --- /dev/null +++ b/tests/flattener_dicos/30mandatory_withvalue/00-base.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + value + + + + + + + + + + + + diff --git a/tests/flattener_dicos/30mandatory_withvalue/result/00-base.xml b/tests/flattener_dicos/30mandatory_withvalue/result/00-base.xml new file mode 100644 index 0000000..f045ed4 --- /dev/null +++ b/tests/flattener_dicos/30mandatory_withvalue/result/00-base.xml @@ -0,0 +1,89 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/30mandatory_withvaluecalc/00-base.xml b/tests/flattener_dicos/30mandatory_withvaluecalc/00-base.xml new file mode 100644 index 0000000..2bc8f0d --- /dev/null +++ b/tests/flattener_dicos/30mandatory_withvaluecalc/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + value + + + + + + + diff --git a/tests/flattener_dicos/30mandatory_withvaluecalc/result/00-base.xml b/tests/flattener_dicos/30mandatory_withvaluecalc/result/00-base.xml new file mode 100644 index 0000000..64df051 --- /dev/null +++ b/tests/flattener_dicos/30mandatory_withvaluecalc/result/00-base.xml @@ -0,0 +1,91 @@ + + + + + value + + + + + + + + diff --git a/tests/flattener_dicos/40condition_base/00-base.xml b/tests/flattener_dicos/40condition_base/00-base.xml new file mode 100644 index 0000000..c3f3fde --- /dev/null +++ b/tests/flattener_dicos/40condition_base/00-base.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + non + + + non + + + + + + + + + + oui + mode_conteneur_actif1 + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos/40condition_base/result/00-base.xml b/tests/flattener_dicos/40condition_base/result/00-base.xml new file mode 100644 index 0000000..92506a2 --- /dev/null +++ b/tests/flattener_dicos/40condition_base/result/00-base.xml @@ -0,0 +1,118 @@ + + + + + oui + creole.general.mode_conteneur_actif1 + creole.general.mode_conteneur_actif2 + + + + + + + + diff --git a/tests/flattener_dicos/40condition_fallback/00-base.xml b/tests/flattener_dicos/40condition_fallback/00-base.xml new file mode 100644 index 0000000..b8eac73 --- /dev/null +++ b/tests/flattener_dicos/40condition_fallback/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + non + + + + + + + + + + oui + mode_conteneur_actif1 + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos/40condition_fallback/result/00-base.xml b/tests/flattener_dicos/40condition_fallback/result/00-base.xml new file mode 100644 index 0000000..a6a4bd5 --- /dev/null +++ b/tests/flattener_dicos/40condition_fallback/result/00-base.xml @@ -0,0 +1,107 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/40condition_optional/00-base.xml b/tests/flattener_dicos/40condition_optional/00-base.xml new file mode 100644 index 0000000..b95d389 --- /dev/null +++ b/tests/flattener_dicos/40condition_optional/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + non + + + non + + + + + + + + + oui + mode_conteneur_actif1 + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos/40condition_optional/result/00-base.xml b/tests/flattener_dicos/40condition_optional/result/00-base.xml new file mode 100644 index 0000000..175822f --- /dev/null +++ b/tests/flattener_dicos/40condition_optional/result/00-base.xml @@ -0,0 +1,110 @@ + + + + + oui + creole.general.mode_conteneur_actif1 + + + + + + + + diff --git a/tests/flattener_dicos/40ifin_masterslaves/00-base.xml b/tests/flattener_dicos/40ifin_masterslaves/00-base.xml new file mode 100644 index 0000000..075f451 --- /dev/null +++ b/tests/flattener_dicos/40ifin_masterslaves/00-base.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + non + + + + + + + + + + + slave1 + slave2 + + + oui + slave1 + + + + + + + diff --git a/tests/flattener_dicos/40ifin_masterslaves/result/00-base.xml b/tests/flattener_dicos/40ifin_masterslaves/result/00-base.xml new file mode 100644 index 0000000..cca4941 --- /dev/null +++ b/tests/flattener_dicos/40ifin_masterslaves/result/00-base.xml @@ -0,0 +1,112 @@ + + + + + oui + creole.general.master.slave1 + + + + + + + + diff --git a/tests/flattener_dicos/40ifin_masterslavesauto/00-base.xml b/tests/flattener_dicos/40ifin_masterslavesauto/00-base.xml new file mode 100644 index 0000000..ed8e4e2 --- /dev/null +++ b/tests/flattener_dicos/40ifin_masterslavesauto/00-base.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + non + + + + + + + + + + + slave1 + slave2 + + + valfill + + + oui + slave1 + + + + + + + diff --git a/tests/flattener_dicos/40ifin_masterslavesauto/result/00-base.xml b/tests/flattener_dicos/40ifin_masterslavesauto/result/00-base.xml new file mode 100644 index 0000000..eb83e99 --- /dev/null +++ b/tests/flattener_dicos/40ifin_masterslavesauto/result/00-base.xml @@ -0,0 +1,118 @@ + + + + + oui + creole.general.master.slave1 + + + valfill + + + + + + + + diff --git a/tests/flattener_dicos/40ifin_multi/00-base.xml b/tests/flattener_dicos/40ifin_multi/00-base.xml new file mode 100644 index 0000000..dd6d7a7 --- /dev/null +++ b/tests/flattener_dicos/40ifin_multi/00-base.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + oui + mode_conteneur_actif3 + + + oui + mode_conteneur_actif3 + + + + + + + diff --git a/tests/flattener_dicos/40ifin_multi/result/00-base.xml b/tests/flattener_dicos/40ifin_multi/result/00-base.xml new file mode 100644 index 0000000..82ba25c --- /dev/null +++ b/tests/flattener_dicos/40ifin_multi/result/00-base.xml @@ -0,0 +1,122 @@ + + + + + oui + creole.general2.mode_conteneur_actif3 + + + oui + creole.general2.mode_conteneur_actif3 + + + + + + + + diff --git a/tests/flattener_dicos/40ifin_validenum/00-base.xml b/tests/flattener_dicos/40ifin_validenum/00-base.xml new file mode 100644 index 0000000..8534979 --- /dev/null +++ b/tests/flattener_dicos/40ifin_validenum/00-base.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + non + + + + + + + + + ['a','b','c'] + + + d + mode_conteneur_actif + + + d + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos/40ifin_validenum/result/00-base.xml b/tests/flattener_dicos/40ifin_validenum/result/00-base.xml new file mode 100644 index 0000000..778a7c0 --- /dev/null +++ b/tests/flattener_dicos/40ifin_validenum/result/00-base.xml @@ -0,0 +1,108 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/50exists_exists/00-base.xml b/tests/flattener_dicos/50exists_exists/00-base.xml new file mode 100644 index 0000000..d7dad36 --- /dev/null +++ b/tests/flattener_dicos/50exists_exists/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/50exists_exists/01-base.xml b/tests/flattener_dicos/50exists_exists/01-base.xml new file mode 100644 index 0000000..0c84afa --- /dev/null +++ b/tests/flattener_dicos/50exists_exists/01-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + oui + + + + + + + + + + + + diff --git a/tests/flattener_dicos/50exists_exists/result/00-base.xml b/tests/flattener_dicos/50exists_exists/result/00-base.xml new file mode 100644 index 0000000..cf4ddcf --- /dev/null +++ b/tests/flattener_dicos/50exists_exists/result/00-base.xml @@ -0,0 +1,94 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/50redefine_description/00-base.xml b/tests/flattener_dicos/50redefine_description/00-base.xml new file mode 100644 index 0000000..5efe527 --- /dev/null +++ b/tests/flattener_dicos/50redefine_description/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/50redefine_description/01-redefine.xml b/tests/flattener_dicos/50redefine_description/01-redefine.xml new file mode 100644 index 0000000..895afb5 --- /dev/null +++ b/tests/flattener_dicos/50redefine_description/01-redefine.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/50redefine_description/result/00-base.xml b/tests/flattener_dicos/50redefine_description/result/00-base.xml new file mode 100644 index 0000000..bf89bcc --- /dev/null +++ b/tests/flattener_dicos/50redefine_description/result/00-base.xml @@ -0,0 +1,94 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/51exists_nonexists/00-base.xml b/tests/flattener_dicos/51exists_nonexists/00-base.xml new file mode 100644 index 0000000..2a9fe83 --- /dev/null +++ b/tests/flattener_dicos/51exists_nonexists/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + non + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/51exists_nonexists/01-base.xml b/tests/flattener_dicos/51exists_nonexists/01-base.xml new file mode 100644 index 0000000..33656f8 --- /dev/null +++ b/tests/flattener_dicos/51exists_nonexists/01-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + oui + + + + + + + + + + + + diff --git a/tests/flattener_dicos/51exists_nonexists/result/00-base.xml b/tests/flattener_dicos/51exists_nonexists/result/00-base.xml new file mode 100644 index 0000000..3371771 --- /dev/null +++ b/tests/flattener_dicos/51exists_nonexists/result/00-base.xml @@ -0,0 +1,108 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_auto/00-base.xml b/tests/flattener_dicos/51redefine_auto/00-base.xml new file mode 100644 index 0000000..2758dcd --- /dev/null +++ b/tests/flattener_dicos/51redefine_auto/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + non + + + + + + + diff --git a/tests/flattener_dicos/51redefine_auto/01-base.xml b/tests/flattener_dicos/51redefine_auto/01-base.xml new file mode 100644 index 0000000..6494769 --- /dev/null +++ b/tests/flattener_dicos/51redefine_auto/01-base.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + non + + + + + + diff --git a/tests/flattener_dicos/51redefine_auto/result/00-base.xml b/tests/flattener_dicos/51redefine_auto/result/00-base.xml new file mode 100644 index 0000000..072235e --- /dev/null +++ b/tests/flattener_dicos/51redefine_auto/result/00-base.xml @@ -0,0 +1,96 @@ + + + + + non + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_autofill/00-base.xml b/tests/flattener_dicos/51redefine_autofill/00-base.xml new file mode 100644 index 0000000..a918ca5 --- /dev/null +++ b/tests/flattener_dicos/51redefine_autofill/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + non + + + + + + + + oui + + + + + + + diff --git a/tests/flattener_dicos/51redefine_autofill/01-base.xml b/tests/flattener_dicos/51redefine_autofill/01-base.xml new file mode 100644 index 0000000..7e13918 --- /dev/null +++ b/tests/flattener_dicos/51redefine_autofill/01-base.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + non + + + + + + diff --git a/tests/flattener_dicos/51redefine_autofill/result/00-base.xml b/tests/flattener_dicos/51redefine_autofill/result/00-base.xml new file mode 100644 index 0000000..f3917bc --- /dev/null +++ b/tests/flattener_dicos/51redefine_autofill/result/00-base.xml @@ -0,0 +1,93 @@ + + + + + non + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_family/00-base.xml b/tests/flattener_dicos/51redefine_family/00-base.xml new file mode 100644 index 0000000..cf0c6cf --- /dev/null +++ b/tests/flattener_dicos/51redefine_family/00-base.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + oui + general2 + + + + + + + diff --git a/tests/flattener_dicos/51redefine_family/01-base.xml b/tests/flattener_dicos/51redefine_family/01-base.xml new file mode 100644 index 0000000..7830ace --- /dev/null +++ b/tests/flattener_dicos/51redefine_family/01-base.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + non + + + + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_family/result/00-base.xml b/tests/flattener_dicos/51redefine_family/result/00-base.xml new file mode 100644 index 0000000..c3910dd --- /dev/null +++ b/tests/flattener_dicos/51redefine_family/result/00-base.xml @@ -0,0 +1,111 @@ + + + + + oui + creole.general2 + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_fill/00-base.xml b/tests/flattener_dicos/51redefine_fill/00-base.xml new file mode 100644 index 0000000..2f3fdc0 --- /dev/null +++ b/tests/flattener_dicos/51redefine_fill/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + oui + + + + + + + diff --git a/tests/flattener_dicos/51redefine_fill/01-base.xml b/tests/flattener_dicos/51redefine_fill/01-base.xml new file mode 100644 index 0000000..7e13918 --- /dev/null +++ b/tests/flattener_dicos/51redefine_fill/01-base.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + non + + + + + + diff --git a/tests/flattener_dicos/51redefine_fill/result/00-base.xml b/tests/flattener_dicos/51redefine_fill/result/00-base.xml new file mode 100644 index 0000000..072235e --- /dev/null +++ b/tests/flattener_dicos/51redefine_fill/result/00-base.xml @@ -0,0 +1,96 @@ + + + + + non + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_fillauto/00-base.xml b/tests/flattener_dicos/51redefine_fillauto/00-base.xml new file mode 100644 index 0000000..2f3fdc0 --- /dev/null +++ b/tests/flattener_dicos/51redefine_fillauto/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + oui + + + + + + + diff --git a/tests/flattener_dicos/51redefine_fillauto/01-base.xml b/tests/flattener_dicos/51redefine_fillauto/01-base.xml new file mode 100644 index 0000000..6494769 --- /dev/null +++ b/tests/flattener_dicos/51redefine_fillauto/01-base.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + non + + + + + + diff --git a/tests/flattener_dicos/51redefine_fillauto/result/00-base.xml b/tests/flattener_dicos/51redefine_fillauto/result/00-base.xml new file mode 100644 index 0000000..072235e --- /dev/null +++ b/tests/flattener_dicos/51redefine_fillauto/result/00-base.xml @@ -0,0 +1,96 @@ + + + + + non + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_help/00-base.xml b/tests/flattener_dicos/51redefine_help/00-base.xml new file mode 100644 index 0000000..a7f3f01 --- /dev/null +++ b/tests/flattener_dicos/51redefine_help/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + redefine help + redefine help family + + + + diff --git a/tests/flattener_dicos/51redefine_help/01-base.xml b/tests/flattener_dicos/51redefine_help/01-base.xml new file mode 100644 index 0000000..2f0b2e1 --- /dev/null +++ b/tests/flattener_dicos/51redefine_help/01-base.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + redefine help ok + redefine help family ok + + + + diff --git a/tests/flattener_dicos/51redefine_help/result/00-base.xml b/tests/flattener_dicos/51redefine_help/result/00-base.xml new file mode 100644 index 0000000..fde83af --- /dev/null +++ b/tests/flattener_dicos/51redefine_help/result/00-base.xml @@ -0,0 +1,97 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_hidden/00-base.xml b/tests/flattener_dicos/51redefine_hidden/00-base.xml new file mode 100644 index 0000000..1a334c2 --- /dev/null +++ b/tests/flattener_dicos/51redefine_hidden/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + non + + + + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_hidden/01-redefine.xml b/tests/flattener_dicos/51redefine_hidden/01-redefine.xml new file mode 100644 index 0000000..d16f76e --- /dev/null +++ b/tests/flattener_dicos/51redefine_hidden/01-redefine.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_hidden/result/00-base.xml b/tests/flattener_dicos/51redefine_hidden/result/00-base.xml new file mode 100644 index 0000000..63028c6 --- /dev/null +++ b/tests/flattener_dicos/51redefine_hidden/result/00-base.xml @@ -0,0 +1,94 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_multi/00-base.xml b/tests/flattener_dicos/51redefine_multi/00-base.xml new file mode 100644 index 0000000..5efe527 --- /dev/null +++ b/tests/flattener_dicos/51redefine_multi/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_multi/01-redefine.xml b/tests/flattener_dicos/51redefine_multi/01-redefine.xml new file mode 100644 index 0000000..e569bf6 --- /dev/null +++ b/tests/flattener_dicos/51redefine_multi/01-redefine.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_remove_check/00-base.xml b/tests/flattener_dicos/51redefine_remove_check/00-base.xml new file mode 100644 index 0000000..1428fbc --- /dev/null +++ b/tests/flattener_dicos/51redefine_remove_check/00-base.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + ['a','b','c'] + + + + + + + diff --git a/tests/flattener_dicos/51redefine_remove_check/01-base.xml b/tests/flattener_dicos/51redefine_remove_check/01-base.xml new file mode 100644 index 0000000..d37887c --- /dev/null +++ b/tests/flattener_dicos/51redefine_remove_check/01-base.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + non + + + + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_remove_check/result/00-base.xml b/tests/flattener_dicos/51redefine_remove_check/result/00-base.xml new file mode 100644 index 0000000..c2aabf6 --- /dev/null +++ b/tests/flattener_dicos/51redefine_remove_check/result/00-base.xml @@ -0,0 +1,92 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_remove_condition/00-base.xml b/tests/flattener_dicos/51redefine_remove_condition/00-base.xml new file mode 100644 index 0000000..37669b4 --- /dev/null +++ b/tests/flattener_dicos/51redefine_remove_condition/00-base.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + non + + + non + + + + + + + + + + oui + mode_conteneur_actif1 + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos/51redefine_remove_condition/01-base.xml b/tests/flattener_dicos/51redefine_remove_condition/01-base.xml new file mode 100644 index 0000000..4ad105f --- /dev/null +++ b/tests/flattener_dicos/51redefine_remove_condition/01-base.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_remove_condition/result/00-base.xml b/tests/flattener_dicos/51redefine_remove_condition/result/00-base.xml new file mode 100644 index 0000000..6321a85 --- /dev/null +++ b/tests/flattener_dicos/51redefine_remove_condition/result/00-base.xml @@ -0,0 +1,120 @@ + + + + + oui + creole.general.mode_conteneur_actif2 + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_remove_condition_no_target/00-base.xml b/tests/flattener_dicos/51redefine_remove_condition_no_target/00-base.xml new file mode 100644 index 0000000..e5f25d7 --- /dev/null +++ b/tests/flattener_dicos/51redefine_remove_condition_no_target/00-base.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + non + + + non + + + + + + + + + + oui + mode_conteneur_actif1 + mode_conteneur_actif2 + + + oui + + + + + + + diff --git a/tests/flattener_dicos/51redefine_remove_condition_no_target/01-base.xml b/tests/flattener_dicos/51redefine_remove_condition_no_target/01-base.xml new file mode 100644 index 0000000..4ad105f --- /dev/null +++ b/tests/flattener_dicos/51redefine_remove_condition_no_target/01-base.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_remove_condition_no_target/result/00-base.xml b/tests/flattener_dicos/51redefine_remove_condition_no_target/result/00-base.xml new file mode 100644 index 0000000..6321a85 --- /dev/null +++ b/tests/flattener_dicos/51redefine_remove_condition_no_target/result/00-base.xml @@ -0,0 +1,120 @@ + + + + + oui + creole.general.mode_conteneur_actif2 + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_removecondition_alltarget/00-base.xml b/tests/flattener_dicos/51redefine_removecondition_alltarget/00-base.xml new file mode 100644 index 0000000..37669b4 --- /dev/null +++ b/tests/flattener_dicos/51redefine_removecondition_alltarget/00-base.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + non + + + non + + + + + + + + + + oui + mode_conteneur_actif1 + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos/51redefine_removecondition_alltarget/01-base.xml b/tests/flattener_dicos/51redefine_removecondition_alltarget/01-base.xml new file mode 100644 index 0000000..97bf364 --- /dev/null +++ b/tests/flattener_dicos/51redefine_removecondition_alltarget/01-base.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_removecondition_alltarget/result/00-base.xml b/tests/flattener_dicos/51redefine_removecondition_alltarget/result/00-base.xml new file mode 100644 index 0000000..81e0bc7 --- /dev/null +++ b/tests/flattener_dicos/51redefine_removecondition_alltarget/result/00-base.xml @@ -0,0 +1,122 @@ + + + + + oui + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_removecondition_nonautofreeze/00-base.xml b/tests/flattener_dicos/51redefine_removecondition_nonautofreeze/00-base.xml new file mode 100644 index 0000000..98da5e7 --- /dev/null +++ b/tests/flattener_dicos/51redefine_removecondition_nonautofreeze/00-base.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + non + + + non + + + + + + + + + + oui + mode_conteneur_actif1 + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos/51redefine_removecondition_nonautofreeze/01-base.xml b/tests/flattener_dicos/51redefine_removecondition_nonautofreeze/01-base.xml new file mode 100644 index 0000000..4ad105f --- /dev/null +++ b/tests/flattener_dicos/51redefine_removecondition_nonautofreeze/01-base.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_removecondition_nonautofreeze/result/00-base.xml b/tests/flattener_dicos/51redefine_removecondition_nonautofreeze/result/00-base.xml new file mode 100644 index 0000000..85b3210 --- /dev/null +++ b/tests/flattener_dicos/51redefine_removecondition_nonautofreeze/result/00-base.xml @@ -0,0 +1,121 @@ + + + + + oui + creole.general.mode_conteneur_actif2 + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_type/00-base.xml b/tests/flattener_dicos/51redefine_type/00-base.xml new file mode 100644 index 0000000..5efe527 --- /dev/null +++ b/tests/flattener_dicos/51redefine_type/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_type/01-redefine.xml b/tests/flattener_dicos/51redefine_type/01-redefine.xml new file mode 100644 index 0000000..b72cd11 --- /dev/null +++ b/tests/flattener_dicos/51redefine_type/01-redefine.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_validenum/00-base.xml b/tests/flattener_dicos/51redefine_validenum/00-base.xml new file mode 100644 index 0000000..044a05d --- /dev/null +++ b/tests/flattener_dicos/51redefine_validenum/00-base.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + ['a','b','c'] + + + + + + + diff --git a/tests/flattener_dicos/51redefine_validenum/01-redefine.xml b/tests/flattener_dicos/51redefine_validenum/01-redefine.xml new file mode 100644 index 0000000..1fef045 --- /dev/null +++ b/tests/flattener_dicos/51redefine_validenum/01-redefine.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + ['a','b'] + + + + + + + diff --git a/tests/flattener_dicos/51redefine_validenum/result/00-base.xml b/tests/flattener_dicos/51redefine_validenum/result/00-base.xml new file mode 100644 index 0000000..327c213 --- /dev/null +++ b/tests/flattener_dicos/51redefine_validenum/result/00-base.xml @@ -0,0 +1,93 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_value/00-base.xml b/tests/flattener_dicos/51redefine_value/00-base.xml new file mode 100644 index 0000000..eee2faa --- /dev/null +++ b/tests/flattener_dicos/51redefine_value/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + non + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_value/01-redefine.xml b/tests/flattener_dicos/51redefine_value/01-redefine.xml new file mode 100644 index 0000000..980eed7 --- /dev/null +++ b/tests/flattener_dicos/51redefine_value/01-redefine.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + oui + + + + + + + + + + + + diff --git a/tests/flattener_dicos/51redefine_value/result/00-base.xml b/tests/flattener_dicos/51redefine_value/result/00-base.xml new file mode 100644 index 0000000..2aa561a --- /dev/null +++ b/tests/flattener_dicos/51redefine_value/result/00-base.xml @@ -0,0 +1,101 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/52exists_redefine/00-base.xml b/tests/flattener_dicos/52exists_redefine/00-base.xml new file mode 100644 index 0000000..05b015a --- /dev/null +++ b/tests/flattener_dicos/52exists_redefine/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/52exists_redefine/01-base.xml b/tests/flattener_dicos/52exists_redefine/01-base.xml new file mode 100644 index 0000000..db76413 --- /dev/null +++ b/tests/flattener_dicos/52exists_redefine/01-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + non + + + + + + + + + + + + diff --git a/tests/flattener_dicos/52exists_redefine/result/00-base.xml b/tests/flattener_dicos/52exists_redefine/result/00-base.xml new file mode 100644 index 0000000..aece14f --- /dev/null +++ b/tests/flattener_dicos/52exists_redefine/result/00-base.xml @@ -0,0 +1,94 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/60action_external/00-base.xml b/tests/flattener_dicos/60action_external/00-base.xml new file mode 100644 index 0000000..aa3b2ed --- /dev/null +++ b/tests/flattener_dicos/60action_external/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60action_external/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60action_external/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..5269565 --- /dev/null +++ b/tests/flattener_dicos/60action_external/extra_dirs/extra/00-base.xml @@ -0,0 +1,34 @@ + + + + Reconfigurer + ead_admin + ead + reconfigure + + + + + + 0 + + + 0 + + + + + + http://localhost/ + + + + diff --git a/tests/flattener_dicos/60action_external/result/00-base.xml b/tests/flattener_dicos/60action_external/result/00-base.xml new file mode 100644 index 0000000..beaecff --- /dev/null +++ b/tests/flattener_dicos/60action_external/result/00-base.xml @@ -0,0 +1,170 @@ + + + + + + http://localhost/ + + + + + + + + diff --git a/tests/flattener_dicos/60extra_externalspace/00-base.xml b/tests/flattener_dicos/60extra_externalspace/00-base.xml new file mode 100644 index 0000000..8dc6d41 --- /dev/null +++ b/tests/flattener_dicos/60extra_externalspace/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60extra_externalspace/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60extra_externalspace/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..01d797d --- /dev/null +++ b/tests/flattener_dicos/60extra_externalspace/extra_dirs/extra/00-base.xml @@ -0,0 +1,17 @@ + + + + + + + Exportation de la base de ejabberd + + + + pre + + + + + + diff --git a/tests/flattener_dicos/60extra_externalspace/extra_dirs/extra1/00-base.xml b/tests/flattener_dicos/60extra_externalspace/extra_dirs/extra1/00-base.xml new file mode 100644 index 0000000..8131c99 --- /dev/null +++ b/tests/flattener_dicos/60extra_externalspace/extra_dirs/extra1/00-base.xml @@ -0,0 +1,19 @@ + + + + + + + test + + + + + + non + activer_ejabberd + none + daily + + + diff --git a/tests/flattener_dicos/60extra_externalspaceauto/00-base.xml b/tests/flattener_dicos/60extra_externalspaceauto/00-base.xml new file mode 100644 index 0000000..8dc6d41 --- /dev/null +++ b/tests/flattener_dicos/60extra_externalspaceauto/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60extra_externalspaceauto/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60extra_externalspaceauto/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..01d797d --- /dev/null +++ b/tests/flattener_dicos/60extra_externalspaceauto/extra_dirs/extra/00-base.xml @@ -0,0 +1,17 @@ + + + + + + + Exportation de la base de ejabberd + + + + pre + + + + + + diff --git a/tests/flattener_dicos/60extra_externalspaceauto/extra_dirs/extra1/00-base.xml b/tests/flattener_dicos/60extra_externalspaceauto/extra_dirs/extra1/00-base.xml new file mode 100644 index 0000000..64ca93b --- /dev/null +++ b/tests/flattener_dicos/60extra_externalspaceauto/extra_dirs/extra1/00-base.xml @@ -0,0 +1,19 @@ + + + + + + + test + + + + + + non + extra.ejabberd.day + none + daily + + + diff --git a/tests/flattener_dicos/60extra_externalspacecondition/00-base.xml b/tests/flattener_dicos/60extra_externalspacecondition/00-base.xml new file mode 100644 index 0000000..2e55d78 --- /dev/null +++ b/tests/flattener_dicos/60extra_externalspacecondition/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + non + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60extra_externalspacecondition/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60extra_externalspacecondition/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..01d797d --- /dev/null +++ b/tests/flattener_dicos/60extra_externalspacecondition/extra_dirs/extra/00-base.xml @@ -0,0 +1,17 @@ + + + + + + + Exportation de la base de ejabberd + + + + pre + + + + + + diff --git a/tests/flattener_dicos/60extra_externalspacecondition/extra_dirs/extra1/00-base.xml b/tests/flattener_dicos/60extra_externalspacecondition/extra_dirs/extra1/00-base.xml new file mode 100644 index 0000000..6ff87ea --- /dev/null +++ b/tests/flattener_dicos/60extra_externalspacecondition/extra_dirs/extra1/00-base.xml @@ -0,0 +1,17 @@ + + + + + + + test + + + + + + non + extra1.external + + + diff --git a/tests/flattener_dicos/60extra_externalspacecondition/result/00-base.xml b/tests/flattener_dicos/60extra_externalspacecondition/result/00-base.xml new file mode 100644 index 0000000..94f2a41 --- /dev/null +++ b/tests/flattener_dicos/60extra_externalspacecondition/result/00-base.xml @@ -0,0 +1,140 @@ + + + + + non + extra1.external + + + + + + + + diff --git a/tests/flattener_dicos/60extra_externalspacecondition2/00-base.xml b/tests/flattener_dicos/60extra_externalspacecondition2/00-base.xml new file mode 100644 index 0000000..8dc6d41 --- /dev/null +++ b/tests/flattener_dicos/60extra_externalspacecondition2/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60extra_externalspacecondition2/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60extra_externalspacecondition2/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..01d797d --- /dev/null +++ b/tests/flattener_dicos/60extra_externalspacecondition2/extra_dirs/extra/00-base.xml @@ -0,0 +1,17 @@ + + + + + + + Exportation de la base de ejabberd + + + + pre + + + + + + diff --git a/tests/flattener_dicos/60extra_externalspacecondition2/extra_dirs/extra1/00-base.xml b/tests/flattener_dicos/60extra_externalspacecondition2/extra_dirs/extra1/00-base.xml new file mode 100644 index 0000000..feb412a --- /dev/null +++ b/tests/flattener_dicos/60extra_externalspacecondition2/extra_dirs/extra1/00-base.xml @@ -0,0 +1,17 @@ + + + + + + + test + + + + + + non + extra.ejabberd + + + diff --git a/tests/flattener_dicos/60extra_externalspacecondition3/00-base.xml b/tests/flattener_dicos/60extra_externalspacecondition3/00-base.xml new file mode 100644 index 0000000..8dc6d41 --- /dev/null +++ b/tests/flattener_dicos/60extra_externalspacecondition3/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60extra_externalspacecondition3/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60extra_externalspacecondition3/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..9919a0a --- /dev/null +++ b/tests/flattener_dicos/60extra_externalspacecondition3/extra_dirs/extra/00-base.xml @@ -0,0 +1,17 @@ + + + + + + + test + + + + + + non + general + + + diff --git a/tests/flattener_dicos/60extra_help/00-base.xml b/tests/flattener_dicos/60extra_help/00-base.xml new file mode 100644 index 0000000..0ec6fce --- /dev/null +++ b/tests/flattener_dicos/60extra_help/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60extra_help/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60extra_help/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..d85c4a3 --- /dev/null +++ b/tests/flattener_dicos/60extra_help/extra_dirs/extra/00-base.xml @@ -0,0 +1,26 @@ + + + + + + + Exportation de la base de ejabberd + + + + pre + + + + + + non + activer_ejabberd + none + daily + + + + Test help + + diff --git a/tests/flattener_dicos/60extra_help/result/00-base.xml b/tests/flattener_dicos/60extra_help/result/00-base.xml new file mode 100644 index 0000000..a3997f2 --- /dev/null +++ b/tests/flattener_dicos/60extra_help/result/00-base.xml @@ -0,0 +1,136 @@ + + + + + non + creole.general.activer_ejabberd + none + daily + + + + + + + + diff --git a/tests/flattener_dicos/60extra_load/00-base.xml b/tests/flattener_dicos/60extra_load/00-base.xml new file mode 100644 index 0000000..0ec6fce --- /dev/null +++ b/tests/flattener_dicos/60extra_load/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60extra_load/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60extra_load/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..e8d0478 --- /dev/null +++ b/tests/flattener_dicos/60extra_load/extra_dirs/extra/00-base.xml @@ -0,0 +1,23 @@ + + + + + + + Exportation de la base de ejabberd + + + + pre + + + + + + non + activer_ejabberd + none + daily + + + diff --git a/tests/flattener_dicos/60extra_load/result/00-base.xml b/tests/flattener_dicos/60extra_load/result/00-base.xml new file mode 100644 index 0000000..4a8f94e --- /dev/null +++ b/tests/flattener_dicos/60extra_load/result/00-base.xml @@ -0,0 +1,134 @@ + + + + + non + creole.general.activer_ejabberd + none + daily + + + + + + + + diff --git a/tests/flattener_dicos/60extra_mandatory/00-base.xml b/tests/flattener_dicos/60extra_mandatory/00-base.xml new file mode 100644 index 0000000..0ec6fce --- /dev/null +++ b/tests/flattener_dicos/60extra_mandatory/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60extra_mandatory/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60extra_mandatory/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..c38bc8a --- /dev/null +++ b/tests/flattener_dicos/60extra_mandatory/extra_dirs/extra/00-base.xml @@ -0,0 +1,22 @@ + + + + + + + Exportation de la base de ejabberd + + + + + + + + + non + activer_ejabberd + none + daily + + + diff --git a/tests/flattener_dicos/60extra_mandatory/result/00-base.xml b/tests/flattener_dicos/60extra_mandatory/result/00-base.xml new file mode 100644 index 0000000..88e9e7f --- /dev/null +++ b/tests/flattener_dicos/60extra_mandatory/result/00-base.xml @@ -0,0 +1,139 @@ + + + + + non + creole.general.activer_ejabberd + none + daily + + + + + + + + diff --git a/tests/flattener_dicos/60extra_redefine/00-base.xml b/tests/flattener_dicos/60extra_redefine/00-base.xml new file mode 100644 index 0000000..0ec6fce --- /dev/null +++ b/tests/flattener_dicos/60extra_redefine/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60extra_redefine/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60extra_redefine/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..e8d0478 --- /dev/null +++ b/tests/flattener_dicos/60extra_redefine/extra_dirs/extra/00-base.xml @@ -0,0 +1,23 @@ + + + + + + + Exportation de la base de ejabberd + + + + pre + + + + + + non + activer_ejabberd + none + daily + + + diff --git a/tests/flattener_dicos/60extra_redefine/extra_dirs/extra/01-redefine.xml b/tests/flattener_dicos/60extra_redefine/extra_dirs/extra/01-redefine.xml new file mode 100644 index 0000000..82f6d6f --- /dev/null +++ b/tests/flattener_dicos/60extra_redefine/extra_dirs/extra/01-redefine.xml @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/tests/flattener_dicos/60extra_redefine/result/00-base.xml b/tests/flattener_dicos/60extra_redefine/result/00-base.xml new file mode 100644 index 0000000..dfbda27 --- /dev/null +++ b/tests/flattener_dicos/60extra_redefine/result/00-base.xml @@ -0,0 +1,137 @@ + + + + + non + creole.general.activer_ejabberd + none + daily + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction/00-base.xml b/tests/flattener_dicos/60familyaction/00-base.xml new file mode 100644 index 0000000..aa3b2ed --- /dev/null +++ b/tests/flattener_dicos/60familyaction/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60familyaction/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..8fd67df --- /dev/null +++ b/tests/flattener_dicos/60familyaction/extra_dirs/extra/00-base.xml @@ -0,0 +1,26 @@ + + + + Reconfigurer + ead_admin + ead + reconfigure + + + + + + 0 + + + + + + + diff --git a/tests/flattener_dicos/60familyaction/result/00-base.xml b/tests/flattener_dicos/60familyaction/result/00-base.xml new file mode 100644 index 0000000..c17311f --- /dev/null +++ b/tests/flattener_dicos/60familyaction/result/00-base.xml @@ -0,0 +1,159 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_accent/00-base.xml b/tests/flattener_dicos/60familyaction_accent/00-base.xml new file mode 100644 index 0000000..aa3b2ed --- /dev/null +++ b/tests/flattener_dicos/60familyaction_accent/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_accent/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60familyaction_accent/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..c7330e8 --- /dev/null +++ b/tests/flattener_dicos/60familyaction_accent/extra_dirs/extra/00-base.xml @@ -0,0 +1,26 @@ + + + + Reconfigurer + ead_admin + ead + reconfigure + + + + + + 0 + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_accent/result/00-base.xml b/tests/flattener_dicos/60familyaction_accent/result/00-base.xml new file mode 100644 index 0000000..001d432 --- /dev/null +++ b/tests/flattener_dicos/60familyaction_accent/result/00-base.xml @@ -0,0 +1,159 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_disable/00-base.xml b/tests/flattener_dicos/60familyaction_disable/00-base.xml new file mode 100644 index 0000000..4c4d0d1 --- /dev/null +++ b/tests/flattener_dicos/60familyaction_disable/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + non + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_disable/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60familyaction_disable/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..1e5426a --- /dev/null +++ b/tests/flattener_dicos/60familyaction_disable/extra_dirs/extra/00-base.xml @@ -0,0 +1,31 @@ + + + + Reconfigurer + ead_admin + ead + reconfigure + + + + + + 0 + + + + + + oui + configure + + + + diff --git a/tests/flattener_dicos/60familyaction_disable/result/00-base.xml b/tests/flattener_dicos/60familyaction_disable/result/00-base.xml new file mode 100644 index 0000000..577c2d3 --- /dev/null +++ b/tests/flattener_dicos/60familyaction_disable/result/00-base.xml @@ -0,0 +1,174 @@ + + + + + + oui + actions.systeme.action0.activate + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_empty/00-base.xml b/tests/flattener_dicos/60familyaction_empty/00-base.xml new file mode 100644 index 0000000..aa3b2ed --- /dev/null +++ b/tests/flattener_dicos/60familyaction_empty/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_empty/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60familyaction_empty/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..e73ad7f --- /dev/null +++ b/tests/flattener_dicos/60familyaction_empty/extra_dirs/extra/00-base.xml @@ -0,0 +1,21 @@ + + + + Reconfigurer + ead_admin + ead + reconfigure + + + + + + diff --git a/tests/flattener_dicos/60familyaction_empty/result/00-base.xml b/tests/flattener_dicos/60familyaction_empty/result/00-base.xml new file mode 100644 index 0000000..4d86e35 --- /dev/null +++ b/tests/flattener_dicos/60familyaction_empty/result/00-base.xml @@ -0,0 +1,153 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_mandatory/00-base.xml b/tests/flattener_dicos/60familyaction_mandatory/00-base.xml new file mode 100644 index 0000000..aa3b2ed --- /dev/null +++ b/tests/flattener_dicos/60familyaction_mandatory/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_mandatory/60familyaction/00-base.xml b/tests/flattener_dicos/60familyaction_mandatory/60familyaction/00-base.xml new file mode 100644 index 0000000..aa3b2ed --- /dev/null +++ b/tests/flattener_dicos/60familyaction_mandatory/60familyaction/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_mandatory/60familyaction/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60familyaction_mandatory/60familyaction/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..8fd67df --- /dev/null +++ b/tests/flattener_dicos/60familyaction_mandatory/60familyaction/extra_dirs/extra/00-base.xml @@ -0,0 +1,26 @@ + + + + Reconfigurer + ead_admin + ead + reconfigure + + + + + + 0 + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_mandatory/60familyaction/result/00-base.xml b/tests/flattener_dicos/60familyaction_mandatory/60familyaction/result/00-base.xml new file mode 100644 index 0000000..568103a --- /dev/null +++ b/tests/flattener_dicos/60familyaction_mandatory/60familyaction/result/00-base.xml @@ -0,0 +1,154 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_mandatory/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60familyaction_mandatory/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..ed6040f --- /dev/null +++ b/tests/flattener_dicos/60familyaction_mandatory/extra_dirs/extra/00-base.xml @@ -0,0 +1,27 @@ + + + + Reconfigurer + ead_admin + ead + reconfigure + + + + + + 0 + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_mandatory/result/00-base.xml b/tests/flattener_dicos/60familyaction_mandatory/result/00-base.xml new file mode 100644 index 0000000..b64514e --- /dev/null +++ b/tests/flattener_dicos/60familyaction_mandatory/result/00-base.xml @@ -0,0 +1,163 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_save/00-base.xml b/tests/flattener_dicos/60familyaction_save/00-base.xml new file mode 100644 index 0000000..aa3b2ed --- /dev/null +++ b/tests/flattener_dicos/60familyaction_save/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_save/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60familyaction_save/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..117d3f7 --- /dev/null +++ b/tests/flattener_dicos/60familyaction_save/extra_dirs/extra/00-base.xml @@ -0,0 +1,27 @@ + + + + Reconfigurer + ead_admin + ead + reconfigure + + + + + + 0 + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_save/result/00-base.xml b/tests/flattener_dicos/60familyaction_save/result/00-base.xml new file mode 100644 index 0000000..23f3d5f --- /dev/null +++ b/tests/flattener_dicos/60familyaction_save/result/00-base.xml @@ -0,0 +1,159 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_twoactions/00-base.xml b/tests/flattener_dicos/60familyaction_twoactions/00-base.xml new file mode 100644 index 0000000..aa3b2ed --- /dev/null +++ b/tests/flattener_dicos/60familyaction_twoactions/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_twoactions/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60familyaction_twoactions/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..c7330e8 --- /dev/null +++ b/tests/flattener_dicos/60familyaction_twoactions/extra_dirs/extra/00-base.xml @@ -0,0 +1,26 @@ + + + + Reconfigurer + ead_admin + ead + reconfigure + + + + + + 0 + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_twoactions/extra_dirs/extra1/00-base.xml b/tests/flattener_dicos/60familyaction_twoactions/extra_dirs/extra1/00-base.xml new file mode 100644 index 0000000..8fd67df --- /dev/null +++ b/tests/flattener_dicos/60familyaction_twoactions/extra_dirs/extra1/00-base.xml @@ -0,0 +1,26 @@ + + + + Reconfigurer + ead_admin + ead + reconfigure + + + + + + 0 + + + + + + + diff --git a/tests/flattener_dicos/60familyaction_twoactions/result/00-base.xml b/tests/flattener_dicos/60familyaction_twoactions/result/00-base.xml new file mode 100644 index 0000000..094c630 --- /dev/null +++ b/tests/flattener_dicos/60familyaction_twoactions/result/00-base.xml @@ -0,0 +1,208 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/60familyactionexternal/00-base.xml b/tests/flattener_dicos/60familyactionexternal/00-base.xml new file mode 100644 index 0000000..aa3b2ed --- /dev/null +++ b/tests/flattener_dicos/60familyactionexternal/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/60familyactionexternal/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/60familyactionexternal/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..2564001 --- /dev/null +++ b/tests/flattener_dicos/60familyactionexternal/extra_dirs/extra/00-base.xml @@ -0,0 +1,22 @@ + + + + Reconfigurer + ead_admin + ead + reconfigure + + + + + + + + diff --git a/tests/flattener_dicos/60familyactionexternal/result/00-base.xml b/tests/flattener_dicos/60familyactionexternal/result/00-base.xml new file mode 100644 index 0000000..f692ed7 --- /dev/null +++ b/tests/flattener_dicos/60familyactionexternal/result/00-base.xml @@ -0,0 +1,154 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_all/00-base.xml b/tests/flattener_dicos/70container_all/00-base.xml new file mode 100644 index 0000000..a13cd52 --- /dev/null +++ b/tests/flattener_dicos/70container_all/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_all/01-base.xml b/tests/flattener_dicos/70container_all/01-base.xml new file mode 100644 index 0000000..ffe40b4 --- /dev/null +++ b/tests/flattener_dicos/70container_all/01-base.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_all/result/00-base.xml b/tests/flattener_dicos/70container_all/result/00-base.xml new file mode 100644 index 0000000..8b5dfe6 --- /dev/null +++ b/tests/flattener_dicos/70container_all/result/00-base.xml @@ -0,0 +1,238 @@ + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_all_nocontainer/00-base.xml b/tests/flattener_dicos/70container_all_nocontainer/00-base.xml new file mode 100644 index 0000000..c4eb07e --- /dev/null +++ b/tests/flattener_dicos/70container_all_nocontainer/00-base.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_all_nocontainer/01-base.xml b/tests/flattener_dicos/70container_all_nocontainer/01-base.xml new file mode 100644 index 0000000..aeb5b92 --- /dev/null +++ b/tests/flattener_dicos/70container_all_nocontainer/01-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_all_nocontainer/result/00-base.xml b/tests/flattener_dicos/70container_all_nocontainer/result/00-base.xml new file mode 100644 index 0000000..956f7b8 --- /dev/null +++ b/tests/flattener_dicos/70container_all_nocontainer/result/00-base.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_all_nocontainer_order/00-base.xml b/tests/flattener_dicos/70container_all_nocontainer_order/00-base.xml new file mode 100644 index 0000000..0e9adc8 --- /dev/null +++ b/tests/flattener_dicos/70container_all_nocontainer_order/00-base.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_all_nocontainer_order/01-base.xml b/tests/flattener_dicos/70container_all_nocontainer_order/01-base.xml new file mode 100644 index 0000000..aeb5b92 --- /dev/null +++ b/tests/flattener_dicos/70container_all_nocontainer_order/01-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_all_nocontainer_order/result/00-base.xml b/tests/flattener_dicos/70container_all_nocontainer_order/result/00-base.xml new file mode 100644 index 0000000..55b9971 --- /dev/null +++ b/tests/flattener_dicos/70container_all_nocontainer_order/result/00-base.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_allfile/00-base.xml b/tests/flattener_dicos/70container_allfile/00-base.xml new file mode 100644 index 0000000..e16ca61 --- /dev/null +++ b/tests/flattener_dicos/70container_allfile/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_allfile/01-base.xml b/tests/flattener_dicos/70container_allfile/01-base.xml new file mode 100644 index 0000000..3c27e9c --- /dev/null +++ b/tests/flattener_dicos/70container_allfile/01-base.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_allfile/result/00-base.xml b/tests/flattener_dicos/70container_allfile/result/00-base.xml new file mode 100644 index 0000000..f8859df --- /dev/null +++ b/tests/flattener_dicos/70container_allfile/result/00-base.xml @@ -0,0 +1,246 @@ + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_allnotexists/00-base.xml b/tests/flattener_dicos/70container_allnotexists/00-base.xml new file mode 100644 index 0000000..a13cd52 --- /dev/null +++ b/tests/flattener_dicos/70container_allnotexists/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_allnotexists/01-base.xml b/tests/flattener_dicos/70container_allnotexists/01-base.xml new file mode 100644 index 0000000..47ba07c --- /dev/null +++ b/tests/flattener_dicos/70container_allnotexists/01-base.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_allnotexists/result/00-base.xml b/tests/flattener_dicos/70container_allnotexists/result/00-base.xml new file mode 100644 index 0000000..f8859df --- /dev/null +++ b/tests/flattener_dicos/70container_allnotexists/result/00-base.xml @@ -0,0 +1,246 @@ + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_disknod/00-base.xml b/tests/flattener_dicos/70container_disknod/00-base.xml new file mode 100644 index 0000000..a857709 --- /dev/null +++ b/tests/flattener_dicos/70container_disknod/00-base.xml @@ -0,0 +1,29 @@ + + + + + + + + /etc/mailname' + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_disknod/result/00-base.xml b/tests/flattener_dicos/70container_disknod/result/00-base.xml new file mode 100644 index 0000000..f064e4e --- /dev/null +++ b/tests/flattener_dicos/70container_disknod/result/00-base.xml @@ -0,0 +1,186 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_disknod/result/probe.json b/tests/flattener_dicos/70container_disknod/result/probe.json new file mode 100644 index 0000000..168bf02 --- /dev/null +++ b/tests/flattener_dicos/70container_disknod/result/probe.json @@ -0,0 +1 @@ +{"containers.disknods.disknod0.minor": {"function": "cdrom_minormajor", "args": ["minor", "/etc/mailname'"], "kwargs": {}}, "containers.disknods.disknod0.type": {"function": "device_type", "args": ["/etc/mailname'"], "kwargs": {}}, "containers.disknods.disknod0.major": {"function": "cdrom_minormajor", "args": ["major", "/etc/mailname'"], "kwargs": {}}} diff --git a/tests/flattener_dicos/70container_files/00-base.xml b/tests/flattener_dicos/70container_files/00-base.xml new file mode 100644 index 0000000..4d91538 --- /dev/null +++ b/tests/flattener_dicos/70container_files/00-base.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_files/result/00-base.xml b/tests/flattener_dicos/70container_files/result/00-base.xml new file mode 100644 index 0000000..d6c741a --- /dev/null +++ b/tests/flattener_dicos/70container_files/result/00-base.xml @@ -0,0 +1,183 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_files2/00-base.xml b/tests/flattener_dicos/70container_files2/00-base.xml new file mode 100644 index 0000000..c157ad5 --- /dev/null +++ b/tests/flattener_dicos/70container_files2/00-base.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_files2/result/00-base.xml b/tests/flattener_dicos/70container_files2/result/00-base.xml new file mode 100644 index 0000000..cc67e3d --- /dev/null +++ b/tests/flattener_dicos/70container_files2/result/00-base.xml @@ -0,0 +1,212 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_filesmulti/00-base.xml b/tests/flattener_dicos/70container_filesmulti/00-base.xml new file mode 100644 index 0000000..cd47dee --- /dev/null +++ b/tests/flattener_dicos/70container_filesmulti/00-base.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_filesmulti/result/00-base.xml b/tests/flattener_dicos/70container_filesmulti/result/00-base.xml new file mode 100644 index 0000000..1a433e4 --- /dev/null +++ b/tests/flattener_dicos/70container_filesmulti/result/00-base.xml @@ -0,0 +1,212 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_filesredefine/00-base.xml b/tests/flattener_dicos/70container_filesredefine/00-base.xml new file mode 100644 index 0000000..4d91538 --- /dev/null +++ b/tests/flattener_dicos/70container_filesredefine/00-base.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_filesredefine/01-base.xml b/tests/flattener_dicos/70container_filesredefine/01-base.xml new file mode 100644 index 0000000..872a8cb --- /dev/null +++ b/tests/flattener_dicos/70container_filesredefine/01-base.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_filesredefine/result/00-base.xml b/tests/flattener_dicos/70container_filesredefine/result/00-base.xml new file mode 100644 index 0000000..64cc1d0 --- /dev/null +++ b/tests/flattener_dicos/70container_filesredefine/result/00-base.xml @@ -0,0 +1,183 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_filesrm/00-base.xml b/tests/flattener_dicos/70container_filesrm/00-base.xml new file mode 100644 index 0000000..cc28368 --- /dev/null +++ b/tests/flattener_dicos/70container_filesrm/00-base.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_filesrm/result/00-base.xml b/tests/flattener_dicos/70container_filesrm/result/00-base.xml new file mode 100644 index 0000000..48a5309 --- /dev/null +++ b/tests/flattener_dicos/70container_filesrm/result/00-base.xml @@ -0,0 +1,183 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_filesroot/00-base.xml b/tests/flattener_dicos/70container_filesroot/00-base.xml new file mode 100644 index 0000000..cd044c4 --- /dev/null +++ b/tests/flattener_dicos/70container_filesroot/00-base.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_filesroot/result/00-base.xml b/tests/flattener_dicos/70container_filesroot/result/00-base.xml new file mode 100644 index 0000000..dc65f25 --- /dev/null +++ b/tests/flattener_dicos/70container_filesroot/result/00-base.xml @@ -0,0 +1,122 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/70container_fstab/00-base.xml b/tests/flattener_dicos/70container_fstab/00-base.xml new file mode 100644 index 0000000..75f15fd --- /dev/null +++ b/tests/flattener_dicos/70container_fstab/00-base.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_fstab/result/00-base.xml b/tests/flattener_dicos/70container_fstab/result/00-base.xml new file mode 100644 index 0000000..3faf6f1 --- /dev/null +++ b/tests/flattener_dicos/70container_fstab/result/00-base.xml @@ -0,0 +1,184 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_fstabsymlink/00-base.xml b/tests/flattener_dicos/70container_fstabsymlink/00-base.xml new file mode 100644 index 0000000..424f9e5 --- /dev/null +++ b/tests/flattener_dicos/70container_fstabsymlink/00-base.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + oui + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_fstabsymlink/result/00-base.xml b/tests/flattener_dicos/70container_fstabsymlink/result/00-base.xml new file mode 100644 index 0000000..5bbabba --- /dev/null +++ b/tests/flattener_dicos/70container_fstabsymlink/result/00-base.xml @@ -0,0 +1,187 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_group/00-base.xml b/tests/flattener_dicos/70container_group/00-base.xml new file mode 100644 index 0000000..16dcc6f --- /dev/null +++ b/tests/flattener_dicos/70container_group/00-base.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_group/01-base.xml b/tests/flattener_dicos/70container_group/01-base.xml new file mode 100644 index 0000000..af1cca8 --- /dev/null +++ b/tests/flattener_dicos/70container_group/01-base.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_group/result/00-base.xml b/tests/flattener_dicos/70container_group/result/00-base.xml new file mode 100644 index 0000000..895c3ec --- /dev/null +++ b/tests/flattener_dicos/70container_group/result/00-base.xml @@ -0,0 +1,213 @@ + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_host/00-base.xml b/tests/flattener_dicos/70container_host/00-base.xml new file mode 100644 index 0000000..a854ad5 --- /dev/null +++ b/tests/flattener_dicos/70container_host/00-base.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_host/result/00-base.xml b/tests/flattener_dicos/70container_host/result/00-base.xml new file mode 100644 index 0000000..bce0d94 --- /dev/null +++ b/tests/flattener_dicos/70container_host/result/00-base.xml @@ -0,0 +1,184 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_instancemode/00-base.xml b/tests/flattener_dicos/70container_instancemode/00-base.xml new file mode 100644 index 0000000..08c4aee --- /dev/null +++ b/tests/flattener_dicos/70container_instancemode/00-base.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_instancemode/result/00-base.xml b/tests/flattener_dicos/70container_instancemode/result/00-base.xml new file mode 100644 index 0000000..5709c1a --- /dev/null +++ b/tests/flattener_dicos/70container_instancemode/result/00-base.xml @@ -0,0 +1,161 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_instancemodenoncontainer/00-base.xml b/tests/flattener_dicos/70container_instancemodenoncontainer/00-base.xml new file mode 100644 index 0000000..986da3b --- /dev/null +++ b/tests/flattener_dicos/70container_instancemodenoncontainer/00-base.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_instancemodenoncontainer/result/00-base.xml b/tests/flattener_dicos/70container_instancemodenoncontainer/result/00-base.xml new file mode 100644 index 0000000..1a5a27c --- /dev/null +++ b/tests/flattener_dicos/70container_instancemodenoncontainer/result/00-base.xml @@ -0,0 +1,135 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_interface/00-base.xml b/tests/flattener_dicos/70container_interface/00-base.xml new file mode 100644 index 0000000..0b9ebdb --- /dev/null +++ b/tests/flattener_dicos/70container_interface/00-base.xml @@ -0,0 +1,32 @@ + + + + + + + + eth1 + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_interface/result/00-base.xml b/tests/flattener_dicos/70container_interface/result/00-base.xml new file mode 100644 index 0000000..de6b600 --- /dev/null +++ b/tests/flattener_dicos/70container_interface/result/00-base.xml @@ -0,0 +1,199 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_new/00-base.xml b/tests/flattener_dicos/70container_new/00-base.xml new file mode 100644 index 0000000..16dcc6f --- /dev/null +++ b/tests/flattener_dicos/70container_new/00-base.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_new/result/00-base.xml b/tests/flattener_dicos/70container_new/result/00-base.xml new file mode 100644 index 0000000..3420d62 --- /dev/null +++ b/tests/flattener_dicos/70container_new/result/00-base.xml @@ -0,0 +1,153 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_newnocont/00-base.xml b/tests/flattener_dicos/70container_newnocont/00-base.xml new file mode 100644 index 0000000..0b3da65 --- /dev/null +++ b/tests/flattener_dicos/70container_newnocont/00-base.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_newnocont/result/00-base.xml b/tests/flattener_dicos/70container_newnocont/result/00-base.xml new file mode 100644 index 0000000..065cf8a --- /dev/null +++ b/tests/flattener_dicos/70container_newnocont/result/00-base.xml @@ -0,0 +1,127 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_newwithip/00-base.xml b/tests/flattener_dicos/70container_newwithip/00-base.xml new file mode 100644 index 0000000..d690856 --- /dev/null +++ b/tests/flattener_dicos/70container_newwithip/00-base.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_newwithip/result/00-base.xml b/tests/flattener_dicos/70container_newwithip/result/00-base.xml new file mode 100644 index 0000000..885052a --- /dev/null +++ b/tests/flattener_dicos/70container_newwithip/result/00-base.xml @@ -0,0 +1,153 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_nocontainer/00-base.xml b/tests/flattener_dicos/70container_nocontainer/00-base.xml new file mode 100644 index 0000000..3305ee0 --- /dev/null +++ b/tests/flattener_dicos/70container_nocontainer/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_nocontainer/result/00-base.xml b/tests/flattener_dicos/70container_nocontainer/result/00-base.xml new file mode 100644 index 0000000..f819916 --- /dev/null +++ b/tests/flattener_dicos/70container_nocontainer/result/00-base.xml @@ -0,0 +1,166 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_package/00-base.xml b/tests/flattener_dicos/70container_package/00-base.xml new file mode 100644 index 0000000..ea90949 --- /dev/null +++ b/tests/flattener_dicos/70container_package/00-base.xml @@ -0,0 +1,29 @@ + + + + + + + + testpkg + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_package/result/00-base.xml b/tests/flattener_dicos/70container_package/result/00-base.xml new file mode 100644 index 0000000..2bbf1fa --- /dev/null +++ b/tests/flattener_dicos/70container_package/result/00-base.xml @@ -0,0 +1,168 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_pathaccess/00-base.xml b/tests/flattener_dicos/70container_pathaccess/00-base.xml new file mode 100644 index 0000000..71a9515 --- /dev/null +++ b/tests/flattener_dicos/70container_pathaccess/00-base.xml @@ -0,0 +1,33 @@ + + + + + + + + + nut_monitor_host + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_pathaccess/result/00-base.xml b/tests/flattener_dicos/70container_pathaccess/result/00-base.xml new file mode 100644 index 0000000..2cdf4dc --- /dev/null +++ b/tests/flattener_dicos/70container_pathaccess/result/00-base.xml @@ -0,0 +1,190 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_pathaccess_masterslaves/00-base.xml b/tests/flattener_dicos/70container_pathaccess_masterslaves/00-base.xml new file mode 100644 index 0000000..a3061e4 --- /dev/null +++ b/tests/flattener_dicos/70container_pathaccess_masterslaves/00-base.xml @@ -0,0 +1,36 @@ + + + + + + + + + nut_monitor_host + + + + + + + + + + + + + + + + + nut_monitor_host + + + + + + + diff --git a/tests/flattener_dicos/70container_pathaccess_masterslaves/result/00-base.xml b/tests/flattener_dicos/70container_pathaccess_masterslaves/result/00-base.xml new file mode 100644 index 0000000..2606f44 --- /dev/null +++ b/tests/flattener_dicos/70container_pathaccess_masterslaves/result/00-base.xml @@ -0,0 +1,192 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_save/00-base.xml b/tests/flattener_dicos/70container_save/00-base.xml new file mode 100644 index 0000000..92f69b8 --- /dev/null +++ b/tests/flattener_dicos/70container_save/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_save/result/00-base.xml b/tests/flattener_dicos/70container_save/result/00-base.xml new file mode 100644 index 0000000..700e812 --- /dev/null +++ b/tests/flattener_dicos/70container_save/result/00-base.xml @@ -0,0 +1,92 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/70container_serviceaccess/00-base.xml b/tests/flattener_dicos/70container_serviceaccess/00-base.xml new file mode 100644 index 0000000..62f486f --- /dev/null +++ b/tests/flattener_dicos/70container_serviceaccess/00-base.xml @@ -0,0 +1,31 @@ + + + + + + + + + 123 + ntpd + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_serviceaccess/result/00-base.xml b/tests/flattener_dicos/70container_serviceaccess/result/00-base.xml new file mode 100644 index 0000000..50c17c7 --- /dev/null +++ b/tests/flattener_dicos/70container_serviceaccess/result/00-base.xml @@ -0,0 +1,211 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_serviceaccess_disabledifin/00-base.xml b/tests/flattener_dicos/70container_serviceaccess_disabledifin/00-base.xml new file mode 100644 index 0000000..8d13c2c --- /dev/null +++ b/tests/flattener_dicos/70container_serviceaccess_disabledifin/00-base.xml @@ -0,0 +1,40 @@ + + + + + + + + ntp + + 123 + ntpd + + + 127.0.0.1 + + + + + + + + + + + + + + + non + active_ntp + + + + + + + diff --git a/tests/flattener_dicos/70container_serviceaccess_disabledifin/result/00-base.xml b/tests/flattener_dicos/70container_serviceaccess_disabledifin/result/00-base.xml new file mode 100644 index 0000000..d388f0e --- /dev/null +++ b/tests/flattener_dicos/70container_serviceaccess_disabledifin/result/00-base.xml @@ -0,0 +1,280 @@ + + + + + non + containers.services.service0.activate + containers.service_accesss.service_access0.activate + containers.service_accesss.service_access1.activate + containers.service_restrictions.service_restriction0.activate + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_serviceaccesslist/00-base.xml b/tests/flattener_dicos/70container_serviceaccesslist/00-base.xml new file mode 100644 index 0000000..a93c36a --- /dev/null +++ b/tests/flattener_dicos/70container_serviceaccesslist/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + 123 + ntpd + + + + + + + + + + + + + + oui + ntp_udp + + + + + + + diff --git a/tests/flattener_dicos/70container_serviceaccesslist/result/00-base.xml b/tests/flattener_dicos/70container_serviceaccesslist/result/00-base.xml new file mode 100644 index 0000000..6108027 --- /dev/null +++ b/tests/flattener_dicos/70container_serviceaccesslist/result/00-base.xml @@ -0,0 +1,216 @@ + + + + + oui + containers.service_accesss.service_access0.activate + + + + + + + + + diff --git a/tests/flattener_dicos/70container_serviceaccesslist_servicelist/00-base.xml b/tests/flattener_dicos/70container_serviceaccesslist_servicelist/00-base.xml new file mode 100644 index 0000000..7dad314 --- /dev/null +++ b/tests/flattener_dicos/70container_serviceaccesslist_servicelist/00-base.xml @@ -0,0 +1,43 @@ + + + + + + + + ntp + + 123 + ntpd + + + + + + + + + + + + + + + oui + ntp_udp + + + oui + ntp + + + + + + + diff --git a/tests/flattener_dicos/70container_serviceaccesslist_servicelist/result/00-base.xml b/tests/flattener_dicos/70container_serviceaccesslist_servicelist/result/00-base.xml new file mode 100644 index 0000000..9720354 --- /dev/null +++ b/tests/flattener_dicos/70container_serviceaccesslist_servicelist/result/00-base.xml @@ -0,0 +1,260 @@ + + + + + oui + containers.service_accesss.service_access0.activate + + + oui + containers.services.service0.activate + containers.service_accesss.service_access0.activate + containers.service_accesss.service_access1.activate + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_servicerestriction/00-base.xml b/tests/flattener_dicos/70container_servicerestriction/00-base.xml new file mode 100644 index 0000000..d11a768 --- /dev/null +++ b/tests/flattener_dicos/70container_servicerestriction/00-base.xml @@ -0,0 +1,32 @@ + + + + + + + + + + 192.168.1.1 + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_servicerestriction/result/00-base.xml b/tests/flattener_dicos/70container_servicerestriction/result/00-base.xml new file mode 100644 index 0000000..19f4874 --- /dev/null +++ b/tests/flattener_dicos/70container_servicerestriction/result/00-base.xml @@ -0,0 +1,186 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_services/00-base.xml b/tests/flattener_dicos/70container_services/00-base.xml new file mode 100644 index 0000000..e4c337a --- /dev/null +++ b/tests/flattener_dicos/70container_services/00-base.xml @@ -0,0 +1,29 @@ + + + + + + + + testsrv + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_services/result/00-base.xml b/tests/flattener_dicos/70container_services/result/00-base.xml new file mode 100644 index 0000000..f5568fd --- /dev/null +++ b/tests/flattener_dicos/70container_services/result/00-base.xml @@ -0,0 +1,178 @@ + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_subgroup/00-base.xml b/tests/flattener_dicos/70container_subgroup/00-base.xml new file mode 100644 index 0000000..d9c0174 --- /dev/null +++ b/tests/flattener_dicos/70container_subgroup/00-base.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_subgroup/01-base.xml b/tests/flattener_dicos/70container_subgroup/01-base.xml new file mode 100644 index 0000000..b1571a0 --- /dev/null +++ b/tests/flattener_dicos/70container_subgroup/01-base.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70container_subgroup/result/00-base.xml b/tests/flattener_dicos/70container_subgroup/result/00-base.xml new file mode 100644 index 0000000..01eee82 --- /dev/null +++ b/tests/flattener_dicos/70container_subgroup/result/00-base.xml @@ -0,0 +1,303 @@ + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70containers_all/00-base.xml b/tests/flattener_dicos/70containers_all/00-base.xml new file mode 100644 index 0000000..31b83f6 --- /dev/null +++ b/tests/flattener_dicos/70containers_all/00-base.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70containers_all/01-base.xml b/tests/flattener_dicos/70containers_all/01-base.xml new file mode 100644 index 0000000..710f7ac --- /dev/null +++ b/tests/flattener_dicos/70containers_all/01-base.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/70containers_all/result/00-base.xml b/tests/flattener_dicos/70containers_all/result/00-base.xml new file mode 100644 index 0000000..56f03d1 --- /dev/null +++ b/tests/flattener_dicos/70containers_all/result/00-base.xml @@ -0,0 +1,350 @@ + + + + + + + + + + + + diff --git a/tests/flattener_dicos/80action_onlyone/00-base.xml b/tests/flattener_dicos/80action_onlyone/00-base.xml new file mode 100644 index 0000000..aa3b2ed --- /dev/null +++ b/tests/flattener_dicos/80action_onlyone/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/80action_onlyone/extra_dirs/extra/00-base.xml b/tests/flattener_dicos/80action_onlyone/extra_dirs/extra/00-base.xml new file mode 100644 index 0000000..8fd67df --- /dev/null +++ b/tests/flattener_dicos/80action_onlyone/extra_dirs/extra/00-base.xml @@ -0,0 +1,26 @@ + + + + Reconfigurer + ead_admin + ead + reconfigure + + + + + + 0 + + + + + + + diff --git a/tests/flattener_dicos/80action_onlyone/extra_dirs/extra/01-base.xml b/tests/flattener_dicos/80action_onlyone/extra_dirs/extra/01-base.xml new file mode 100644 index 0000000..8ac889e --- /dev/null +++ b/tests/flattener_dicos/80action_onlyone/extra_dirs/extra/01-base.xml @@ -0,0 +1,22 @@ + + + + Reconfigurer2 + ead_admin + ead + reconfigure + + + + + + + + + diff --git a/tests/flattener_dicos/80auto_autofreeze/00-base.xml b/tests/flattener_dicos/80auto_autofreeze/00-base.xml new file mode 100644 index 0000000..4b893b8 --- /dev/null +++ b/tests/flattener_dicos/80auto_autofreeze/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + non + + + + + + + + value + + + + + + + diff --git a/tests/flattener_dicos/80auto_autosave/00-base.xml b/tests/flattener_dicos/80auto_autosave/00-base.xml new file mode 100644 index 0000000..e447a66 --- /dev/null +++ b/tests/flattener_dicos/80auto_autosave/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + non + + + + + + + + value + + + + + + + diff --git a/tests/flattener_dicos/80auto_error/00-base.xml b/tests/flattener_dicos/80auto_error/00-base.xml new file mode 100644 index 0000000..9d7cea1 --- /dev/null +++ b/tests/flattener_dicos/80auto_error/00-base.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + valeur + + + valeur2 + + + + + + + diff --git a/tests/flattener_dicos/80auto_multi/00-base.xml b/tests/flattener_dicos/80auto_multi/00-base.xml new file mode 100644 index 0000000..da3e0d9 --- /dev/null +++ b/tests/flattener_dicos/80auto_multi/00-base.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + non + + + + + + + + value + + + mode_conteneur_actif1 + + + + + + + diff --git a/tests/flattener_dicos/80condition_itself/00-base.xml b/tests/flattener_dicos/80condition_itself/00-base.xml new file mode 100644 index 0000000..387ea35 --- /dev/null +++ b/tests/flattener_dicos/80condition_itself/00-base.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + master-master + replicationType + + + + + + + diff --git a/tests/flattener_dicos/80condition_not_exists_error/00-base.xml b/tests/flattener_dicos/80condition_not_exists_error/00-base.xml new file mode 100644 index 0000000..e1278bf --- /dev/null +++ b/tests/flattener_dicos/80condition_not_exists_error/00-base.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + non + + + + + + + + oui + notexists + + + + + + + diff --git a/tests/flattener_dicos/80container_filesredefine_error/00-base.xml b/tests/flattener_dicos/80container_filesredefine_error/00-base.xml new file mode 100644 index 0000000..4d91538 --- /dev/null +++ b/tests/flattener_dicos/80container_filesredefine_error/00-base.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/80container_filesredefine_error/01-base.xml b/tests/flattener_dicos/80container_filesredefine_error/01-base.xml new file mode 100644 index 0000000..7e1413a --- /dev/null +++ b/tests/flattener_dicos/80container_filesredefine_error/01-base.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/tests/flattener_dicos/80container_no_id/00-base.xml b/tests/flattener_dicos/80container_no_id/00-base.xml new file mode 100644 index 0000000..47bc733 --- /dev/null +++ b/tests/flattener_dicos/80container_no_id/00-base.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/tests/flattener_dicos/80container_no_id_modecontainer/00-base.xml b/tests/flattener_dicos/80container_no_id_modecontainer/00-base.xml new file mode 100644 index 0000000..7bb6b2e --- /dev/null +++ b/tests/flattener_dicos/80container_no_id_modecontainer/00-base.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/80container_same_id/00-base.xml b/tests/flattener_dicos/80container_same_id/00-base.xml new file mode 100644 index 0000000..42a710c --- /dev/null +++ b/tests/flattener_dicos/80container_same_id/00-base.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/tests/flattener_dicos/80empty_typeeole_container/00_base.xml b/tests/flattener_dicos/80empty_typeeole_container/00_base.xml new file mode 100644 index 0000000..3900984 --- /dev/null +++ b/tests/flattener_dicos/80empty_typeeole_container/00_base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + 3127 + + + + + + + non + + 3128 + toto2 + + + + + diff --git a/tests/flattener_dicos/80empty_typeeole_eole/00_base.xml b/tests/flattener_dicos/80empty_typeeole_eole/00_base.xml new file mode 100644 index 0000000..9913049 --- /dev/null +++ b/tests/flattener_dicos/80empty_typeeole_eole/00_base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + 3127 + + + + + + + non + + 3128 + toto2 + + + + + diff --git a/tests/flattener_dicos/80empty_typeeole_number/00_base.xml b/tests/flattener_dicos/80empty_typeeole_number/00_base.xml new file mode 100644 index 0000000..10f9f14 --- /dev/null +++ b/tests/flattener_dicos/80empty_typeeole_number/00_base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + 3127 + + + + + + + non + + 3128 + toto2 + + + + + diff --git a/tests/flattener_dicos/80empty_typeeole_python/00_base.xml b/tests/flattener_dicos/80empty_typeeole_python/00_base.xml new file mode 100644 index 0000000..dfe6c4b --- /dev/null +++ b/tests/flattener_dicos/80empty_typeeole_python/00_base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + 3127 + + + + + + + + + + + + diff --git a/tests/flattener_dicos/80empty_validenum/00-base.xml b/tests/flattener_dicos/80empty_validenum/00-base.xml new file mode 100644 index 0000000..ea604c3 --- /dev/null +++ b/tests/flattener_dicos/80empty_validenum/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + [] + + + + + + + diff --git a/tests/flattener_dicos/80family_several/00-base.xml b/tests/flattener_dicos/80family_several/00-base.xml new file mode 100644 index 0000000..4b5b365 --- /dev/null +++ b/tests/flattener_dicos/80family_several/00-base.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + non + + + + + + + + + + + + valfill + + + slave1 + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/80masterslave_auto_save/00-base.xml b/tests/flattener_dicos/80masterslave_auto_save/00-base.xml new file mode 100644 index 0000000..f4571d6 --- /dev/null +++ b/tests/flattener_dicos/80masterslave_auto_save/00-base.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + non + + + + + + + + + + valfill + + + slave1 + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/80masterslave_notexists/00-base.xml b/tests/flattener_dicos/80masterslave_notexists/00-base.xml new file mode 100644 index 0000000..2c2c948 --- /dev/null +++ b/tests/flattener_dicos/80masterslave_notexists/00-base.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + non + + + + + + + + + + valfill + + + slave1 + + + slave1 + slave2 + + + slave3 + slave4 + + + + + + + diff --git a/tests/flattener_dicos/80masterslaves_autofreeze/00-base.xml b/tests/flattener_dicos/80masterslaves_autofreeze/00-base.xml new file mode 100644 index 0000000..2dd2cdb --- /dev/null +++ b/tests/flattener_dicos/80masterslaves_autofreeze/00-base.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + valfill + + + slave1 + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/80masterslaves_notmulti/00-base.xml b/tests/flattener_dicos/80masterslaves_notmulti/00-base.xml new file mode 100644 index 0000000..6ae754e --- /dev/null +++ b/tests/flattener_dicos/80masterslaves_notmulti/00-base.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + valfill + + + slave1 + + + slave1 + slave2 + + + + + + + diff --git a/tests/flattener_dicos/80redefine_autoerror/00-base.xml b/tests/flattener_dicos/80redefine_autoerror/00-base.xml new file mode 100644 index 0000000..8fe4089 --- /dev/null +++ b/tests/flattener_dicos/80redefine_autoerror/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + valeur + + + + + + + diff --git a/tests/flattener_dicos/80redefine_autoerror/01-base.xml b/tests/flattener_dicos/80redefine_autoerror/01-base.xml new file mode 100644 index 0000000..378fe56 --- /dev/null +++ b/tests/flattener_dicos/80redefine_autoerror/01-base.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + valeur + + + + + + diff --git a/tests/flattener_dicos/80redefine_error/00-base.xml b/tests/flattener_dicos/80redefine_error/00-base.xml new file mode 100644 index 0000000..5efe527 --- /dev/null +++ b/tests/flattener_dicos/80redefine_error/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/80redefine_error/01-redefine.xml b/tests/flattener_dicos/80redefine_error/01-redefine.xml new file mode 100644 index 0000000..5efe527 --- /dev/null +++ b/tests/flattener_dicos/80redefine_error/01-redefine.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/80redefine_helperror/00-base.xml b/tests/flattener_dicos/80redefine_helperror/00-base.xml new file mode 100644 index 0000000..746752e --- /dev/null +++ b/tests/flattener_dicos/80redefine_helperror/00-base.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + redefine help + + + + diff --git a/tests/flattener_dicos/80redefine_helperror/01-base.xml b/tests/flattener_dicos/80redefine_helperror/01-base.xml new file mode 100644 index 0000000..301e58f --- /dev/null +++ b/tests/flattener_dicos/80redefine_helperror/01-base.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + redefine help + + + + diff --git a/tests/flattener_dicos/80redefine_notexists/00-base.xml b/tests/flattener_dicos/80redefine_notexists/00-base.xml new file mode 100644 index 0000000..5efe527 --- /dev/null +++ b/tests/flattener_dicos/80redefine_notexists/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/flattener_dicos/80redefine_notexists/01-redefine.xml b/tests/flattener_dicos/80redefine_notexists/01-redefine.xml new file mode 100644 index 0000000..356c6fb --- /dev/null +++ b/tests/flattener_dicos/80redefine_notexists/01-redefine.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + non + + + + + + + + + + + + diff --git a/tests/flattener_dicos/80separator_multi/00-base.xml b/tests/flattener_dicos/80separator_multi/00-base.xml new file mode 100644 index 0000000..9a85c62 --- /dev/null +++ b/tests/flattener_dicos/80separator_multi/00-base.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + Établissement + Établissement + + + + + + + + + + diff --git a/tests/flattener_dicos/80separator_multi2/00-base.xml b/tests/flattener_dicos/80separator_multi2/00-base.xml new file mode 100644 index 0000000..711c533 --- /dev/null +++ b/tests/flattener_dicos/80separator_multi2/00-base.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + Établissement + + + + + + + + + + diff --git a/tests/flattener_dicos/80separator_multi2/01-base.xml b/tests/flattener_dicos/80separator_multi2/01-base.xml new file mode 100644 index 0000000..123d544 --- /dev/null +++ b/tests/flattener_dicos/80separator_multi2/01-base.xml @@ -0,0 +1,20 @@ + + + + + + + + + + Établissement + + + + + + + + + + diff --git a/tests/flattener_dicos/80unknown_validenum/00-base.xml b/tests/flattener_dicos/80unknown_validenum/00-base.xml new file mode 100644 index 0000000..01d0c67 --- /dev/null +++ b/tests/flattener_dicos/80unknown_validenum/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + ['oui', 'non'] + + + + + + + diff --git a/tests/flattener_dicos/80validenum_ouinon/00-base.xml b/tests/flattener_dicos/80validenum_ouinon/00-base.xml new file mode 100644 index 0000000..e07cad4 --- /dev/null +++ b/tests/flattener_dicos/80validenum_ouinon/00-base.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + ['maybe'] + + + + + + + diff --git a/tests/flattener_dicos/80validenum_python_not_list/00-base.xml b/tests/flattener_dicos/80validenum_python_not_list/00-base.xml new file mode 100644 index 0000000..75279a1 --- /dev/null +++ b/tests/flattener_dicos/80validenum_python_not_list/00-base.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + non + + + + + c + + + + + + + + eosfunc.valid_lower('toto') + + + + + bla bla bla + + + + diff --git a/tests/flattener_dicos/80validenum_python_unknown/00-base.xml b/tests/flattener_dicos/80validenum_python_unknown/00-base.xml new file mode 100644 index 0000000..75e8ddc --- /dev/null +++ b/tests/flattener_dicos/80validenum_python_unknown/00-base.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + non + + + + + c + + + + + + + + toto + + + + + bla bla bla + + + + diff --git a/tests/flattener_dicos/80validenum_python_unknownvalue/00-base.xml b/tests/flattener_dicos/80validenum_python_unknownvalue/00-base.xml new file mode 100644 index 0000000..9108c3a --- /dev/null +++ b/tests/flattener_dicos/80validenum_python_unknownvalue/00-base.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + non + + + + + c + + + + + + + + eosfunc.calc_multi_val(['pouet']) + + + + + bla bla bla + + + + diff --git a/tests/flattener_dicos/88valid_enum_not_number/00-base.xml b/tests/flattener_dicos/88valid_enum_not_number/00-base.xml new file mode 100644 index 0000000..bc79cc8 --- /dev/null +++ b/tests/flattener_dicos/88valid_enum_not_number/00-base.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + non + + + + + + + + + + + [i for i in range(3, 13)] + + + + + bla bla bla + + + + diff --git a/tests/flattener_dicos/90_container_not_exist_error/00_base.xml b/tests/flattener_dicos/90_container_not_exist_error/00_base.xml new file mode 100644 index 0000000..b8dfca8 --- /dev/null +++ b/tests/flattener_dicos/90_container_not_exist_error/00_base.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tests/flattener_dicos_a_voir/10load_frozenifin_noexist/00-base.xml b/tests/flattener_dicos_a_voir/10load_frozenifin_noexist/00-base.xml new file mode 100644 index 0000000..257e33e --- /dev/null +++ b/tests/flattener_dicos_a_voir/10load_frozenifin_noexist/00-base.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + tous + + + + + + + + + + ['tous', 'authentifié', 'aucun'] + + + oui + non + mode_conteneur_actif + mode_conteneur_actif2 + + + + + + + diff --git a/tests/flattener_dicos_a_voir/10load_frozenifin_noexist/result/00-base.xml b/tests/flattener_dicos_a_voir/10load_frozenifin_noexist/result/00-base.xml new file mode 100644 index 0000000..4294c7e --- /dev/null +++ b/tests/flattener_dicos_a_voir/10load_frozenifin_noexist/result/00-base.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + oui + creole.general.mode_conteneur_actif + creole.general.mode_conteneur_actif2 + afilllist + + + + diff --git a/tests/test_compare_loader.py b/tests/test_compare_loader.py new file mode 100644 index 0000000..a1906ef --- /dev/null +++ b/tests/test_compare_loader.py @@ -0,0 +1,703 @@ +from lxml import etree +from os.path import isfile, join, isdir +from pytest import fixture, raises +from os import listdir + +from tiramisu.option import SymLinkOption, OptionDescription, ChoiceOption, Option +from tiramisu.setting import groups + +from creole.objspace import CreoleObjSpace +from creole.error import CreoleDictConsistencyError +from creole.xml_compare import xml_compare +#from creole.loader import creole_loader +from creole import loader1 as loader, loader as loader2, config +#from creole.loader2 import creole_loader as creole_loader2 +from creole.eosfunc import gen_random, random_int +from pyeole.encode import normalize + + +dtdfile = 'data/creole.dtd' +if isfile(dtdfile): + relative = True +else: + relative = False + dtdfile = '/usr/share/creole/creole.dtd' + if not isfile(dtdfile): + raise Exception('unable to find dtdfile') + +destfile = '/tmp/test.xml' +if relative: + dico_dirs = 'tests/flattener_dicos' +else: + dico_dirs = '/usr/share/creole/tests/flattener_dicos' + + +TEST = set() + +for testfile in listdir(dico_dirs): + if isdir(join(dico_dirs, testfile)): + if isdir(join(dico_dirs, testfile, 'result')): + TEST.add(testfile) + +TEST = list(TEST) +TEST.remove('51redefine_help') +TEST.remove('52exists_redefine') +TEST.remove('60extra_load') +TEST.remove('60extra_redefine') +TEST.remove('60extra_mandatory') +TEST.remove('60action_external') +TEST.remove('60extra_externalspacecondition') +TEST.remove('60familyaction') +TEST.remove('60familyaction_accent') +TEST.remove('60familyaction_disable') +TEST.remove('60familyaction_twoactions') +TEST.remove('60familyaction_mandatory') +TEST.remove('60familyaction_empty') +TEST.remove('60familyactionexternal') +TEST.remove('10check_option') +TEST.remove('10valid_enum_numberdefault') +TEST.remove('60familyaction_save') +TEST.remove('60extra_help') +EOLE_DIR = '/usr/share/eole/creole/dicos' +if isdir(EOLE_DIR): + TEST.append(EOLE_DIR) +TEST.sort() + + +@fixture(scope="module", params=TEST) +def test_dir(request): + return request.param + + +def fake_config_save_values(*args, **kwargs): + return True + + +def setup_module(module): + module.config_save_values_ori = loader2.config_save_values + loader2.config_save_values = fake_config_save_values + +def teardown_module(module): + loader2.config_save_values = module.config_save_values_ori + loader2.eoleextradico = config.eoleextradico + loader2.eoledirs = config.eoledirs + +def launch_flattener(test_dir): + is_eole = test_dir == EOLE_DIR + + dirs = [test_dir] + if not is_eole: + subfolder = join(test_dir, 'subfolder') + if isdir(subfolder): + dirs.append(subfolder) + extra = list() + subfolder = join(test_dir, 'extra_dirs') + load_extra = False + if isdir(subfolder): + load_extra = True + loader.eoleextradico = subfolder + loader2.eoleextradico = subfolder + #FIXME cannot redefine from now ... :/ + #return None, None + force_dirs = dirs + else: + load_extra = False + force_dirs = None + + loader.eoledirs = dirs + loader2.eoledirs = dirs + + try: + config1 = loader.creole_loader(load_values=False, load_extra=load_extra) + except OSError: + # for disknod + return None, None + + config2 = loader2.creole_loader(load_values=False, load_extra=load_extra, force_flattened=destfile) + #eolobj = CreoleObjSpace(dtdfile) + #eolobj.create_or_populate_from_xml('creole', dirs) + #if not is_eole: + # subfolder = join(test_dir, 'extra') + # if isdir(subfolder): + # eolobj.create_or_populate_from_xml('extra', [subfolder]) + # subfolder = join(test_dir, 'extra1') + # if isdir(subfolder): + # eolobj.create_or_populate_from_xml('extra1', [subfolder]) + #eolobj.space_visitor() + #eolobj.save(destfile) + + #config2 = creole_loader2(destfile) + return config1, config2 + + +def filter_path(path): + if path.startswith('containers.'): + return not (path.endswith('.level') or path.endswith('_type') or path.endswith('.redefine') or path.startswith('containers.interfaces.')) + else: + return True + + +def get_descr1_paths(descr1, config1): + set1 = set() + options1 = {} + dict1 = {} + containers = {} + redefinable = {} + for path in descr1._cache_paths[1]: + if path.startswith('containers.') and not path.startswith('containers.network.') and not path.startswith('containers.containers'): + spath = path.split('.') + opt = getattr(config1.cfgimpl_get_description(), path) + if len(spath) == 3: + _, type_, idx = spath + name = None + elif len(spath) == 4: + _, type_, idx, name = spath + else: + if not filter_path(path): + continue + set1.add(path) + options1[path] = opt + if not isinstance(opt, OptionDescription): + try: + value = getattr(config1, path) + dict1[path] = value + except: + pass + continue + if not filter_path(path): + continue + num = int(idx[len(type_) - 1:]) + d = {'name': name, 'opt': opt} + try: + value = getattr(config1, path) + d['value'] = value + except: + pass + containers.setdefault(type_, {}).setdefault(num, []).append(d) + if name == None: + copt = getattr(config1.cfgimpl_get_description(), 'containers.{}.{}.container'.format(type_, idx)) + container = copt.impl_getdefault() + copt = getattr(config1.cfgimpl_get_description(), 'containers.{}.{}.name'.format(type_, idx)) + name = copt.impl_getdefault() + if not isinstance(name, unicode): + continue + try: + copt = getattr(config1.cfgimpl_get_description(), 'containers.{}.{}.redefine'.format(type_, idx)) + redefine = copt.impl_getdefault() == 'True' + except AttributeError: + redefine = False + if redefine: + del(containers[type_][redefinable[name][container]]) + redefinable.setdefault(name, {})[container] = num + + elif filter_path(path): + opt = getattr(config1.cfgimpl_get_description(), path) + options1[path] = opt + set1.add(path) + if not isinstance(opt, OptionDescription): + try: + value = getattr(config1, path) + dict1[path] = value + except: + pass + for container, cont_values in containers.items(): + idx = 0 + for lst in cont_values.values(): + name = container[:-1] + str(idx) + subpath = 'containers.{}.{}'.format(container, name) + for name in lst: + if name['name'] is None: + set1.add(subpath) + options1[subpath] = name['opt'] + else: + path = subpath + '.' + name['name'] + set1.add(path) + options1[path] = name['opt'] + if 'value' in name: + dict1[path] = name['value'] + idx += 1 + + return set1, options1, dict1 + + +def test_variable_name(test_dir): + test_dir = join(dico_dirs, test_dir) + config1, config2 = launch_flattener(test_dir) + if config1 is None: + return + descr1 = config1.cfgimpl_get_description() + descr2 = config2.cfgimpl_get_description() + + set1 = get_descr1_paths(descr1, config1)[0] + + set2 = set() + for path in descr2._cache_paths[1]: + if filter_path(path): + set2.add(path) + + for path in set1: + try: + assert path in set2 + except AssertionError as err: + print + msg = ('path in set1 not present in set2 in {}'.format(test_dir)) + print(msg) + print('-' * len(msg)) + print(set1 - set2) + print + msg = ('path in set2 not present in set1 in {}'.format(test_dir)) + print(msg) + print('-' * len(msg)) + print(set2 - set1) + raise err + + for path in set2: + try: + assert path in set1 + except AssertionError as err: + print + msg = ('path in set1 not present in set2 in {}'.format(test_dir)) + print(msg) + print('-' * len(msg)) + print(set1 - set2) + print + msg = ('path in set2 not present in set1 in {}'.format(test_dir)) + print(msg) + print('-' * len(msg)) + print(set2 - set1) + raise err + +def test_variable_multi(test_dir): + test_dir = join(dico_dirs, test_dir) + config1, config2 = launch_flattener(test_dir) + if config1 is None: + return + descr1 = config1.cfgimpl_get_description() + descr2 = config2.cfgimpl_get_description() + #paths1 = descr1._cache_paths[1] + set1, options1, _ = get_descr1_paths(descr1, config1) + for path in set1: + try: + #opt1 = getattr(descr1, path) + opt1 = options1[path] + opt2 = getattr(descr2, path) + if not isinstance(opt1, SymLinkOption): + assert opt1.impl_is_multi() == opt2.impl_is_multi() + assert opt1.impl_is_submulti() == opt2.impl_is_submulti() + assert opt1.impl_allow_empty_list() == opt2.impl_allow_empty_list() + except AssertionError as err: + print + msg = 'multi differents for {} in {}'.format(path, test_dir) + print(msg) + print('-' * len(msg)) + print(opt1.impl_is_multi(), opt1.impl_is_submulti()) + print(opt2.impl_is_multi(), opt2.impl_is_submulti()) + raise err + + +def test_variable_information(test_dir): + test_dir = join(dico_dirs, test_dir) + config1, config2 = launch_flattener(test_dir) + if config1 is None: + return + descr1 = config1.cfgimpl_get_description() + descr2 = config2.cfgimpl_get_description() + set1, options1, _ = get_descr1_paths(descr1, config1) + for path in set1: + try: + opt1 = options1[path] + opt2 = getattr(descr2, path) + if not isinstance(opt1, SymLinkOption): + information1 = opt1._informations + if isinstance(information1, str): + information1 = normalize(information1) + if isinstance(information1, tuple): + tuple1 = [] + for info1 in information1[1]: + if isinstance(info1, str): + info1 = normalize(info1) + tuple1.append(info1) + information1 = list(information1) + information1[1] = tuple(tuple1) + information1 = tuple(information1) + + + check_info = True + if isinstance(opt1, OptionDescription) and opt1.impl_get_group_type() == groups.master: + check_info = False + if check_info: + assert information1 == opt2._informations + except AssertionError as err: + import traceback + traceback.print_exc() + print + msg = 'informations differents for {} in {}'.format(path, test_dir) + print(msg) + print('-' * len(msg)) + print information1 + print opt2._informations + raise err + + +def test_variable_consistencies(test_dir): + test_dir = join(dico_dirs, test_dir) + config1, config2 = launch_flattener(test_dir) + if config1 is None: + return + descr1 = config1.cfgimpl_get_description() + descr2 = config2.cfgimpl_get_description() + set1, options1, _ = get_descr1_paths(descr1, config1) + for path in set1: + try: + opt1 = options1[path] + opt2 = getattr(descr2, path) + if not isinstance(opt1, SymLinkOption): + assert opt1._is_warnings_only() == opt2._is_warnings_only() + cons1 = opt1._get_consistencies() + cons2 = opt2._get_consistencies() + if cons1 != tuple(): + assert len(cons1) == len(cons2) + for idx, val1 in enumerate(cons1): + val2 = cons2[idx] + for subidx, c1 in enumerate(val1): + c2 = val2[subidx] + if isinstance(c1, tuple): + for validx, val in enumerate(c1): + assert descr1.impl_get_path_by_opt(val) == descr2.impl_get_path_by_opt(c2[validx]) + elif isinstance(c1, dict): + assert set(c1.keys()) == set(c2.keys()) + for key, val in c1.items(): + assert val == c2[key] + else: + assert c1 == c2 + else: + assert cons1 == cons2 + except AssertionError as err: + print + msg = 'consistencies differents for {} in {}'.format(path, test_dir) + print(msg) + print('-' * len(msg)) + print + print cons1 + print cons2 + raise err + + +def test_variable_callback(test_dir): + test_dir = join(dico_dirs, test_dir) + config1, config2 = launch_flattener(test_dir) + if config1 is None: + return + descr1 = config1.cfgimpl_get_description() + descr2 = config2.cfgimpl_get_description() + set1, options1, _ = get_descr1_paths(descr1, config1) + for path in set1: + if not (path.startswith('containers.disknods.disknod') and (path.endswith('.major') or path.endswith('.minor') or path.endswith('.type'))): + try: + opt1 = options1[path] + opt2 = getattr(descr2, path) + if not isinstance(opt1, SymLinkOption): + callback1 = opt1.impl_get_callback() + callback2 = opt2.impl_get_callback() + if not callback1 == (None, {}): + assert callback1[0] == callback2[0] + assert set(callback1[1].keys()) == set(callback2[1].keys()) + for key, val1 in callback1[1].items(): + val2 = callback2[1][key] + assert len(val1) == len(val2) + for idx, idx1 in enumerate(val1): + idx2 = val2[idx] + if not isinstance(idx1, tuple): + assert idx1 == idx2 + else: + if idx1[0] == idx1[0] == None: + continue + assert descr1.impl_get_path_by_opt(idx1[0]) == descr2.impl_get_path_by_opt(idx2[0]) + assert idx1[1] == idx2[1] + else: + assert callback1 == callback2 + except AssertionError as err: + import traceback + traceback.print_exc() + print + msg = 'callback differents for {} in {}'.format(path, test_dir) + print(msg) + print('-' * len(msg)) + raise err + + +def test_variable_validator(test_dir): + test_dir = join(dico_dirs, test_dir) + config1, config2 = launch_flattener(test_dir) + if config1 is None: + return + descr1 = config1.cfgimpl_get_description() + descr2 = config2.cfgimpl_get_description() + set1, options1, _ = get_descr1_paths(descr1, config1) + for path in set1: + try: + opt1 = options1[path] + opt2 = getattr(descr2, path) + if not isinstance(opt1, SymLinkOption): + validator1 = opt1.impl_get_validator() + validator2 = opt2.impl_get_validator() + if validator1 == (None, {}): + assert validator1 == validator2 + else: + assert validator1[0] == validator2[0] + assert validator1[1].keys() == validator2[1].keys() + for key, vals1 in validator1[1].items(): + vals2 = validator2[1][key] + assert len(vals2) == len(vals1) + for idx, val1 in enumerate(vals1): + val2 = vals2[idx] + if isinstance(val1[0], Option) and isinstance(val1, tuple): + assert len(val1) == len(val2) == 2 + path1 = config1.cfgimpl_get_description().impl_get_path_by_opt(val1[0]) + path2 = config2.cfgimpl_get_description().impl_get_path_by_opt(val2[0]) + assert path1 == path2 + assert val1[1] == val2[1] + else: + assert val1 == val2 + + + except AssertionError as err: + print + msg = 'consistencies differents for {} in {}'.format(path, test_dir) + print(msg) + print('-' * len(msg)) + raise err + + +def test_variable_choice(test_dir): + test_dir = join(dico_dirs, test_dir) + config1, config2 = launch_flattener(test_dir) + if config1 is None: + return + descr1 = config1.cfgimpl_get_description() + descr2 = config2.cfgimpl_get_description() + set1, options1, _ = get_descr1_paths(descr1, config1) + for path in set1: + try: + opt1 = options1[path] + opt2 = getattr(descr2, path) + ischoice1 = isinstance(opt1, ChoiceOption) + ischoice2 = isinstance(opt2, ChoiceOption) + + assert ischoice1 == ischoice2 + if ischoice1: + assert opt1.impl_get_values(None) == opt2.impl_get_values(None) + assert opt1.impl_get_choice_values_params() == opt2.impl_get_choice_values_params() + except AssertionError as err: + print + msg = 'multi differents for {} in {}'.format(path, test_dir) + print(msg) + print('-' * len(msg)) + raise err + + +def test_variable_default(test_dir): + test_dir = join(dico_dirs, test_dir) + config1, config2 = launch_flattener(test_dir) + if config1 is None: + return + descr1 = config1.cfgimpl_get_description() + descr2 = config2.cfgimpl_get_description() + set1, options1, _ = get_descr1_paths(descr1, config1) + for path in set1: + if not (path.startswith('containers.disknods.disknod') and (path.endswith('.major') or path.endswith('.minor') or path.endswith('.type'))): + try: + opt1 = options1[path] + opt2 = getattr(descr2, path) + if not isinstance(opt1, SymLinkOption): + assert opt1.impl_getdefault() == opt2.impl_getdefault() + assert opt1.impl_getdefault_multi() == opt2.impl_getdefault_multi() + assert opt1.impl_is_unique() == opt2.impl_is_unique() + #if hasattr(opt1, '_extra'): + # assert opt1._extra == opt2._extra + except AssertionError as err: + print + msg = 'default value differents for {} in {}'.format(path, test_dir) + print(msg) + print('-' * len(msg)) + print(opt1.impl_getdefault(), opt1.impl_getdefault_multi()) + print(opt2.impl_getdefault(), opt2.impl_getdefault_multi()) + raise err + + +def test_variable_symlink(test_dir): + test_dir = join(dico_dirs, test_dir) + config1, config2 = launch_flattener(test_dir) + if config1 is None: + return + descr1 = config1.cfgimpl_get_description() + descr2 = config2.cfgimpl_get_description() + set1, options1, _ = get_descr1_paths(descr1, config1) + for path in set1: + opt1 = options1[path] + opt2 = getattr(descr2, path) + try: + symlink1 = isinstance(opt1, SymLinkOption) + symlink2 = isinstance(opt2, SymLinkOption) + assert symlink1 == symlink2 + if symlink1: + path1 = descr1.impl_get_path_by_opt(opt1._opt) + path2 = descr2.impl_get_path_by_opt(opt2._opt) + assert path1 == path2 + + except AssertionError as err: + print + msg = 'symlink differents for {} in {}'.format(path, test_dir) + print(msg) + print('-' * len(msg)) + raise err + + +def test_variable_properties(test_dir): + test_dir = join(dico_dirs, test_dir) + config1, config2 = launch_flattener(test_dir) + if config1 is None: + return + descr1 = config1.cfgimpl_get_description() + descr2 = config2.cfgimpl_get_description() + set1, options1, _ = get_descr1_paths(descr1, config1) + for path in set1: + if not (path.startswith('containers.disknods.disknod') and (path.endswith('.major') or path.endswith('.minor') or path.endswith('.type'))): + try: + opt1 = options1[path] + opt2 = getattr(descr2, path) + if not isinstance(opt1, SymLinkOption): + assert set(opt1._properties) == set(opt2._properties) + requires1 = opt1.impl_getrequires() + requires2 = opt2.impl_getrequires() + assert opt1.impl_get_calc_properties() == opt2.impl_get_calc_properties() + requires1 = opt1.impl_getrequires() + requires2 = opt2.impl_getrequires() + assert len(requires1) == len(requires2) + dictreq1 = dict() + dictreq2 = dict() + for idx, require1 in enumerate(requires1): + require2 = requires2[idx] + assert len(require1) == len(require2) + for req_idx, req1 in enumerate(require1): + req2 = require2[req_idx] + dictreq1.setdefault(descr1.impl_get_path_by_opt(req1[0]), []).append(req1[1:]) + dictreq2.setdefault(descr2.impl_get_path_by_opt(req2[0]), []).append(req2[1:]) + for key, val1 in dictreq1.items(): + val2 = dictreq2[key] + try: + assert val1 == val2 + except AssertionError as err: + # sur horus on a : [('non', 'non'), 'disabled', False, True, True] au lieu de [('non'), 'disabled', False, True, True] + # sur l'ancien loader, on fait un "set" pour supprimer les doublons + # pour containers.service_accesss.service_access3 + for idx, req1 in enumerate(val1): + lval1 = list(req1) + lval2 = list(val2[idx]) + if lval1[1:] != lval2[1:] or set(lval1[0]) != set(lval2[0]): + raise err + except AssertionError as err: + import traceback + traceback.print_exc() + print + msg = 'properties different for {} in {}'.format(path, test_dir) + print(msg) + print('-' * len(msg)) + raise err + + +def test_variable_value(test_dir): + test_dir = join(dico_dirs, test_dir) + config1, config2 = launch_flattener(test_dir) + if config1 is None: + return + config1.cfgimpl_get_settings().remove('mandatory') + config2.cfgimpl_get_settings().remove('mandatory') + descr1 = config1.cfgimpl_get_description() + dict1 = get_descr1_paths(descr1, config1)[2] + dict2 = config2.make_dict() + for path in dict1.keys(): + try: + assert dict1[path] == dict2[path] + except AssertionError as err: + opt1 = config1.cfgimpl_get_description().impl_get_opt_by_path(path) + opt2 = config2.cfgimpl_get_description().impl_get_opt_by_path(path) + callback1 = opt1.impl_get_callback() + callback2 = opt2.impl_get_callback() + if callback1[0] in [gen_random, random_int]: + continue + print + msg = 'value different for {} in {}'.format(path, test_dir) + print(msg) + print('-' * len(msg)) + print(opt1) + print(opt2) + raise err + + +def test_config(test_dir): + test_dir = join(dico_dirs, test_dir) + config1, config2 = launch_flattener(test_dir) + if config1 is None: + return + + # information + information1 = config1.cfgimpl_get_values()._p_._informations + information2 = config2.cfgimpl_get_values()._p_._informations + try: + if isinstance(information1, str): + information1 = normalize(information1) + if isinstance(information1, tuple): + tuple1 = [] + for info1 in information1[1]: + if isinstance(info1, str): + info1 = normalize(info1) + tuple1.append(info1) + information1 = list(information1) + information1[1] = tuple(tuple1) + information1 = tuple(information1) + assert information1 == information2 + except AssertionError as err: + print + msg = 'informations differents for config in {}'.format(test_dir) + print(msg) + print('-' * len(msg)) + print information1 + print information2 + raise err + + # properties + props1 = config1.cfgimpl_get_settings()._p_._properties + props2 = config2.cfgimpl_get_settings()._p_._properties + try: + lst1 = set(props1.keys()) + lst2 = set(props2.keys()) + assert lst1 == lst2 + for lst in lst1: + assert set(props1[lst]) == set(props2[lst]) + except AssertionError as err: + print + msg = 'properties differents for config in {}'.format(test_dir) + print(msg) + print('-' * len(msg)) + print props1 + print props2 + raise err + + # permissives + props1 = config1.cfgimpl_get_settings()._p_._permissives + props2 = config2.cfgimpl_get_settings()._p_._permissives + try: + lst1 = set(props1.keys()) + lst2 = set(props2.keys()) + assert lst1 == lst2 + for lst in lst1: + assert set(props1[lst]) == set(props2[lst]) + except AssertionError as err: + print + msg = 'permissives differents for config in {}'.format(test_dir) + print(msg) + print('-' * len(msg)) + print props1 + print props2 + raise err diff --git a/tests/test_creoleclient.py b/tests/test_creoleclient.py new file mode 100644 index 0000000..deeab80 --- /dev/null +++ b/tests/test_creoleclient.py @@ -0,0 +1,159 @@ +# -*- coding: utf-8 -*- + +"""Test L{creole.client} API +""" + +import unittest + +from creole.client import CreoleClient +from creole.client import NotFoundError + +good_variable_name = u'eole_version' +good_variable_path = u'/creole/general/{0}'.format(good_variable_name) +good_variable_key = good_variable_path.lstrip(u'/').replace(u'/', u'.') + +unknown_variable_name = u'absolutely_inexistant' +unknown_variable_path = u'/creole/general/{0}'.format(unknown_variable_name) + +# z_stats is not available on Zéphir module +root_services = [u'networking', u'cron', u'ead-server', u'eoleflask', u'nginx', u'bastion'] + +class TestCreoleClient(unittest.TestCase): + """CreoleClient Tests + + """ + + client = CreoleClient() + + + def check_services(self, services, first=None, last=None, contains=None): + """Check services + FIXME (first, last) : with upstart Creole ordrer doesn't matter + + """ + self.assertIsInstance(services, list) + self.assertGreaterEqual(len(services), 1) + self.assertIsInstance(services[0], dict) + names = [ s[u'name'] for s in services ] + + if first is not None: + self.assertEqual(names[0], + first, + msg=u'“{0}” must be first service'.format(first)) + + if last is not None: + # z_stats can be the last service (#9486) + if names[-1] == u'z_stats': + place = -2 + else: + place = -1 + self.assertEqual(names[place], + last, + msg='“{0}” must be last service'.format(last)) + + if contains is not None: + if not isinstance(contains, list): + contains = [contains] + for service in contains: + self.assertIn(service, names) + + + def test_get_root(self): + """Get root configuration. + + """ + config = self.client.get('/') + self.assertIsInstance(config, dict) + self.assertIn(good_variable_key, config) + + + def test_list_root(self): + """List configuration root path. + + """ + root = self.client.list('/') + self.assertIsInstance(root, list) + self.assertIn(u'creole/', root) + + + def test_get_variable(self): + """Get variable with full path. + + """ + version = self.client.get(good_variable_path) + self.assertIsInstance(version, unicode) + + + def test_list_variable(self): + """Listing a variable result in a list of its value. + + """ + version = self.client.get(good_variable_path) + version_list = self.client.list(good_variable_path) + self.assertIsInstance(version_list, list) + self.assertEqual(len(version_list), 1) + self.assertEqual(version_list[0], version) + + + def test_get_creole(self): + """Get full creole configuration + + """ + creole = self.client.get_creole() + self.assertIsInstance(creole, dict) + self.assertIn(good_variable_name, creole) + + + def test_get_creole_variable(self): + """Get creole variable + + """ + version = self.client.get(good_variable_path) + creole_version = self.client.get_creole(good_variable_name) + self.assertIsInstance(version, unicode) + self.assertEqual(creole_version, version) + + + def test_get_NotFoundError(self): + """Unknown variable must raise :exc:`NotFoundError` + + """ + self.assertRaises(NotFoundError, self.client.get, path=unknown_variable_path) + + + def test_get_creole_NotFoundError(self): + """Unknown variable must raise :exc:`NotFoundError` + + """ + self.assertRaises(NotFoundError, self.client.get_creole, name=unknown_variable_name) + + + def test_get_services(self): + """Ordering of services with :meth:`CreoleClient.get_services()` + + """ + services = self.client.get_services() + self.check_services(services, u'networking', contains=root_services) + + + def test_root_container_services(self): + """Ordering of services for ``root`` container + + This check :meth:`CreoleClient.get_container_infos()`. + + """ + root = self.client.get_container_infos(u'root') + services = root['services'] + self.check_services(services, u'networking', contains=root_services) + + + def test_root_group_services(self): + """Ordering of services for ``root`` group + + This check :meth:`CreoleClient.get_group_infos()`. + + """ + root = self.client.get_group_infos(u'root') + services = root['services'] + self.check_services(services, u'networking', contains=root_services) + diff --git a/tests/test_creolerun.py b/tests/test_creolerun.py new file mode 100644 index 0000000..93b7965 --- /dev/null +++ b/tests/test_creolerun.py @@ -0,0 +1,55 @@ +#-*-coding:utf-8*-* +from commands import getstatusoutput +from os import unlink, system +from os.path import isfile +from creole.client import CreoleClient + +test_file = '/tmp/test_process' + +def _delete_test_file(): + if isfile(test_file): + unlink(test_file) + +def test_runcmd_code_ok(): + assert system('CreoleRun "echo"') == 0 + +def test_runcmd_code_err(): + _delete_test_file() + assert system('CreoleRun "ls %s 2>/dev/null"' % test_file) != 0 + +def test_runcmd_out_ok(): + output = getstatusoutput('CreoleRun "echo -n coucou"') + assert output[0] == 0 + assert output[1] == 'coucou' + +def test_runcmd_out_err(): + _delete_test_file() + output = getstatusoutput('CreoleRun "ls %s"' % test_file) + assert output[0] != 1 + # getstatusoutput concatène stdout et stderr + assert test_file in output[1] + +def test_runcmd_out_stdin(): + output = getstatusoutput('echo hello | CreoleRun "cat"') + assert output[1] == 'hello' + +def test_containers(): + """ + Vérifie que la sortie est identique quelque soit le mode + """ + containers = CreoleClient().get_containers() + for container in containers: + # recherche du 1er conteneur différent de root + if container['name'] not in ['all', 'root']: + s1 = getstatusoutput('CreoleRun "echo \'\\\\\'" root') + s2 = getstatusoutput('CreoleRun "echo \'\\\\\'" %s' % container['name']) + assert s1 == s2 + # Gestion du caractère "*" : #14894 + system('touch {0}'.format(test_file)) + system('CreoleRun "touch {0}" {1}'.format(test_file+'2', container['name'])) + code, res = getstatusoutput('CreoleRun "ls {0}*" {1}'.format(test_file, container['name'])) + if container['real_container'] == 'root': + assert res == '{0}\n{0}2'.format(test_file) + else: + assert res == test_file+'2' + break diff --git a/tests/test_creoleservice.py b/tests/test_creoleservice.py new file mode 100644 index 0000000..9d53f4e --- /dev/null +++ b/tests/test_creoleservice.py @@ -0,0 +1,25 @@ +#-*-coding:utf-8*-* +from os import system +from os.path import isfile +from creole.client import CreoleClient + +def test_service_code(): + """ + test sur les codes retour de CreoleService + """ + assert system('CreoleService nginx stop') == 0 + assert system('CreoleService nginx status') != 0 + assert system('CreoleService nginx start') == 0 + assert system('CreoleService nginx status') == 0 + +def test_bad_service(): + """ + service inconnu + """ + assert system('CreoleService unknown start') != 0 + +#def test_no_networking_stop(): +# """ +# networking est censé être protégé :) +# """ +# assert system('CreoleService networking stop') != 0 diff --git a/tests/test_dicos.py b/tests/test_dicos.py new file mode 100644 index 0000000..9678e1f --- /dev/null +++ b/tests/test_dicos.py @@ -0,0 +1,30 @@ +#-*-coding:utf-8*-* +from os.path import isfile, join +from creole.loader import creole_loader +from creole.lxml_parser import parse_xml_file +from creole.dtd_parser import parse_dtd +from creole.config import dtdfilename + +def test_timezone(): + """ + Vérifie la disponibilité des configurations + proposées pour la timezone + """ + loader = creole_loader() + var = loader.unwrap_from_path('creole.general.time_zone') + for tzone in var.impl_get_information('proposed_value'): + assert isfile(join("/usr/share/zoneinfo", tzone)) + +def test_nut_ups_driver(): + """ + Vérifie la disponibilité des drivers nut proposés + """ + dico = parse_xml_file('/usr/share/eole/creole/dicos/20_nut.xml', parse_dtd(dtdfilename)) + fonction = dico['checks']['nut_ups_driver'][0][1][0]['value'] + from creole import eosfunc + default_drivers = eval('[{0}]'.format(fonction.split('[')[1].split(']')[0])) + calculated_drivers = eval(fonction) + print default_drivers + print calculated_drivers + assert default_drivers == calculated_drivers + diff --git a/tests/test_eosfunc.py b/tests/test_eosfunc.py new file mode 100644 index 0000000..0c0f3f1 --- /dev/null +++ b/tests/test_eosfunc.py @@ -0,0 +1,85 @@ +#-*- coding:utf-8 -*- +from os import mkdir +from os.path import isdir, join +from shutil import rmtree +from creole import eosfunc +from creole.client import CreoleClient + +def test_is_ip(): + """ + Tests sur la fonction is_ip + """ + assert eosfunc.is_ip('1.1.1.1') + assert eosfunc.is_ip('0.0.0.0') + assert not eosfunc.is_ip('eole.ac-test.fr') + +def test_calc_classe(): + """ + Tests sur la fonction calc_classe + """ + classe = eosfunc.calc_classe('255.255.255.0') + # la fonction doit retourner de l'unicode (#8356) + assert type(classe) == unicode + assert classe == u'24' + +def test_concat(): + """ + Tests sur la fonction concat + """ + assert eosfunc.concat(u'a', u'b') == u'ab' + assert eosfunc.concat(u'a', attr=u'b') == u'ab' + assert eosfunc.concat(attr1=u'a', attr2='b') == u'ab' + # argument à None (#7701) + assert eosfunc.concat(u'a', None, u'b') is None + # argument nommé à None (#7138) + assert eosfunc.concat(attr1=None, attr2='b') is None + # mélange des deux + assert eosfunc.concat(u'a', attr=None) is None + assert eosfunc.concat(None, attr=u'b') is None + +def test_concat_path(): + """ + Tests sur la fonction de concaténation de chemins + """ + assert eosfunc.concat_path(u'/home', u'test') == u'/home/test' + assert eosfunc.concat_path(u'/home', u'/test') == u'/home/test' + assert eosfunc.concat_path(u'home', u'test') == u'/home/test' + assert eosfunc.concat_path(u'home', u'/test') == u'/home/test' + assert eosfunc.concat_path(u'/', u'test') == u'/test' + assert eosfunc.concat_path(u'/', u'/test') == u'/test' + assert eosfunc.concat_path(u'', u'test') == u'/test' + assert eosfunc.concat_path(u'', u'/test') == u'/test' + +def test_list_files(): + """ + Tests sur la fonction listant des fichiers dans un répertoire + """ + files = ['abc', 'abc.txt', 'abc.xml', 'bcd.txt'] + tmp_dir = '/tmp/test_list_files' + if isdir(tmp_dir): + rmtree(tmp_dir) + mkdir(tmp_dir) + for fname in files: + fh = file(join(tmp_dir, fname), 'w') + fh.write('') + fh.close() + + assert eosfunc.list_files(tmp_dir) == files + assert eosfunc.list_files(tmp_dir, wildcards='*.txt') == ['abc.txt', 'bcd.txt'] + assert eosfunc.list_files(tmp_dir, wildcards='*.txt', stripext=True) == ['abc', 'bcd'] + assert eosfunc.list_files(tmp_dir, wildcards='*.txt', basename=False) == [join(tmp_dir, 'abc.txt'), join(tmp_dir, 'bcd.txt')] + assert eosfunc.list_files(tmp_dir, exception='abc') == ['bcd.txt'] + assert eosfunc.list_files(tmp_dir, exception='abc', substring=False) == ['abc.txt', 'abc.xml', 'bcd.txt'] + assert eosfunc.list_files(tmp_dir, exception=['d.txt', '.xml']) == ['abc', 'abc.txt'] + assert eosfunc.list_files(tmp_dir, exception='tmp') == files + assert eosfunc.list_files(tmp_dir, exception='bc') == [] + assert eosfunc.list_files(tmp_dir, exception='bc', default=['def']) == ['def'] + +def test_gw(): + client = CreoleClient() + adresse_ip_gw = client.get('creole.interface_0.adresse_ip_gw') + if adresse_ip_gw is not None: + assert eosfunc.auto_defaultroute()[0][0] == adresse_ip_gw + else: + assert eosfunc.auto_defaultroute()[0][0] == '192.168.0.1' + assert eosfunc.auto_defaultroute()[0][1] == client.get('creole.interface_0.nom_zone_eth0') diff --git a/tests/test_flattener.py b/tests/test_flattener.py new file mode 100644 index 0000000..4cc4606 --- /dev/null +++ b/tests/test_flattener.py @@ -0,0 +1,138 @@ +from lxml import etree +from os.path import isfile, join, isdir +from pytest import fixture, raises +from os import listdir +from json import load + +#from creole.xmlreflector import CreoleObjSpace, CreoleDictConsistencyError +#from creole import xmlreflector +from creole import objspace, annotator +from creole.xml_compare import xml_compare +from creole.error import CreoleDictConsistencyError + + +dtdfile = 'data/creole.dtd' +if isfile(dtdfile): + relative = True +else: + relative = False + dtdfile = '/usr/share/creole/creole.dtd' + if not isfile(dtdfile): + raise Exception('unable to find dtdfile') + +destfile = '/tmp/test.xml' +if relative: + dico_dirs = 'tests/flattener_dicos' +else: + dico_dirs = '/usr/share/creole/tests/flattener_dicos' + + +test_ok = set() +test_raise = set() + +for test in listdir(dico_dirs): + if isdir(join(dico_dirs, test)): + if isdir(join(dico_dirs, test, 'result')): + test_ok.add(test) + else: + test_raise.add(test) + +excludes = set([]) +test_ok -= excludes +test_raise -= excludes +#test_ok = ['02auto_probe'] +#test_raise = [] + + +test_ok = list(test_ok) +test_raise = list(test_raise) +test_ok.sort() +test_raise.sort() + + +@fixture(scope="module", params=test_ok) +def test_dir(request): + return request.param + + +@fixture(scope="module", params=test_raise) +def test_dir_error(request): + return request.param + + +def compare_xml(exported_xmlfile, expected_xmlfile): + exported_document = etree.parse(exported_xmlfile).getroot() + expected_document = etree.parse(expected_xmlfile).getroot() + try: + assert xml_compare(exported_document, expected_document) + except AssertionError as err: + print() + print('Le dictionnaire exporte :') + print() + print(etree.tostring(exported_document, pretty_print=True, encoding="UTF-8")) + print() + print('Le dictionnaire attendu :') + print() + print(etree.tostring(expected_document, pretty_print=True, encoding="UTF-8")) + raise err + + +def launch_flattener(test_dir): + eolobj = objspace.CreoleObjSpace(dtdfile) + dirs = [test_dir] + subfolder = join(test_dir, 'subfolder') + if isdir(subfolder): + dirs.append(subfolder) + eolobj.create_or_populate_from_xml('creole', dirs) + subfolder = join(test_dir, 'extra_dirs', 'extra') + if isdir(subfolder): + eolobj.create_or_populate_from_xml('extra', [subfolder]) + subfolder = join(test_dir, 'extra_dirs', 'extra1') + if isdir(subfolder): + eolobj.create_or_populate_from_xml('extra1', [subfolder]) + eolobj.space_visitor() + eolobj.save(destfile) + result_file = join(test_dir, 'result/00-base.xml') + if isfile(result_file): + #eolobj.save(result_file) + compare_xml(destfile, result_file) + probe = eolobj.save_probes(destfile) + result_json = join(test_dir, 'result/probe.json') + if isfile(result_json): + with open(result_json) as fhj: + json = load(fhj) + assert probe == json + else: + assert probe == {} + + + +def fake_traduc(txt): + return txt + + +def setup_module(module): + module.traduc_ori = objspace._ + objspace._ = fake_traduc + annotator._ = fake_traduc + objspace.ContainerAnnotator = getattr(annotator, 'ContainerAnnotator') + + +def teardown_module(module): + objspace._ = module.traduc_ori + annotator._ = module.traduc_ori + + +def test_dictionary(test_dir): + test_dir = join(dico_dirs, test_dir) + launch_flattener(test_dir) + + +def test_error_dictionary(test_dir_error): + test_dir = join(dico_dirs, test_dir_error) + raises(CreoleDictConsistencyError, "launch_flattener(test_dir)") + + +def test_no_dtd(): + raises(IOError, "eolobj = objspace.CreoleObjSpace('notexists.dtd')") + diff --git a/tests/test_genconfig.py b/tests/test_genconfig.py new file mode 100644 index 0000000..36afca5 --- /dev/null +++ b/tests/test_genconfig.py @@ -0,0 +1,350 @@ +#-*-coding:utf-8*-* + +from os.path import join, isdir +from json import load +from py.test import raises +from creole.loader import config_save_values +from creole.config import eoleroot +from tiramisu.error import PropertiesOptionError +from eolegenconfig import lib +ID_ = 'test' +DICO_DIR = '/usr/share/creole/tests/dicos' +if not isdir(DICO_DIR): + DICO_DIR = 'tests/dicos' +CONFIG_DIR = '/usr/share/creole/tests/configs' +if not isdir(CONFIG_DIR): + CONFIG_DIR = 'tests/configs' + +def _calc_config_file(test): + """ + nom du fichier eol lié au test + """ + if isdir(CONFIG_DIR): + config_dir = CONFIG_DIR + else: + config_dir = 'tests/configs' + return join(config_dir, '{0}.eol'.format(test)) + +def _load(test, erase=True): + """ + Chargement des dictionnaires liés au test + Initialisation du fichier eol lié au test + """ + config_file = _calc_config_file(test) + if erase: + file(config_file, 'w') + if isdir(DICO_DIR): + dico_dir = DICO_DIR + else: + dico_dir = 'tests/dicos' + return lib.get_config(ID_, force_dirs=join(dico_dir, test), + force_configfile=config_file) + +def _reload(test): + """ + recharge une configuration enregistrée + """ + _load(test, erase=False) + +def _save(test): + """ + Enregistement des données + """ + config_file = _calc_config_file(test) + config = lib.get_config(ID_) + config_save_values(config, 'creole', eol_file=config_file, reload_config=False) + +def test_basic_rules(): + """ + Vérifie l'application de certines règles de base #7432 + """ + config = _load('basic') + # variable obligatoire sans valeur par défaut => mode basique + assert lib.get_variable(ID_, 'test', 'obligatoire')['mode'] == 'basic' + # variable non obligatoire avec valeur par défaut => obligatoire + assert lib.get_variable(ID_, 'test', 'facultatif')['mandatory'] + +def test_obligatoire(): + """ + Vérifie la validation des variables mandatory (#16660) + """ + config = _load('obligatoire') + # sauvegarde avec aucune variable renseignée + raises(PropertiesOptionError, "_save('obligatoire')") + lib.set_value(ID_, 'test', 'vmaster', ['val']) + # sauvegarde avec uniquement la master renseignée + raises(PropertiesOptionError, "_save('obligatoire')") + lib.set_value(ID_, 'test', 'vmaster.vslave1', ['val']) + # sauvegarde avec toutes les mandatory renseignées + _save('obligatoire') + lib.set_value(ID_, 'test', 'vmaster.vslave3', [None]) + # sauvegarde avec la slave pré-remplie "vidée" + raises(PropertiesOptionError, "_save('obligatoire')") + +def test_calc_multi_condition(): + """ + calc_multi_condition avec une variable désactivée #8439 + calc_multi_condition avec 2 valeurs différentes en entrée #9797 + """ + config = _load('multicondition') + assert config.creole.test.target1 == 'resultat2' + assert config.creole.test.target2 == 'resultat1' + assert config.creole.test.target3 == 'oui' + lib.set_value(ID_, 'test', 'condition', 'non') + assert config.creole.test.target1 == 'resultat1' + assert config.creole.test.target2 == 'mismatch' + assert config.creole.test.target3 == 'non' + +def test_auto_save(): + """ + auto_save sur une variable multi (#8020) + """ + config = _load('autosave') + assert config.creole.test.autosave == [u'a', u'b'] + _save('autosave') + content = load(file(_calc_config_file('autosave'))) + assert content['autosave'] == {'owner': 'forced', 'val': [u'a', u'b']} + +def test_auto_freeze(): + """ + Comportement des variables auto_freeze='True' + """ + config = _load('autofreeze') + lib.set_mode(ID_, 'expert') + # variable auto_freeze => mode basic + assert lib.get_variable(ID_, 'test', 'autofreeze')['mode'] == 'basic' + # mais exception si mode='expert' (#7349) + assert lib.get_variable(ID_, 'test', 'autofreeze_x')['mode'] == 'expert' + lib.set_value(ID_, 'test', 'autofreeze', 'freeze') + + # filling automatically an auto_freeze variable + assert config.creole.test.autofreeze_filled is None + lib.set_value(ID_, 'test', 'fixedvariable', 'filled') + assert config.creole.test.autofreeze_filled == 'filled' + + assert lib.get_variable(ID_, 'test', 'autofreeze')['editable'] == True + assert lib.get_variable(ID_, 'test', 'autofreeze_filled')['editable'] == True + assert lib.get_variable(ID_, 'test', 'autofreeze_x')['editable'] == True + _save('autofreeze') + content = load(file(_calc_config_file('autofreeze'))) + # les variables auto_freeze sont enregistrées + assert content[u'autofreeze'] == {u'owner': u'gen_config', u'val': u'freeze'} + assert content[u'autofreeze_x'] == {u'owner': u'forced', u'val': None} + assert content[u'autofreeze_filled'] == {u'owner': u'forced', u'val': u'filled'} + config = _reload('autofreeze') + # passage en mode debug pour accéder à la variable hidden "module_instancie" + lib.set_debug(ID_, True) + if lib.get_variable(ID_, 'general', 'module_instancie')['value'] == 'oui': + # la variable n'est plus éditable après instance + assert lib.get_variable(ID_, 'test', 'autofreeze')['editable'] == False + assert lib.get_variable(ID_, 'test', 'autofreeze_filled')['editable'] == False + assert lib.get_variable(ID_, 'test', 'autofreeze_x')['editable'] == False + else: + # la variable est toujours éditable avant instance + assert lib.get_variable(ID_, 'test', 'autofreeze')['editable'] == True + assert lib.get_variable(ID_, 'test', 'autofreeze_filled')['editable'] == True + assert lib.get_variable(ID_, 'test', 'autofreeze_x')['editable'] == True + +def test_wrong_calc(): + """ + pas de traceback en cas de valeur calculée invalide + """ + config = _load('wrong_calc') + assert config.creole.test.test_value == 'FR' + assert config.creole.test.test_country_name == 'FR' + assert config.creole.test.test_country_name2 == 'FR' + lib.set_value(ID_, 'test', 'test_value', 'EU') + assert config.creole.test.test_country_name == 'EU' + assert config.creole.test.test_country_name2 == 'EU' + lib.set_value(ID_, 'test', 'test_value', 'I2') + var = lib.get_variable(ID_, 'test', 'test_country_name') + assert var['value'] is None + assert var['description'].encode('utf8') in var.get('warning', '') + assert config.creole.test.test_country_name2 == 'FR' + +def test_redefine(): + """ + Vérifie que redefine et remove_check font leur travail #9468 + Vérifie le redefine entre fill et auto #10475 + Vérifie que redefine et remove_condition font leur travail #13729 + """ + config = _load('redefine') + # tests redefine et remove_check + assert config.creole.test.abc1 == 'a' + assert config.creole.test.abc2 == 'b' + assert config.creole.test.abc3 == 'b' + raises(ValueError, "lib.set_value(ID_, 'test', 'abc1', 'd')") + raises(ValueError, "lib.set_value(ID_, 'test', 'abc2', 'd')") + lib.set_value(ID_, 'test', 'abc3', 'd') + assert config.creole.test.abc3 == 'd' + # tests redefine sur fill et auto + assert config.creole.test.fill2auto == 'valeur1valeur2' + assert config.creole.test.auto2fill == 'valeur' + raises(PropertiesOptionError, "lib.set_value(ID_, 'test', 'fill2auto', 'valeur3')") + lib.set_value(ID_, 'test', 'auto2fill', 'valeur3') + assert config.creole.test.auto2fill == 'valeur3' + # tests redefine et remove_condition + raises(PropertiesOptionError, "lib.set_value(ID_, 'test', 'disabled_if', 'val')") + lib.set_value(ID_, 'test', 'disabled_if_redefine', 'val') + lib.set_value(ID_, 'test', 'enabled_if', 'val') + raises(PropertiesOptionError, "lib.set_value(ID_, 'test', 'enabled_if_redefine', 'val')") + raises(PropertiesOptionError, "lib.set_value(ID_, 'test', 'frozen_if', 'val')") + lib.set_value(ID_, 'test', 'frozen_if_redefine', 'val') + +def test_check(): + """ + Vérifie le fonctionnement de optional & hidden + sur les check avec des variables #9472 + """ + config = _load('check') + # variable inconnue dans le check + lib.set_value(ID_, 'test', 'check_unknown', 'ok') + assert config.creole.test.check_unknown == 'ok' + # variable désactivable dans le check + lib.set_value(ID_, 'test', 'check_disabled', 'ok') + assert config.creole.test.check_disabled == 'ok' + raises(ValueError, "lib.set_value(ID_, 'test', 'check_disabled', 'sample')") + lib.set_value(ID_, 'test', 'disable', 'oui') + lib.set_value(ID_, 'test', 'check_disabled', 'sample') + assert config.creole.test.check_disabled == 'sample' + lib.set_value(ID_, 'test', 'disable', 'non') + raises(ValueError, "lib.set_value(ID_, 'test', 'check_disabled', 'sample')") + lib.set_value(ID_, 'test', 'check_disabled', 'ok') + assert config.creole.test.check_disabled == 'ok' + +def test_disabled(): + """ + Vérifie le fonctionnement de disabled_if_in et disabled_if_not_in + sur une même variable #18657 + """ + config = _load('disabled') + assert config.creole.test.source1 == 'oui' + assert config.creole.test.source2 == 'oui' + assert config.creole.test.cible == 'oui' + lib.set_value(ID_, 'test', 'source1', 'non') + raises(PropertiesOptionError, 'config.creole.test.cible') + lib.set_value(ID_, 'test', 'source2', 'non') + raises(PropertiesOptionError, 'config.creole.test.cible') + lib.set_value(ID_, 'test', 'source1', 'oui') + raises(PropertiesOptionError, 'config.creole.test.cible') + lib.set_value(ID_, 'test', 'source2', 'oui') + assert config.creole.test.cible == 'oui' + +def test_disabled_slave(): + """ + Vérifie le fonctionnement de disabled_if_in entre + variables esclaves d'un même groupe de variables #17536 + """ + config = _load('disabled') + lib.set_value(ID_, 'test', 'ma_master', [u'v1', u'v2']) + for idx in (0,1): + assert config.creole.test.ma_master.ma_slave1[idx] == u'oui' + assert config.creole.test.ma_master.ma_slave2[idx] is None + raises(PropertiesOptionError, 'config.creole.test.ma_master.ma_slave3[idx]') + lib.set_value(ID_, 'test', 'ma_master.ma_slave1', [u'non', u'oui']) + assert config.creole.test.ma_master.ma_slave2[1] is None + assert config.creole.test.ma_master.ma_slave3[0] is None + raises(PropertiesOptionError, 'config.creole.test.ma_master.ma_slave2[0]') + raises(PropertiesOptionError, 'config.creole.test.ma_master.ma_slave3[1]') + +def test_calc_multi_val(): + """ + Vérifie le fonctionnement de calc_multi_val + Ajouté pour valider #10251 mais pourra être complété + """ + config = _load('multival') + # variable non multi => None + assert config.creole.test.mail_src == None + # variable multi => [] + assert config.creole.test.mail_dest == [] + # désactivation de "mail_dest" + lib.set_value(ID_, 'test', 'condition', 'non') + # adresse invalide en source + lib.set_value(ID_, 'test', 'mail_src', 'badmail') + raises(PropertiesOptionError, "config.creole.test.mail_dest") + # ré-activation de "mail_dest" + lib.set_value(ID_, 'test', 'condition', 'oui') + raises(ValueError, "config.creole.test.mail_dest") + +def test_mandatory_if_in(): + """ + Vérifie le fonctionnement de mandatory_if_in (#15563) + """ + config = _load('mandatory') + # la condition n'est pas remplie + assert not lib.get_variable(ID_, 'test', 'mandatory_if')['mandatory'] + assert not lib.get_variable(ID_, 'test', 'mandatory_ifnot')['mandatory'] + _save('mandatory') + # la condition est remplie + lib.set_value(ID_, 'test', 'active_mandatory', 'oui') + assert lib.get_variable(ID_, 'test', 'mandatory_if')['mandatory'] + assert lib.get_variable(ID_, 'test', 'mandatory_ifnot')['mandatory'] + raises(PropertiesOptionError, "_save('mandatory')") + +def test_bad_ips(): + """ + Vérifie l'impossibilité de saisir des adresse invalides + (#11480 et #12858) + """ + config = _load('badips') + # moins de 3 éléments + raises(ValueError, "lib.set_value(ID_, 'test', 'adresse_ip', '1.1')") + raises(ValueError, "lib.set_value(ID_, 'test', 'adresse_network', '1.1')") + raises(ValueError, "lib.set_value(ID_, 'test', 'adresse_netmask', '255.255.255')") + # doubles zéros + raises(ValueError, "lib.set_value(ID_, 'test', 'adresse_ip', '1.1.1.00')") + raises(ValueError, "lib.set_value(ID_, 'test', 'adresse_network', '1.1.1.00')") + raises(ValueError, "lib.set_value(ID_, 'test', 'adresse_netmask', '255.255.255.00')") + +def test_warning(): + """ + Vérifie l'affichage et la disparition des warnings (#15796) + """ + if not isdir(eoleroot): + return + # utilisation des dictionnaires du module + lib.del_config(ID_) + lib.get_config(ID_) + lib.set_value(ID_, 'interface_0', 'adresse_ip_gw', '192.168.0.1') + # pas de warning au départ + assert lib.get_variable(ID_, 'interface_0', 'adresse_netmask_eth0')['warning'] == '' + lib.set_value(ID_, 'interface_0', 'adresse_ip_eth0', '192.168.20.240') + # warning parce que la gateway n'est pas dans le bon réseau + assert len(lib.get_variable(ID_, 'interface_0', 'adresse_netmask_eth0')['warning']) != '' + lib.set_value(ID_, 'interface_0', 'adresse_netmask_eth0', '255.255.255.128') + # warning parce que la gateway n'est (toujours) pas dans le bon réseau + assert len(lib.get_variable(ID_, 'interface_0', 'adresse_netmask_eth0')['warning']) != '' + lib.set_value(ID_, 'interface_0', 'adresse_netmask_eth0', '255.255.255.128') + lib.set_value(ID_, 'interface_0', 'adresse_ip_gw', '192.168.20.254') + # plus d'erreur mais le warning est conservé en cache (spécifique gen_config) + assert lib.get_variable(ID_, 'interface_0', 'adresse_netmask_eth0')['warning'] != '' + assert lib.get_variable(ID_, 'interface_0', 'adresse_netmask_eth0')['warning'] == '' + +def test_types(): + """ + Vérifie que la validation de certains types est bien fonctionnelle (#16831) + """ + config = _load('types') + + # nom de domaine "souple" + lib.set_value(ID_, 'test', 'domaine', 'domaine.lan') + lib.set_value(ID_, 'test', 'domaine', 'sanspoint') + lib.set_value(ID_, 'test', 'domaine', '1.1.1.1') + raises(ValueError, "lib.set_value(ID_, 'test', 'domaine', '.lan')") + + # nom de domaine "strict" + lib.set_value(ID_, 'test', 'domaine_strict', 'domaine.lan') + raises(ValueError, "lib.set_value(ID_, 'test', 'domaine_strict', 'sanspoint')") + raises(ValueError, "lib.set_value(ID_, 'test', 'domaine_strict', '1.1.1.1')") + raises(ValueError, "lib.set_value(ID_, 'test', 'domaine_strict', '.lan')") + + # nom d'hôte "souple" + lib.set_value(ID_, 'test', 'nom_hote', 'toto') + lib.set_value(ID_, 'test', 'nom_hote', '1.1.1.1') + raises(ValueError, "lib.set_value(ID_, 'test', 'nom_hote', 'domaine.lan')") + + # nom d'hôte "strict" + lib.set_value(ID_, 'test', 'nom_hote_strict', 'toto') + raises(ValueError, "lib.set_value(ID_, 'test', 'nom_hote_strict', '1.1.1.1')") + raises(ValueError, "lib.set_value(ID_, 'test', 'nom_hote_strict', 'domaine.lan')") + diff --git a/tests/test_loader.py b/tests/test_loader.py new file mode 100644 index 0000000..1a8835c --- /dev/null +++ b/tests/test_loader.py @@ -0,0 +1,117 @@ +from pytest import raises +from os import listdir +from os.path import isfile, join, isdir + +from creole import config, loader + + +dtdfile = 'data/creole.dtd' +if isfile(dtdfile): + relative = True +else: + relative = False + dtdfile = '/usr/share/creole/creole.dtd' + if not isfile(dtdfile): + raise Exception('unable to find dtdfile') + +destfile = '/tmp/test.xml' +if relative: + dico_dirs = 'tests/flattener_dicos' +else: + dico_dirs = '/usr/share/creole/tests/flattener_dicos' + + +def test_extra_no_action(): + test_dir = join(dico_dirs, '60extra_mandatory') + dirs = [test_dir] + subfolder = join(test_dir, 'subfolder') + if isdir(subfolder): + dirs.append(subfolder) + extra = list() + subfolder = join(test_dir, 'extra_dirs') + load_extra = False + if isdir(subfolder): + load_extra = True + loader.eoleextradico = subfolder + loader.eoledirs = dirs + cfg = loader.creole_loader(load_values=False, load_extra=True) + assert len(list(cfg.cfgimpl_get_values().mandatory_warnings())) == 1 + cfg = loader.creole_loader(load_values=False, load_extra=True, mandatory_permissive=False) + assert len(list(cfg.cfgimpl_get_values().mandatory_warnings())) == 1 + loader.eoleextradico = config.eoleextradico + loader.eoledirs = config.eoledirs + + +def test_extra_action(): + test_dir = join(dico_dirs, '60familyaction_mandatory') + dirs = [test_dir] + subfolder = join(test_dir, 'subfolder') + if isdir(subfolder): + dirs.append(subfolder) + extra = list() + subfolder = join(test_dir, 'extra_dirs') + load_extra = False + if isdir(subfolder): + load_extra = True + loader.eoleextradico = subfolder + loader.eoledirs = dirs + cfg = loader.creole_loader(load_values=False, load_extra=True) + assert len(list(cfg.cfgimpl_get_values().mandatory_warnings())) == 0 + cfg = loader.creole_loader(load_values=False, load_extra=True, mandatory_permissive=False) + assert len(list(cfg.cfgimpl_get_values().mandatory_warnings())) == 1 + loader.eoleextradico = config.eoleextradico + loader.eoledirs = config.eoledirs + + +def test_check_variable(): + test_dir = join(dico_dirs, '10check_option') + dirs = [test_dir] + subfolder = join(test_dir, 'subfolder') + if isdir(subfolder): + dirs.append(subfolder) + extra = list() + subfolder = join(test_dir, 'extra_dirs') + load_extra = False + if isdir(subfolder): + load_extra = True + else: + subfolder = '' + loader.eoleextradico = subfolder + loader.eoledirs = dirs + # + cfg = loader.creole_loader(load_values=False, load_extra=True, rw=True) + assert(ValueError, "cfg.creole.general.int = 150") + cfg.creole.general.int = 50 + # + loader.eoleextradico = config.eoleextradico + loader.eoledirs = config.eoledirs + + +def test_valid_enum_number(): + test_dir = join(dico_dirs, '10valid_enum_number') + dirs = [test_dir] + subfolder = join(test_dir, 'subfolder') + if isdir(subfolder): + dirs.append(subfolder) + loader.eoledirs = dirs + # + cfg = loader.creole_loader(load_values=False, load_extra=False, rw=True) + assert cfg.creole.enumfam.enumvar == 1 + # + loader.eoleextradico = config.eoleextradico + loader.eoledirs = config.eoledirs + + +def test_valid_enum_number(): + test_dir = join(dico_dirs, '10valid_enum_numberdefault') + dirs = [test_dir] + subfolder = join(test_dir, 'subfolder') + if isdir(subfolder): + dirs.append(subfolder) + loader.eoledirs = dirs + # + cfg = loader.creole_loader(load_values=False, load_extra=False, rw=True) + assert cfg.creole.enumfam.enumvar == 3 + # + loader.eoleextradico = config.eoleextradico + loader.eoledirs = config.eoledirs diff --git a/tests/test_packages.py b/tests/test_packages.py new file mode 100644 index 0000000..94a2bc4 --- /dev/null +++ b/tests/test_packages.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +from os.path import isfile +from pyeole.pkg import EolePkg +from pyeole.process import system_out + +def setup_module(module): + """ + Initialisation du cache APT + """ + module.repo = EolePkg("apt") + + +def _test_eole_package(pkgname): + """ + Si le paquet est installé, vérifie que c'est la version EOLE + """ + pkg = repo.get_package(pkgname) + if pkg.installed is None: + print "Le paquet {0} n'est pas installé".format(pkgname) + else: + print "Test du paquet {0}".format(pkgname) + assert pkg.installed.origins[0].origin == 'Eole' + + +def test_eole_packages(): + """ + Paquets recompilés par EOLE + """ + + _test_eole_package('e2guardian') + _test_eole_package('interbase') + _test_eole_package('lightsquid') + _test_eole_package('python-xmlsec') + _test_eole_package('python-m2crypto') + _test_eole_package('smbldap-tools') + _test_eole_package('uucp') + + +def test_apt_changelog(): + """ + is apt changelog working ? + """ + if not isfile('/etc/eole/.instance'): + print "apt changelog n'est pas fonctionnel sur un serveur non instancié" + return + PACKAGES = ['eole-server', 'eole-open-iscsi', 'vim', 'mc'] + for pkgname in PACKAGES: + assert system_out(['apt', 'changelog', pkgname])[0] == 0 + diff --git a/tests/test_services.py b/tests/test_services.py new file mode 100644 index 0000000..65d1772 --- /dev/null +++ b/tests/test_services.py @@ -0,0 +1,19 @@ +#-*-coding:utf-8*-* +from pyeole.process import system_out + +NGINX_TEST = """nginx: the configuration file /etc/nginx/nginx.conf syntax is ok +nginx: configuration file /etc/nginx/nginx.conf test is successful +""" + +def test_nginx(): + """ + Vérifie que la configuration nginx ne signale pas de problème + """ + assert system_out(['nginx', '-t'])[2] == NGINX_TEST + +def test_disabled_services(): + """ + Vérifie que certains services non désirés sont bien désactivés (#17354) + """ + assert system_out(['systemctl', 'is-enabled', 'apt-daily.timer'])[1].rstrip() == "masked" + assert system_out(['systemctl', 'is-enabled', 'apt-daily.service'])[1].rstrip() == "masked" diff --git a/tests/test_upgrade.py b/tests/test_upgrade.py new file mode 100644 index 0000000..e2f3410 --- /dev/null +++ b/tests/test_upgrade.py @@ -0,0 +1,308 @@ +#-*-coding:utf-8*-* +""" +Tests liés à la migration de variables +""" +from os.path import join, isfile +from creole import eosfunc +from creole.loader import creole_loader +from pyeole.log import init_logging + +log=init_logging() + +CONFIG_DIR = '/usr/share/creole/tests/configs' +DICO_DIR = '/usr/share/eole/creole/dicos' + +def _calc_config_file(test): + """ + nom du fichier eol lié au test + """ + return join(CONFIG_DIR, '{0}.eol'.format(test)) + +def _get_value(config, variable): + """ + Retourne la valeur d'une variable "connue" + """ + path = config.find_first(byname=variable, type_='path') + return config.getattr(path, force_permissive=True) + +def _isdico(name): + """ + Vérifie la présence d'un dictionnaire + """ + return isfile(join(DICO_DIR, '{}.xml'.format(name))) + + +def _is_default(config, variable): + option = config.find_first(byname=variable, type_='option') + return config.cfgimpl_get_values().is_default_owner(option) + + +def test_upgrade_hosts_from23(): + """ + Vérifie la migration des variables "activer_ajout_hosts" + depuis une configuration 2.3 contenant des majuscules #11473 + et un doublon sur le nom court #12266 + """ + config = creole_loader(force_configeol=_calc_config_file('hosts23')) + assert _get_value(config, 'activer_ajout_hosts') == 'oui' + assert _get_value(config, 'nom_court_hosts') == ['min', 'maj', 'wpad', None] + assert _get_value(config, 'nom_long_hosts') == ['min.min', 'maj.maj', 'wpad.admin.lan', 'wpad.pedago.lan'] + +def test_upgrade_scribe_dmz(): + """ + Vérifie la migration de la variable "install_scribe_dmz" + en fonction du remplissage des esclaves associées #11713 + ce test n'est pas compatible avec AmonEcole #11796 + """ + if isfile(join(DICO_DIR, '10_era.xml')) and not isfile(join(DICO_DIR, '50_amonecole.xml')): + config = creole_loader(force_configeol=_calc_config_file('scribe_dmz_ok')) + assert _get_value(config, 'install_scribe_dmz') == 'oui' + config = creole_loader(force_configeol=_calc_config_file('scribe_dmz_ko')) + assert _get_value(config, 'install_scribe_dmz') == 'non' + +def test_serveur_maj(): + """ + Vérifie la migration de la variable serveur_maj + Les serveurs officiels doivent être renommés + """ + config = creole_loader(force_configeol=_calc_config_file('maj23')) + assert _get_value(config, 'serveur_maj') == ['test-eole.ac-dijon.fr', 'eole.ac-dijon.fr', 'eoleng.ac-test.fr', 'ftp.crihan.fr'] + + +##################################### +# tests spécifiques à EOLE >= 2.4.2 # +##################################### + +def test_upgrade_force_envole(): + """ + Vérifie la valeur de la redirection par défaut "web_redirection" + dans le cas où Envole était activé #11582 + test modifié suite à la suppression de la variable alias_envole #10549 + """ + if isfile('/usr/share/eole/creole/dicos/20_web.xml'): + config = creole_loader(force_configeol=_calc_config_file('envole')) + if isfile('/usr/share/eole/creole/dicos/21_posh.xml'): + assert _get_value(config, 'web_redirection') == u'/envole' + else: + assert _get_value(config, 'web_redirection') == u'/testenvole' + + +##################################### +# tests spécifiques à EOLE >= 2.5.0 # +##################################### + +def test_upgrade_nut_monitor(): + """ + Vérifie l'activation de la variable "nut_monitor" + si un onduleur esclave était déclaré #11608 + """ + config = creole_loader(force_configeol=_calc_config_file('onduleur24')) + assert _get_value(config, 'nut_monitor') == u'oui' + +def test_upgrade_postgresql(): + """ + Vérifie la mise à jour des variables postgeSQL #11222 + """ + if isfile('/usr/share/eole/creole/dicos/22_postgresql.xml'): + config = creole_loader(force_configeol=_calc_config_file('postgres23_default')) + assert _get_value(config, 'pg_shared_buffers') == 128 + assert _get_value(config, 'pg_shared_buffers_unit') == u'MB' + config = creole_loader(force_configeol=_calc_config_file('postgres23_modif')) + assert _get_value(config, 'pg_shared_buffers') == 6000 + assert _get_value(config, 'pg_shared_buffers_unit') == u'kB' + + +##################################### +# tests spécifiques à EOLE >= 2.5.1 # +##################################### + +def test_upgrade_zone_forward(): + """ + Vérifie l'activation de la variable "activer_zone_forward" + si des zones étaient déclarées #11922 + """ + if isfile('/usr/share/eole/creole/dicos/22_dns.xml'): + config = creole_loader(force_configeol=_calc_config_file('zone_forward24')) + assert _get_value(config, 'activer_zone_forward') == u'oui' + +def test_upgrade_bareos_from23(): + """ + Valide le renommage des variables bacula en bareos + entre 2.3 et 2.5.1 #13957 + """ + if isfile('/usr/share/eole/creole/dicos/23_bareos.xml'): + config = creole_loader(force_configeol=_calc_config_file('bacula23')) + assert _get_value(config, 'bareos_full_retention') == 13 + +def test_upgrade_amon23(): + """ + Valide que la migration des variables "etb1.amon" va à son terme #14589 + """ + if isfile('/usr/share/eole/creole/dicos/30_amon.xml'): + config = creole_loader(force_configeol=_calc_config_file('amon23')) + assert config.impl_get_information('upgrade', False) == '2.3' + assert _get_value(config, 'half_closed_clients') == 'off' + + +##################################### +# tests spécifiques à EOLE >= 2.5.2 # +##################################### + +def test_upgrade_sphynxhamaster(): + """ + Valide la migration des variables haute-dispo + sur le master #14881 + """ + if isfile('/usr/share/eole/creole/dicos/30_sphynx.xml'): + config = creole_loader(force_configeol=_calc_config_file('hamaster241')) + assert _get_value(config, 'activer_haute_dispo') == 'maitre' + assert _get_value(config, 'vip_externe') == '192.168.0.10' + assert _get_value(config, 'vip_interne') == '172.30.101.10' + assert _get_value(config, 'vip_resource_netmask') == ['255.255.255.0', '255.255.255.0'] + assert _get_value(config, 'vip_resource_gw') == ['192.168.0.1', '255.255.255.255'] + assert _get_value(config, 'service_resource_name') == [u'ipsec_rsc', u'arv_rsc'] + assert _get_value(config, 'service_resource_script') == [u'strongswan', u'arv'] + assert _get_value(config, 'service_resource_arv_startdelay') == 30 + assert _get_value(config, 'service_resource_startdelay') == [15, 30] + assert _get_value(config, 'activer_resource_arv') == u'oui' + + +##################################### +# tests spécifiques à EOLE >= 2.6.0 # +##################################### + +def test_upgrade_eth_name(): + """ + Valide la migration des variables faisant référence aux noms des interfaces ethX sur eolebase + """ + config = creole_loader(force_configeol=_calc_config_file('upgrade_eth_name252')) + assert _get_value(config, 'route_int') == ['0', '1', '2', '3', '4'] + if _isdico('20_dhcrelay') and not _isdico('50_amonecole'): + assert _get_value(config, 'dhcrelay_interfaces') == ['1', '2'] + assert _get_value(config, 'dhcrelay_server_interface') == '3' + if _isdico('26_freeradius'): + assert _get_value(config, 'freerad_listen_int') == '2' + if _isdico('20_vpn'): + assert _get_value(config, 'sw_force_ip_src') == '1' + if _isdico('02_haute_dispo'): + assert _get_value(config, 'activer_haute_dispo') == 'maitre' + assert _get_value(config, 'vip_resource_if') == ['0', '1'] + assert _get_value(config, 'corosync_dial_if') == '2' + + +##################################### +# tests spécifiques à EOLE >= 2.6.1 # +##################################### + +def test_upgrade_ntlm(): + """ + Migration des variables NTLM/SMB (#18277) + """ + if isfile('/usr/share/eole/creole/dicos/23_proxy.xml'): + config = creole_loader(force_configeol=_calc_config_file('ntlm')) + assert _get_value(config, 'nom_serveur_smb') == 'scribe' + assert _get_value(config, 'nom_domaine_smb') == 'dompedago' + assert _get_value(config, 'ip_serveur_smb') == '10.1.3.5' + +def test_upgrade_nom_interface(): + """ + Migration des variables nom_carte_ethX + """ + config = creole_loader(force_configeol=_calc_config_file('nom_carte')) + assert _get_value(config, 'nom_carte_eth0') == [eosfunc.get_net_devices()[0]] + assert _get_value(config, 'nom_carte_eth1') == [u'carte1'] + + +##################################### +# tests spécifiques à EOLE >= 2.6.2 # +##################################### + +def test_upgrade_dhcp(): + """ + Valide le remplissage de la nouvelle variable obligatoire nom_plage_dhcp + """ + if isfile('/usr/share/eole/creole/dicos/20_dhcp.xml'): + config = creole_loader(force_configeol=_calc_config_file('plagedhcp'), rw=True) + config.creole.services.activer_dhcp = u'oui' + assert _get_value(config, 'nom_plage_dhcp') == [u'plage0', u'plage1'] + +def test_upgrade_backend_ead(): + """ + Valide le remplissage des nouvelles variables obligatoires ip_frontend_ead_distant_ethX et netmask_frontend_ead_distant_ethX + """ + config = creole_loader(force_configeol=_calc_config_file('config_261')) + assert _get_value(config, 'acces_distant_backend_ead') == 'oui' + if isfile('/usr/share/eole/creole/dicos/28_openvswitch.xml'): + nombre_interfaces = 1 #hack for Hâpy #21039 + else: + nombre_interfaces = int(_get_value(config, 'nombre_interfaces')) + for interface in [str(n) for n in range(nombre_interfaces)]: + variable_frontend = 'frontend_ead_distant_eth' + interface + variable_ip = 'ip_frontend_ead_distant_eth' + interface + variable_netmask = 'netmask_frontend_ead_distant_eth' + interface + assert _get_value(config, variable_frontend) == 'oui' + assert _get_value(config, variable_ip) == [u'0.0.0.0'] + assert _get_value(config, variable_netmask) == [u'0.0.0.0'] + +def test_upgrade_seth(): + """ + Valide les modifications apportées dans le dico AD + - remplissage de la variable oui/non : ad_force_domain_sid (#21295) + - remplissage de la variable oui/non : ad_filter_network (#21324) + - fusion des autorisations de pare-feu (#21324) + """ + if isfile('/usr/share/eole/creole/dicos/25_smb_ad.xml'): + config = creole_loader(force_configeol=_calc_config_file('seth261')) + assert _get_value(config, 'ad_force_domain_sid') == 'oui' + assert _get_value(config, 'ad_filter_network') == 'oui' + # FIXME: doublons ? + assert _get_value(config, 'ad_peer_ip') == [u'1.1.1.1', u'2.2.2.2', u'1.1.1.1', u'3.3.3.0'] + assert _get_value(config, 'ad_peer_netmask') == [u'255.255.255.255', u'255.255.255.255', u'255.255.255.255', u'255.255.255.0'] + +def test_upgrade_squid(): + """ + Valide la transformation des variables Squid passées de minutes en secondes + * connect_timeout is not customised (60s is the new default value) + * peer_connect_timeout was already in seconds + """ + if isfile('/usr/share/eole/creole/dicos/23_proxy.xml'): + config = creole_loader(force_configeol=_calc_config_file('squid261')) + for squidvar in ['forward_timeout', 'connect_timeout', 'peer_connect_timeout', 'read_timeout', 'request_timeout', 'persistent_request_timeout']: + assert _get_value(config, squidvar) == 60 + +def test_upgrade_exim_relay(): + """ + Valide le remplissage des variables exim_relay et exim_relay_dhcp : + - Sur Scribe remplissage à 'oui' + - Sur les autres modules, on garde la valeur par défaut ('non') + """ + config = creole_loader(force_configeol=_calc_config_file('exim_relay_261')) + if isfile('/usr/share/eole/creole/dicos/30_scribe.xml'): + assert _get_value(config, 'exim_relay') == 'oui' + assert _get_value(config, 'exim_relay_dhcp') == 'oui' + elif isfile('/usr/share/eole/creole/dicos/30_seshat.xml'): + assert _get_value(config, 'exim_relay') == 'oui' + else: + assert _get_value(config, 'exim_relay') == 'non' + + +def test_upgrade_cert_empty(): + config = creole_loader(force_configeol=_calc_config_file('certempty_261')) + assert _get_value(config, 'cert_type') == u'autosigné' + assert _is_default(config, 'server_cert') + assert _get_value(config, 'server_cert') == '/etc/ssl/certs/eole.crt' + assert _is_default(config, 'server_key') + assert _get_value(config, 'server_key') == '/etc/ssl/certs/eole.key' + assert _is_default(config, 'server_pem') + assert _get_value(config, 'server_pem') == '/etc/ssl/certs/eole.pem' + + +def test_upgrade_cert(): + config = creole_loader(force_configeol=_calc_config_file('cert_261')) + assert _get_value(config, 'cert_type') == 'manuel' + assert not _is_default(config, 'server_cert') + assert _get_value(config, 'server_cert') == '/etc/ssl/certs/eole.crt' + assert not _is_default(config, 'server_key') + assert _get_value(config, 'server_key') == '/etc/ssl/certs/eole.key' + assert not _is_default(config, 'server_pem') + assert _get_value(config, 'server_pem') == '/etc/ssl/certs/eole.pem' diff --git a/tests/tools/add_to_dico.py b/tests/tools/add_to_dico.py new file mode 100644 index 0000000..177b393 --- /dev/null +++ b/tests/tools/add_to_dico.py @@ -0,0 +1,55 @@ +from lxml import etree +from os import listdir +from os.path import join, isdir + + + + +root_dir = '../flattener_dicos' + +def xml_parse_document(document): + families = document.xpath('variables/family') + for family in families: + if family.attrib['path'] == 'creole.containers': + return + family = etree.Element('family', hidden="True", icon="puzzle-piece", mode="expert", name="Containers", path="creole.containers") + variable = etree.SubElement(family, 'variable', auto_freeze="False", auto_save="False", description="Bridge IP address", disabled="False", hidden="True", mandatory="False", mode="expert", multi="False", name="adresse_ip_br0", path="creole.containers.adresse_ip_br0", type="string") + value = etree.SubElement(variable, 'value') + value.text = '127.0.0.1' + variable = etree.SubElement(family, 'variable', auto_freeze="False", auto_save="False", description="Bridge IP subnet mask", disabled="False", hidden="True", mandatory="False", mode="expert", multi="False", name="adresse_netmask_br0", path="creole.containers.adresse_netmask_br0", type="string") + value = etree.SubElement(variable, 'value') + value.text = '255.0.0.0' + variable = etree.SubElement(family, 'variable', auto_freeze="False", auto_save="False", description="Bridge IP network_br0 address", disabled="False", hidden="True", mandatory="False", mode="expert", multi="False", name="adresse_network_br0", path="creole.containers.adresse_network_br0", type="string") + value = etree.SubElement(variable, 'value') + value.text = '127.0.0.0' + variable = etree.SubElement(family, 'variable', auto_freeze="False", auto_save="False", description="Bridge broadcast IP address", disabled="False", hidden="True", mandatory="False", mode="expert", multi="False", name="adresse_broadcast_br0", path="creole.containers.adresse_broadcast_br0", type="string") + value = etree.SubElement(variable, 'value') + value.text = '127.255.255.255' + elt = document.xpath('variables')[0] + elt.insert(0, family) + + +def edit(xmlfile): + print('process {}'.format(xmlfile)) + document = etree.parse(xmlfile).getroot() + xml_parse_document(document) + with file(xmlfile, 'w') as fh: + fh.write(etree.tostring(document, pretty_print=True, encoding="UTF-8")) + + +def main(): + for xmldir in listdir(root_dir): + xmldir = join(root_dir, xmldir) + resultdir = join(xmldir, 'result') + #if isdir(xmldir): + # for dico in listdir(xmldir): + # if dico.endswith('.xml'): + # edit(join(xmldir, dico)) + if isdir(resultdir): + for dico in listdir(resultdir): + if dico.endswith('.xml'): + edit(join(resultdir, dico)) + + +if __name__ == "__main__": + main() diff --git a/tests/tools/update_dico_attr.py b/tests/tools/update_dico_attr.py new file mode 100644 index 0000000..5abf304 --- /dev/null +++ b/tests/tools/update_dico_attr.py @@ -0,0 +1,83 @@ +# coding: utf-8 +from lxml import etree +from os import listdir +from os.path import join, isdir + +#update_attrs = {'family': {'hidden': 'False', 'mode': 'normal'}, +# 'variable': {'auto_freeze': 'False', +# 'auto_save': 'False', +# 'disabled': 'False', +# 'hidden': 'False', +# 'mandatory': 'False', +# 'mode': 'normal', +# 'multi': 'False', +# 'remove_check': 'False', +# 'remove_condition': 'False'}, +# 'param': {'hidden': 'True'}, +# 'separator': {'never_hidden': 'False'} +# } +#remove_attrs = {'param': ['optional'], +# 'variable': ['redefine', 'exists']} +#update_attrs = {'check': {'level': 'error'}} +#remove_attrs = {'variable': ['remove_condition']} +update_attrs = {'param': ['pouet']} +remove_attrs = {} +remove_tags = () + +root_dir = '../flattener_dicos' + +def xml_parse_document(document): + for child in document: + if not isinstance(child.tag, str): + continue + #if child.tag in remove_tags: + # etree.SubElement(document, 'containers') + # print list(child) + # #document.remove(child) + # continue + if child.tag in update_attrs: + if child.attrib.get('type') == None: + child.attrib['type'] = 'string' + #for key, value in update_attrs[child.tag].items(): + # if key not in child.attrib: + # child.attrib[key] = value + if child.tag in remove_attrs: + for key in remove_attrs[child.tag]: + if key in child.attrib: + del(child.attrib[key]) + #print(child.tag) + #print(child.attrib) + #if child.text is None: + # text = None + #else: + # text = child.text.strip() + #if text: + # print(text) + if list(child) != []: + ret = xml_parse_document(child) + + +def edit(xmlfile): + print('process {}'.format(xmlfile)) + document = etree.parse(xmlfile).getroot() + xml_parse_document(document) + with file(xmlfile, 'w') as fh: + fh.write(etree.tostring(document, pretty_print=True, encoding="UTF-8")) + + +def main(): + for xmldir in listdir(root_dir): + xmldir = join(root_dir, xmldir) + resultdir = join(xmldir, 'result') + #if isdir(xmldir): + # for dico in listdir(xmldir): + # if dico.endswith('.xml'): + # edit(join(xmldir, dico)) + if isdir(resultdir): + for dico in listdir(resultdir): + if dico.endswith('.xml'): + edit(join(resultdir, dico)) + + +if __name__ == "__main__": + main() diff --git a/translation/creole.pot b/translation/creole.pot new file mode 100644 index 0000000..ef7fe15 --- /dev/null +++ b/translation/creole.pot @@ -0,0 +1,2083 @@ +# SOME DESCRIPTIVE TITLE. +# This file is put in the public domain. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: creole\n" +"Report-Msgid-Bugs-To: eole@ac-dijon.fr\n" +"POT-Creation-Date: 2017-12-11 10:20+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: bin/Maj-Auto:66 creole/reconfigure.py:185 +msgid "! Abandoning configuration !" +msgstr "" + +#: bin/Maj-Auto:67 creole/reconfigure.py:186 +msgid "" +"System may be in an incoherent state.\n" +"\n" +msgstr "" + +#: bin/Maj-Auto:75 +msgid "Manage EOLE server automatic update" +msgstr "" + +#: bin/Maj-Auto:81 bin/Maj-Release:35 +msgid "show this help message and exit" +msgstr "" + +#: bin/Maj-Auto:84 +msgid "run in dry-run mode (force to True when using Query-Auto)." +msgstr "" + +#: bin/Maj-Auto:87 +msgid "bypass Zephir authorizations." +msgstr "" + +#: bin/Maj-Auto:90 +msgid "update your server without any confirmation." +msgstr "" + +#: bin/Maj-Auto:94 +msgid "ask apt-get to simulate packages installation" +msgstr "" + +#: bin/Maj-Auto:101 +msgid "use testing packages." +msgstr "" + +#: bin/Maj-Auto:105 +msgid "use development packages." +msgstr "" + +#: bin/Maj-Auto:113 +msgid "run reconfigure on successful upgrade." +msgstr "" + +#: bin/Maj-Auto:117 +msgid "" +"run reconfigure on successful upgrade and reboot if necessary (implies -r)." +msgstr "" + +#: bin/Maj-Auto:119 +msgid "only download packages in cache." +msgstr "" + +#: bin/Maj-Auto:122 +msgid "EOLE repository server." +msgstr "" + +#: bin/Maj-Auto:124 +msgid "Ubuntu repository server." +msgstr "" + +#: bin/Maj-Auto:126 +msgid "Envole repository server." +msgstr "" + +#: bin/Maj-Auto:128 +msgid "use CDROM as source." +msgstr "" + +#: bin/Maj-Auto:132 +msgid "specific output for EAD." +msgstr "" + +#: bin/Maj-Auto:135 +msgid "ignore local configuration if creoled not responding." +msgstr "" + +#: bin/Maj-Auto:182 +#, python-brace-format +msgid "Update at {0}" +msgstr "" + +#: bin/Maj-Auto:234 +msgid "Unknown release number" +msgstr "" + +#: bin/Maj-Auto:247 +msgid "Update is locked, please contact Zéphir administrator" +msgstr "" + +#: bin/Maj-Auto:248 creole/reconfigure.py:313 +msgid "Use -f option if you want to force execution" +msgstr "" + +#: bin/Maj-Auto:280 +msgid "(CHANGE RELEASE LEVEL)" +msgstr "" + +#: bin/Maj-Auto:282 +msgid "(UNSTABLE VERSION)" +msgstr "" + +#: bin/Maj-Auto:284 +msgid "(TESTING VERSION)" +msgstr "" + +#: bin/Maj-Auto:287 +#, python-brace-format +msgid "{0} - Raising update level may prevent lowering back to stable version." +msgstr "" + +#: bin/Maj-Auto:290 +msgid "Do you wish to proceed?" +msgstr "" + +#: bin/Maj-Auto:295 +msgid "Cancelling!" +msgstr "" + +#: bin/Maj-Auto:330 bin/Maj-Auto:374 +msgid "Update successful." +msgstr "" + +#: bin/Maj-Auto:331 +msgid "Nothing to install." +msgstr "" + +#: bin/Maj-Auto:339 +#, python-brace-format +msgid "{0} new," +msgid_plural "{0} news," +msgstr[0] "" +msgstr[1] "" + +#: bin/Maj-Auto:340 +#, python-brace-format +msgid "{0} upgrade," +msgid_plural "{0} upgrades," +msgstr[0] "" +msgstr[1] "" + +#: bin/Maj-Auto:341 +#, python-brace-format +msgid "{0} delete" +msgid_plural "{0} deletes" +msgstr[0] "" +msgstr[1] "" + +#: bin/Maj-Auto:383 +msgid "Upgrade post Maj-Release, please wait" +msgstr "" + +#: bin/Maj-Auto:389 +msgid "error in post maj release" +msgstr "" + +#: bin/Maj-Auto:402 +msgid "" +"At least one packages has been updated, use command [reconfigure] to apply " +"modifications." +msgstr "" + +#: bin/Maj-Auto:415 +msgid "" +". If restarting creoled service does not help, try {} command with '-i' " +"option." +msgstr "" + +#: bin/Maj-Release:28 bin/Maj-Release:50 +msgid "This script will upgrade to a new release of this distribution" +msgstr "" + +#: bin/Maj-Release:37 +msgid "Target release number" +msgstr "" + +#: bin/Maj-Release:40 +msgid "Do not ask confirmation" +msgstr "" + +#: bin/Maj-Release:56 +msgid "No stable new release available" +msgstr "" + +#: bin/Maj-Release:68 +msgid "q|quit: abort" +msgstr "" + +#: bin/Maj-Release:73 +msgid "" +"\n" +"Upgrade aborted by user" +msgstr "" + +#: bin/Maj-Release:87 +msgid "Voluntary stay of proceedings" +msgstr "" + +#: bin/Maj-Release:90 bin/Maj-Release:97 +#, python-brace-format +msgid "Invalid response: {0}" +msgstr "" + +#: creole/annotator.py:255 creole/var_loader.py:519 +msgid "Bridge IP address" +msgstr "" + +#: creole/annotator.py:260 creole/var_loader.py:521 +msgid "Bridge IP subnet mask" +msgstr "" + +#: creole/annotator.py:274 creole/var_loader.py:525 +msgid "Bridge broadcast IP address" +msgstr "" + +#: creole/annotator.py:372 +msgid "{} family already exists" +msgstr "" + +#: creole/annotator.py:378 creole/var_loader.py:582 +msgid "Containers informations" +msgstr "" + +#: creole/annotator.py:417 +msgid "the container \"{}\" does not exist" +msgstr "" + +#: creole/annotator.py:419 +msgid "mandatory attribute \"id\" missing for container \"{}\"" +msgstr "" + +#: creole/annotator.py:423 +msgid "" +"attribute \"id\" must be unique, but \"{}\" is used for containers \"{}\" " +"and \"{}\"" +msgstr "" + +#: creole/annotator.py:437 creole/var_loader.py:549 creole/var_loader.py:568 +#, python-brace-format +msgid "Path of container {0}" +msgstr "" + +#: creole/annotator.py:453 creole/var_loader.py:559 +#, python-brace-format +msgid "Group name of container {0}" +msgstr "" + +#: creole/annotator.py:620 +msgid "attribute {} already exists for {}" +msgstr "" + +#: creole/annotator.py:625 +msgid "attribute node_name or name_type already exists for {}" +msgstr "" + +#: creole/annotator.py:788 +msgid "only one action allow for {}" +msgstr "" + +#: creole/annotator.py:826 +msgid "No configuration variables available in the configuration set" +msgstr "" + +#: creole/annotator.py:837 +msgid "valid_enum sets for unknown variables {}" +msgstr "" + +#: creole/annotator.py:910 +msgid "the variable {} in a group must be multi" +msgstr "" + +#: creole/annotator.py:917 +msgid "cannot found a master {} nor a slave {}" +msgstr "" + +#: creole/annotator.py:1048 +msgid "master/slaves {} could not be auto_save" +msgstr "" + +#: creole/annotator.py:1052 +msgid "master/slaves {} could not be auto_freeze" +msgstr "" + +#: creole/annotator.py:1101 +msgid "cannot set valid enum for variable with type {}" +msgstr "" + +#: creole/annotator.py:1111 creole/annotator.py:1133 +msgid "empty valid enum is not allowed for variable {}" +msgstr "" + +#: creole/annotator.py:1130 +msgid "" +"value \"{}\" of variable \"{}\" is not in list of all expected values ({})" +msgstr "" + +#: creole/annotator.py:1198 +msgid "An auto or fill already exists for the target: {}" +msgstr "" + +#: creole/annotator.py:1218 +msgid "variable with auto value cannot be auto_freeze" +msgstr "" + +#: creole/annotator.py:1221 +msgid "variable with auto value cannot be auto_save" +msgstr "" + +#: creole/annotator.py:1246 +msgid "{} already has a separator" +msgstr "" + +#: creole/annotator.py:1256 creole/annotator.py:1414 +msgid "All '{}' variables shall be set in order to calculate {}" +msgstr "" + +#: creole/annotator.py:1260 +msgid "The function {} is unknown" +msgstr "" + +#: creole/annotator.py:1262 +msgid "Function {} shall return a list" +msgstr "" + +#: creole/annotator.py:1282 +msgid "cannot use {} type as a param in check for {}" +msgstr "" + +#: creole/annotator.py:1344 +msgid "cannot load checkval value for variable {}: {}" +msgstr "" + +#: creole/annotator.py:1349 +msgid "cannot set more than one param for valid_enum for variable {}" +msgstr "" + +#: creole/annotator.py:1357 +msgid "cannot load value for variable {}: {}" +msgstr "" + +#: creole/annotator.py:1365 +msgid "valid_enum already set for {}" +msgstr "" + +#: creole/annotator.py:1409 +msgid "cannot use {} type as a param in a fill/auto" +msgstr "" + +#: creole/annotator.py:1448 +msgid "cannot found family {}" +msgstr "" + +#: creole/annotator.py:1581 +msgid "cannot use {} type as a param in a condition" +msgstr "" + +#: creole/cert.py:57 +msgid "! Error while generating entropy file !" +msgstr "" + +#: creole/cert.py:94 +#, python-brace-format +msgid "! Error while generating ssl key in {0} !" +msgstr "" + +#: creole/cert.py:107 creole/cert.py:114 creole/cert.py:121 creole/cert.py:128 +#: creole/cert.py:135 creole/cert.py:142 +#, python-brace-format +msgid "" +"\n" +"! Rights on {0} can't be modified" +msgstr "" + +#: creole/cert.py:201 +msgid "Certificate chain incomplete." +msgstr "" + +#: creole/cert.py:231 +#, python-brace-format +msgid "Error: file {0} does not exist" +msgstr "" + +#: creole/cert.py:307 creole/cert.py:358 +#, python-brace-format +msgid "" +"Certificate configuration template can not be found:\n" +"\t{0}\n" +msgstr "" + +#: creole/cert.py:309 +msgid "Generating CA certificate" +msgstr "" + +#: creole/cert.py:315 +msgid "Error while generating CA" +msgstr "" + +#: creole/cert.py:326 +msgid "Generating certificate revocation list (CRL)" +msgstr "" + +#: creole/cert.py:330 +#, python-brace-format +msgid "Error while generating CRL ({0}/eole.crl)" +msgstr "" + +#: creole/cert.py:373 creole/cert.py:375 +#, python-brace-format +msgid "Folder {0} does not exist." +msgstr "" + +#: creole/cert.py:390 +#, python-brace-format +msgid "! Error while generating certificate request {0} !" +msgstr "" + +#: creole/cert.py:403 +#, python-brace-format +msgid "! Error while signing certificate request {0} !" +msgstr "" + +#: creole/cert.py:404 +#, python-brace-format +msgid "* Certificate {0} successfully generated" +msgstr "" + +#: creole/cert.py:543 creole/cert.py:571 +msgid "cert or certfile must be None" +msgstr "" + +#: creole/cert.py:545 creole/cert.py:573 +msgid "cert or certfile must be set" +msgstr "" + +#: creole/cert.py:554 creole/cert.py:582 +#, python-brace-format +msgid "error in {0}: {1}" +msgstr "" + +#: creole/cert.py:557 +#, python-brace-format +msgid "Invalid certificate subject: {0} " +msgstr "" + +#: creole/cert.py:585 +#, python-brace-format +msgid "Invalid certificate issuer: {0} " +msgstr "" + +#: creole/client.py:287 +#, python-brace-format +msgid "Connexion error '{0}', retry {1}/{2}" +msgstr "" + +#: creole/client.py:292 +#, python-brace-format +msgid "" +"HTTP error: {0}\n" +"Please check creoled's log (/var/log/rsyslog/local/creoled/creoled.info." +"log)\n" +"and restart service with command 'service creoled start'" +msgstr "" + +#: creole/client.py:294 +#, python-brace-format +msgid "HTTP error: {0}" +msgstr "" + +#: creole/client.py:296 +msgid "creoled service didn't respond in time" +msgstr "" + +#: creole/client.py:323 +#, python-brace-format +msgid "HTML content: {0}" +msgstr "" + +#: creole/client.py:324 +#, python-brace-format +msgid "" +"HTML error {0}, please consult creoled events log (/var/log/rsyslog/local/" +"creoled/creoled.info.log) to have more informations" +msgstr "" + +#: creole/client.py:334 +#, python-brace-format +msgid "Creole error {0}: {1}" +msgstr "" + +#: creole/client.py:356 +#, python-brace-format +msgid "Path must not mix dotted and slash notation: '{0}'" +msgstr "" + +#: creole/client.py:361 +#, python-brace-format +msgid "Path must start with '/': '{0}'" +msgstr "" + +#: creole/client.py:383 +#, python-brace-format +msgid "Too many positional parameters {0}." +msgstr "" + +#: creole/client.py:435 creole/eosfunc.py:58 +#, python-brace-format +msgid "Unknown variable {0}" +msgstr "" + +#: creole/client.py:475 +#, python-brace-format +msgid "No container found for group {0}" +msgstr "" + +#: creole/client.py:477 +msgid "No container found! Is that possible?" +msgstr "" + +#: creole/client.py:498 +#, python-brace-format +msgid "Unknown container {0}" +msgstr "" + +#: creole/client.py:667 creole/client.py:676 +#, python-brace-format +msgid "Unknown container components {0} for container {1}" +msgstr "" + +#: creole/client.py:669 +#, python-brace-format +msgid "Unknown container components {0}" +msgstr "" + +#: creole/client.py:838 +#, python-brace-format +msgid "Error: {0}" +msgstr "" + +#: creole/containers.py:79 +msgid "Invalid LXC lock files state: both are present." +msgstr "" + +#: creole/containers.py:103 +msgid "LXC is enabled but LXC commands not found in PATH." +msgstr "" + +#: creole/containers.py:106 +msgid "" +"Server already instantiated in no containers mode, attempt to activate " +"containers mode aborted." +msgstr "" + +#: creole/containers.py:108 +msgid "" +"Server already instantiated in containers mode, attempt to activate no " +"containers mode aborted." +msgstr "" + +#: creole/containers.py:124 +msgid "" +"cacher not available, please start check log in /var/log/apt-cacher-ng/ and " +"restart it with \"service apt-cacher-ng start\" command" +msgstr "" + +#: creole/containers.py:129 +#, python-brace-format +msgid "Managing container {0}" +msgstr "" + +#: creole/containers.py:135 +#, python-brace-format +msgid "" +"error during the process of container creation, more informations in {0}" +msgstr "" + +#: creole/containers.py:140 +#, python-brace-format +msgid "" +"eole-common-pkg not installed in container, something goes wrong, more " +"informations in {0}" +msgstr "" + +#: creole/containers.py:174 +msgid "Container has no name" +msgstr "" + +#: creole/containers.py:177 +#, python-brace-format +msgid "Container {0} has no IP" +msgstr "" + +#: creole/dtd_parser.py:52 +msgid "Do not write \"ChoiceOption\" in comments" +msgstr "" + +#: creole/dtd_parser.py:56 +msgid "Unvalid comment content: must match a valid attribute name" +msgstr "" + +#: creole/dtd_parser.py:87 +#, python-brace-format +msgid "Using name {0} is forbidden in attributes" +msgstr "" + +#: creole/dtd_parser.py:93 +msgid "Not a valid list" +msgstr "" + +#: creole/eosfunc.py:70 +msgid "Wrong IP address format" +msgstr "" + +#: creole/eosfunc.py:77 +msgid "An IP address is a sequence of four numbers separated by dots." +msgstr "" + +#: creole/eosfunc.py:80 +msgid "Each number is in range [0, 255]." +msgstr "" + +#: creole/eosfunc.py:92 +msgid "Two IP addresses are required." +msgstr "" + +#: creole/eosfunc.py:112 +#, python-brace-format +msgid "Specified network does not match IP address {0}" +msgstr "" + +#: creole/eosfunc.py:145 +msgid "Subnet mask format invalid" +msgstr "" + +#: creole/eosfunc.py:157 +msgid "You must answer 'O' or 'N'" +msgstr "" + +#: creole/eosfunc.py:166 +msgid "Value must be uppercase." +msgstr "" + +#: creole/eosfunc.py:174 +msgid "Value must be lowercase." +msgstr "" + +#: creole/eosfunc.py:188 +msgid "Invalid potential values list" +msgstr "" + +#: creole/eosfunc.py:190 +#, python-brace-format +msgid "Choose one of these options: {0}" +msgstr "" + +#: creole/eosfunc.py:193 +msgid "Invalid syntax" +msgstr "" + +#: creole/eosfunc.py:210 +msgid "A number is required." +msgstr "" + +#: creole/eosfunc.py:213 +#, python-brace-format +msgid "Give an integer greater than {0}" +msgstr "" + +#: creole/eosfunc.py:215 +#, python-brace-format +msgid "Give an integer lesser than {0}" +msgstr "" + +#: creole/eosfunc.py:228 +msgid "" +"valid_len : a length must be given, either an exact length or a maximum or " +"minimum length." +msgstr "" + +#: creole/eosfunc.py:230 +msgid "" +"valid_len : an exact length can not be used with a minimum or a maximum " +"length." +msgstr "" + +#: creole/eosfunc.py:233 +#, python-brace-format +msgid "The exact length of the given variable must be {0}." +msgstr "" + +#: creole/eosfunc.py:236 +#, python-brace-format +msgid "The length of the given variable must be lesser than {0}" +msgstr "" + +#: creole/eosfunc.py:238 +#, python-brace-format +msgid "The length of the given variable must be greater than {0}" +msgstr "" + +#: creole/eosfunc.py:243 +msgid "Value must be either Yes or No." +msgstr "" + +#: creole/eosfunc.py:261 +#, python-brace-format +msgid "Command {0} execution has failed" +msgstr "" + +#: creole/eosfunc.py:266 +#, python-brace-format +msgid "Value must be different from {0}" +msgstr "" + +#: creole/eosfunc.py:277 +#, python-brace-format +msgid "\"{0}\" character is not allowed." +msgstr "" + +#: creole/eosfunc.py:293 +msgid "Domain name is missing a top-level domain (TLD)." +msgstr "" + +#: creole/eosfunc.py:301 +msgid "Aliases must start with a slash (\"/\")." +msgstr "" + +#: creole/eosfunc.py:307 +msgid "Activating Apache is required in order to activate phpMyAdmin." +msgstr "" + +#: creole/eosfunc.py:313 +msgid "SSO service must listen on an interface other than localhost." +msgstr "" + +#: creole/eosfunc.py:316 +#, python-brace-format +msgid "" +"Local SSO service is in conflict with reverse proxy, use IP address {0} " +"instead." +msgstr "" + +#: creole/eosfunc.py:324 +msgid "Value must be of type string." +msgstr "" + +#: creole/eosfunc.py:326 +msgid "Value must be uppercase letters." +msgstr "" + +#: creole/eosfunc.py:340 +#, python-brace-format +msgid "" +"Please activate \"Utilisation du service sso pour les applications de votre " +"serveur Scribe\" before activating {0}." +msgstr "" + +#: creole/eosfunc.py:348 +msgid "This parameter is mandatory." +msgstr "" + +#: creole/eosfunc.py:388 +#, python-brace-format +msgid "Error running command {0} : {1}" +msgstr "" + +#: creole/eosfunc.py:469 creole/eosfunc.py:992 creole/eosfunc.py:1000 +#: creole/eosfunc.py:1012 +#, python-brace-format +msgid "IP or subnet mask invalid ({0}, {1})" +msgstr "" + +#: creole/eosfunc.py:609 +msgid "Operator must be either \"AND\" or \"OR\"" +msgstr "" + +#: creole/eosfunc.py:611 +msgid "eval_match must be either \"True\" or \"False\"" +msgstr "" + +#: creole/eosfunc.py:613 +msgid "eval_mismatch must be either \"True\" or \"False\"" +msgstr "" + +#: creole/eosfunc.py:634 +msgid "Condition keys must start with \"condition\"." +msgstr "" + +#: creole/eosfunc.py:644 +msgid "Conditions and parameters counts do not match in calc_multi_condition." +msgstr "" + +#: creole/eosfunc.py:715 +#, python-brace-format +msgid "LDAP directory of {0}.{1}" +msgstr "" + +#: creole/eosfunc.py:720 +#, python-brace-format +msgid "LDAP directory of {0}" +msgstr "" + +#: creole/eosfunc.py:1300 +msgid "Unknown job type" +msgstr "" + +#: creole/eosfunc.py:1334 +#, python-brace-format +msgid "Disknod '{0}' is not a directory or a device." +msgstr "" + +#: creole/eosfunc.py:1433 +#, python-brace-format +msgid "Error loading custom functions in {0}." +msgstr "" + +#: creole/fonctionseole.py:119 +msgid "Updating Grub configuration" +msgstr "" + +#: creole/fonctionseole.py:131 +msgid "Initramfs missing, generating :" +msgstr "" + +#: creole/fonctionseole.py:189 +#, python-brace-format +msgid "Syslog logging is not working properly: {0}" +msgstr "" + +#: creole/fonctionseole.py:190 +msgid "You may need to start/restart systemd-journald" +msgstr "" + +#: creole/fonctionseole.py:255 +#, python-brace-format +msgid "Checking permissions on Zéphir for {0} impossible." +msgstr "" + +#: creole/fonctionseole.py:256 +#, python-brace-format +msgid "Error message: {0}" +msgstr "" + +#: creole/fonctionseole.py:261 +msgid "Using stored parameters" +msgstr "" + +#: creole/fonctionseole.py:276 +#, python-brace-format +msgid "Updating {0} impossible (insufficient rights)." +msgstr "" + +#: creole/loader.py:84 creole/xmlreflector.py:33 +msgid "no such DTD file: {}" +msgstr "" + +#: creole/loader.py:132 creole/loader.py:358 +msgid "unknown tag {}" +msgstr "" + +#: creole/loader.py:169 +msgid "unknown constraint {}" +msgstr "" + +#: creole/loader.py:185 creole/loader.py:286 +msgid "unknown hidden boolean {}" +msgstr "" + +#: creole/loader.py:192 +msgid "unknown param type {} in fill to {}" +msgstr "" + +#: creole/loader.py:207 +msgid "valid_enum cannot have more than one param for {}" +msgstr "" + +#: creole/loader.py:218 creole/var_loader.py:933 +msgid "valid_differ length should be 1" +msgstr "" + +#: creole/loader.py:230 creole/var_loader.py:937 +msgid "valid_networknetmask length should be 1" +msgstr "" + +#: creole/loader.py:232 creole/var_loader.py:939 +msgid "valid_networknetmask must have only eole variable" +msgstr "" + +#: creole/loader.py:241 creole/var_loader.py:943 +msgid "valid_ipnetmask length should be 1" +msgstr "" + +#: creole/loader.py:243 creole/var_loader.py:945 +msgid "valid_ipnetmask must have only eole variable" +msgstr "" + +#: creole/loader.py:252 creole/var_loader.py:949 +msgid "valid_broadcast length should be 2" +msgstr "" + +#: creole/loader.py:254 creole/var_loader.py:957 +msgid "valid_broadcast must have only eole variable" +msgstr "" + +#: creole/loader.py:264 creole/var_loader.py:961 +msgid "valid_in_network length should be 2" +msgstr "" + +#: creole/loader.py:266 creole/var_loader.py:969 +msgid "valid_in_network must have only eole variable" +msgstr "" + +#: creole/loader.py:311 +msgid "unknown condition type {} for {}" +msgstr "" + +#: creole/loader.py:371 +msgid "variable without family" +msgstr "" + +#: creole/loader.py:417 +msgid "path already loaded {}" +msgstr "" + +#: creole/loader.py:446 +msgid "there is no element for path {}" +msgstr "" + +#: creole/loader.py:472 creole/loader.py:626 +msgid "unknown value {} for {}" +msgstr "" + +#: creole/loader.py:505 +msgid "default value already set for {}" +msgstr "" + +#: creole/loader.py:526 creole/loader.py:648 +msgid "key already exists in information {}" +msgstr "" + +#: creole/loader.py:581 +msgid "cannot create option {}: {}" +msgstr "" + +#: creole/loader.py:600 +msgid "cannot load consistency for {}: {}" +msgstr "" + +#: creole/loader.py:670 +msgid "cannot create optiondescription {}: {}" +msgstr "" + +#: creole/loader.py:715 +msgid "Only creole namespace is supported" +msgstr "" + +#: creole/loader.py:724 creole/loader1.py:408 +#, python-brace-format +msgid "Configuration file unexistent : {0}" +msgstr "" + +#: creole/loader.py:728 creole/loader1.py:412 +msgid "Unable to force_configeol with load_extra." +msgstr "" + +#: creole/loader.py:730 creole/loader1.py:414 +msgid "" +"If force_dirs is defined, namespace must be set to creole and load_extra " +"must be set to False." +msgstr "" + +#: creole/loader.py:758 creole/loader1.py:433 +msgid "Namespace {} for extra dictionary not allowed" +msgstr "" + +#: creole/loader1.py:74 +#, python-brace-format +msgid "Unable to find namespace: {0}" +msgstr "" + +#: creole/loader1.py:292 +msgid "extra name {} not allowed" +msgstr "" + +#: creole/loader1.py:350 creole/loader1.py:376 +msgid "Error when trying to upgrade config file: {}" +msgstr "" + +#: creole/loader1.py:358 +#, python-brace-format +msgid "eol_version ({0}) is greater than current version ({1})" +msgstr "" + +#: creole/loader1.py:416 +msgid "namespace is not creole, so load_extra is forbidden." +msgstr "" + +#: creole/loader1.py:605 +msgid "master's len is lower than the slave variable ({})" +msgstr "" + +#: creole/loader1.py:610 +msgid "owner must be a string for {}" +msgstr "" + +#: creole/loader1.py:626 +msgid "unable to load variable {} with value {}: {}" +msgstr "" + +#: creole/loader1.py:663 creole/loader1.py:741 +msgid "config must have eol_file attribute" +msgstr "" + +#: creole/loader1.py:667 +#, python-brace-format +msgid "Can not find file {0}" +msgstr "" + +#: creole/loader1.py:695 +#, python-brace-format +msgid "Mandatory variable '{0}' from family '{1}' is not set !" +msgstr "" + +#: creole/loader1.py:758 +#, python-brace-format +msgid "Error saving file: {0}" +msgstr "" + +#: creole/lxml_parser.py:24 +#, python-brace-format +msgid "Error while parsing file {0}: {1}" +msgstr "" + +#: creole/lxml_parser.py:36 +#, python-brace-format +msgid "Error while parsing: {0}" +msgstr "" + +#: creole/lxml_parser.py:60 +#, python-brace-format +msgid "Error, var {0} already exists in current dictionaries" +msgstr "" + +#: creole/lxml_parser.py:73 +msgid "Error: extra tags in dictionaries." +msgstr "" + +#: creole/lxml_parser.py:82 +msgid "Error: extra tags in dictionaries." +msgstr "" + +#: creole/lxml_parser.py:87 +#, python-brace-format +msgid "Name '{0}' is not allowed in tag ." +msgstr "" + +#: creole/lxml_parser.py:90 +#, python-brace-format +msgid "There must be only one name '{0}' in a dictionary." +msgstr "" + +#: creole/lxml_parser.py:101 +msgid "Error: extra tags in dictionaries." +msgstr "" + +#: creole/lxml_parser.py:190 creole/lxml_parser.py:197 +#, python-brace-format +msgid "Value {0} not in {1}" +msgstr "" + +#: creole/lxml_parser.py:261 +#, python-brace-format +msgid "Family {0} is set several times." +msgstr "" + +#: creole/lxml_parser.py:303 +#, python-brace-format +msgid "Action Family {0} is set several times." +msgstr "" + +#: creole/lxml_parser.py:310 +msgid "Error: extra tags in dictionaries." +msgstr "" + +#: creole/lxml_parser.py:400 +#, python-brace-format +msgid "Unknown type {0} for condition target." +msgstr "" + +#: creole/lxml_parser.py:406 +#, python-brace-format +msgid "Impossible condition without source for {0}." +msgstr "" + +#: creole/lxml_parser.py:432 +#, python-brace-format +msgid "Invalid help for variable {0}." +msgstr "" + +#: creole/lxml_parser.py:439 +#, python-brace-format +msgid "Invalid help for family {0}" +msgstr "" + +#: creole/maj.py:106 +#, python-brace-format +msgid "An update is scheduled at {0}" +msgstr "" + +#: creole/maj.py:145 +#, python-brace-format +msgid "{0} the {1}" +msgstr "" + +#: creole/objspace.py:167 +msgid "{} is not True or False" +msgstr "" + +#: creole/objspace.py:266 +msgid "Already present in another XML file, {} cannot be re-created" +msgstr "" + +#: creole/objspace.py:274 +msgid "Redefined object: {} does not exist yet" +msgstr "" + +#: creole/objspace.py:314 +msgid "Creole object {} has a wrong type" +msgstr "" + +#: creole/objspace.py:352 +msgid "cannot redefine attribute {} for variable {}" +msgstr "" + +#: creole/objspace.py:359 +msgid "value for {} must be True or False, not {}" +msgstr "" + +#: creole/objspace.py:397 +msgid "Family {} is set several times" +msgstr "" + +#: creole/objspace.py:572 +msgid "" +"A family located in the {} namespace shall not be used in the {} namespace" +msgstr "" + +#: creole/objspace.py:588 +msgid "unknown family {}" +msgstr "" + +#: creole/objspace.py:620 +msgid "" +"A variable located in the {} namespace shall not be used in the {} namespace" +msgstr "" + +#: creole/objspace.py:638 +msgid "Already defined master {} for variable {}" +msgstr "" + +#: creole/objspace.py:651 +msgid "don't set full path variable in creole's namespace (set '{}' not '{}')" +msgstr "" + +#: creole/objspace.py:653 +msgid "unknown option {}" +msgstr "" + +#: creole/reconfigure.py:61 +msgid "" +"For more informations, read section\n" +"'Mise en œuvre des modules EOLE' in module documentation or\n" +"common documentation." +msgstr "" + +#: creole/reconfigure.py:104 +msgid "Applying EOLE configuration." +msgstr "" + +#: creole/reconfigure.py:108 +msgid "leave process in interactive mode" +msgstr "" + +#: creole/reconfigure.py:110 +msgid "override Zéphir lock" +msgstr "" + +#: creole/reconfigure.py:112 +msgid "automatic reboot if necessary" +msgstr "" + +#: creole/reconfigure.py:229 +#, python-brace-format +msgid "Running scripts {0}" +msgstr "" + +#: creole/reconfigure.py:232 +#, python-brace-format +msgid "Error {0}" +msgstr "" + +#: creole/reconfigure.py:242 +msgid "" +"Please check creoled's log (/var/log/rsyslog/local/creoled/creoled.info." +"log)\n" +"and restart service with command 'service creoled start'" +msgstr "" + +#: creole/reconfigure.py:258 +#, python-brace-format +msgid "Preparation for {0}" +msgstr "" + +#: creole/reconfigure.py:261 +msgid "Server is not configured." +msgstr "" + +#: creole/reconfigure.py:265 +#, python-brace-format +msgid "Missing file {0}." +msgstr "" + +#: creole/reconfigure.py:270 +msgid "Server must be instantiated before any reconfiguration can occur." +msgstr "" + +#: creole/reconfigure.py:276 +msgid "Server already instantiated." +msgstr "" + +#: creole/reconfigure.py:278 +msgid "To modify configuration parameter (e.g. IP address), use:" +msgstr "" + +#: creole/reconfigure.py:279 +msgid "'gen_config'" +msgstr "" + +#: creole/reconfigure.py:280 +msgid "then 'reconfigure' to apply changes." +msgstr "" + +#: creole/reconfigure.py:284 +msgid "you have run gen_conteneurs, please use instance instead of reconfigure" +msgstr "" + +#: creole/reconfigure.py:287 +msgid "You have to run gen_conteneurs before instance" +msgstr "" + +#: creole/reconfigure.py:294 +msgid "First instantiate server." +msgstr "" + +#: creole/reconfigure.py:296 +msgid "Proceeding with instantiation ?" +msgstr "" + +#: creole/reconfigure.py:308 +msgid "This process is blocked, contact Zéphir administrator." +msgstr "" + +#: creole/reconfigure.py:309 +msgid "Force execution?" +msgstr "" + +#: creole/reconfigure.py:325 +msgid "Configuration validation problem, please check server configuration." +msgstr "" + +#: creole/reconfigure.py:391 +#, python-brace-format +msgid "Unable to start LXC container : {0}" +msgid_plural "Unable to start LXC containers : {0}" +msgstr[0] "" +msgstr[1] "" + +#: creole/reconfigure.py:406 +msgid "Container mode is disabled." +msgstr "" + +#: creole/reconfigure.py:411 +#, python-brace-format +msgid "" +"container {0} does not already exist, please use gen_conteneurs to create " +"this container" +msgstr "" + +#: creole/reconfigure.py:415 +#, python-brace-format +msgid "Setting up {0}" +msgstr "" + +#: creole/reconfigure.py:423 +msgid "Generating containers" +msgstr "" + +#: creole/reconfigure.py:457 +msgid "Starting containers" +msgstr "" + +#: creole/reconfigure.py:473 +#, python-brace-format +msgid "Can not read file {0}: {1}" +msgstr "" + +#: creole/reconfigure.py:483 +msgid "Removing old linux kernels and associate headers." +msgstr "" + +#: creole/reconfigure.py:490 +#, python-brace-format +msgid "Unable to remove some packages: {0}" +msgstr "" + +#: creole/reconfigure.py:492 +msgid "These packages will be removed next 'reconfigure'" +msgstr "" + +#: creole/reconfigure.py:519 +msgid "Checking Packages for container" +msgstr "" + +#: creole/reconfigure.py:533 +msgid "Managing packages" +msgstr "" + +#: creole/reconfigure.py:534 +msgid " Removing packages" +msgstr "" + +#: creole/reconfigure.py:535 +msgid "Removing packages" +msgstr "" + +#: creole/reconfigure.py:537 +msgid " Installing packages" +msgstr "" + +#: creole/reconfigure.py:538 +msgid "Installing packages" +msgstr "" + +#: creole/reconfigure.py:545 creole/reconfigure.py:546 +msgid "Generating configuration files" +msgstr "" + +#: creole/reconfigure.py:566 +msgid "Stopping services" +msgstr "" + +#: creole/reconfigure.py:570 +msgid "Starting services" +msgstr "" + +#: creole/reconfigure.py:583 +msgid "Configuring services" +msgstr "" + +#: creole/reconfigure.py:585 +#, python-brace-format +msgid "Unknown service action: {0}" +msgstr "" + +#: creole/reconfigure.py:617 +msgid "Managing system user accounts" +msgstr "" + +#: creole/reconfigure.py:625 +msgid "No system user account management in non-interactive mode." +msgstr "" + +#: creole/reconfigure.py:633 +msgid "'root' user unknown. This is abnormal." +msgstr "" + +#: creole/reconfigure.py:638 +msgid "No new EOLE account with /home on NFS" +msgstr "" + +#: creole/reconfigure.py:641 +#, python-brace-format +msgid "Create new administrator user account {0}?" +msgstr "" + +#: creole/reconfigure.py:645 +#, python-brace-format +msgid "Creating unexistent user {0}" +msgstr "" + +#: creole/reconfigure.py:653 +#, python-brace-format +msgid "Unable to create user {0}" +msgstr "" + +#: creole/reconfigure.py:659 +#, python-brace-format +msgid "Unable to add '{0}' to group 'adm'." +msgstr "" + +#: creole/reconfigure.py:666 +#, python-brace-format +msgid "No modification of password of administrator user account {0}." +msgstr "" + +#: creole/reconfigure.py:678 +#, python-brace-format +msgid "# Modificating password for user account {0} #" +msgstr "" + +#: creole/reconfigure.py:685 +msgid "New password" +msgstr "" + +#: creole/reconfigure.py:686 +msgid "Confirming new password" +msgstr "" + +#: creole/reconfigure.py:690 +#, python-brace-format +msgid "Password input errors for {0}. Abandon." +msgstr "" + +#: creole/reconfigure.py:700 +msgid "Can not use default password." +msgstr "" + +#: creole/reconfigure.py:707 +#, python-brace-format +msgid "User {0} password updated." +msgstr "" + +#: creole/reconfigure.py:711 +#, python-brace-format +msgid "Error changing password for {0}." +msgstr "" + +#: creole/reconfigure.py:717 +msgid "Passwords mismatch." +msgstr "" + +#: creole/reconfigure.py:727 +msgid "Managing certificates" +msgstr "" + +#: creole/reconfigure.py:738 +#, python-brace-format +msgid "Error while generating certificates: {0}" +msgstr "" + +#: creole/reconfigure.py:744 +#, python-brace-format +msgid "Copying certificates in {0}" +msgstr "" + +#: creole/reconfigure.py:753 +msgid "Applying kernel parameters" +msgstr "" + +#: creole/reconfigure.py:766 +msgid "Finalizing configuration" +msgstr "" + +#: creole/reconfigure.py:787 creole/reconfigure.py:792 +#: creole/reconfigure.py:794 +#, python-brace-format +msgid "Backup {0} in {1}" +msgstr "" + +#: creole/reconfigure.py:790 +#, python-brace-format +msgid "{0} was not modified" +msgstr "" + +#: creole/reconfigure.py:805 +msgid "Managing update" +msgstr "" + +#: creole/reconfigure.py:807 +msgid "Updating server" +msgstr "" + +#: creole/reconfigure.py:808 +msgid "" +"An update is recommended.\n" +"Do you want to proceed with network update now ?" +msgstr "" + +#: creole/reconfigure.py:834 +msgid "No updates available." +msgstr "" + +#: creole/reconfigure.py:844 +msgid "Task scheduling" +msgstr "" + +#: creole/reconfigure.py:868 +msgid "" +"Reboot is necessary.\n" +"Do you want to reboot now?" +msgstr "" + +#: creole/reconfigure.py:881 +msgid "Reboot necessary" +msgstr "" + +#: creole/reconfigure.py:944 +msgid "Beginning of configuration" +msgstr "" + +#: creole/reconfigure.py:959 creole/reconfigure.py:964 +msgid "eth0 network interface does not have a valid IP address." +msgstr "" + +#: creole/reconfigure.py:960 +msgid "Restarting networking service" +msgstr "" + +#: creole/reconfigure.py:965 +msgid "Unable to obtain IP address." +msgstr "" + +#: creole/reconfigure.py:981 +msgid "Reconfiguration OK" +msgstr "" + +#: creole/server.py:99 +#, python-brace-format +msgid "File not accessible: {0}" +msgstr "" + +#: creole/server.py:103 +#, python-brace-format +msgid "File with null size: {0}" +msgstr "" + +#: creole/server.py:146 +#, python-brace-format +msgid "Reload config.eol due to {0} on {1}" +msgstr "" + +#: creole/server.py:153 +#, python-brace-format +msgid "Filtered inotify event for {0}" +msgstr "" + +#: creole/server.py:170 +msgid "Loading tiramisu configuration" +msgstr "" + +#: creole/server.py:192 +msgid "Load creole configuration with errors" +msgstr "" + +#: creole/server.py:198 +msgid "Unable to load creole configuration: " +msgstr "" + +#: creole/server.py:232 +msgid "Unable to load creole configuration from config.eol: " +msgstr "" + +#: creole/server.py:244 +msgid "Unable to load creole configuration from extra: " +msgstr "" + +#: creole/server.py:272 +msgid "All variables are not set, please configure your system:" +msgstr "" + +#: creole/server.py:277 +msgid "variables are mandatories" +msgstr "" + +#: creole/server.py:288 +msgid "variables must be in config file" +msgstr "" + +#: creole/server.py:350 +#, python-brace-format +msgid "Mandatory variable {0} is not set." +msgstr "" + +#: creole/server.py:429 +msgid "No configuration" +msgstr "" + +#: creole/server.py:460 +msgid "Base directory in which the server is launched (default: /tmp)" +msgstr "" + +#: creole/server.py:464 +msgid "Configuration file of the server (default: /etc/eole/creoled.conf" +msgstr "" + +#: creole/server.py:467 +msgid "Run the server as a daemon (default: false)" +msgstr "" + +#: creole/server.py:470 +msgid "Listen on the specified IP:PORT (default: 127.0.0.1:8000)" +msgstr "" + +#: creole/server.py:473 creole/server.py:478 +msgid "Base under which the application is mounted (default: /)" +msgstr "" + +#: creole/server.py:481 +msgid "User of the running process (default: nobody)" +msgstr "" + +#: creole/server.py:484 +msgid "Group of the running process (default: nogroup)" +msgstr "" + +#: creole/server.py:487 +msgid "Umask of the running process (default: 0644)" +msgstr "" + +#: creole/server.py:593 +msgid "No configuration found: do not check for container mode." +msgstr "" + +#: creole/server.py:608 +#, python-brace-format +msgid "Unable to listen for containers: {0}" +msgstr "" + +#: creole/service.py:8 creole/service.py:16 creole/service.py:28 +#: creole/service.py:40 +msgid "Use new API “manage_services()”" +msgstr "" + +#: creole/template.py:59 +msgid "Group variables must be of type master.slave" +msgstr "" + +#: creole/template.py:239 +msgid "length mismatch" +msgstr "" + +#: creole/template.py:302 +#, python-brace-format +msgid "Patching template '{0}' with '{1}'" +msgstr "" + +#: creole/template.py:306 +#, python-brace-format +msgid "" +"Error applying patch: '{0}'\n" +"To reproduce and fix this error {1}" +msgstr "" + +#: creole/template.py:320 +#, python-brace-format +msgid "Cleaning file '{0}'" +msgstr "" + +#: creole/template.py:325 +#, python-brace-format +msgid "Error removing comments '{0}': {1}" +msgstr "" + +#: creole/template.py:340 +#, python-brace-format +msgid "Template file not enabled: {0}" +msgstr "" + +#: creole/template.py:343 +#, python-brace-format +msgid "Template file not set: {0}" +msgstr "" + +#: creole/template.py:347 +#, python-brace-format +msgid "Template target not set: {0}" +msgstr "" + +#: creole/template.py:364 +#, python-brace-format +msgid "Template {0} unexistent" +msgstr "" + +#: creole/template.py:367 +#, python-brace-format +msgid "Copy template: '{0}' -> '{1}'" +msgstr "" + +#: creole/template.py:383 +#, python-brace-format +msgid "File {0} does not exist." +msgstr "" + +#: creole/template.py:388 +#, python-brace-format +msgid "Folder {0} does not exist but is required by {1}" +msgstr "" + +#: creole/template.py:410 +#, python-brace-format +msgid "Cheetah processing: '{0}' -> '{1}'" +msgstr "" + +#: creole/template.py:429 +#, python-brace-format +msgid "Error: unknown variable used in template {0} : {1}" +msgstr "" + +#: creole/template.py:432 +#, python-brace-format +msgid "Encoding issue detected in template {0}" +msgstr "" + +#: creole/template.py:435 +#, python-brace-format +msgid "Error while instantiating template {0}: {1}" +msgstr "" + +#: creole/template.py:448 +#, python-brace-format +msgid "Unable to write in file '{0}': '{1}'" +msgstr "" + +#: creole/template.py:480 creole/template.py:485 +#, python-brace-format +msgid "Changing properties: {0}" +msgstr "" + +#: creole/template.py:483 creole/template.py:488 +#, python-brace-format +msgid "Error changing properties {0}: {1}" +msgstr "" + +#: creole/template.py:498 +#, python-brace-format +msgid "File '{0}' unexistent." +msgstr "" + +#: creole/template.py:517 +#, python-brace-format +msgid "Removing file '{0}' from container '{1}'" +msgstr "" + +#: creole/template.py:523 +#, python-brace-format +msgid "Instantiation of file '{0}' disabled" +msgstr "" + +#: creole/template.py:525 +#, python-brace-format +msgid "Instantiating file '{0}' from '{1}'" +msgstr "" + +#: creole/template.py:592 +#, python-brace-format +msgid "Removing file '{0}'" +msgstr "" + +#: creole/upgrade.py:104 +#, python-brace-format +msgid "Variable {0} has been copied in {1}" +msgstr "" + +#: creole/upgrade.py:107 creole/upgrade24.py:239 +#, python-brace-format +msgid "Variable {0} has been renamed to {1}" +msgstr "" + +#: creole/upgrade.py:119 +#, python-brace-format +msgid "Variable {0} has been removed" +msgstr "" + +#: creole/upgrade.py:133 +#, python-brace-format +msgid "Source variable {0} invalid" +msgstr "" + +#: creole/upgrade.py:145 creole/upgrade24.py:155 creole/upgrade24.py:173 +#, python-brace-format +msgid "Variable updated: {0} = {1}" +msgstr "" + +#: creole/upgrade.py:167 +msgid "config.eol upgrade started" +msgstr "" + +#: creole/upgrade.py:208 +#, python-brace-format +msgid "Unknown variable: {0}" +msgstr "" + +#: creole/upgrade.py:224 creole/upgrade.py:393 creole/upgrade24.py:287 +#: creole/upgrade24.py:353 creole/upgrade24.py:392 creole/upgrade24.py:419 +#: creole/upgrade24.py:457 creole/upgrade24.py:531 creole/upgrade24.py:583 +#: creole/upgrade24.py:614 +#, python-brace-format +msgid "Starting {0} to {1} upgrade" +msgstr "" + +#: creole/upgrade.py:554 +msgid "Migrating SMTP parameters" +msgstr "" + +#: creole/upgrade.py:581 +msgid "Mail configuration not recognised, not processed" +msgstr "" + +#: creole/upgrade24.py:78 +msgid "get_noncalculated_value_for_auto: unknown variable {}" +msgstr "" + +#: creole/upgrade24.py:149 +#, python-brace-format +msgid "Try to set value to unknown option: {0} = {1}" +msgstr "" + +#: creole/upgrade24.py:167 creole/upgrade24.py:230 +msgid "empty value" +msgstr "" + +#: creole/upgrade24.py:168 creole/upgrade24.py:175 creole/upgrade24.py:179 +#: creole/upgrade24.py:231 +#, python-brace-format +msgid "{0} for {1}" +msgstr "" + +#: creole/upgrade24.py:186 +#, python-brace-format +msgid "Try to delete an unknown option: {0}" +msgstr "" + +#: creole/upgrade24.py:190 +#, python-brace-format +msgid "Variable {0} reinitialized" +msgstr "" + +#: creole/upgrade24.py:199 +#, python-brace-format +msgid "Try to append a value to an unknown option: {0} += {1}" +msgstr "" + +#: creole/upgrade24.py:213 +#, python-brace-format +msgid "Try to modify last value of an unknown option: {0}[-1] = {1}" +msgstr "" + +#: creole/upgrade24.py:306 creole/upgrade24.py:330 +#, python-brace-format +msgid "Invalid value : {0} in old variable {1}" +msgstr "" + +#: creole/upgrade24.py:525 +#, python-brace-format +msgid "Interface {0} name has not an 'ethX' format" +msgstr "" + +#: creole/utils.py:149 +msgid "Choose a number in the list" +msgstr "" + +#: creole/var_loader.py:39 +msgid "mac address" +msgstr "" + +#: creole/var_loader.py:110 +#, python-brace-format +msgid "option {0}'s value should be in {1}" +msgstr "" + +#: creole/var_loader.py:265 +#, python-brace-format +msgid "{0} {1} redefined but unexistent." +msgstr "" + +#: creole/var_loader.py:267 +#, python-brace-format +msgid "{0} {1} existent." +msgstr "" + +#: creole/var_loader.py:306 +#, python-brace-format +msgid "Name ({0}) already used." +msgstr "" + +#: creole/var_loader.py:377 +#, python-brace-format +msgid "Unknown key {0}" +msgstr "" + +#: creole/var_loader.py:402 +msgid "No requires for SymLinkOption" +msgstr "" + +#: creole/var_loader.py:407 +#, python-brace-format +msgid "SymLinkOption targetting unexistent variable: {0}." +msgstr "" + +#: creole/var_loader.py:485 +#, python-brace-format +msgid "Two containers with the same id ({0})" +msgstr "" + +#: creole/var_loader.py:487 +#, python-brace-format +msgid "Multiple ids for the container {0}" +msgstr "" + +#: creole/var_loader.py:523 +msgid "Bridge IP network_br0 address" +msgstr "" + +#: creole/var_loader.py:554 +#, python-brace-format +msgid "IP address of container {0}" +msgstr "" + +#: creole/var_loader.py:661 +#, python-brace-format +msgid "Two variables with the same name ({0})" +msgstr "" + +#: creole/var_loader.py:663 +#, python-brace-format +msgid "Attempt to redefine unexistent variable: {0}." +msgstr "" + +#: creole/var_loader.py:700 +#, python-brace-format +msgid "Redefining multi attribute is not allowed for variable {0}" +msgstr "" + +#: creole/var_loader.py:703 +#, python-brace-format +msgid "Redefining type attribute is not allowed for variable {0}" +msgstr "" + +#: creole/var_loader.py:744 creole/var_loader.py:751 +#, python-brace-format +msgid "help already set for {0}" +msgstr "" + +#: creole/var_loader.py:761 +#, python-brace-format +msgid "More than one separator for {0}" +msgstr "" + +#: creole/var_loader.py:800 +#, python-brace-format +msgid "Unknown condition type for {0}" +msgstr "" + +#: creole/var_loader.py:806 creole/var_loader.py:1530 +#, python-brace-format +msgid "Unknown type {0}" +msgstr "" + +#: creole/var_loader.py:809 +#, python-brace-format +msgid "Unknown hidden {0}" +msgstr "" + +#: creole/var_loader.py:812 +#, python-brace-format +msgid "Unknown name {0}" +msgstr "" + +#: creole/var_loader.py:815 +#, python-brace-format +msgid "Unknown optional {0}" +msgstr "" + +#: creole/var_loader.py:851 +#, python-brace-format +msgid "More than one function for target: {0}" +msgstr "" + +#: creole/var_loader.py:856 +#, python-brace-format +msgid "Can not set level to {0} for this kind of callback" +msgstr "" + +#: creole/var_loader.py:869 +msgid "Namespace different in param not allowed: {} - {}" +msgstr "" + +#: creole/var_loader.py:885 +#, python-brace-format +msgid "Type {0} not yet implemented for {1} for {2}" +msgstr "" + +#: creole/var_loader.py:901 +#, python-brace-format +msgid "Computing function already defined for {0}" +msgstr "" + +#: creole/var_loader.py:1071 +#, python-brace-format +msgid "File {0} does not exist" +msgstr "" + +#: creole/var_loader.py:1086 +msgid "Unable to run read_dir if Config already exists." +msgstr "" + +#: creole/var_loader.py:1112 +#, python-brace-format +msgid "Unable to populate {0}: {1}" +msgstr "" + +#: creole/var_loader.py:1215 +#, python-brace-format +msgid "Condition using unexistent variable {0} as parameter." +msgstr "" + +#: creole/var_loader.py:1246 +#, python-brace-format +msgid "Condition targetting unexistent variable {0}" +msgstr "" + +#: creole/var_loader.py:1250 +#, python-brace-format +msgid "requires already set for this option preventing changing properties {0}" +msgstr "" + +#: creole/var_loader.py:1254 +#, python-brace-format +msgid "requires already set for this option {0}" +msgstr "" + +#: creole/var_loader.py:1345 +#, python-brace-format +msgid "Check using unexistent variable {0} as parameter." +msgstr "" + +#: creole/var_loader.py:1386 +#, python-brace-format +msgid "unknown function {0} in eosfunc" +msgstr "" + +#: creole/var_loader.py:1403 creole/var_loader.py:1416 +#, python-brace-format +msgid "Variable computing function using unknown variable {0}" +msgstr "" + +#: creole/var_loader.py:1492 +msgid "Slave value length can not be greater than 1." +msgstr "" + +#: creole/var_loader.py:1597 creole/var_loader.py:1605 +#, python-brace-format +msgid "{0} is auto, so must not be auto_freeze or auto_save" +msgstr "" + +#: creole/var_loader.py:1700 +#, python-brace-format +msgid "Unknown family {0} has requires" +msgstr "" + +#: creole/xmlreflector.py:46 +msgid "not a valid xml file: {}" +msgstr "" diff --git a/translation/en/creole.po b/translation/en/creole.po new file mode 100644 index 0000000..28861c9 --- /dev/null +++ b/translation/en/creole.po @@ -0,0 +1,2138 @@ +msgid "" +msgstr "" +"Project-Id-Version: creole\n" +"Report-Msgid-Bugs-To: eole@ac-dijon.fr\n" +"POT-Creation-Date: 2017-12-11 10:20+0100\n" +"PO-Revision-Date: 2017-12-11 10:20+0100\n" +"Last-Translator: Équipe EOLE \n" +"Language-Team: Équipe EOLE \n" +"Language: en\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: bin/Maj-Auto:66 creole/reconfigure.py:185 +msgid "! Abandoning configuration !" +msgstr "! Abandoning configuration !" + +#: bin/Maj-Auto:67 creole/reconfigure.py:186 +msgid "" +"System may be in an incoherent state.\n" +"\n" +msgstr "" +"System may be in an incoherent state.\n" +"\n" + +#: bin/Maj-Auto:75 +msgid "Manage EOLE server automatic update" +msgstr "Manage EOLE server automatic update" + +#: bin/Maj-Auto:81 bin/Maj-Release:35 +msgid "show this help message and exit" +msgstr "show this help message and exit" + +#: bin/Maj-Auto:84 +msgid "run in dry-run mode (force to True when using Query-Auto)." +msgstr "run in dry-run mode (force to True when using Query-Auto)." + +#: bin/Maj-Auto:87 +msgid "bypass Zephir authorizations." +msgstr "bypass Zephir authorizations." + +#: bin/Maj-Auto:90 +msgid "update your server without any confirmation." +msgstr "update your server without any confirmation." + +#: bin/Maj-Auto:94 +msgid "ask apt-get to simulate packages installation" +msgstr "ask apt-get to simulate packages installation" + +#: bin/Maj-Auto:101 +msgid "use testing packages." +msgstr "use testing packages." + +#: bin/Maj-Auto:105 +msgid "use development packages." +msgstr "use development packages." + +#: bin/Maj-Auto:113 +msgid "run reconfigure on successful upgrade." +msgstr "run reconfigure on successful upgrade." + +#: bin/Maj-Auto:117 +msgid "" +"run reconfigure on successful upgrade and reboot if necessary (implies -r)." +msgstr "" +"run reconfigure on successful upgrade and reboot if necessary (implies -r)." + +#: bin/Maj-Auto:119 +msgid "only download packages in cache." +msgstr "only download packages in cache." + +#: bin/Maj-Auto:122 +msgid "EOLE repository server." +msgstr "EOLE repository server." + +#: bin/Maj-Auto:124 +msgid "Ubuntu repository server." +msgstr "Ubuntu repository server." + +#: bin/Maj-Auto:126 +msgid "Envole repository server." +msgstr "Envole repository server." + +#: bin/Maj-Auto:128 +msgid "use CDROM as source." +msgstr "use CDROM as source." + +#: bin/Maj-Auto:132 +msgid "specific output for EAD." +msgstr "specific output for EAD." + +#: bin/Maj-Auto:135 +msgid "ignore local configuration if creoled not responding." +msgstr "ignore local configuration if creoled not responding." + +#: bin/Maj-Auto:182 +#, python-brace-format +msgid "Update at {0}" +msgstr "Update at {0}" + +#: bin/Maj-Auto:234 +msgid "Unknown release number" +msgstr "Unknown release number" + +#: bin/Maj-Auto:247 +msgid "Update is locked, please contact Zéphir administrator" +msgstr "Update is locked, please contact Zéphir administrator" + +#: bin/Maj-Auto:248 creole/reconfigure.py:313 +msgid "Use -f option if you want to force execution" +msgstr "Use -f option if you want to force execution" + +#: bin/Maj-Auto:280 +msgid "(CHANGE RELEASE LEVEL)" +msgstr "(CHANGE RELEASE LEVEL)" + +#: bin/Maj-Auto:282 +msgid "(UNSTABLE VERSION)" +msgstr "(UNSTABLE VERSION)" + +#: bin/Maj-Auto:284 +msgid "(TESTING VERSION)" +msgstr "(TESTING VERSION)" + +#: bin/Maj-Auto:287 +#, python-brace-format +msgid "{0} - Raising update level may prevent lowering back to stable version." +msgstr "" +"{0} - Raising update level may prevent lowering back to stable version." + +#: bin/Maj-Auto:290 +msgid "Do you wish to proceed?" +msgstr "Do you wish to proceed?" + +#: bin/Maj-Auto:295 +msgid "Cancelling!" +msgstr "Cancelling!" + +#: bin/Maj-Auto:330 bin/Maj-Auto:374 +msgid "Update successful." +msgstr "Update successful." + +#: bin/Maj-Auto:331 +msgid "Nothing to install." +msgstr "Nothing to install." + +#: bin/Maj-Auto:339 +#, python-brace-format +msgid "{0} new," +msgid_plural "{0} news," +msgstr[0] "{0} new," +msgstr[1] "{0} news," + +#: bin/Maj-Auto:340 +#, python-brace-format +msgid "{0} upgrade," +msgid_plural "{0} upgrades," +msgstr[0] "{0} upgrade," +msgstr[1] "{0} upgrades," + +#: bin/Maj-Auto:341 +#, python-brace-format +msgid "{0} delete" +msgid_plural "{0} deletes" +msgstr[0] "{0} delete" +msgstr[1] "{0} deletes" + +#: bin/Maj-Auto:383 +msgid "Upgrade post Maj-Release, please wait" +msgstr "Upgrade post Maj-Release, please wait" + +#: bin/Maj-Auto:389 +msgid "error in post maj release" +msgstr "error in post maj release" + +#: bin/Maj-Auto:402 +msgid "" +"At least one packages has been updated, use command [reconfigure] to apply " +"modifications." +msgstr "" +"At least one packages has been updated, use command [reconfigure] to apply " +"modifications." + +#: bin/Maj-Auto:415 +msgid "" +". If restarting creoled service does not help, try {} command with '-i' " +"option." +msgstr "" +". If restarting creoled service does not help, try {} command with '-i' " +"option." + +#: bin/Maj-Release:28 bin/Maj-Release:50 +msgid "This script will upgrade to a new release of this distribution" +msgstr "This script will upgrade to a new release of this distribution" + +#: bin/Maj-Release:37 +msgid "Target release number" +msgstr "Target release number" + +#: bin/Maj-Release:40 +msgid "Do not ask confirmation" +msgstr "Do not ask confirmation" + +#: bin/Maj-Release:56 +msgid "No stable new release available" +msgstr "No stable new release available" + +#: bin/Maj-Release:68 +msgid "q|quit: abort" +msgstr "q|quit: abort" + +#: bin/Maj-Release:73 +msgid "" +"\n" +"Upgrade aborted by user" +msgstr "" +"\n" +"Upgrade aborted by user" + +#: bin/Maj-Release:87 +msgid "Voluntary stay of proceedings" +msgstr "Voluntary stay of proceedings" + +#: bin/Maj-Release:90 bin/Maj-Release:97 +#, python-brace-format +msgid "Invalid response: {0}" +msgstr "Invalid response: {0}" + +#: creole/annotator.py:255 creole/var_loader.py:519 +msgid "Bridge IP address" +msgstr "Bridge IP address" + +#: creole/annotator.py:260 creole/var_loader.py:521 +msgid "Bridge IP subnet mask" +msgstr "Bridge IP subnet mask" + +#: creole/annotator.py:274 creole/var_loader.py:525 +msgid "Bridge broadcast IP address" +msgstr "Bridge broadcast IP address" + +#: creole/annotator.py:372 +msgid "{} family already exists" +msgstr "{} family already exists" + +#: creole/annotator.py:378 creole/var_loader.py:582 +msgid "Containers informations" +msgstr "Containers informations" + +#: creole/annotator.py:417 +msgid "the container \"{}\" does not exist" +msgstr "the container \"{}\" does not exist" + +#: creole/annotator.py:419 +msgid "mandatory attribute \"id\" missing for container \"{}\"" +msgstr "mandatory attribute \"id\" missing for container \"{}\"" + +#: creole/annotator.py:423 +msgid "" +"attribute \"id\" must be unique, but \"{}\" is used for containers \"{}\" " +"and \"{}\"" +msgstr "" +"attribute \"id\" must be unique, but \"{}\" is used for containers \"{}\" " +"and \"{}\"" + +#: creole/annotator.py:437 creole/var_loader.py:549 creole/var_loader.py:568 +#, python-brace-format +msgid "Path of container {0}" +msgstr "Path of container {0}" + +#: creole/annotator.py:453 creole/var_loader.py:559 +#, python-brace-format +msgid "Group name of container {0}" +msgstr "Group name of container {0}" + +#: creole/annotator.py:620 +msgid "attribute {} already exists for {}" +msgstr "attribute {} already exists for {}" + +#: creole/annotator.py:625 +msgid "attribute node_name or name_type already exists for {}" +msgstr "attribute node_name or name_type already exists for {}" + +#: creole/annotator.py:788 +msgid "only one action allow for {}" +msgstr "only one action allow for {}" + +#: creole/annotator.py:826 +msgid "No configuration variables available in the configuration set" +msgstr "No configuration variables available in the configuration set" + +#: creole/annotator.py:837 +msgid "valid_enum sets for unknown variables {}" +msgstr "valid_enum sets for unknown variables {}" + +#: creole/annotator.py:910 +msgid "the variable {} in a group must be multi" +msgstr "the variable {} in a group must be multi" + +#: creole/annotator.py:917 +msgid "cannot found a master {} nor a slave {}" +msgstr "cannot found a master {} nor a slave {}" + +#: creole/annotator.py:1048 +msgid "master/slaves {} could not be auto_save" +msgstr "master/slaves {} could not be auto_save" + +#: creole/annotator.py:1052 +msgid "master/slaves {} could not be auto_freeze" +msgstr "master/slaves {} could not be auto_freeze" + +#: creole/annotator.py:1101 +msgid "cannot set valid enum for variable with type {}" +msgstr "cannot set valid enum for variable with type {}" + +#: creole/annotator.py:1111 creole/annotator.py:1133 +msgid "empty valid enum is not allowed for variable {}" +msgstr "empty valid enum is not allowed for variable {}" + +#: creole/annotator.py:1130 +msgid "" +"value \"{}\" of variable \"{}\" is not in list of all expected values ({})" +msgstr "" +"value \"{}\" of variable \"{}\" is not in list of all expected values ({})" + +#: creole/annotator.py:1198 +msgid "An auto or fill already exists for the target: {}" +msgstr "An auto or fill already exists for the target: {}" + +#: creole/annotator.py:1218 +msgid "variable with auto value cannot be auto_freeze" +msgstr "variable with auto value cannot be auto_freeze" + +#: creole/annotator.py:1221 +msgid "variable with auto value cannot be auto_save" +msgstr "variable with auto value cannot be auto_save" + +#: creole/annotator.py:1246 +msgid "{} already has a separator" +msgstr "{} already has a separator" + +#: creole/annotator.py:1256 creole/annotator.py:1414 +msgid "All '{}' variables shall be set in order to calculate {}" +msgstr "All '{}' variables shall be set in order to calculate {}" + +#: creole/annotator.py:1260 +msgid "The function {} is unknown" +msgstr "The function {} is unknown" + +#: creole/annotator.py:1262 +msgid "Function {} shall return a list" +msgstr "Function {} shall return a list" + +#: creole/annotator.py:1282 +msgid "cannot use {} type as a param in check for {}" +msgstr "cannot use {} type as a param in check for {}" + +#: creole/annotator.py:1344 +msgid "cannot load checkval value for variable {}: {}" +msgstr "cannot load checkval value for variable {}: {}" + +#: creole/annotator.py:1349 +msgid "cannot set more than one param for valid_enum for variable {}" +msgstr "cannot set more than one param for valid_enum for variable {}" + +#: creole/annotator.py:1357 +msgid "cannot load value for variable {}: {}" +msgstr "cannot load value for variable {}: {}" + +#: creole/annotator.py:1365 +msgid "valid_enum already set for {}" +msgstr "valid_enum already set for {}" + +#: creole/annotator.py:1409 +msgid "cannot use {} type as a param in a fill/auto" +msgstr "cannot use {} type as a param in a fill/auto" + +#: creole/annotator.py:1448 +msgid "cannot found family {}" +msgstr "cannot found family {}" + +#: creole/annotator.py:1581 +msgid "cannot use {} type as a param in a condition" +msgstr "cannot use {} type as a param in a condition" + +#: creole/cert.py:57 +msgid "! Error while generating entropy file !" +msgstr "! Error while generating entropy file !" + +#: creole/cert.py:94 +#, python-brace-format +msgid "! Error while generating ssl key in {0} !" +msgstr "! Error while generating ssl key in {0} !" + +#: creole/cert.py:107 creole/cert.py:114 creole/cert.py:121 creole/cert.py:128 +#: creole/cert.py:135 creole/cert.py:142 +#, python-brace-format +msgid "" +"\n" +"! Rights on {0} can't be modified" +msgstr "" +"\n" +"! Rights on {0} can't be modified" + +#: creole/cert.py:201 +msgid "Certificate chain incomplete." +msgstr "Certificate chain incomplete." + +#: creole/cert.py:231 +#, python-brace-format +msgid "Error: file {0} does not exist" +msgstr "Error: file {0} does not exist" + +#: creole/cert.py:307 creole/cert.py:358 +#, python-brace-format +msgid "" +"Certificate configuration template can not be found:\n" +"\t{0}\n" +msgstr "" +"Certificate configuration template can not be found:\n" +"\t{0}\n" + +#: creole/cert.py:309 +msgid "Generating CA certificate" +msgstr "Generating CA certificate" + +#: creole/cert.py:315 +msgid "Error while generating CA" +msgstr "Error while generating CA" + +#: creole/cert.py:326 +msgid "Generating certificate revocation list (CRL)" +msgstr "Generating certificate revocation list (CRL)" + +#: creole/cert.py:330 +#, python-brace-format +msgid "Error while generating CRL ({0}/eole.crl)" +msgstr "Error while generating CRL ({0}/eole.crl)" + +#: creole/cert.py:373 creole/cert.py:375 +#, python-brace-format +msgid "Folder {0} does not exist." +msgstr "Folder {0} does not exist." + +#: creole/cert.py:390 +#, python-brace-format +msgid "! Error while generating certificate request {0} !" +msgstr "! Error while generating certificate request {0} !" + +#: creole/cert.py:403 +#, python-brace-format +msgid "! Error while signing certificate request {0} !" +msgstr "! Error while signing certificate request {0} !" + +#: creole/cert.py:404 +#, python-brace-format +msgid "* Certificate {0} successfully generated" +msgstr "* Certificate {0} successfully generated" + +#: creole/cert.py:543 creole/cert.py:571 +msgid "cert or certfile must be None" +msgstr "cert or certfile must be None" + +#: creole/cert.py:545 creole/cert.py:573 +msgid "cert or certfile must be set" +msgstr "cert or certfile must be set" + +#: creole/cert.py:554 creole/cert.py:582 +#, python-brace-format +msgid "error in {0}: {1}" +msgstr "error in {0}: {1}" + +#: creole/cert.py:557 +#, python-brace-format +msgid "Invalid certificate subject: {0} " +msgstr "Invalid certificate subject: {0} " + +#: creole/cert.py:585 +#, python-brace-format +msgid "Invalid certificate issuer: {0} " +msgstr "Invalid certificate issuer: {0} " + +#: creole/client.py:287 +#, python-brace-format +msgid "Connexion error '{0}', retry {1}/{2}" +msgstr "Connexion error '{0}', retry {1}/{2}" + +#: creole/client.py:292 +#, python-brace-format +msgid "" +"HTTP error: {0}\n" +"Please check creoled's log (/var/log/rsyslog/local/creoled/creoled.info." +"log)\n" +"and restart service with command 'service creoled start'" +msgstr "" +"HTTP error: {0}\n" +"Please check creoled's log (/var/log/rsyslog/local/creoled/creoled.info." +"log)\n" +"and restart service with command 'service creoled start'" + +#: creole/client.py:294 +#, python-brace-format +msgid "HTTP error: {0}" +msgstr "HTTP error: {0}" + +#: creole/client.py:296 +msgid "creoled service didn't respond in time" +msgstr "creoled service didn't respond in time" + +#: creole/client.py:323 +#, python-brace-format +msgid "HTML content: {0}" +msgstr "HTML content: {0}" + +#: creole/client.py:324 +#, python-brace-format +msgid "" +"HTML error {0}, please consult creoled events log (/var/log/rsyslog/local/" +"creoled/creoled.info.log) to have more informations" +msgstr "" +"HTML error {0}, please consult creoled events log (/var/log/rsyslog/local/" +"creoled/creoled.info.log) to have more informations" + +#: creole/client.py:334 +#, python-brace-format +msgid "Creole error {0}: {1}" +msgstr "Creole error {0}: {1}" + +#: creole/client.py:356 +#, python-brace-format +msgid "Path must not mix dotted and slash notation: '{0}'" +msgstr "Path must not mix dotted and slash notation: '{0}'" + +#: creole/client.py:361 +#, python-brace-format +msgid "Path must start with '/': '{0}'" +msgstr "Path must start with '/': '{0}'" + +#: creole/client.py:383 +#, python-brace-format +msgid "Too many positional parameters {0}." +msgstr "Too many positional parameters {0}." + +#: creole/client.py:435 creole/eosfunc.py:58 +#, python-brace-format +msgid "Unknown variable {0}" +msgstr "Unknown variable {0}" + +#: creole/client.py:475 +#, python-brace-format +msgid "No container found for group {0}" +msgstr "No container found for group {0}" + +#: creole/client.py:477 +msgid "No container found! Is that possible?" +msgstr "No container found! Is that possible?" + +#: creole/client.py:498 +#, python-brace-format +msgid "Unknown container {0}" +msgstr "Unknown container {0}" + +#: creole/client.py:667 creole/client.py:676 +#, python-brace-format +msgid "Unknown container components {0} for container {1}" +msgstr "Unknown container components {0} for container {1}" + +#: creole/client.py:669 +#, python-brace-format +msgid "Unknown container components {0}" +msgstr "Unknown container components {0}" + +#: creole/client.py:838 +#, python-brace-format +msgid "Error: {0}" +msgstr "Error: {0}" + +#: creole/containers.py:79 +msgid "Invalid LXC lock files state: both are present." +msgstr "Invalid LXC lock files state: both are present." + +#: creole/containers.py:103 +msgid "LXC is enabled but LXC commands not found in PATH." +msgstr "LXC is enabled but LXC commands not found in PATH." + +#: creole/containers.py:106 +msgid "" +"Server already instantiated in no containers mode, attempt to activate " +"containers mode aborted." +msgstr "" +"Server already instantiated in no containers mode, attempt to activate " +"containers mode aborted." + +#: creole/containers.py:108 +msgid "" +"Server already instantiated in containers mode, attempt to activate no " +"containers mode aborted." +msgstr "" +"Server already instantiated in containers mode, attempt to activate no " +"containers mode aborted." + +#: creole/containers.py:124 +msgid "" +"cacher not available, please start check log in /var/log/apt-cacher-ng/ and " +"restart it with \"service apt-cacher-ng start\" command" +msgstr "" +"cacher not available, please start check log in /var/log/apt-cacher-ng/ and " +"restart it with \"service apt-cacher-ng start\" command" + +#: creole/containers.py:129 +#, python-brace-format +msgid "Managing container {0}" +msgstr "Managing container {0}" + +#: creole/containers.py:135 +#, python-brace-format +msgid "" +"error during the process of container creation, more informations in {0}" +msgstr "" +"error during the process of container creation, more informations in {0}" + +#: creole/containers.py:140 +#, python-brace-format +msgid "" +"eole-common-pkg not installed in container, something goes wrong, more " +"informations in {0}" +msgstr "" +"eole-common-pkg not installed in container, something goes wrong, more " +"informations in {0}" + +#: creole/containers.py:174 +msgid "Container has no name" +msgstr "Container has no name" + +#: creole/containers.py:177 +#, python-brace-format +msgid "Container {0} has no IP" +msgstr "Container {0} has no IP" + +#: creole/dtd_parser.py:52 +msgid "Do not write \"ChoiceOption\" in comments" +msgstr "Do not write \"ChoiceOption\" in comments" + +#: creole/dtd_parser.py:56 +msgid "Unvalid comment content: must match a valid attribute name" +msgstr "Unvalid comment content: must match a valid attribute name" + +#: creole/dtd_parser.py:87 +#, python-brace-format +msgid "Using name {0} is forbidden in attributes" +msgstr "Using name {0} is forbidden in attributes" + +#: creole/dtd_parser.py:93 +msgid "Not a valid list" +msgstr "Not a valid list" + +#: creole/eosfunc.py:70 +msgid "Wrong IP address format" +msgstr "Wrong IP address format" + +#: creole/eosfunc.py:77 +msgid "An IP address is a sequence of four numbers separated by dots." +msgstr "An IP address is a sequence of four numbers separated by dots." + +#: creole/eosfunc.py:80 +msgid "Each number is in range [0, 255]." +msgstr "Each number is in range [0, 255]." + +#: creole/eosfunc.py:92 +msgid "Two IP addresses are required." +msgstr "Two IP addresses are required." + +#: creole/eosfunc.py:112 +#, python-brace-format +msgid "Specified network does not match IP address {0}" +msgstr "Specified network does not match IP address {0}" + +#: creole/eosfunc.py:145 +msgid "Subnet mask format invalid" +msgstr "Subnet mask format invalid" + +#: creole/eosfunc.py:157 +msgid "You must answer 'O' or 'N'" +msgstr "You must answer 'O' or 'N'" + +#: creole/eosfunc.py:166 +msgid "Value must be uppercase." +msgstr "Value must be uppercase." + +#: creole/eosfunc.py:174 +msgid "Value must be lowercase." +msgstr "Value must be lowercase." + +#: creole/eosfunc.py:188 +msgid "Invalid potential values list" +msgstr "Invalid potential values list" + +#: creole/eosfunc.py:190 +#, python-brace-format +msgid "Choose one of these options: {0}" +msgstr "Choose one of these options: {0}" + +#: creole/eosfunc.py:193 +msgid "Invalid syntax" +msgstr "Invalid syntax" + +#: creole/eosfunc.py:210 +msgid "A number is required." +msgstr "A number is required." + +#: creole/eosfunc.py:213 +#, python-brace-format +msgid "Give an integer greater than {0}" +msgstr "Give an integer greater than {0}" + +#: creole/eosfunc.py:215 +#, python-brace-format +msgid "Give an integer lesser than {0}" +msgstr "Give an integer lesser than {0}" + +#: creole/eosfunc.py:228 +msgid "" +"valid_len : a length must be given, either an exact length or a maximum or " +"minimum length." +msgstr "" +"valid_len : a length must be given, either an exact length or a maximum or " +"minimum length." + +#: creole/eosfunc.py:230 +msgid "" +"valid_len : an exact length can not be used with a minimum or a maximum " +"length." +msgstr "" +"valid_len : an exact length can not be used with a minimum or a maximum " +"length." + +#: creole/eosfunc.py:233 +#, python-brace-format +msgid "The exact length of the given variable must be {0}." +msgstr "The exact length of the given variable must be {0}." + +#: creole/eosfunc.py:236 +#, python-brace-format +msgid "The length of the given variable must be lesser than {0}" +msgstr "The length of the given variable must be lesser than {0}" + +#: creole/eosfunc.py:238 +#, python-brace-format +msgid "The length of the given variable must be greater than {0}" +msgstr "The length of the given variable must be greater than {0}" + +#: creole/eosfunc.py:243 +msgid "Value must be either Yes or No." +msgstr "Value must be either Yes or No." + +#: creole/eosfunc.py:261 +#, python-brace-format +msgid "Command {0} execution has failed" +msgstr "Command {0} execution has failed" + +#: creole/eosfunc.py:266 +#, python-brace-format +msgid "Value must be different from {0}" +msgstr "Value must be different from {0}" + +#: creole/eosfunc.py:277 +#, python-brace-format +msgid "\"{0}\" character is not allowed." +msgstr "\"{0}\" character is not allowed." + +#: creole/eosfunc.py:293 +msgid "Domain name is missing a top-level domain (TLD)." +msgstr "Domain name is missing a top-level domain (TLD)." + +#: creole/eosfunc.py:301 +msgid "Aliases must start with a slash (\"/\")." +msgstr "Aliases must start with a slash (\"/\")." + +#: creole/eosfunc.py:307 +msgid "Activating Apache is required in order to activate phpMyAdmin." +msgstr "Activating Apache is required in order to activate phpMyAdmin." + +#: creole/eosfunc.py:313 +msgid "SSO service must listen on an interface other than localhost." +msgstr "SSO service must listen on an interface other than localhost." + +#: creole/eosfunc.py:316 +#, python-brace-format +msgid "" +"Local SSO service is in conflict with reverse proxy, use IP address {0} " +"instead." +msgstr "" +"Local SSO service is in conflict with reverse proxy, use IP address {0} " +"instead." + +#: creole/eosfunc.py:324 +msgid "Value must be of type string." +msgstr "Value must be of type string." + +#: creole/eosfunc.py:326 +msgid "Value must be uppercase letters." +msgstr "Value must be uppercase letters." + +#: creole/eosfunc.py:340 +#, python-brace-format +msgid "" +"Please activate \"Utilisation du service sso pour les applications de votre " +"serveur Scribe\" before activating {0}." +msgstr "" +"Please activate \"Utilisation du service sso pour les applications de votre " +"serveur Scribe\" before activating {0}." + +#: creole/eosfunc.py:348 +msgid "This parameter is mandatory." +msgstr "This parameter is mandatory." + +#: creole/eosfunc.py:388 +#, python-brace-format +msgid "Error running command {0} : {1}" +msgstr "Error running command {0} : {1}" + +#: creole/eosfunc.py:469 creole/eosfunc.py:992 creole/eosfunc.py:1000 +#: creole/eosfunc.py:1012 +#, python-brace-format +msgid "IP or subnet mask invalid ({0}, {1})" +msgstr "IP or subnet mask invalid ({0}, {1})" + +#: creole/eosfunc.py:609 +msgid "Operator must be either \"AND\" or \"OR\"" +msgstr "Operator must be either \"AND\" or \"OR\"" + +#: creole/eosfunc.py:611 +msgid "eval_match must be either \"True\" or \"False\"" +msgstr "eval_match must be either \"True\" or \"False\"" + +#: creole/eosfunc.py:613 +msgid "eval_mismatch must be either \"True\" or \"False\"" +msgstr "eval_mismatch must be either \"True\" or \"False\"" + +#: creole/eosfunc.py:634 +msgid "Condition keys must start with \"condition\"." +msgstr "Condition keys must start with \"condition\"." + +#: creole/eosfunc.py:644 +msgid "Conditions and parameters counts do not match in calc_multi_condition." +msgstr "Conditions and parameters counts do not match in calc_multi_condition." + +#: creole/eosfunc.py:715 +#, python-brace-format +msgid "LDAP directory of {0}.{1}" +msgstr "LDAP directory of {0}.{1}" + +#: creole/eosfunc.py:720 +#, python-brace-format +msgid "LDAP directory of {0}" +msgstr "LDAP directory of {0}" + +#: creole/eosfunc.py:1300 +msgid "Unknown job type" +msgstr "Unknown job type" + +#: creole/eosfunc.py:1334 +#, python-brace-format +msgid "Disknod '{0}' is not a directory or a device." +msgstr "Disknod '{0}' is not a directory or a device." + +#: creole/eosfunc.py:1433 +#, python-brace-format +msgid "Error loading custom functions in {0}." +msgstr "Error loading custom functions in {0}." + +#: creole/fonctionseole.py:119 +msgid "Updating Grub configuration" +msgstr "Updating Grub configuration" + +#: creole/fonctionseole.py:131 +msgid "Initramfs missing, generating :" +msgstr "Initramfs missing, generating :" + +#: creole/fonctionseole.py:189 +#, python-brace-format +msgid "Syslog logging is not working properly: {0}" +msgstr "Syslog logging is not working properly: {0}" + +#: creole/fonctionseole.py:190 +msgid "You may need to start/restart systemd-journald" +msgstr "You may need to start/restart systemd-journald" + +#: creole/fonctionseole.py:255 +#, python-brace-format +msgid "Checking permissions on Zéphir for {0} impossible." +msgstr "Checking permissions on Zéphir for {0} impossible." + +#: creole/fonctionseole.py:256 +#, python-brace-format +msgid "Error message: {0}" +msgstr "Error message: {0}" + +#: creole/fonctionseole.py:261 +msgid "Using stored parameters" +msgstr "Using stored parameters" + +#: creole/fonctionseole.py:276 +#, python-brace-format +msgid "Updating {0} impossible (insufficient rights)." +msgstr "Updating {0} impossible (insufficient rights)." + +#: creole/loader.py:84 creole/xmlreflector.py:33 +msgid "no such DTD file: {}" +msgstr "no such DTD file: {}" + +#: creole/loader.py:132 creole/loader.py:358 +msgid "unknown tag {}" +msgstr "unknown tag {}" + +#: creole/loader.py:169 +msgid "unknown constraint {}" +msgstr "unknown constraint {}" + +#: creole/loader.py:185 creole/loader.py:286 +msgid "unknown hidden boolean {}" +msgstr "unknown hidden boolean {}" + +#: creole/loader.py:192 +msgid "unknown param type {} in fill to {}" +msgstr "unknown param type {} in fill to {}" + +#: creole/loader.py:207 +msgid "valid_enum cannot have more than one param for {}" +msgstr "valid_enum cannot have more than one param for {}" + +#: creole/loader.py:218 creole/var_loader.py:933 +msgid "valid_differ length should be 1" +msgstr "valid_differ length should be 1" + +#: creole/loader.py:230 creole/var_loader.py:937 +msgid "valid_networknetmask length should be 1" +msgstr "valid_networknetmask length should be 1" + +#: creole/loader.py:232 creole/var_loader.py:939 +msgid "valid_networknetmask must have only eole variable" +msgstr "valid_networknetmask must have only eole variable" + +#: creole/loader.py:241 creole/var_loader.py:943 +msgid "valid_ipnetmask length should be 1" +msgstr "valid_ipnetmask length should be 1" + +#: creole/loader.py:243 creole/var_loader.py:945 +msgid "valid_ipnetmask must have only eole variable" +msgstr "valid_ipnetmask must have only eole variable" + +#: creole/loader.py:252 creole/var_loader.py:949 +msgid "valid_broadcast length should be 2" +msgstr "valid_broadcast length should be 2" + +#: creole/loader.py:254 creole/var_loader.py:957 +msgid "valid_broadcast must have only eole variable" +msgstr "valid_broadcast must have only eole variable" + +#: creole/loader.py:264 creole/var_loader.py:961 +msgid "valid_in_network length should be 2" +msgstr "valid_in_network length should be 2" + +#: creole/loader.py:266 creole/var_loader.py:969 +msgid "valid_in_network must have only eole variable" +msgstr "valid_in_network must have only eole variable" + +#: creole/loader.py:311 +msgid "unknown condition type {} for {}" +msgstr "unknown condition type {} for {}" + +#: creole/loader.py:371 +msgid "variable without family" +msgstr "variable without family" + +#: creole/loader.py:417 +msgid "path already loaded {}" +msgstr "path already loaded {}" + +#: creole/loader.py:446 +msgid "there is no element for path {}" +msgstr "there is no element for path {}" + +#: creole/loader.py:472 creole/loader.py:626 +msgid "unknown value {} for {}" +msgstr "unknown value {} for {}" + +#: creole/loader.py:505 +msgid "default value already set for {}" +msgstr "default value already set for {}" + +#: creole/loader.py:526 creole/loader.py:648 +msgid "key already exists in information {}" +msgstr "key already exists in information {}" + +#: creole/loader.py:581 +msgid "cannot create option {}: {}" +msgstr "cannot create option {}: {}" + +#: creole/loader.py:600 +msgid "cannot load consistency for {}: {}" +msgstr "cannot load consistency for {}: {}" + +#: creole/loader.py:670 +msgid "cannot create optiondescription {}: {}" +msgstr "cannot create optiondescription {}: {}" + +#: creole/loader.py:715 +msgid "Only creole namespace is supported" +msgstr "Only creole namespace is supported" + +#: creole/loader.py:724 creole/loader1.py:408 +#, python-brace-format +msgid "Configuration file unexistent : {0}" +msgstr "Configuration file unexistent : {0}" + +#: creole/loader.py:728 creole/loader1.py:412 +msgid "Unable to force_configeol with load_extra." +msgstr "Unable to force_configeol with load_extra." + +#: creole/loader.py:730 creole/loader1.py:414 +msgid "" +"If force_dirs is defined, namespace must be set to creole and load_extra " +"must be set to False." +msgstr "" +"If force_dirs is defined, namespace must be set to creole and load_extra " +"must be set to False." + +#: creole/loader.py:758 creole/loader1.py:433 +msgid "Namespace {} for extra dictionary not allowed" +msgstr "Namespace {} for extra dictionary not allowed" + +#: creole/loader1.py:74 +#, python-brace-format +msgid "Unable to find namespace: {0}" +msgstr "Unable to find namespace: {0}" + +#: creole/loader1.py:292 +msgid "extra name {} not allowed" +msgstr "extra name {} not allowed" + +#: creole/loader1.py:350 creole/loader1.py:376 +msgid "Error when trying to upgrade config file: {}" +msgstr "Error when trying to upgrade config file: {}" + +#: creole/loader1.py:358 +#, python-brace-format +msgid "eol_version ({0}) is greater than current version ({1})" +msgstr "eol_version ({0}) is greater than current version ({1})" + +#: creole/loader1.py:416 +msgid "namespace is not creole, so load_extra is forbidden." +msgstr "namespace is not creole, so load_extra is forbidden." + +#: creole/loader1.py:605 +msgid "master's len is lower than the slave variable ({})" +msgstr "master's len is lower than the slave variable ({})" + +#: creole/loader1.py:610 +msgid "owner must be a string for {}" +msgstr "owner must be a string for {}" + +#: creole/loader1.py:626 +msgid "unable to load variable {} with value {}: {}" +msgstr "unable to load variable {} with value {}: {}" + +#: creole/loader1.py:663 creole/loader1.py:741 +msgid "config must have eol_file attribute" +msgstr "config must have eol_file attribute" + +#: creole/loader1.py:667 +#, python-brace-format +msgid "Can not find file {0}" +msgstr "Can not find file {0}" + +#: creole/loader1.py:695 +#, python-brace-format +msgid "Mandatory variable '{0}' from family '{1}' is not set !" +msgstr "Mandatory variable '{0}' from family '{1}' is not set !" + +#: creole/loader1.py:758 +#, python-brace-format +msgid "Error saving file: {0}" +msgstr "Error saving file: {0}" + +#: creole/lxml_parser.py:24 +#, python-brace-format +msgid "Error while parsing file {0}: {1}" +msgstr "Error while parsing file {0}: {1}" + +#: creole/lxml_parser.py:36 +#, python-brace-format +msgid "Error while parsing: {0}" +msgstr "Error while parsing: {0}" + +#: creole/lxml_parser.py:60 +#, python-brace-format +msgid "Error, var {0} already exists in current dictionaries" +msgstr "Error, var {0} already exists in current dictionaries" + +#: creole/lxml_parser.py:73 +msgid "Error: extra tags in dictionaries." +msgstr "Error: extra tags in dictionaries." + +#: creole/lxml_parser.py:82 +msgid "Error: extra tags in dictionaries." +msgstr "Error: extra tags in dictionaries." + +#: creole/lxml_parser.py:87 +#, python-brace-format +msgid "Name '{0}' is not allowed in tag ." +msgstr "Name '{0}' is not allowed in tag ." + +#: creole/lxml_parser.py:90 +#, python-brace-format +msgid "There must be only one name '{0}' in a dictionary." +msgstr "There must be only one name '{0}' in a dictionary." + +#: creole/lxml_parser.py:101 +msgid "Error: extra tags in dictionaries." +msgstr "Error: extra tags in dictionaries." + +#: creole/lxml_parser.py:190 creole/lxml_parser.py:197 +#, python-brace-format +msgid "Value {0} not in {1}" +msgstr "Value {0} not in {1}" + +#: creole/lxml_parser.py:261 +#, python-brace-format +msgid "Family {0} is set several times." +msgstr "Family {0} is set several times." + +#: creole/lxml_parser.py:303 +#, python-brace-format +msgid "Action Family {0} is set several times." +msgstr "Action Family {0} is set several times." + +#: creole/lxml_parser.py:310 +msgid "Error: extra tags in dictionaries." +msgstr "Error: extra tags in dictionaries." + +#: creole/lxml_parser.py:400 +#, python-brace-format +msgid "Unknown type {0} for condition target." +msgstr "Unknown type {0} for condition target." + +#: creole/lxml_parser.py:406 +#, python-brace-format +msgid "Impossible condition without source for {0}." +msgstr "Impossible condition without source for {0}." + +#: creole/lxml_parser.py:432 +#, python-brace-format +msgid "Invalid help for variable {0}." +msgstr "Invalid help for variable {0}." + +#: creole/lxml_parser.py:439 +#, python-brace-format +msgid "Invalid help for family {0}" +msgstr "Invalid help for family {0}" + +#: creole/maj.py:106 +#, python-brace-format +msgid "An update is scheduled at {0}" +msgstr "An update is scheduled at {0}" + +#: creole/maj.py:145 +#, python-brace-format +msgid "{0} the {1}" +msgstr "{0} the {1}" + +#: creole/objspace.py:167 +msgid "{} is not True or False" +msgstr "{} is not True or False" + +#: creole/objspace.py:266 +msgid "Already present in another XML file, {} cannot be re-created" +msgstr "Already present in another XML file, {} cannot be re-created" + +#: creole/objspace.py:274 +msgid "Redefined object: {} does not exist yet" +msgstr "Redefined object: {} does not exist yet" + +#: creole/objspace.py:314 +msgid "Creole object {} has a wrong type" +msgstr "Creole object {} has a wrong type" + +#: creole/objspace.py:352 +msgid "cannot redefine attribute {} for variable {}" +msgstr "cannot redefine attribute {} for variable {}" + +#: creole/objspace.py:359 +msgid "value for {} must be True or False, not {}" +msgstr "value for {} must be True or False, not {}" + +#: creole/objspace.py:397 +msgid "Family {} is set several times" +msgstr "Family {} is set several times" + +#: creole/objspace.py:572 +msgid "" +"A family located in the {} namespace shall not be used in the {} namespace" +msgstr "" +"A family located in the {} namespace shall not be used in the {} namespace" + +#: creole/objspace.py:588 +msgid "unknown family {}" +msgstr "unknown family {}" + +#: creole/objspace.py:620 +msgid "" +"A variable located in the {} namespace shall not be used in the {} namespace" +msgstr "" +"A variable located in the {} namespace shall not be used in the {} namespace" + +#: creole/objspace.py:638 +msgid "Already defined master {} for variable {}" +msgstr "Already defined master {} for variable {}" + +#: creole/objspace.py:651 +msgid "don't set full path variable in creole's namespace (set '{}' not '{}')" +msgstr "don't set full path variable in creole's namespace (set '{}' not '{}')" + +#: creole/objspace.py:653 +msgid "unknown option {}" +msgstr "unknown option {}" + +#: creole/reconfigure.py:61 +msgid "" +"For more informations, read section\n" +"'Mise en œuvre des modules EOLE' in module documentation or\n" +"common documentation." +msgstr "" +"For more informations, read section\n" +"'Mise en œuvre des modules EOLE' in module documentation or\n" +"common documentation." + +#: creole/reconfigure.py:104 +msgid "Applying EOLE configuration." +msgstr "Applying EOLE configuration." + +#: creole/reconfigure.py:108 +msgid "leave process in interactive mode" +msgstr "leave process in interactive mode" + +#: creole/reconfigure.py:110 +msgid "override Zéphir lock" +msgstr "override Zéphir lock" + +#: creole/reconfigure.py:112 +msgid "automatic reboot if necessary" +msgstr "automatic reboot if necessary" + +#: creole/reconfigure.py:229 +#, python-brace-format +msgid "Running scripts {0}" +msgstr "Running scripts {0}" + +#: creole/reconfigure.py:232 +#, python-brace-format +msgid "Error {0}" +msgstr "Error {0}" + +#: creole/reconfigure.py:242 +msgid "" +"Please check creoled's log (/var/log/rsyslog/local/creoled/creoled.info." +"log)\n" +"and restart service with command 'service creoled start'" +msgstr "" +"Please check creoled's log (/var/log/rsyslog/local/creoled/creoled.info." +"log)\n" +"and restart service with command 'service creoled start'" + +#: creole/reconfigure.py:258 +#, python-brace-format +msgid "Preparation for {0}" +msgstr "Preparation for {0}" + +#: creole/reconfigure.py:261 +msgid "Server is not configured." +msgstr "Server is not configured." + +#: creole/reconfigure.py:265 +#, python-brace-format +msgid "Missing file {0}." +msgstr "Missing file {0}." + +#: creole/reconfigure.py:270 +msgid "Server must be instantiated before any reconfiguration can occur." +msgstr "Server must be instantiated before any reconfiguration can occur." + +#: creole/reconfigure.py:276 +msgid "Server already instantiated." +msgstr "Server already instantiated." + +#: creole/reconfigure.py:278 +msgid "To modify configuration parameter (e.g. IP address), use:" +msgstr "To modify configuration parameter (e.g. IP address), use:" + +#: creole/reconfigure.py:279 +msgid "'gen_config'" +msgstr "'gen_config'" + +#: creole/reconfigure.py:280 +msgid "then 'reconfigure' to apply changes." +msgstr "then 'reconfigure' to apply changes." + +#: creole/reconfigure.py:284 +msgid "you have run gen_conteneurs, please use instance instead of reconfigure" +msgstr "" +"you have run gen_conteneurs, please use instance instead of reconfigure" + +#: creole/reconfigure.py:287 +msgid "You have to run gen_conteneurs before instance" +msgstr "You have to run gen_conteneurs before instance" + +#: creole/reconfigure.py:294 +msgid "First instantiate server." +msgstr "First instantiate server." + +#: creole/reconfigure.py:296 +msgid "Proceeding with instantiation ?" +msgstr "Proceeding with instantiation ?" + +#: creole/reconfigure.py:308 +msgid "This process is blocked, contact Zéphir administrator." +msgstr "This process is blocked, contact Zéphir administrator." + +#: creole/reconfigure.py:309 +msgid "Force execution?" +msgstr "Force execution?" + +#: creole/reconfigure.py:325 +msgid "Configuration validation problem, please check server configuration." +msgstr "Configuration validation problem, please check server configuration." + +#: creole/reconfigure.py:391 +#, python-brace-format +msgid "Unable to start LXC container : {0}" +msgid_plural "Unable to start LXC containers : {0}" +msgstr[0] "Unable to start LXC container : {0}" +msgstr[1] "Unable to start LXC containers : {0}" + +#: creole/reconfigure.py:406 +msgid "Container mode is disabled." +msgstr "Container mode is disabled." + +#: creole/reconfigure.py:411 +#, python-brace-format +msgid "" +"container {0} does not already exist, please use gen_conteneurs to create " +"this container" +msgstr "" +"container {0} does not already exist, please use gen_conteneurs to create " +"this container" + +#: creole/reconfigure.py:415 +#, python-brace-format +msgid "Setting up {0}" +msgstr "Setting up {0}" + +#: creole/reconfigure.py:423 +msgid "Generating containers" +msgstr "Generating containers" + +#: creole/reconfigure.py:457 +msgid "Starting containers" +msgstr "Starting containers" + +#: creole/reconfigure.py:473 +#, python-brace-format +msgid "Can not read file {0}: {1}" +msgstr "Can not read file {0}: {1}" + +#: creole/reconfigure.py:483 +msgid "Removing old linux kernels and associate headers." +msgstr "Removing old linux kernels and associate headers." + +#: creole/reconfigure.py:490 +#, python-brace-format +msgid "Unable to remove some packages: {0}" +msgstr "Unable to remove some packages: {0}" + +#: creole/reconfigure.py:492 +msgid "These packages will be removed next 'reconfigure'" +msgstr "These packages will be removed next 'reconfigure'" + +#: creole/reconfigure.py:519 +msgid "Checking Packages for container" +msgstr "Checking Packages for container" + +#: creole/reconfigure.py:533 +msgid "Managing packages" +msgstr "Managing packages" + +#: creole/reconfigure.py:534 +msgid " Removing packages" +msgstr " Removing packages" + +#: creole/reconfigure.py:535 +msgid "Removing packages" +msgstr "Removing packages" + +#: creole/reconfigure.py:537 +msgid " Installing packages" +msgstr " Installing packages" + +#: creole/reconfigure.py:538 +msgid "Installing packages" +msgstr "Installing packages" + +#: creole/reconfigure.py:545 creole/reconfigure.py:546 +msgid "Generating configuration files" +msgstr "Generating configuration files" + +#: creole/reconfigure.py:566 +msgid "Stopping services" +msgstr "Stopping services" + +#: creole/reconfigure.py:570 +msgid "Starting services" +msgstr "Starting services" + +#: creole/reconfigure.py:583 +msgid "Configuring services" +msgstr "Configuring services" + +#: creole/reconfigure.py:585 +#, python-brace-format +msgid "Unknown service action: {0}" +msgstr "Unknown service action: {0}" + +#: creole/reconfigure.py:617 +msgid "Managing system user accounts" +msgstr "Managing system user accounts" + +#: creole/reconfigure.py:625 +msgid "No system user account management in non-interactive mode." +msgstr "No system user account management in non-interactive mode." + +#: creole/reconfigure.py:633 +msgid "'root' user unknown. This is abnormal." +msgstr "'root' user unknown. This is abnormal." + +#: creole/reconfigure.py:638 +msgid "No new EOLE account with /home on NFS" +msgstr "No new EOLE account with /home on NFS" + +#: creole/reconfigure.py:641 +#, python-brace-format +msgid "Create new administrator user account {0}?" +msgstr "Create new administrator user account {0}?" + +#: creole/reconfigure.py:645 +#, python-brace-format +msgid "Creating unexistent user {0}" +msgstr "Creating unexistent user {0}" + +#: creole/reconfigure.py:653 +#, python-brace-format +msgid "Unable to create user {0}" +msgstr "Unable to create user {0}" + +#: creole/reconfigure.py:659 +#, python-brace-format +msgid "Unable to add '{0}' to group 'adm'." +msgstr "Unable to add '{0}' to group 'adm'." + +#: creole/reconfigure.py:666 +#, python-brace-format +msgid "No modification of password of administrator user account {0}." +msgstr "No modification of password of administrator user account {0}." + +#: creole/reconfigure.py:678 +#, python-brace-format +msgid "# Modificating password for user account {0} #" +msgstr "# Modificating password for user account {0} #" + +#: creole/reconfigure.py:685 +msgid "New password" +msgstr "New password" + +#: creole/reconfigure.py:686 +msgid "Confirming new password" +msgstr "Confirming new password" + +#: creole/reconfigure.py:690 +#, python-brace-format +msgid "Password input errors for {0}. Abandon." +msgstr "Password input errors for {0}. Abandon." + +#: creole/reconfigure.py:700 +msgid "Can not use default password." +msgstr "Can not use default password." + +#: creole/reconfigure.py:707 +#, python-brace-format +msgid "User {0} password updated." +msgstr "User {0} password updated." + +#: creole/reconfigure.py:711 +#, python-brace-format +msgid "Error changing password for {0}." +msgstr "Error changing password for {0}." + +#: creole/reconfigure.py:717 +msgid "Passwords mismatch." +msgstr "Passwords mismatch." + +#: creole/reconfigure.py:727 +msgid "Managing certificates" +msgstr "Managing certificates" + +#: creole/reconfigure.py:738 +#, python-brace-format +msgid "Error while generating certificates: {0}" +msgstr "Error while generating certificates: {0}" + +#: creole/reconfigure.py:744 +#, python-brace-format +msgid "Copying certificates in {0}" +msgstr "Copying certificates in {0}" + +#: creole/reconfigure.py:753 +msgid "Applying kernel parameters" +msgstr "Applying kernel parameters" + +#: creole/reconfigure.py:766 +msgid "Finalizing configuration" +msgstr "Finalizing configuration" + +#: creole/reconfigure.py:787 creole/reconfigure.py:792 +#: creole/reconfigure.py:794 +#, python-brace-format +msgid "Backup {0} in {1}" +msgstr "Backup {0} in {1}" + +#: creole/reconfigure.py:790 +#, python-brace-format +msgid "{0} was not modified" +msgstr "{0} was not modified" + +#: creole/reconfigure.py:805 +msgid "Managing update" +msgstr "Managing update" + +#: creole/reconfigure.py:807 +msgid "Updating server" +msgstr "Updating server" + +#: creole/reconfigure.py:808 +msgid "" +"An update is recommended.\n" +"Do you want to proceed with network update now ?" +msgstr "" +"An update is recommended.\n" +"Do you want to proceed with network update now ?" + +#: creole/reconfigure.py:834 +msgid "No updates available." +msgstr "No updates available." + +#: creole/reconfigure.py:844 +msgid "Task scheduling" +msgstr "Task scheduling" + +#: creole/reconfigure.py:868 +msgid "" +"Reboot is necessary.\n" +"Do you want to reboot now?" +msgstr "" +"Reboot is necessary.\n" +"Do you want to reboot now?" + +#: creole/reconfigure.py:881 +msgid "Reboot necessary" +msgstr "Reboot necessary" + +#: creole/reconfigure.py:944 +msgid "Beginning of configuration" +msgstr "Beginning of configuration" + +#: creole/reconfigure.py:959 creole/reconfigure.py:964 +msgid "eth0 network interface does not have a valid IP address." +msgstr "eth0 network interface does not have a valid IP address." + +#: creole/reconfigure.py:960 +msgid "Restarting networking service" +msgstr "Restarting networking service" + +#: creole/reconfigure.py:965 +msgid "Unable to obtain IP address." +msgstr "Unable to obtain IP address." + +#: creole/reconfigure.py:981 +msgid "Reconfiguration OK" +msgstr "Reconfiguration OK" + +#: creole/server.py:99 +#, python-brace-format +msgid "File not accessible: {0}" +msgstr "File not accessible: {0}" + +#: creole/server.py:103 +#, python-brace-format +msgid "File with null size: {0}" +msgstr "File with null size: {0}" + +#: creole/server.py:146 +#, python-brace-format +msgid "Reload config.eol due to {0} on {1}" +msgstr "Reload config.eol due to {0} on {1}" + +#: creole/server.py:153 +#, python-brace-format +msgid "Filtered inotify event for {0}" +msgstr "Filtered inotify event for {0}" + +#: creole/server.py:170 +msgid "Loading tiramisu configuration" +msgstr "Loading tiramisu configuration" + +#: creole/server.py:192 +msgid "Load creole configuration with errors" +msgstr "Load creole configuration with errors" + +#: creole/server.py:198 +msgid "Unable to load creole configuration: " +msgstr "Unable to load creole configuration: " + +#: creole/server.py:232 +msgid "Unable to load creole configuration from config.eol: " +msgstr "Unable to load creole configuration from config.eol: " + +#: creole/server.py:244 +msgid "Unable to load creole configuration from extra: " +msgstr "Unable to load creole configuration from extra: " + +#: creole/server.py:272 +msgid "All variables are not set, please configure your system:" +msgstr "All variables are not set, please configure your system:" + +#: creole/server.py:277 +msgid "variables are mandatories" +msgstr "variables are mandatories" + +#: creole/server.py:288 +msgid "variables must be in config file" +msgstr "variables must be in config file" + +#: creole/server.py:350 +#, python-brace-format +msgid "Mandatory variable {0} is not set." +msgstr "Mandatory variable {0} is not set." + +#: creole/server.py:429 +msgid "No configuration" +msgstr "No configuration" + +#: creole/server.py:460 +msgid "Base directory in which the server is launched (default: /tmp)" +msgstr "Base directory in which the server is launched (default: /tmp)" + +#: creole/server.py:464 +msgid "Configuration file of the server (default: /etc/eole/creoled.conf" +msgstr "Configuration file of the server (default: /etc/eole/creoled.conf" + +#: creole/server.py:467 +msgid "Run the server as a daemon (default: false)" +msgstr "Run the server as a daemon (default: false)" + +#: creole/server.py:470 +msgid "Listen on the specified IP:PORT (default: 127.0.0.1:8000)" +msgstr "Listen on the specified IP:PORT (default: 127.0.0.1:8000)" + +#: creole/server.py:473 creole/server.py:478 +msgid "Base under which the application is mounted (default: /)" +msgstr "Base under which the application is mounted (default: /)" + +#: creole/server.py:481 +msgid "User of the running process (default: nobody)" +msgstr "User of the running process (default: nobody)" + +#: creole/server.py:484 +msgid "Group of the running process (default: nogroup)" +msgstr "Group of the running process (default: nogroup)" + +#: creole/server.py:487 +msgid "Umask of the running process (default: 0644)" +msgstr "Umask of the running process (default: 0644)" + +#: creole/server.py:593 +msgid "No configuration found: do not check for container mode." +msgstr "No configuration found: do not check for container mode." + +#: creole/server.py:608 +#, python-brace-format +msgid "Unable to listen for containers: {0}" +msgstr "Unable to listen for containers: {0}" + +#: creole/service.py:8 creole/service.py:16 creole/service.py:28 +#: creole/service.py:40 +msgid "Use new API “manage_services()”" +msgstr "Use new API “manage_services()”" + +#: creole/template.py:59 +msgid "Group variables must be of type master.slave" +msgstr "Group variables must be of type master.slave" + +#: creole/template.py:239 +msgid "length mismatch" +msgstr "length mismatch" + +#: creole/template.py:302 +#, python-brace-format +msgid "Patching template '{0}' with '{1}'" +msgstr "Patching template '{0}' with '{1}'" + +#: creole/template.py:306 +#, python-brace-format +msgid "" +"Error applying patch: '{0}'\n" +"To reproduce and fix this error {1}" +msgstr "" +"Error applying patch: '{0}'\n" +"To reproduce and fix this error {1}" + +#: creole/template.py:320 +#, python-brace-format +msgid "Cleaning file '{0}'" +msgstr "Cleaning file '{0}'" + +#: creole/template.py:325 +#, python-brace-format +msgid "Error removing comments '{0}': {1}" +msgstr "Error removing comments '{0}': {1}" + +#: creole/template.py:340 +#, python-brace-format +msgid "Template file not enabled: {0}" +msgstr "Template file not enabled: {0}" + +#: creole/template.py:343 +#, python-brace-format +msgid "Template file not set: {0}" +msgstr "Template file not set: {0}" + +#: creole/template.py:347 +#, python-brace-format +msgid "Template target not set: {0}" +msgstr "Template target not set: {0}" + +#: creole/template.py:364 +#, python-brace-format +msgid "Template {0} unexistent" +msgstr "Template {0} unexistent" + +#: creole/template.py:367 +#, python-brace-format +msgid "Copy template: '{0}' -> '{1}'" +msgstr "Copy template: '{0}' -> '{1}'" + +#: creole/template.py:383 +#, python-brace-format +msgid "File {0} does not exist." +msgstr "File {0} does not exist." + +#: creole/template.py:388 +#, python-brace-format +msgid "Folder {0} does not exist but is required by {1}" +msgstr "Folder {0} does not exist but is required by {1}" + +#: creole/template.py:410 +#, python-brace-format +msgid "Cheetah processing: '{0}' -> '{1}'" +msgstr "Cheetah processing: '{0}' -> '{1}'" + +#: creole/template.py:429 +#, python-brace-format +msgid "Error: unknown variable used in template {0} : {1}" +msgstr "Error: unknown variable used in template {0} : {1}" + +#: creole/template.py:432 +#, python-brace-format +msgid "Encoding issue detected in template {0}" +msgstr "Encoding issue detected in template {0}" + +#: creole/template.py:435 +#, python-brace-format +msgid "Error while instantiating template {0}: {1}" +msgstr "Error while instantiating template {0}: {1}" + +#: creole/template.py:448 +#, python-brace-format +msgid "Unable to write in file '{0}': '{1}'" +msgstr "Unable to write in file '{0}': '{1}'" + +#: creole/template.py:480 creole/template.py:485 +#, python-brace-format +msgid "Changing properties: {0}" +msgstr "Changing properties: {0}" + +#: creole/template.py:483 creole/template.py:488 +#, python-brace-format +msgid "Error changing properties {0}: {1}" +msgstr "Error changing properties {0}: {1}" + +#: creole/template.py:498 +#, python-brace-format +msgid "File '{0}' unexistent." +msgstr "File '{0}' unexistent." + +#: creole/template.py:517 +#, python-brace-format +msgid "Removing file '{0}' from container '{1}'" +msgstr "Removing file '{0}' from container '{1}'" + +#: creole/template.py:523 +#, python-brace-format +msgid "Instantiation of file '{0}' disabled" +msgstr "Instantiation of file '{0}' disabled" + +#: creole/template.py:525 +#, python-brace-format +msgid "Instantiating file '{0}' from '{1}'" +msgstr "Instantiating file '{0}' from '{1}'" + +#: creole/template.py:592 +#, python-brace-format +msgid "Removing file '{0}'" +msgstr "Removing file '{0}'" + +#: creole/upgrade.py:104 +#, python-brace-format +msgid "Variable {0} has been copied in {1}" +msgstr "Variable {0} has been copied in {1}" + +#: creole/upgrade.py:107 creole/upgrade24.py:239 +#, python-brace-format +msgid "Variable {0} has been renamed to {1}" +msgstr "Variable {0} has been renamed to {1}" + +#: creole/upgrade.py:119 +#, python-brace-format +msgid "Variable {0} has been removed" +msgstr "Variable {0} has been removed" + +#: creole/upgrade.py:133 +#, python-brace-format +msgid "Source variable {0} invalid" +msgstr "Source variable {0} invalid" + +#: creole/upgrade.py:145 creole/upgrade24.py:155 creole/upgrade24.py:173 +#, python-brace-format +msgid "Variable updated: {0} = {1}" +msgstr "Variable updated: {0} = {1}" + +#: creole/upgrade.py:167 +msgid "config.eol upgrade started" +msgstr "config.eol upgrade started" + +#: creole/upgrade.py:208 +#, python-brace-format +msgid "Unknown variable: {0}" +msgstr "Unknown variable: {0}" + +#: creole/upgrade.py:224 creole/upgrade.py:393 creole/upgrade24.py:287 +#: creole/upgrade24.py:353 creole/upgrade24.py:392 creole/upgrade24.py:419 +#: creole/upgrade24.py:457 creole/upgrade24.py:531 creole/upgrade24.py:583 +#: creole/upgrade24.py:614 +#, python-brace-format +msgid "Starting {0} to {1} upgrade" +msgstr "Starting {0} to {1} upgrade" + +#: creole/upgrade.py:554 +msgid "Migrating SMTP parameters" +msgstr "Migrating SMTP parameters" + +#: creole/upgrade.py:581 +msgid "Mail configuration not recognised, not processed" +msgstr "Mail configuration not recognised, not processed" + +#: creole/upgrade24.py:78 +msgid "get_noncalculated_value_for_auto: unknown variable {}" +msgstr "get_noncalculated_value_for_auto: unknown variable {}" + +#: creole/upgrade24.py:149 +#, python-brace-format +msgid "Try to set value to unknown option: {0} = {1}" +msgstr "Try to set value to unknown option: {0} = {1}" + +#: creole/upgrade24.py:167 creole/upgrade24.py:230 +msgid "empty value" +msgstr "empty value" + +#: creole/upgrade24.py:168 creole/upgrade24.py:175 creole/upgrade24.py:179 +#: creole/upgrade24.py:231 +#, python-brace-format +msgid "{0} for {1}" +msgstr "{0} for {1}" + +#: creole/upgrade24.py:186 +#, python-brace-format +msgid "Try to delete an unknown option: {0}" +msgstr "Try to delete an unknown option: {0}" + +#: creole/upgrade24.py:190 +#, python-brace-format +msgid "Variable {0} reinitialized" +msgstr "Variable {0} reinitialized" + +#: creole/upgrade24.py:199 +#, python-brace-format +msgid "Try to append a value to an unknown option: {0} += {1}" +msgstr "Try to append a value to an unknown option: {0} += {1}" + +#: creole/upgrade24.py:213 +#, python-brace-format +msgid "Try to modify last value of an unknown option: {0}[-1] = {1}" +msgstr "Try to modify last value of an unknown option: {0}[-1] = {1}" + +#: creole/upgrade24.py:306 creole/upgrade24.py:330 +#, python-brace-format +msgid "Invalid value : {0} in old variable {1}" +msgstr "Invalid value : {0} in old variable {1}" + +#: creole/upgrade24.py:525 +#, python-brace-format +msgid "Interface {0} name has not an 'ethX' format" +msgstr "Interface {0} name has not an 'ethX' format" + +#: creole/utils.py:149 +msgid "Choose a number in the list" +msgstr "Choose a number in the list" + +#: creole/var_loader.py:39 +msgid "mac address" +msgstr "mac address" + +#: creole/var_loader.py:110 +#, python-brace-format +msgid "option {0}'s value should be in {1}" +msgstr "option {0}'s value should be in {1}" + +#: creole/var_loader.py:265 +#, python-brace-format +msgid "{0} {1} redefined but unexistent." +msgstr "{0} {1} redefined but unexistent." + +#: creole/var_loader.py:267 +#, python-brace-format +msgid "{0} {1} existent." +msgstr "{0} {1} existent." + +#: creole/var_loader.py:306 +#, python-brace-format +msgid "Name ({0}) already used." +msgstr "Name ({0}) already used." + +#: creole/var_loader.py:377 +#, python-brace-format +msgid "Unknown key {0}" +msgstr "Unknown key {0}" + +#: creole/var_loader.py:402 +msgid "No requires for SymLinkOption" +msgstr "No requires for SymLinkOption" + +#: creole/var_loader.py:407 +#, python-brace-format +msgid "SymLinkOption targetting unexistent variable: {0}." +msgstr "SymLinkOption targetting unexistent variable: {0}." + +#: creole/var_loader.py:485 +#, python-brace-format +msgid "Two containers with the same id ({0})" +msgstr "Two containers with the same id ({0})" + +#: creole/var_loader.py:487 +#, python-brace-format +msgid "Multiple ids for the container {0}" +msgstr "Multiple ids for the container {0}" + +#: creole/var_loader.py:523 +msgid "Bridge IP network_br0 address" +msgstr "Bridge IP network_br0 address" + +#: creole/var_loader.py:554 +#, python-brace-format +msgid "IP address of container {0}" +msgstr "IP address of container {0}" + +#: creole/var_loader.py:661 +#, python-brace-format +msgid "Two variables with the same name ({0})" +msgstr "Two variables with the same name ({0})" + +#: creole/var_loader.py:663 +#, python-brace-format +msgid "Attempt to redefine unexistent variable: {0}." +msgstr "Attempt to redefine unexistent variable: {0}." + +#: creole/var_loader.py:700 +#, python-brace-format +msgid "Redefining multi attribute is not allowed for variable {0}" +msgstr "Redefining multi attribute is not allowed for variable {0}" + +#: creole/var_loader.py:703 +#, python-brace-format +msgid "Redefining type attribute is not allowed for variable {0}" +msgstr "Redefining type attribute is not allowed for variable {0}" + +#: creole/var_loader.py:744 creole/var_loader.py:751 +#, python-brace-format +msgid "help already set for {0}" +msgstr "help already set for {0}" + +#: creole/var_loader.py:761 +#, python-brace-format +msgid "More than one separator for {0}" +msgstr "More than one separator for {0}" + +#: creole/var_loader.py:800 +#, python-brace-format +msgid "Unknown condition type for {0}" +msgstr "Unknown condition type for {0}" + +#: creole/var_loader.py:806 creole/var_loader.py:1530 +#, python-brace-format +msgid "Unknown type {0}" +msgstr "Unknown type {0}" + +#: creole/var_loader.py:809 +#, python-brace-format +msgid "Unknown hidden {0}" +msgstr "Unknown hidden {0}" + +#: creole/var_loader.py:812 +#, python-brace-format +msgid "Unknown name {0}" +msgstr "Unknown name {0}" + +#: creole/var_loader.py:815 +#, python-brace-format +msgid "Unknown optional {0}" +msgstr "Unknown optional {0}" + +#: creole/var_loader.py:851 +#, python-brace-format +msgid "More than one function for target: {0}" +msgstr "More than one function for target: {0}" + +#: creole/var_loader.py:856 +#, python-brace-format +msgid "Can not set level to {0} for this kind of callback" +msgstr "Can not set level to {0} for this kind of callback" + +#: creole/var_loader.py:869 +msgid "Namespace different in param not allowed: {} - {}" +msgstr "Namespace different in param not allowed: {} - {}" + +#: creole/var_loader.py:885 +#, python-brace-format +msgid "Type {0} not yet implemented for {1} for {2}" +msgstr "Type {0} not yet implemented for {1} for {2}" + +#: creole/var_loader.py:901 +#, python-brace-format +msgid "Computing function already defined for {0}" +msgstr "Computing function already defined for {0}" + +#: creole/var_loader.py:1071 +#, python-brace-format +msgid "File {0} does not exist" +msgstr "File {0} does not exist" + +#: creole/var_loader.py:1086 +msgid "Unable to run read_dir if Config already exists." +msgstr "Unable to run read_dir if Config already exists." + +#: creole/var_loader.py:1112 +#, python-brace-format +msgid "Unable to populate {0}: {1}" +msgstr "Unable to populate {0}: {1}" + +#: creole/var_loader.py:1215 +#, python-brace-format +msgid "Condition using unexistent variable {0} as parameter." +msgstr "Condition using unexistent variable {0} as parameter." + +#: creole/var_loader.py:1246 +#, python-brace-format +msgid "Condition targetting unexistent variable {0}" +msgstr "Condition targetting unexistent variable {0}" + +#: creole/var_loader.py:1250 +#, python-brace-format +msgid "requires already set for this option preventing changing properties {0}" +msgstr "" +"requires already set for this option preventing changing properties {0}" + +#: creole/var_loader.py:1254 +#, python-brace-format +msgid "requires already set for this option {0}" +msgstr "requires already set for this option {0}" + +#: creole/var_loader.py:1345 +#, python-brace-format +msgid "Check using unexistent variable {0} as parameter." +msgstr "Check using unexistent variable {0} as parameter." + +#: creole/var_loader.py:1386 +#, python-brace-format +msgid "unknown function {0} in eosfunc" +msgstr "unknown function {0} in eosfunc" + +#: creole/var_loader.py:1403 creole/var_loader.py:1416 +#, python-brace-format +msgid "Variable computing function using unknown variable {0}" +msgstr "Variable computing function using unknown variable {0}" + +#: creole/var_loader.py:1492 +msgid "Slave value length can not be greater than 1." +msgstr "Slave value length can not be greater than 1." + +#: creole/var_loader.py:1597 creole/var_loader.py:1605 +#, python-brace-format +msgid "{0} is auto, so must not be auto_freeze or auto_save" +msgstr "{0} is auto, so must not be auto_freeze or auto_save" + +#: creole/var_loader.py:1700 +#, python-brace-format +msgid "Unknown family {0} has requires" +msgstr "Unknown family {0} has requires" + +#: creole/xmlreflector.py:46 +msgid "not a valid xml file: {}" +msgstr "not a valid xml file: {}" diff --git a/translation/en/eole-schedule.po b/translation/en/eole-schedule.po new file mode 100644 index 0000000..8e54c76 --- /dev/null +++ b/translation/en/eole-schedule.po @@ -0,0 +1,66 @@ +msgid "" +msgstr "" +"Project-Id-Version: eole-schedule\n" +"Report-Msgid-Bugs-To: eole@ac-dijon.fr\n" +"POT-Creation-Date: 2017-12-11 10:20+0100\n" +"PO-Revision-Date: 2017-12-11 10:20+0100\n" +"Last-Translator: Équipe EOLE \n" +"Language-Team: Équipe EOLE \n" +"Language: en\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: schedule/schedule:69 +msgid "Starting {}" +msgstr "Starting {}" + +#: schedule/schedule:106 +msgid "Error detected\n" +msgstr "Error detected\n" + +#: schedule/schedule:107 +msgid "{} exited with error return code" +msgstr "{} exited with error return code" + +#: schedule/schedule:110 +msgid "{} finished" +msgstr "{} finished" + +#: schedule/schedule:126 +msgid "Job already running, cancelling" +msgstr "Job already running, cancelling" + +#: schedule/schedule:140 +msgid "bareos is set for this day, cancelled" +msgstr "bareos is set for this day, cancelled" + +#: schedule/schedule:156 +#, python-brace-format +msgid "Unknown job: {0}" +msgstr "Unknown job: {0}" + +#: schedule/schedule:186 +#, python-brace-format +msgid "Too many arguments: {0}" +msgstr "Too many arguments: {0}" + +#: schedule/schedule:195 +#, python-brace-format +msgid "Not enough arguments: {0}" +msgstr "Not enough arguments: {0}" + +#: schedule/schedule:199 +#, python-brace-format +msgid "Second argument must be pre or post: {0}" +msgstr "Second argument must be pre or post: {0}" + +#: schedule/schedule:210 +#, python-brace-format +msgid "Too many arguments for cron: {0}" +msgstr "Too many arguments for cron: {0}" + +#: schedule/schedule:215 +#, python-brace-format +msgid "Unknown schedule type : {0}" +msgstr "Unknown schedule type : {0}" diff --git a/translation/en/update-manager.po b/translation/en/update-manager.po new file mode 100644 index 0000000..74ebac3 --- /dev/null +++ b/translation/en/update-manager.po @@ -0,0 +1,252 @@ +msgid "" +msgstr "" +"Project-Id-Version: update-manager\n" +"Report-Msgid-Bugs-To: eole@ac-dijon.fr\n" +"POT-Creation-Date: 2017-12-11 10:20+0100\n" +"PO-Revision-Date: 2017-12-11 10:20+0100\n" +"Last-Translator: Équipe EOLE \n" +"Language-Team: Équipe EOLE \n" +"Language: en\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: upgrade/Upgrade-Auto:63 +msgid "Upgrade to a newer major version is not available" +msgstr "Upgrade to a newer major version is not available" + +#: upgrade/Upgrade-Auto:64 +msgid "Use Maj-Release script to upgrade to next minoir version" +msgstr "Use Maj-Release script to upgrade to next minoir version" + +#: upgrade/Upgrade-Auto:98 +msgid "" +"Available choices:\n" +"{}\n" +msgstr "" +"Available choices:\n" +"{}\n" + +#: upgrade/Upgrade-Auto:103 +msgid "Automatically selected first choice: {}\n" +msgstr "Automatically selected first choice: {}\n" + +#: upgrade/Upgrade-Auto:107 +msgid "" +"\n" +"[1]: " +msgstr "" +"\n" +"[1]: " + +#: upgrade/Upgrade-Auto:110 upgrade/Upgrade-Auto:594 +msgid "" +"\n" +"Upgrade aborted by user" +msgstr "" +"\n" +"Upgrade aborted by user" + +#: upgrade/Upgrade-Auto:122 +msgid "Choice {} not available\n" +msgstr "Choice {} not available\n" + +#: upgrade/Upgrade-Auto:126 upgrade/Upgrade-Auto:495 +msgid "Upgrade cancelled by user" +msgstr "Upgrade cancelled by user" + +#: upgrade/Upgrade-Auto:129 +msgid "Invalid input: {}\n" +msgstr "Invalid input: {}\n" + +#: upgrade/Upgrade-Auto:240 +#, python-brace-format +msgid "Verifying ISO image {iso}" +msgstr "Verifying ISO image {iso}" + +#: upgrade/Upgrade-Auto:243 +msgid "Download SHA256SUMS file" +msgstr "Download SHA256SUMS file" + +#: upgrade/Upgrade-Auto:247 +msgid "Download SHA256SUMS.gpg file" +msgstr "Download SHA256SUMS.gpg file" + +#: upgrade/Upgrade-Auto:250 +msgid "Check SHA256SUMS file signature" +msgstr "Check SHA256SUMS file signature" + +#: upgrade/Upgrade-Auto:258 +msgid "Check ISO SHA256..." +msgstr "Check ISO SHA256..." + +#: upgrade/Upgrade-Auto:275 +msgid "OK" +msgstr "OK" + +#: upgrade/Upgrade-Auto:278 +msgid "Error" +msgstr "Error" + +#: upgrade/Upgrade-Auto:302 +#, python-brace-format +msgid "Error downloading {file} with wget from {url}" +msgstr "Error downloading {file} with wget from {url}" + +#: upgrade/Upgrade-Auto:313 +msgid "Error downloading the image with zsync" +msgstr "Error downloading the image with zsync" + +#: upgrade/Upgrade-Auto:351 +#, python-brace-format +msgid "Unable to umount {cdrom}" +msgstr "Unable to umount {cdrom}" + +#: upgrade/Upgrade-Auto:383 +#, python-brace-format +msgid "Downloading ISO image for {release}" +msgstr "Downloading ISO image for {release}" + +#: upgrade/Upgrade-Auto:402 +msgid "No CDROM found" +msgstr "No CDROM found" + +#: upgrade/Upgrade-Auto:406 +#, python-brace-format +msgid "No such file: {iso}" +msgstr "No such file: {iso}" + +#: upgrade/Upgrade-Auto:408 +#, python-brace-format +msgid "Unreadable file: {iso}" +msgstr "Unreadable file: {iso}" + +#: upgrade/Upgrade-Auto:414 +#, python-brace-format +msgid "Copying {source} to {iso}" +msgstr "Copying {source} to {iso}" + +#: upgrade/Upgrade-Auto:423 +#, python-brace-format +msgid "Error checking ISO after copy, remove {iso}" +msgstr "Error checking ISO after copy, remove {iso}" + +#: upgrade/Upgrade-Auto:436 +#, python-brace-format +msgid "Error checking ISO image after download, remove {iso}" +msgstr "Error checking ISO image after download, remove {iso}" + +#: upgrade/Upgrade-Auto:444 +msgid "EOLE distribution upgrade tool." +msgstr "EOLE distribution upgrade tool." + +#: upgrade/Upgrade-Auto:447 +msgid "Target release number" +msgstr "Target release number" + +#: upgrade/Upgrade-Auto:450 +msgid "Only download the ISO image" +msgstr "Only download the ISO image" + +#: upgrade/Upgrade-Auto:453 +msgid "Path to an ISO image" +msgstr "Path to an ISO image" + +#: upgrade/Upgrade-Auto:456 +msgid "Use CDROM device instead of downloading ISO image" +msgstr "Use CDROM device instead of downloading ISO image" + +#: upgrade/Upgrade-Auto:459 +msgid "Pass limit rate to wget. “0” to disable." +msgstr "Pass limit rate to wget. “0” to disable." + +#: upgrade/Upgrade-Auto:462 +msgid "Do not ask confirmation" +msgstr "Do not ask confirmation" + +#: upgrade/Upgrade-Auto:472 +msgid "This script will upgrade this server to a new release" +msgstr "This script will upgrade this server to a new release" + +#: upgrade/Upgrade-Auto:473 +msgid "Modifications will be irreversible." +msgstr "Modifications will be irreversible." + +#: upgrade/Upgrade-Auto:475 +msgid "Starting Upgrade-Auto ({})" +msgstr "Starting Upgrade-Auto ({})" + +#: upgrade/Upgrade-Auto:480 +#, python-brace-format +msgid "Invalid release {version} use: {values}" +msgstr "Invalid release {version} use: {values}" + +#: upgrade/Upgrade-Auto:487 +msgid "Choose which version you want to upgrade to\n" +msgstr "Choose which version you want to upgrade to\n" + +#: upgrade/Upgrade-Auto:488 +msgid "Which version do you want to upgrade to (or 'q' to quit)?" +msgstr "Which version do you want to upgrade to (or 'q' to quit)?" + +#: upgrade/Upgrade-Auto:493 +msgid "Do you really want to upgrade to version {}?" +msgstr "Do you really want to upgrade to version {}?" + +#: upgrade/Upgrade-Auto:504 +msgid "Check update status" +msgstr "Check update status" + +#: upgrade/Upgrade-Auto:513 +msgid "Some packages are not up-to-date!" +msgstr "Some packages are not up-to-date!" + +#: upgrade/Upgrade-Auto:516 +msgid "Update this server (Maj-Auto) before another attempt to upgrade" +msgstr "Update this server (Maj-Auto) before another attempt to upgrade" + +#: upgrade/Upgrade-Auto:519 +msgid "Server is up-to-date" +msgstr "Server is up-to-date" + +#: upgrade/Upgrade-Auto:522 +msgid "" +"In order to upgrade, most recent kernel endorsed for this release must be " +"used" +msgstr "" +"In order to upgrade, most recent kernel endorsed for this release must be " +"used" + +#: upgrade/Upgrade-Auto:527 +msgid "This server uses most recent kernel" +msgstr "This server uses most recent kernel" + +#: upgrade/Upgrade-Auto:532 +msgid "Download only detected, stop" +msgstr "Download only detected, stop" + +#: upgrade/Upgrade-Auto:537 +msgid "Copying upgrade scripts" +msgstr "Copying upgrade scripts" + +#: upgrade/Upgrade-Auto:539 +#, python-brace-format +msgid "Directory {0} already exists" +msgstr "Directory {0} already exists" + +#: upgrade/Upgrade-Auto:547 +msgid "Configuring upgrade" +msgstr "Configuring upgrade" + +#: upgrade/Upgrade-Auto:563 +msgid "Module specific commands" +msgstr "Module specific commands" + +#: upgrade/Upgrade-Auto:566 +#, python-brace-format +msgid "Error {0}" +msgstr "Error {0}" + +#: upgrade/Upgrade-Auto:586 +msgid "Upgrading server" +msgstr "Upgrading server" diff --git a/translation/eole-schedule.pot b/translation/eole-schedule.pot new file mode 100644 index 0000000..3eb7981 --- /dev/null +++ b/translation/eole-schedule.pot @@ -0,0 +1,71 @@ +# SOME DESCRIPTIVE TITLE. +# This file is put in the public domain. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: eole-schedule\n" +"Report-Msgid-Bugs-To: eole@ac-dijon.fr\n" +"POT-Creation-Date: 2017-12-11 10:20+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: schedule/schedule:69 +msgid "Starting {}" +msgstr "" + +#: schedule/schedule:106 +msgid "Error detected\n" +msgstr "" + +#: schedule/schedule:107 +msgid "{} exited with error return code" +msgstr "" + +#: schedule/schedule:110 +msgid "{} finished" +msgstr "" + +#: schedule/schedule:126 +msgid "Job already running, cancelling" +msgstr "" + +#: schedule/schedule:140 +msgid "bareos is set for this day, cancelled" +msgstr "" + +#: schedule/schedule:156 +#, python-brace-format +msgid "Unknown job: {0}" +msgstr "" + +#: schedule/schedule:186 +#, python-brace-format +msgid "Too many arguments: {0}" +msgstr "" + +#: schedule/schedule:195 +#, python-brace-format +msgid "Not enough arguments: {0}" +msgstr "" + +#: schedule/schedule:199 +#, python-brace-format +msgid "Second argument must be pre or post: {0}" +msgstr "" + +#: schedule/schedule:210 +#, python-brace-format +msgid "Too many arguments for cron: {0}" +msgstr "" + +#: schedule/schedule:215 +#, python-brace-format +msgid "Unknown schedule type : {0}" +msgstr "" diff --git a/translation/fr/creole.po b/translation/fr/creole.po new file mode 100644 index 0000000..4e3efd4 --- /dev/null +++ b/translation/fr/creole.po @@ -0,0 +1,2243 @@ +msgid "" +msgstr "" +"Project-Id-Version: creole\n" +"Report-Msgid-Bugs-To: eole@ac-dijon.fr\n" +"POT-Creation-Date: 2017-12-11 10:20+0100\n" +"PO-Revision-Date: 2016-09-08 09:57+0200\n" +"Last-Translator: Benjamin Bohard \n" +"Language-Team: Équipe EOLE \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Poedit 1.5.4\n" + +#: bin/Maj-Auto:66 creole/reconfigure.py:185 +msgid "! Abandoning configuration !" +msgstr "! Abandon de la configuration !" + +#: bin/Maj-Auto:67 creole/reconfigure.py:186 +msgid "" +"System may be in an incoherent state.\n" +"\n" +msgstr "" +"Le système peut être dans un état incohérent\n" +"\n" + +#: bin/Maj-Auto:75 +msgid "Manage EOLE server automatic update" +msgstr "Gère la mise à jour automatisée d'un serveur EOLE" + +#: bin/Maj-Auto:81 bin/Maj-Release:35 +msgid "show this help message and exit" +msgstr "afficher ce message d'aide et quitter" + +#: bin/Maj-Auto:84 +msgid "run in dry-run mode (force to True when using Query-Auto)." +msgstr "exécuter en mode simulation (option forcée en invoquant Query-Auto)." + +#: bin/Maj-Auto:87 +msgid "bypass Zephir authorizations." +msgstr "passer outre les autorisations Zéphir." + +#: bin/Maj-Auto:90 +msgid "update your server without any confirmation." +msgstr "mettre à jour le serveur sans confirmation" + +#: bin/Maj-Auto:94 +msgid "ask apt-get to simulate packages installation" +msgstr "demande à apt-get de simuler l'installation des paquets" + +#: bin/Maj-Auto:101 +msgid "use testing packages." +msgstr "utiliser les paquets candidats." + +#: bin/Maj-Auto:105 +msgid "use development packages." +msgstr "utiliser les paquets en développement." + +#: bin/Maj-Auto:113 +msgid "run reconfigure on successful upgrade." +msgstr "exécuter reconfigure après une mise à jour réussie." + +#: bin/Maj-Auto:117 +msgid "" +"run reconfigure on successful upgrade and reboot if necessary (implies -r)." +msgstr "" +"exécuter reconfigure après une mise à jour réussie et redémarrer si " +"nécessaire (implique l'option -r)." + +#: bin/Maj-Auto:119 +msgid "only download packages in cache." +msgstr "procéder uniquement au téléchargement des paquets en cache." + +#: bin/Maj-Auto:122 +msgid "EOLE repository server." +msgstr "adresse des dépôts EOLE." + +#: bin/Maj-Auto:124 +msgid "Ubuntu repository server." +msgstr "adresse des dépôts Ubuntu." + +#: bin/Maj-Auto:126 +msgid "Envole repository server." +msgstr "adresse des dépôts Envole." + +#: bin/Maj-Auto:128 +msgid "use CDROM as source." +msgstr "utiliser une source de type CDROM" + +#: bin/Maj-Auto:132 +msgid "specific output for EAD." +msgstr "sortie formatée pour l'EAD." + +#: bin/Maj-Auto:135 +msgid "ignore local configuration if creoled not responding." +msgstr "ignore la configuration locale si creoled ne répond pas." + +#: bin/Maj-Auto:182 +#, python-brace-format +msgid "Update at {0}" +msgstr "Mise à jour le {0}" + +#: bin/Maj-Auto:234 +msgid "Unknown release number" +msgstr "Numéro de version mineure inconnu" + +#: bin/Maj-Auto:247 +msgid "Update is locked, please contact Zéphir administrator" +msgstr "La mise à jour est bloquée. Contacter l'administrateur Zéphir" + +#: bin/Maj-Auto:248 creole/reconfigure.py:313 +msgid "Use -f option if you want to force execution" +msgstr "Utilisez l'option -f si vous désirez forcer l'exécution" + +#: bin/Maj-Auto:280 +msgid "(CHANGE RELEASE LEVEL)" +msgstr "(CHANGEMENT DU NIVEAU DE VERSION MINEURE)" + +#: bin/Maj-Auto:282 +msgid "(UNSTABLE VERSION)" +msgstr "(VERSION DE DEVELOPPEMENT)" + +#: bin/Maj-Auto:284 +msgid "(TESTING VERSION)" +msgstr "(VERSION CANDIDATE)" + +#: bin/Maj-Auto:287 +#, python-brace-format +msgid "{0} - Raising update level may prevent lowering back to stable version." +msgstr "" +"{0} - Augmenter le niveau de mise à jour peut empêcher de revenir au niveau " +"de mise à jour stable." + +#: bin/Maj-Auto:290 +msgid "Do you wish to proceed?" +msgstr "Voulez-vous continuer ?" + +#: bin/Maj-Auto:295 +msgid "Cancelling!" +msgstr "Annulation !" + +#: bin/Maj-Auto:330 bin/Maj-Auto:374 +msgid "Update successful." +msgstr "Mise à jour OK" + +#: bin/Maj-Auto:331 +msgid "Nothing to install." +msgstr "Aucun paquet à installer." + +#: bin/Maj-Auto:339 +#, python-brace-format +msgid "{0} new," +msgid_plural "{0} news," +msgstr[0] "{0} nouveau," +msgstr[1] "{0} nouveaux," + +#: bin/Maj-Auto:340 +#, python-brace-format +msgid "{0} upgrade," +msgid_plural "{0} upgrades," +msgstr[0] "{0} mis à jour," +msgstr[1] "{0} mis à jour," + +#: bin/Maj-Auto:341 +#, python-brace-format +msgid "{0} delete" +msgid_plural "{0} deletes" +msgstr[0] "{0} à enlever" +msgstr[1] "{0} à enlever" + +#: bin/Maj-Auto:383 +msgid "Upgrade post Maj-Release, please wait" +msgstr "Upgrade post Maj-Release, veuillez patienter" + +#: bin/Maj-Auto:389 +msgid "error in post maj release" +msgstr "erreur au post maj release" + +#: bin/Maj-Auto:402 +msgid "" +"At least one packages has been updated, use command [reconfigure] to apply " +"modifications." +msgstr "" +"Un ou plusieurs paquets ont été mis à jour, utilisez la commande " +"[reconfigure] pour que les modifications soient prises en compte." + +#: bin/Maj-Auto:415 +msgid "" +". If restarting creoled service does not help, try {} command with '-i' " +"option." +msgstr "" +".\n" +"Si le démarrage du service creoled ne résout pas le problème, essayez la " +"commande {} avec l'option '-i'." + +#: bin/Maj-Release:28 bin/Maj-Release:50 +msgid "This script will upgrade to a new release of this distribution" +msgstr "" +"Ce script va effectuer la migration vers une nouvelle version mineure de la " +"distribution" + +#: bin/Maj-Release:37 +msgid "Target release number" +msgstr "Numéro de version mineure" + +#: bin/Maj-Release:40 +msgid "Do not ask confirmation" +msgstr "Ne pas demander de confirmation" + +#: bin/Maj-Release:56 +msgid "No stable new release available" +msgstr "Pas de nouvelle version mineure stable disponible" + +#: bin/Maj-Release:68 +msgid "q|quit: abort" +msgstr "q|quit : abandonner" + +#: bin/Maj-Release:73 +msgid "" +"\n" +"Upgrade aborted by user" +msgstr "" +"\n" +"Migration stoppée par l'utilisateur" + +#: bin/Maj-Release:87 +msgid "Voluntary stay of proceedings" +msgstr "Arrêt volontaire de la procédure" + +#: bin/Maj-Release:90 bin/Maj-Release:97 +#, python-brace-format +msgid "Invalid response: {0}" +msgstr "Réponse invalide : {0}" + +#: creole/annotator.py:255 creole/var_loader.py:519 +msgid "Bridge IP address" +msgstr "Adresse IP du bridge" + +#: creole/annotator.py:260 creole/var_loader.py:521 +msgid "Bridge IP subnet mask" +msgstr "Adresse IP du netmask du bridge" + +#: creole/annotator.py:274 creole/var_loader.py:525 +msgid "Bridge broadcast IP address" +msgstr "Adresse IP du broadcast du bridge" + +#: creole/annotator.py:372 +msgid "{} family already exists" +msgstr "la famille {} existe déjà" + +#: creole/annotator.py:378 creole/var_loader.py:582 +msgid "Containers informations" +msgstr "Information sur les conteneurs" + +#: creole/annotator.py:417 +msgid "the container \"{}\" does not exist" +msgstr "le conteneur \"{}\" n'existe pas" + +#: creole/annotator.py:419 +msgid "mandatory attribute \"id\" missing for container \"{}\"" +msgstr "l'attribut \"id\" est manquant pour le conteneur \"{}\"" + +#: creole/annotator.py:423 +msgid "" +"attribute \"id\" must be unique, but \"{}\" is used for containers \"{}\" " +"and \"{}\"" +msgstr "" +"l'attribut \"id\" doit être unique mais \"{}\" est utilisé pour les " +"conteneurs \"{}\" et \"{}\"" + +#: creole/annotator.py:437 creole/var_loader.py:549 creole/var_loader.py:568 +#, python-brace-format +msgid "Path of container {0}" +msgstr "Chemin du conteneur {0}" + +#: creole/annotator.py:453 creole/var_loader.py:559 +#, python-brace-format +msgid "Group name of container {0}" +msgstr "Nom du groupe du conteneur {0}" + +#: creole/annotator.py:620 +msgid "attribute {} already exists for {}" +msgstr "l'attribut {} est déjà défini pour {}" + +#: creole/annotator.py:625 +msgid "attribute node_name or name_type already exists for {}" +msgstr "l'attribut node_name ou name_type est déjà défini pour {}" + +#: creole/annotator.py:788 +msgid "only one action allow for {}" +msgstr "une seule action est autorisée pour {}" + +#: creole/annotator.py:826 +msgid "No configuration variables available in the configuration set" +msgstr "Aucune variable disponible dans la configuration" + +#: creole/annotator.py:837 +msgid "valid_enum sets for unknown variables {}" +msgstr "un valid_enum a été renseigné pour des variables inconnues {}" + +#: creole/annotator.py:910 +msgid "the variable {} in a group must be multi" +msgstr "la variable groupée {} doit être de type multi" + +#: creole/annotator.py:917 +msgid "cannot found a master {} nor a slave {}" +msgstr "impossible de trouver une variable master {} ou esclave {}" + +#: creole/annotator.py:1048 +msgid "master/slaves {} could not be auto_save" +msgstr "les variables maître/esclaves ne peut être des auto_save" + +#: creole/annotator.py:1052 +msgid "master/slaves {} could not be auto_freeze" +msgstr "les variables maître/esclaves ne peut être des auto_freeze" + +#: creole/annotator.py:1101 +msgid "cannot set valid enum for variable with type {}" +msgstr "" +"impossible d'appliquer une liste de choix (valid enum) sur une variable de " +"type {}" + +#: creole/annotator.py:1111 creole/annotator.py:1133 +msgid "empty valid enum is not allowed for variable {}" +msgstr "la variable {} possède une liste de choix (valid enum) vide" + +#: creole/annotator.py:1130 +msgid "" +"value \"{}\" of variable \"{}\" is not in list of all expected values ({})" +msgstr "" + +#: creole/annotator.py:1198 +msgid "An auto or fill already exists for the target: {}" +msgstr "Un auto ou un fill est déjà défini pour la variable cible : {}" + +#: creole/annotator.py:1218 +msgid "variable with auto value cannot be auto_freeze" +msgstr "une variable possédant une valeur auto ne peut être une auto_freeze" + +#: creole/annotator.py:1221 +msgid "variable with auto value cannot be auto_save" +msgstr "une variable possédant une valeur auto ne peut être une auto_save" + +#: creole/annotator.py:1246 +msgid "{} already has a separator" +msgstr "la variable {} possède déjà une balise separator" + +#: creole/annotator.py:1256 creole/annotator.py:1414 +msgid "All '{}' variables shall be set in order to calculate {}" +msgstr "" +"Toutes les variables de type '{}' doivent être renseignées pour le calcul de " +"{}" + +#: creole/annotator.py:1260 +msgid "The function {} is unknown" +msgstr "La fonction {} est inconnue" + +#: creole/annotator.py:1262 +msgid "Function {} shall return a list" +msgstr "" + +#: creole/annotator.py:1282 +msgid "cannot use {} type as a param in check for {}" +msgstr "" +"impossible d'utiliser le type {} en tant que paramètre d'un check pour {}" + +#: creole/annotator.py:1344 +msgid "cannot load checkval value for variable {}: {}" +msgstr "impossible de charger la valeur du checkval pour la variable {} : {}" + +#: creole/annotator.py:1349 +msgid "cannot set more than one param for valid_enum for variable {}" +msgstr "valid_enum ne peut avoir plus d'un seul paramètre pour la variable {}" + +#: creole/annotator.py:1357 +msgid "cannot load value for variable {}: {}" +msgstr "impossible de charger la valeur de la variable {} : {}" + +#: creole/annotator.py:1365 +msgid "valid_enum already set for {}" +msgstr "valid_enum déjà présent pour {}" + +#: creole/annotator.py:1409 +msgid "cannot use {} type as a param in a fill/auto" +msgstr "impossible d'utiliser le type {} en tant que paramètre de fill ou auto" + +#: creole/annotator.py:1448 +msgid "cannot found family {}" +msgstr "famille {} non définie" + +#: creole/annotator.py:1581 +msgid "cannot use {} type as a param in a condition" +msgstr "impossible d'utiliser le type {} en tant que paramètre d'une condition" + +#: creole/cert.py:57 +msgid "! Error while generating entropy file !" +msgstr "! Erreur lors de la génération du fichier d'entropie !" + +#: creole/cert.py:94 +#, python-brace-format +msgid "! Error while generating ssl key in {0} !" +msgstr "! Erreur lors de la génération de la clé ssl dans {0} !" + +#: creole/cert.py:107 creole/cert.py:114 creole/cert.py:121 creole/cert.py:128 +#: creole/cert.py:135 creole/cert.py:142 +#, python-brace-format +msgid "" +"\n" +"! Rights on {0} can't be modified" +msgstr "" +"\n" +"! Impossible de changer les droits de {0}" + +#: creole/cert.py:201 +msgid "Certificate chain incomplete." +msgstr "Chaîne de certificats incomplète." + +#: creole/cert.py:231 +#, python-brace-format +msgid "Error: file {0} does not exist" +msgstr "Erreur : le fichier {0} n'existe pas." + +#: creole/cert.py:307 creole/cert.py:358 +#, python-brace-format +msgid "" +"Certificate configuration template can not be found:\n" +"\t{0}\n" +msgstr "" +"Fichier template de la configuration du certificat non trouvé :\n" +"\t{0}\n" + +#: creole/cert.py:309 +msgid "Generating CA certificate" +msgstr "Génération du certificat de la CA" + +#: creole/cert.py:315 +msgid "Error while generating CA" +msgstr "Erreur lors de la génération de la CA" + +#: creole/cert.py:326 +msgid "Generating certificate revocation list (CRL)" +msgstr "Génération de la liste de révocation (CRL)" + +#: creole/cert.py:330 +#, python-brace-format +msgid "Error while generating CRL ({0}/eole.crl)" +msgstr "Erreur lors de la génération de la CRL ({0}/eole.crl)" + +#: creole/cert.py:373 creole/cert.py:375 +#, python-brace-format +msgid "Folder {0} does not exist." +msgstr "Le répertoire {0} n'existe pas" + +#: creole/cert.py:390 +#, python-brace-format +msgid "! Error while generating certificate request {0} !" +msgstr "! Erreur lors de la génération de la requête ssl dans {0} !" + +#: creole/cert.py:403 +#, python-brace-format +msgid "! Error while signing certificate request {0} !" +msgstr "! Erreur lors de la signature de la requête dans {0} !" + +#: creole/cert.py:404 +#, python-brace-format +msgid "* Certificate {0} successfully generated" +msgstr "* Certificat {0} généré" + +#: creole/cert.py:543 creole/cert.py:571 +msgid "cert or certfile must be None" +msgstr "La valeur de cert ou certfile doit être None " + +#: creole/cert.py:545 creole/cert.py:573 +msgid "cert or certfile must be set" +msgstr "La variable cert ou certfile doit être assignée" + +#: creole/cert.py:554 creole/cert.py:582 +#, python-brace-format +msgid "error in {0}: {1}" +msgstr "Erreur dans {0} : {1}" + +#: creole/cert.py:557 +#, python-brace-format +msgid "Invalid certificate subject: {0} " +msgstr "Sujet du certificat invalide : {0}" + +#: creole/cert.py:585 +#, python-brace-format +msgid "Invalid certificate issuer: {0} " +msgstr "Sujet de la CA du certificat invalide : {0}" + +#: creole/client.py:287 +#, python-brace-format +msgid "Connexion error '{0}', retry {1}/{2}" +msgstr "Erreur de connexion '{0}', essai {1}/{2}" + +#: creole/client.py:292 +#, python-brace-format +msgid "" +"HTTP error: {0}\n" +"Please check creoled's log (/var/log/rsyslog/local/creoled/creoled.info." +"log)\n" +"and restart service with command 'service creoled start'" +msgstr "" +"Erreur HTTP : {0}\n" +"Veuillez vous référer au journal d'événement de creoled (/var/log/rsyslog/" +"local/creoled/creoled.info.log) pour avoir plus d'informations\n" +"et redémarrer le service avec la commande 'service creoled start'" + +#: creole/client.py:294 +#, python-brace-format +msgid "HTTP error: {0}" +msgstr "Erreur HTTP : {0}" + +#: creole/client.py:296 +msgid "creoled service didn't respond in time" +msgstr "le service creoled n'a pas répondu dans les délais" + +#: creole/client.py:323 +#, python-brace-format +msgid "HTML content: {0}" +msgstr "Contenu HTML : {0}" + +#: creole/client.py:324 +#, python-brace-format +msgid "" +"HTML error {0}, please consult creoled events log (/var/log/rsyslog/local/" +"creoled/creoled.info.log) to have more informations" +msgstr "" +"Erreur HTML {0}, veuillez vous référer au journal d'événement de creoled (/" +"var/log/rsyslog/local/creoled/creoled.info.log) pour avoir plus " +"d'informations" + +#: creole/client.py:334 +#, python-brace-format +msgid "Creole error {0}: {1}" +msgstr "Erreur creole {0} : {1}" + +#: creole/client.py:356 +#, python-brace-format +msgid "Path must not mix dotted and slash notation: '{0}'" +msgstr "" +"Le chemin ne doit pas mélanger la notation pointée et la notation '/' : '{0}'" + +#: creole/client.py:361 +#, python-brace-format +msgid "Path must start with '/': '{0}'" +msgstr "Le chemin doit commencer par '/' : '{0}'" + +#: creole/client.py:383 +#, python-brace-format +msgid "Too many positional parameters {0}." +msgstr "Trop de paramètres positionnels {0}" + +#: creole/client.py:435 creole/eosfunc.py:58 +#, python-brace-format +msgid "Unknown variable {0}" +msgstr "Variable inconnue {0}" + +#: creole/client.py:475 +#, python-brace-format +msgid "No container found for group {0}" +msgstr "Pas de conteneur trouvé pour le groupe {0}" + +#: creole/client.py:477 +msgid "No container found! Is that possible?" +msgstr "Pas de conteneur trouvé ! Est-ce possible ?" + +#: creole/client.py:498 +#, python-brace-format +msgid "Unknown container {0}" +msgstr "Conteneur inconnu {0}" + +#: creole/client.py:667 creole/client.py:676 +#, python-brace-format +msgid "Unknown container components {0} for container {1}" +msgstr "Composants de conteneur inconnus {0} pour le conteneur {1}" + +#: creole/client.py:669 +#, python-brace-format +msgid "Unknown container components {0}" +msgstr "Composants de conteneur inconnus {0}" + +#: creole/client.py:838 +#, python-brace-format +msgid "Error: {0}" +msgstr "Erreur : {0}" + +#: creole/containers.py:79 +msgid "Invalid LXC lock files state: both are present." +msgstr "État des verrous LXC invalide : les deux sont présents." + +#: creole/containers.py:103 +msgid "LXC is enabled but LXC commands not found in PATH." +msgstr "LXC est activé mais ses commandes ne sont pas dans le PATH." + +#: creole/containers.py:106 +msgid "" +"Server already instantiated in no containers mode, attempt to activate " +"containers mode aborted." +msgstr "" +"Serveur déjà instancié en mode non conteneur ; le passage en mode conteneur " +"est interrompu." + +#: creole/containers.py:108 +msgid "" +"Server already instantiated in containers mode, attempt to activate no " +"containers mode aborted." +msgstr "" +"Serveur déjà instancié en mode conteneur ; le passage en mode non conteneur " +"est interrompu." + +#: creole/containers.py:124 +msgid "" +"cacher not available, please start check log in /var/log/apt-cacher-ng/ and " +"restart it with \"service apt-cacher-ng start\" command" +msgstr "" +"Le cache des paquets n'est pas disponible, veuillez consulter les logs dans /" +"var/log/apt-cacher-ng/ et redémarrer le service avec la commande \"service " +"apt-cacher-ng start\"" + +#: creole/containers.py:129 +#, python-brace-format +msgid "Managing container {0}" +msgstr "Gestion du conteneur {0}" + +#: creole/containers.py:135 +#, python-brace-format +msgid "" +"error during the process of container creation, more informations in {0}" +msgstr "Erreur durant le processus de création de conteneur, consulter {0}" + +#: creole/containers.py:140 +#, python-brace-format +msgid "" +"eole-common-pkg not installed in container, something goes wrong, more " +"informations in {0}" +msgstr "" +"eole-common-pkg n'est pas installé dans le conteneur, quelque chose s'est " +"mal passé, consulter {0}" + +#: creole/containers.py:174 +msgid "Container has no name" +msgstr "Le conteneur n'a pas de nom." + +#: creole/containers.py:177 +#, python-brace-format +msgid "Container {0} has no IP" +msgstr "Le conteneur {0} n'a pas d'adresse IP." + +#: creole/dtd_parser.py:52 +msgid "Do not write \"ChoiceOption\" in comments" +msgstr "Ne pas mettre ChoiceOption dans les commentaires" + +#: creole/dtd_parser.py:56 +msgid "Unvalid comment content: must match a valid attribute name" +msgstr "Commentaire invalide : doit correspondre à un type d'option valide." + +#: creole/dtd_parser.py:87 +#, python-brace-format +msgid "Using name {0} is forbidden in attributes" +msgstr "Le nom {0} est interdit pour les attributs" + +#: creole/dtd_parser.py:93 +msgid "Not a valid list" +msgstr "N'est pas une liste valide." + +#: creole/eosfunc.py:70 +msgid "Wrong IP address format" +msgstr "Mauvaise syntaxe d'adresse ip" + +#: creole/eosfunc.py:77 +msgid "An IP address is a sequence of four numbers separated by dots." +msgstr "l'adresse IP doit être constituée de 4 nombres séparés par des points" + +#: creole/eosfunc.py:80 +msgid "Each number is in range [0, 255]." +msgstr "Chaque nombre doit être compris entre 0 et 255" + +#: creole/eosfunc.py:92 +msgid "Two IP addresses are required." +msgstr "Vous devez spécifier 2 adresses IP" + +#: creole/eosfunc.py:112 +#, python-brace-format +msgid "Specified network does not match IP address {0}" +msgstr "Le réseau spécifié ne correspond pas à l'adresse IP {0}" + +#: creole/eosfunc.py:145 +msgid "Subnet mask format invalid" +msgstr "Syntaxe de masque réseau invalide" + +#: creole/eosfunc.py:157 +msgid "You must answer 'O' or 'N'" +msgstr "Vous devez répondre par 'O' ou 'N'" + +#: creole/eosfunc.py:166 +msgid "Value must be uppercase." +msgstr "La valeur doit être en majuscules" + +#: creole/eosfunc.py:174 +msgid "Value must be lowercase." +msgstr "La valeur doit être en minuscules" + +#: creole/eosfunc.py:188 +msgid "Invalid potential values list" +msgstr "La liste des valeurs possibles n'est pas valide" + +#: creole/eosfunc.py:190 +#, python-brace-format +msgid "Choose one of these options: {0}" +msgstr "Répondez par un des choix suivants : {0}" + +#: creole/eosfunc.py:193 +msgid "Invalid syntax" +msgstr "La syntaxe est incorrecte" + +#: creole/eosfunc.py:210 +msgid "A number is required." +msgstr "Vous devez saisir un nombre" + +#: creole/eosfunc.py:213 +#, python-brace-format +msgid "Give an integer greater than {0}" +msgstr "Donnez un entier supérieur à {0}" + +#: creole/eosfunc.py:215 +#, python-brace-format +msgid "Give an integer lesser than {0}" +msgstr "Donnez un entier inférieur à {0}" + +#: creole/eosfunc.py:228 +msgid "" +"valid_len : a length must be given, either an exact length or a maximum or " +"minimum length." +msgstr "" +"valid_len : il est nécessaire de spécifier soit une taille, soit une taille " +"minimum, soit une taille maximum" + +#: creole/eosfunc.py:230 +msgid "" +"valid_len : an exact length can not be used with a minimum or a maximum " +"length." +msgstr "valid_len : il ne faut pas renseigner length avec max_len ou min_len" + +#: creole/eosfunc.py:233 +#, python-brace-format +msgid "The exact length of the given variable must be {0}." +msgstr "La longueur de la variable doit être de {0}" + +#: creole/eosfunc.py:236 +#, python-brace-format +msgid "The length of the given variable must be lesser than {0}" +msgstr "La longueur de la variable doit être au maximum {0}" + +#: creole/eosfunc.py:238 +#, python-brace-format +msgid "The length of the given variable must be greater than {0}" +msgstr "La longueur de la variable doit être au minimum {0}" + +#: creole/eosfunc.py:243 +msgid "Value must be either Yes or No." +msgstr "La valeur doit être Yes ou No" + +#: creole/eosfunc.py:261 +#, python-brace-format +msgid "Command {0} execution has failed" +msgstr "La commande {0} a echoué" + +#: creole/eosfunc.py:266 +#, python-brace-format +msgid "Value must be different from {0}" +msgstr "La valeur doit être différente de {0}" + +#: creole/eosfunc.py:277 +#, python-brace-format +msgid "\"{0}\" character is not allowed." +msgstr "Le caractère \"{0}\" est interdit" + +#: creole/eosfunc.py:293 +msgid "Domain name is missing a top-level domain (TLD)." +msgstr "Le nom de domaine nécessite une extension" + +#: creole/eosfunc.py:301 +msgid "Aliases must start with a slash (\"/\")." +msgstr "Les alias doivent débuter par un \"/\"" + +#: creole/eosfunc.py:307 +msgid "Activating Apache is required in order to activate phpMyAdmin." +msgstr "L'activation de PhpMyAdmin nécessite celle d'Apache" + +#: creole/eosfunc.py:313 +msgid "SSO service must listen on an interface other than localhost." +msgstr "Le servive SSO doit écouter sur une interface autre que localhost" + +#: creole/eosfunc.py:316 +#, python-brace-format +msgid "" +"Local SSO service is in conflict with reverse proxy, use IP address {0} " +"instead." +msgstr "" +"Le service SSO local est en conflit avec le reverse proxy, utilisez {0} " +"comme adresse SSO" + +#: creole/eosfunc.py:324 +msgid "Value must be of type string." +msgstr "La valeur doit être de type string" + +#: creole/eosfunc.py:326 +msgid "Value must be uppercase letters." +msgstr "La valeur doit être composée uniquement de lettres majuscules" + +#: creole/eosfunc.py:340 +#, python-brace-format +msgid "" +"Please activate \"Utilisation du service sso pour les applications de votre " +"serveur Scribe\" before activating {0}." +msgstr "" +"Veuillez activer l'\"Utilisation du service SSO pour les applications de " +"votre serveur Scribe\" avant d'activer {0}" + +#: creole/eosfunc.py:348 +msgid "This parameter is mandatory." +msgstr "Ce paramètre est obligatoire" + +#: creole/eosfunc.py:388 +#, python-brace-format +msgid "Error running command {0} : {1}" +msgstr "Erreur à la commande {0} : {1}" + +#: creole/eosfunc.py:469 creole/eosfunc.py:992 creole/eosfunc.py:1000 +#: creole/eosfunc.py:1012 +#, python-brace-format +msgid "IP or subnet mask invalid ({0}, {1})" +msgstr "IP ou netmask invalide ({0}, {1})" + +#: creole/eosfunc.py:609 +msgid "Operator must be either \"AND\" or \"OR\"" +msgstr "Operator doit être \"AND\" ou \"OR\"" + +#: creole/eosfunc.py:611 +msgid "eval_match must be either \"True\" or \"False\"" +msgstr "Operator doit être \"AND\" ou \"OR\"" + +#: creole/eosfunc.py:613 +msgid "eval_mismatch must be either \"True\" or \"False\"" +msgstr "Operator doit être \"AND\" ou \"OR\"" + +#: creole/eosfunc.py:634 +msgid "Condition keys must start with \"condition\"." +msgstr "Les clefs de condition doivent commencer par \"condition_\"" + +#: creole/eosfunc.py:644 +msgid "Conditions and parameters counts do not match in calc_multi_condition." +msgstr "Nombre de conditions et de params différent dans calc_multi_condition" + +#: creole/eosfunc.py:715 +#, python-brace-format +msgid "LDAP directory of {0}.{1}" +msgstr "Annuaire de {0}.{1}" + +#: creole/eosfunc.py:720 +#, python-brace-format +msgid "LDAP directory of {0}" +msgstr "Annuaire de {0}" + +#: creole/eosfunc.py:1300 +msgid "Unknown job type" +msgstr "Type de job inconnu" + +#: creole/eosfunc.py:1334 +#, python-brace-format +msgid "Disknod '{0}' is not a directory or a device." +msgstr "Disknod '{0}' n'est pas un répertoire ou un périphérique." + +#: creole/eosfunc.py:1433 +#, python-brace-format +msgid "Error loading custom functions in {0}." +msgstr "Erreur lors du chargement des fonctions personnalisées dans {0}" + +#: creole/fonctionseole.py:119 +msgid "Updating Grub configuration" +msgstr "Mise à jour de la configuration Grub :" + +#: creole/fonctionseole.py:131 +msgid "Initramfs missing, generating :" +msgstr "Initramfs manquant, génération :" + +#: creole/fonctionseole.py:189 +#, python-brace-format +msgid "Syslog logging is not working properly: {0}" +msgstr "La journalisation syslog ne fonctionne pas correctement : {0}" + +#: creole/fonctionseole.py:190 +msgid "You may need to start/restart systemd-journald" +msgstr "Vous devez peut-être démarrer ou redémarrer systemd-journald" + +#: creole/fonctionseole.py:255 +#, python-brace-format +msgid "Checking permissions on Zéphir for {0} impossible." +msgstr "Impossible de vérifier sur Zéphir les interdictions pour {0}." + +#: creole/fonctionseole.py:256 +#, python-brace-format +msgid "Error message: {0}" +msgstr "Message d'erreur : {0}" + +#: creole/fonctionseole.py:261 +msgid "Using stored parameters" +msgstr "Utilisation des paramètres en cache" + +#: creole/fonctionseole.py:276 +#, python-brace-format +msgid "Updating {0} impossible (insufficient rights)." +msgstr "impossible de mettre à jour {0} (droits insuffisants)" + +#: creole/loader.py:84 creole/xmlreflector.py:33 +msgid "no such DTD file: {}" +msgstr "" + +#: creole/loader.py:132 creole/loader.py:358 +msgid "unknown tag {}" +msgstr "tag {} inconnu" + +#: creole/loader.py:169 +msgid "unknown constraint {}" +msgstr "contrainte {} inconnue" + +#: creole/loader.py:185 creole/loader.py:286 +msgid "unknown hidden boolean {}" +msgstr "booléen hidden {} inconnu" + +#: creole/loader.py:192 +msgid "unknown param type {} in fill to {}" +msgstr "paramètre de type {} inconnu dans le calcul de la variable {}" + +#: creole/loader.py:207 +msgid "valid_enum cannot have more than one param for {}" +msgstr "valid_enum ne peut avoir plus d'un seul paramètre pour la variable {}" + +#: creole/loader.py:218 creole/var_loader.py:933 +msgid "valid_differ length should be 1" +msgstr "valid_differ devrait avoir une longueur de 1." + +#: creole/loader.py:230 creole/var_loader.py:937 +msgid "valid_networknetmask length should be 1" +msgstr "valid_networknetmask devrait avoir une longueur de 1." + +#: creole/loader.py:232 creole/var_loader.py:939 +msgid "valid_networknetmask must have only eole variable" +msgstr "valid_networknetmask doit comporter uniquement des variables EOLE" + +#: creole/loader.py:241 creole/var_loader.py:943 +msgid "valid_ipnetmask length should be 1" +msgstr "valid_ipnetmask devrait avoir une longueur de 1." + +#: creole/loader.py:243 creole/var_loader.py:945 +msgid "valid_ipnetmask must have only eole variable" +msgstr "valid_ipnetmask doit comporter uniquement des variables EOLE" + +#: creole/loader.py:252 creole/var_loader.py:949 +msgid "valid_broadcast length should be 2" +msgstr "valid_broadcast devrait avoir une longueur de 2." + +#: creole/loader.py:254 creole/var_loader.py:957 +msgid "valid_broadcast must have only eole variable" +msgstr "valid_broadcast doit comporter uniquement des variables EOLE" + +#: creole/loader.py:264 creole/var_loader.py:961 +msgid "valid_in_network length should be 2" +msgstr "valid_in_network devrait avoir une longueur de 2." + +#: creole/loader.py:266 creole/var_loader.py:969 +msgid "valid_in_network must have only eole variable" +msgstr "valid_in_network doit comporter uniquement des variables EOLE" + +#: creole/loader.py:311 +msgid "unknown condition type {} for {}" +msgstr "Type de condition {} inconnu pour {}" + +#: creole/loader.py:371 +msgid "variable without family" +msgstr "variable sans famille" + +#: creole/loader.py:417 +msgid "path already loaded {}" +msgstr "chemin déjà chargé {}" + +#: creole/loader.py:446 +msgid "there is no element for path {}" +msgstr "aucun élément trouvé avec le chemin {}" + +#: creole/loader.py:472 creole/loader.py:626 +msgid "unknown value {} for {}" +msgstr "valeur inconnue {} pour {}" + +#: creole/loader.py:505 +msgid "default value already set for {}" +msgstr "valeur par défaut déjà définie pour {}" + +#: creole/loader.py:526 creole/loader.py:648 +msgid "key already exists in information {}" +msgstr "la clé est déjà définie dans les informations {}" + +#: creole/loader.py:581 +msgid "cannot create option {}: {}" +msgstr "impossible de créer l'option {} : {}" + +#: creole/loader.py:600 +msgid "cannot load consistency for {}: {}" +msgstr "impossible de charger le test de consistance pour {} : {}" + +#: creole/loader.py:670 +msgid "cannot create optiondescription {}: {}" +msgstr "impossible de créer l'optiondescription {} : {}" + +#: creole/loader.py:715 +msgid "Only creole namespace is supported" +msgstr "Seul l'espace de nom creole est supporté" + +#: creole/loader.py:724 creole/loader1.py:408 +#, python-brace-format +msgid "Configuration file unexistent : {0}" +msgstr "Fichier de configuration inexistant : {0}" + +#: creole/loader.py:728 creole/loader1.py:412 +msgid "Unable to force_configeol with load_extra." +msgstr "" +"Impossible de forcer la lecture d'un fichier de configuration avec l'option " +"load_extra." + +#: creole/loader.py:730 creole/loader1.py:414 +msgid "" +"If force_dirs is defined, namespace must be set to creole and load_extra " +"must be set to False." +msgstr "" +"Si force_dirs est défini, namespace doit etre creole et load_extra doit etre " +"à False" + +#: creole/loader.py:758 creole/loader1.py:433 +msgid "Namespace {} for extra dictionary not allowed" +msgstr "" +"L'espace de nom {} n'est pas permis pour les dictionnaires supplémentaires." + +#: creole/loader1.py:74 +#, python-brace-format +msgid "Unable to find namespace: {0}" +msgstr "Impossible de trouver l'espace de nom {0}." + +#: creole/loader1.py:292 +msgid "extra name {} not allowed" +msgstr "le nom {} n'est pas autorisé dans les extra" + +#: creole/loader1.py:350 creole/loader1.py:376 +msgid "Error when trying to upgrade config file: {}" +msgstr "Erreur lors de la mise à niveau du fichier de configuration : {}" + +#: creole/loader1.py:358 +#, python-brace-format +msgid "eol_version ({0}) is greater than current version ({1})" +msgstr "" +"La version du fichier EOL ({0}) est supérieure à la version courante ({1})" + +#: creole/loader1.py:416 +msgid "namespace is not creole, so load_extra is forbidden." +msgstr "l'espace de nom n'est pas creole, load_extra est interdit" + +#: creole/loader1.py:605 +msgid "master's len is lower than the slave variable ({})" +msgstr "" +"la variable maître possède moins de valeurs que la variable esclave ({})" + +#: creole/loader1.py:610 +msgid "owner must be a string for {}" +msgstr "le owner doit être une chaîne pour {}" + +#: creole/loader1.py:626 +msgid "unable to load variable {} with value {}: {}" +msgstr "impossible de charger la variable {} avec la valeur {} : {}" + +#: creole/loader1.py:663 creole/loader1.py:741 +msgid "config must have eol_file attribute" +msgstr "la configuration doit avoir un attribut eol_file." + +#: creole/loader1.py:667 +#, python-brace-format +msgid "Can not find file {0}" +msgstr "Impossible de trouver le fichier {0}" + +#: creole/loader1.py:695 +#, python-brace-format +msgid "Mandatory variable '{0}' from family '{1}' is not set !" +msgstr "" +"La variable obligatoire '{0}' de la famille '{1}' n'est pas renseignée !" + +#: creole/loader1.py:758 +#, python-brace-format +msgid "Error saving file: {0}" +msgstr "Erreur à la sauvegarde du fichier : {0}" + +#: creole/lxml_parser.py:24 +#, python-brace-format +msgid "Error while parsing file {0}: {1}" +msgstr "Erreur lors du parsing du fichier {0} : {1}" + +#: creole/lxml_parser.py:36 +#, python-brace-format +msgid "Error while parsing: {0}" +msgstr "\"Erreur lors du parsing : {0}" + +#: creole/lxml_parser.py:60 +#, python-brace-format +msgid "Error, var {0} already exists in current dictionaries" +msgstr "" +"Erreur la variable {0} est déclarée plusieurs fois dans le dictionnaire" + +#: creole/lxml_parser.py:73 +msgid "Error: extra tags in dictionaries." +msgstr "Erreur plusieurs balises par dictionnaire" + +#: creole/lxml_parser.py:82 +msgid "Error: extra tags in dictionaries." +msgstr "Erreur plusieurs balises par dictionnaire" + +#: creole/lxml_parser.py:87 +#, python-brace-format +msgid "Name '{0}' is not allowed in tag ." +msgstr "Le nom '{0}' est interdit pour une balise " + +#: creole/lxml_parser.py:90 +#, python-brace-format +msgid "There must be only one name '{0}' in a dictionary." +msgstr "Le nom {0} doit être unique par dictionnaire" + +#: creole/lxml_parser.py:101 +msgid "Error: extra tags in dictionaries." +msgstr "Erreur plusieurs balises par dictionnaire" + +#: creole/lxml_parser.py:190 creole/lxml_parser.py:197 +#, python-brace-format +msgid "Value {0} not in {1}" +msgstr "la valeur {0} n'est pas dans {1}" + +#: creole/lxml_parser.py:261 +#, python-brace-format +msgid "Family {0} is set several times." +msgstr "La famille {0} est déclarée plusieurs fois" + +#: creole/lxml_parser.py:303 +#, python-brace-format +msgid "Action Family {0} is set several times." +msgstr "La famille d'action {0} est déclarée plusieurs fois" + +#: creole/lxml_parser.py:310 +msgid "Error: extra tags in dictionaries." +msgstr "Erreur plusieurs balises par dictionnaire" + +#: creole/lxml_parser.py:400 +#, python-brace-format +msgid "Unknown type {0} for condition target." +msgstr "Type inconnu {0} pour une target de condition" + +#: creole/lxml_parser.py:406 +#, python-brace-format +msgid "Impossible condition without source for {0}." +msgstr "Condition sans source impossible pour {0}" + +#: creole/lxml_parser.py:432 +#, python-brace-format +msgid "Invalid help for variable {0}." +msgstr "Aide invalide pour la variable {0}" + +#: creole/lxml_parser.py:439 +#, python-brace-format +msgid "Invalid help for family {0}" +msgstr "Aide invalide pour la famille {0}" + +#: creole/maj.py:106 +#, python-brace-format +msgid "An update is scheduled at {0}" +msgstr "Une mise à jour est programmée pour {0}" + +#: creole/maj.py:145 +#, python-brace-format +msgid "{0} the {1}" +msgstr "{0} le {1}" + +#: creole/objspace.py:167 +msgid "{} is not True or False" +msgstr "{} n'est ni True ni False" + +#: creole/objspace.py:266 +msgid "Already present in another XML file, {} cannot be re-created" +msgstr "Déjà défini dans un autre fichier XML, {} ne peut être créé de nouveau" + +#: creole/objspace.py:274 +msgid "Redefined object: {} does not exist yet" +msgstr "impossible de redéfinir l'objet inexistant {}" + +#: creole/objspace.py:314 +msgid "Creole object {} has a wrong type" +msgstr "L'objet Creole {} a un mauvais type" + +#: creole/objspace.py:352 +msgid "cannot redefine attribute {} for variable {}" +msgstr "impossible de redéfinir l'attribut {} pour la variable {}" + +#: creole/objspace.py:359 +msgid "value for {} must be True or False, not {}" +msgstr "la valeur de {} doit être True ou False, et pas {}" + +#: creole/objspace.py:397 +msgid "Family {} is set several times" +msgstr "La famille {} est initialisée plusieurs fois" + +#: creole/objspace.py:572 +msgid "" +"A family located in the {} namespace shall not be used in the {} namespace" +msgstr "" +"Une famille de l'espace de nom {} ne devrait pas être utilisée dans l'espace " +"de nom {}" + +#: creole/objspace.py:588 +msgid "unknown family {}" +msgstr "famille {} inconnue" + +#: creole/objspace.py:620 +msgid "" +"A variable located in the {} namespace shall not be used in the {} namespace" +msgstr "" +"Une variable de l'espace de nom {} ne devrait pas être utilisée dans " +"l'espace {}" + +#: creole/objspace.py:638 +msgid "Already defined master {} for variable {}" +msgstr "Une master est déjà définie pour la variable {}" + +#: creole/objspace.py:651 +msgid "don't set full path variable in creole's namespace (set '{}' not '{}')" +msgstr "" +"ne pas utiliser le chemin complet pour une variable de l'espace de nom " +"creole (mettre '{}' au lieu de '{}')" + +#: creole/objspace.py:653 +msgid "unknown option {}" +msgstr "option {} inconnue" + +#: creole/reconfigure.py:61 +msgid "" +"For more informations, read section\n" +"'Mise en œuvre des modules EOLE' in module documentation or\n" +"common documentation." +msgstr "" +"Pour plus d'informations consulter : la documentation du module ou\n" +"la documentation commune 'Mise en œuvre des modules EOLE'." + +#: creole/reconfigure.py:104 +msgid "Applying EOLE configuration." +msgstr "Application de la configuration EOLE" + +#: creole/reconfigure.py:108 +msgid "leave process in interactive mode" +msgstr "laisser le processus en mode interactif" + +#: creole/reconfigure.py:110 +msgid "override Zéphir lock" +msgstr "outrepasser le blocage Zéphir" + +#: creole/reconfigure.py:112 +msgid "automatic reboot if necessary" +msgstr "redémarrage automatique si nécessaire" + +#: creole/reconfigure.py:229 +#, python-brace-format +msgid "Running scripts {0}" +msgstr "Exécution des scripts {0}" + +#: creole/reconfigure.py:232 +#, python-brace-format +msgid "Error {0}" +msgstr "Erreur : {0}" + +#: creole/reconfigure.py:242 +msgid "" +"Please check creoled's log (/var/log/rsyslog/local/creoled/creoled.info." +"log)\n" +"and restart service with command 'service creoled start'" +msgstr "" +"Veuillez vous référer au journal d'événement de creoled (/var/log/rsyslog/" +"local/creoled/creoled.info.log) pour avoir plus d'informations\n" +"et redémarrer le service avec la commande 'service creoled start'" + +#: creole/reconfigure.py:258 +#, python-brace-format +msgid "Preparation for {0}" +msgstr "Préparation pour {0}" + +#: creole/reconfigure.py:261 +msgid "Server is not configured." +msgstr "Le serveur n'est pas configuré." + +#: creole/reconfigure.py:265 +#, python-brace-format +msgid "Missing file {0}." +msgstr "Fichier {0} manquant." + +#: creole/reconfigure.py:270 +msgid "Server must be instantiated before any reconfiguration can occur." +msgstr "" +"Le serveur n'a jamais été instancié alors que c'est une étape obligatoire " +"avant la reconfiguration." + +#: creole/reconfigure.py:276 +msgid "Server already instantiated." +msgstr "Le serveur est déjà instancié" + +#: creole/reconfigure.py:278 +msgid "To modify configuration parameter (e.g. IP address), use:" +msgstr "" +"Pour modifier un paramètre de configuration (ex.: adresse IP) utiliser :" + +#: creole/reconfigure.py:279 +msgid "'gen_config'" +msgstr "'gen_config'" + +#: creole/reconfigure.py:280 +msgid "then 'reconfigure' to apply changes." +msgstr "et 'reconfigure' pour appliquer les modifications." + +#: creole/reconfigure.py:284 +msgid "you have run gen_conteneurs, please use instance instead of reconfigure" +msgstr "" +"Vous avez lancé gen_conteneurs, veuillez utiliser la commande instance au " +"lieu de reconfigure." + +#: creole/reconfigure.py:287 +msgid "You have to run gen_conteneurs before instance" +msgstr "" +"Vous devez utiliser la commande gen_conteneurs avant d'utiliser la commande " +"instance." + +#: creole/reconfigure.py:294 +msgid "First instantiate server." +msgstr "Instancier d'abord le serveur." + +#: creole/reconfigure.py:296 +msgid "Proceeding with instantiation ?" +msgstr "Continuer instanciation quand même ?" + +#: creole/reconfigure.py:308 +msgid "This process is blocked, contact Zéphir administrator." +msgstr "Cette procédure est bloquée, Contacter l'administrateur Zephir" + +#: creole/reconfigure.py:309 +msgid "Force execution?" +msgstr "Forcer l'exécution ?" + +#: creole/reconfigure.py:325 +msgid "Configuration validation problem, please check server configuration." +msgstr "" +"Problème de validation de la configuration, veuillez vérifier la " +"configuration du serveur" + +#: creole/reconfigure.py:391 +#, python-brace-format +msgid "Unable to start LXC container : {0}" +msgid_plural "Unable to start LXC containers : {0}" +msgstr[0] "Impossible de démarrer le conteneur : {0}" +msgstr[1] "Impossible de démarrer les conteneurs : {0}" + +#: creole/reconfigure.py:406 +msgid "Container mode is disabled." +msgstr "Le mode conteneur est désactivé." + +#: creole/reconfigure.py:411 +#, python-brace-format +msgid "" +"container {0} does not already exist, please use gen_conteneurs to create " +"this container" +msgstr "" +"Le conteneur {0} n'existe pas encore, veuillez utiliser la commande " +"gen_conteneurs pour le créer." + +#: creole/reconfigure.py:415 +#, python-brace-format +msgid "Setting up {0}" +msgstr "Mise en place {0}" + +#: creole/reconfigure.py:423 +msgid "Generating containers" +msgstr "Génération des conteneurs" + +#: creole/reconfigure.py:457 +msgid "Starting containers" +msgstr "Lancement des conteneurs" + +#: creole/reconfigure.py:473 +#, python-brace-format +msgid "Can not read file {0}: {1}" +msgstr "Impossible de lire le fichier {0} : {1}" + +#: creole/reconfigure.py:483 +msgid "Removing old linux kernels and associate headers." +msgstr "Suppression des anciens noyaux et fichiers d'en-tête associés." + +#: creole/reconfigure.py:490 +#, python-brace-format +msgid "Unable to remove some packages: {0}" +msgstr "Impossible de supprimer certains paquets: {0}" + +#: creole/reconfigure.py:492 +msgid "These packages will be removed next 'reconfigure'" +msgstr "Ces paquets seront supprimés au prochain reconfigure" + +#: creole/reconfigure.py:519 +msgid "Checking Packages for container" +msgstr "Vérification des paquets pour le conteneur" + +#: creole/reconfigure.py:533 +msgid "Managing packages" +msgstr "Gestion des paquets" + +#: creole/reconfigure.py:534 +msgid " Removing packages" +msgstr " Suppression des paquets" + +#: creole/reconfigure.py:535 +msgid "Removing packages" +msgstr "Suppression des paquets" + +#: creole/reconfigure.py:537 +msgid " Installing packages" +msgstr " Installation des paquets" + +#: creole/reconfigure.py:538 +msgid "Installing packages" +msgstr "Installation des paquets" + +#: creole/reconfigure.py:545 creole/reconfigure.py:546 +msgid "Generating configuration files" +msgstr "Génération des fichiers de configuration." + +#: creole/reconfigure.py:566 +msgid "Stopping services" +msgstr "Arrêt des services" + +#: creole/reconfigure.py:570 +msgid "Starting services" +msgstr "Démarrage des services" + +#: creole/reconfigure.py:583 +msgid "Configuring services" +msgstr "Configuration des services" + +#: creole/reconfigure.py:585 +#, python-brace-format +msgid "Unknown service action: {0}" +msgstr "Action de service inconnue: {0}" + +#: creole/reconfigure.py:617 +msgid "Managing system user accounts" +msgstr "Gestion des utilisateurs systèmes" + +#: creole/reconfigure.py:625 +msgid "No system user account management in non-interactive mode." +msgstr "Aucune gestion utilisateur en mode non interactif" + +#: creole/reconfigure.py:633 +msgid "'root' user unknown. This is abnormal." +msgstr "Utilisateur « root » inconnu, ce n’est pas normal" + +#: creole/reconfigure.py:638 +msgid "No new EOLE account with /home on NFS" +msgstr "" +"Aucune création de compte EOLE supplémentaire car /home est monté en NFS" + +#: creole/reconfigure.py:641 +#, python-brace-format +msgid "Create new administrator user account {0}?" +msgstr "Créer un nouvel administrateur {0} ?" + +#: creole/reconfigure.py:645 +#, python-brace-format +msgid "Creating unexistent user {0}" +msgstr "Création de l’utilisateur inexistant {0}" + +#: creole/reconfigure.py:653 +#, python-brace-format +msgid "Unable to create user {0}" +msgstr "Impossible de créer l’utilisateur {0}" + +#: creole/reconfigure.py:659 +#, python-brace-format +msgid "Unable to add '{0}' to group 'adm'." +msgstr "Impossible d’ajouter {0} au groupe adm" + +#: creole/reconfigure.py:666 +#, python-brace-format +msgid "No modification of password of administrator user account {0}." +msgstr "" +"Pas de changement de mot de passe de l’administrateur supplémentaire {0}" + +#: creole/reconfigure.py:678 +#, python-brace-format +msgid "# Modificating password for user account {0} #" +msgstr "# Changement du mot de passe pour l’utilisateur {0} #" + +#: creole/reconfigure.py:685 +msgid "New password" +msgstr "Nouveau mot de passe" + +#: creole/reconfigure.py:686 +msgid "Confirming new password" +msgstr "Confirmation du mot de passe" + +#: creole/reconfigure.py:690 +#, python-brace-format +msgid "Password input errors for {0}. Abandon." +msgstr "Erreurs de saisie de mot de passe de {0}, abandon." + +#: creole/reconfigure.py:700 +msgid "Can not use default password." +msgstr "Impossible d'utiliser le mot de passe par défaut." + +#: creole/reconfigure.py:707 +#, python-brace-format +msgid "User {0} password updated." +msgstr "Mot de passe de l’utilisateur {0} mis à jour." + +#: creole/reconfigure.py:711 +#, python-brace-format +msgid "Error changing password for {0}." +msgstr "Erreur de changement de mot de passe de {0}." + +#: creole/reconfigure.py:717 +msgid "Passwords mismatch." +msgstr "Les mots de passe ne correspondent pas." + +#: creole/reconfigure.py:727 +msgid "Managing certificates" +msgstr "Génération des certificats" + +#: creole/reconfigure.py:738 +#, python-brace-format +msgid "Error while generating certificates: {0}" +msgstr "Erreur lors de la génération des certificats : {0}" + +#: creole/reconfigure.py:744 +#, python-brace-format +msgid "Copying certificates in {0}" +msgstr "Copie des certificats dans {0}" + +#: creole/reconfigure.py:753 +msgid "Applying kernel parameters" +msgstr "Application des paramètres Noyau" + +#: creole/reconfigure.py:766 +msgid "Finalizing configuration" +msgstr "Finalisation de la configuration" + +#: creole/reconfigure.py:787 creole/reconfigure.py:792 +#: creole/reconfigure.py:794 +#, python-brace-format +msgid "Backup {0} in {1}" +msgstr "Sauvegarde de {0} dans {1}" + +#: creole/reconfigure.py:790 +#, python-brace-format +msgid "{0} was not modified" +msgstr "{0} n'a pas été modifié." + +#: creole/reconfigure.py:805 +msgid "Managing update" +msgstr "Gestion de la mise à jour" + +#: creole/reconfigure.py:807 +msgid "Updating server" +msgstr "Mise à jour du serveur" + +#: creole/reconfigure.py:808 +msgid "" +"An update is recommended.\n" +"Do you want to proceed with network update now ?" +msgstr "" +"Une mise à jour est recommandée\n" +"Voulez-vous effectuer une mise à jour via le réseau maintenant ?" + +#: creole/reconfigure.py:834 +msgid "No updates available." +msgstr "Aucune mise à jour à effectuer." + +#: creole/reconfigure.py:844 +msgid "Task scheduling" +msgstr "Planificateur de tâche" + +#: creole/reconfigure.py:868 +msgid "" +"Reboot is necessary.\n" +"Do you want to reboot now?" +msgstr "" +"Un redémarrage est nécessaire.\n" +"Faut-il l'effectuer maintenant ?" + +#: creole/reconfigure.py:881 +msgid "Reboot necessary" +msgstr "Reboot nécessaire" + +#: creole/reconfigure.py:944 +msgid "Beginning of configuration" +msgstr "Début de configuration" + +#: creole/reconfigure.py:959 creole/reconfigure.py:964 +msgid "eth0 network interface does not have a valid IP address." +msgstr "La carte eth0 ne dispose pas d'une adresse IP valide" + +#: creole/reconfigure.py:960 +msgid "Restarting networking service" +msgstr "Relance du service réseau" + +#: creole/reconfigure.py:965 +msgid "Unable to obtain IP address." +msgstr "Impossible d'obtenir une adresse IP" + +#: creole/reconfigure.py:981 +msgid "Reconfiguration OK" +msgstr "Reconfiguration OK" + +#: creole/server.py:99 +#, python-brace-format +msgid "File not accessible: {0}" +msgstr "Fichier non accessible : {0}" + +#: creole/server.py:103 +#, python-brace-format +msgid "File with null size: {0}" +msgstr "Fichier avec une taille nulle : {0}" + +#: creole/server.py:146 +#, python-brace-format +msgid "Reload config.eol due to {0} on {1}" +msgstr "Rechargement du fichier config.eol suite à l'évènement {0} sur {1}" + +#: creole/server.py:153 +#, python-brace-format +msgid "Filtered inotify event for {0}" +msgstr "Évènement inotify filtré pour {0}" + +#: creole/server.py:170 +msgid "Loading tiramisu configuration" +msgstr "Chargement de la configuration tiramisu" + +#: creole/server.py:192 +msgid "Load creole configuration with errors" +msgstr "La configuration Creole a été chargée avec des erreurs" + +#: creole/server.py:198 +msgid "Unable to load creole configuration: " +msgstr "Impossible de charger la configuration Creole." + +#: creole/server.py:232 +msgid "Unable to load creole configuration from config.eol: " +msgstr "" +"Impossible de charger la configuration Creole depuis le fichier config.eol" + +#: creole/server.py:244 +msgid "Unable to load creole configuration from extra: " +msgstr "" +"Impossible de charger la configuration Creole depuis les fichiers extra: " + +#: creole/server.py:272 +msgid "All variables are not set, please configure your system:" +msgstr "" +"Toutes les variables ne sont pas renseignées, veuillez configurer votre " +"système :" + +#: creole/server.py:277 +msgid "variables are mandatories" +msgstr "les variables sont obligatoires" + +#: creole/server.py:288 +msgid "variables must be in config file" +msgstr "les variables doivent être dans le fichier de configuration" + +#: creole/server.py:350 +#, python-brace-format +msgid "Mandatory variable {0} is not set." +msgstr "variable {0} obligatoire sans valeur renseignée" + +#: creole/server.py:429 +msgid "No configuration" +msgstr "Pas de configuration chargée" + +#: creole/server.py:460 +msgid "Base directory in which the server is launched (default: /tmp)" +msgstr "Répertoire à la racine duquel le serveur est lancé (par défaut, /tmp)" + +#: creole/server.py:464 +msgid "Configuration file of the server (default: /etc/eole/creoled.conf" +msgstr "" +"Fichier de configuration du serveur (par défaut, /etc/eole/creoled.conf)" + +#: creole/server.py:467 +msgid "Run the server as a daemon (default: false)" +msgstr "Exécution du serveur en mode démon (par défaut, false)" + +#: creole/server.py:470 +msgid "Listen on the specified IP:PORT (default: 127.0.0.1:8000)" +msgstr "Écoute sur le port spécifié (par défaut, 127.0.0.1:8000)" + +#: creole/server.py:473 creole/server.py:478 +msgid "Base under which the application is mounted (default: /)" +msgstr "Base under which the application is mounted (default: /)" + +#: creole/server.py:481 +msgid "User of the running process (default: nobody)" +msgstr "Utilisateur exécutant le processus (par défaut, nobody)" + +#: creole/server.py:484 +msgid "Group of the running process (default: nogroup)" +msgstr "Groupe auquel appartient le processus (par défaut, nogroup)" + +#: creole/server.py:487 +msgid "Umask of the running process (default: 0644)" +msgstr "Umask du processus (par défaut, 0644)" + +#: creole/server.py:593 +msgid "No configuration found: do not check for container mode." +msgstr "Pas de configuration trouvée : ne pas tester le mode conteneur." + +#: creole/server.py:608 +#, python-brace-format +msgid "Unable to listen for containers: {0}" +msgstr "Impossible d'être à l'écoute des conteneurs : {0}" + +#: creole/service.py:8 creole/service.py:16 creole/service.py:28 +#: creole/service.py:40 +msgid "Use new API “manage_services()”" +msgstr "Utilisez la nouvelle API “manage_services()”" + +#: creole/template.py:59 +msgid "Group variables must be of type master.slave" +msgstr "Les variables d'un groupe doivent être du type master.slave" + +#: creole/template.py:239 +msgid "length mismatch" +msgstr "Les longueurs ne correspondent pas." + +#: creole/template.py:302 +#, python-brace-format +msgid "Patching template '{0}' with '{1}'" +msgstr "Patch du template '{0}' avec '{1}'" + +#: creole/template.py:306 +#, python-brace-format +msgid "" +"Error applying patch: '{0}'\n" +"To reproduce and fix this error {1}" +msgstr "" +"Erreur d’application du patch: '{0}'\n" +"Pour reproduire et corriger l'erreur {1}" + +#: creole/template.py:320 +#, python-brace-format +msgid "Cleaning file '{0}'" +msgstr "Nettoyage du fichier '{0}'" + +#: creole/template.py:325 +#, python-brace-format +msgid "Error removing comments '{0}': {1}" +msgstr "Erreur de suppression des commentaires '{0}': {1}" + +#: creole/template.py:340 +#, python-brace-format +msgid "Template file not enabled: {0}" +msgstr "Fichier template non actif : {0}" + +#: creole/template.py:343 +#, python-brace-format +msgid "Template file not set: {0}" +msgstr "Fichier template non défini : {0}" + +#: creole/template.py:347 +#, python-brace-format +msgid "Template target not set: {0}" +msgstr "Cible du template non définie : {0}" + +#: creole/template.py:364 +#, python-brace-format +msgid "Template {0} unexistent" +msgstr "Template {0} inexistant" + +#: creole/template.py:367 +#, python-brace-format +msgid "Copy template: '{0}' -> '{1}'" +msgstr "Copie du template '{0}' vers '{1}'" + +#: creole/template.py:383 +#, python-brace-format +msgid "File {0} does not exist." +msgstr "Le fichier {0} n'existe pas" + +#: creole/template.py:388 +#, python-brace-format +msgid "Folder {0} does not exist but is required by {1}" +msgstr "le répertoire {0} n'existe pas mais est obligatoire pour {1}" + +#: creole/template.py:410 +#, python-brace-format +msgid "Cheetah processing: '{0}' -> '{1}'" +msgstr "Traitement Cheetah : '{0}' vers '{1}'" + +#: creole/template.py:429 +#, python-brace-format +msgid "Error: unknown variable used in template {0} : {1}" +msgstr "" +"Erreur: Utilisation d'une variable non existante dans le template de {0} : " +"{1}" + +#: creole/template.py:432 +#, python-brace-format +msgid "Encoding issue detected in template {0}" +msgstr "Problème d'encodage détecté dans le template de {0}" + +#: creole/template.py:435 +#, python-brace-format +msgid "Error while instantiating template {0}: {1}" +msgstr "Erreur lors de l'instanciation du template de {0} : {1}" + +#: creole/template.py:448 +#, python-brace-format +msgid "Unable to write in file '{0}': '{1}'" +msgstr "Impossible d'écrire dans le fichier '{0}' : '{1}'" + +#: creole/template.py:480 creole/template.py:485 +#, python-brace-format +msgid "Changing properties: {0}" +msgstr "Changement des propriétés : {0}" + +#: creole/template.py:483 creole/template.py:488 +#, python-brace-format +msgid "Error changing properties {0}: {1}" +msgstr "Erreur lors du changement des propriétés {0} : {1}" + +#: creole/template.py:498 +#, python-brace-format +msgid "File '{0}' unexistent." +msgstr "Fichier '{0}' inexistant." + +#: creole/template.py:517 +#, python-brace-format +msgid "Removing file '{0}' from container '{1}'" +msgstr "Suppression du fichier '{0}' du conteneur '{1}'" + +#: creole/template.py:523 +#, python-brace-format +msgid "Instantiation of file '{0}' disabled" +msgstr "Instanciation du fichier '{0}' désactivée" + +#: creole/template.py:525 +#, python-brace-format +msgid "Instantiating file '{0}' from '{1}'" +msgstr "Instanciation du fichier '{0}' depuis '{1}'" + +#: creole/template.py:592 +#, python-brace-format +msgid "Removing file '{0}'" +msgstr "Suppression du fichier '{0}'" + +#: creole/upgrade.py:104 +#, python-brace-format +msgid "Variable {0} has been copied in {1}" +msgstr "La variable {0} a été copiée dans {1}" + +#: creole/upgrade.py:107 creole/upgrade24.py:239 +#, python-brace-format +msgid "Variable {0} has been renamed to {1}" +msgstr "La variable {0} a été renommée en {1}" + +#: creole/upgrade.py:119 +#, python-brace-format +msgid "Variable {0} has been removed" +msgstr "La variable {0} a été supprimée" + +#: creole/upgrade.py:133 +#, python-brace-format +msgid "Source variable {0} invalid" +msgstr "Variable source {0} invalide" + +#: creole/upgrade.py:145 creole/upgrade24.py:155 creole/upgrade24.py:173 +#, python-brace-format +msgid "Variable updated: {0} = {1}" +msgstr "Mise a jour de la variable : {0} = {1}" + +#: creole/upgrade.py:167 +msgid "config.eol upgrade started" +msgstr "La montée de version de config.eol a été lancée" + +#: creole/upgrade.py:208 +#, python-brace-format +msgid "Unknown variable: {0}" +msgstr "Variable inconnue : {0}" + +#: creole/upgrade.py:224 creole/upgrade.py:393 creole/upgrade24.py:287 +#: creole/upgrade24.py:353 creole/upgrade24.py:392 creole/upgrade24.py:419 +#: creole/upgrade24.py:457 creole/upgrade24.py:531 creole/upgrade24.py:583 +#: creole/upgrade24.py:614 +#, python-brace-format +msgid "Starting {0} to {1} upgrade" +msgstr "Lancement de la montée de version de {0} vers {1}" + +#: creole/upgrade.py:554 +msgid "Migrating SMTP parameters" +msgstr "Migration des paramètres SMTP" + +#: creole/upgrade.py:581 +msgid "Mail configuration not recognised, not processed" +msgstr "Configuration mail non reconnue, laissée en l’état" + +#: creole/upgrade24.py:78 +msgid "get_noncalculated_value_for_auto: unknown variable {}" +msgstr "get_noncalculated_value_for_auto : variable inconnue {}" + +#: creole/upgrade24.py:149 +#, python-brace-format +msgid "Try to set value to unknown option: {0} = {1}" +msgstr "Tentative d'affectation de valeur à une option inconnue : {0} = {1}" + +#: creole/upgrade24.py:167 creole/upgrade24.py:230 +msgid "empty value" +msgstr "valeur vide" + +#: creole/upgrade24.py:168 creole/upgrade24.py:175 creole/upgrade24.py:179 +#: creole/upgrade24.py:231 +#, python-brace-format +msgid "{0} for {1}" +msgstr "{0} pour {1}" + +#: creole/upgrade24.py:186 +#, python-brace-format +msgid "Try to delete an unknown option: {0}" +msgstr "Tentative de supression d'une option inconnu : {0}" + +#: creole/upgrade24.py:190 +#, python-brace-format +msgid "Variable {0} reinitialized" +msgstr "Réinitialisation de la variable {0}" + +#: creole/upgrade24.py:199 +#, python-brace-format +msgid "Try to append a value to an unknown option: {0} += {1}" +msgstr "Tentative d'ajout de valeur à une option inconnue : {0} += {1}" + +#: creole/upgrade24.py:213 +#, python-brace-format +msgid "Try to modify last value of an unknown option: {0}[-1] = {1}" +msgstr "" +"Tentative de modification de la dernière valeur d'une option inconnue : {0}" +"[-1] = {1}" + +#: creole/upgrade24.py:306 creole/upgrade24.py:330 +#, python-brace-format +msgid "Invalid value : {0} in old variable {1}" +msgstr "Valeur {0} invalide pour la variable {1}" + +#: creole/upgrade24.py:525 +#, python-brace-format +msgid "Interface {0} name has not an 'ethX' format" +msgstr "Le nom de l'interface {0} n'est pas au format ethX" + +#: creole/utils.py:149 +msgid "Choose a number in the list" +msgstr "Choisissez un nombre dans la liste." + +#: creole/var_loader.py:39 +msgid "mac address" +msgstr "" + +#: creole/var_loader.py:110 +#, python-brace-format +msgid "option {0}'s value should be in {1}" +msgstr "La valeur de l'option {0} devrait être choisie dans {1}." + +#: creole/var_loader.py:265 +#, python-brace-format +msgid "{0} {1} redefined but unexistent." +msgstr "{0} {1} redefinie mais non existant" + +#: creole/var_loader.py:267 +#, python-brace-format +msgid "{0} {1} existent." +msgstr "{0} {1} existant." + +#: creole/var_loader.py:306 +#, python-brace-format +msgid "Name ({0}) already used." +msgstr "Le nom ({0}) est déjà utilisé." + +#: creole/var_loader.py:377 +#, python-brace-format +msgid "Unknown key {0}" +msgstr "Clé inconnue {0}" + +#: creole/var_loader.py:402 +msgid "No requires for SymLinkOption" +msgstr "Pas de « requires » pour une « SymLinkOption »." + +#: creole/var_loader.py:407 +#, python-brace-format +msgid "SymLinkOption targetting unexistent variable: {0}." +msgstr "Variable {0} inexistante utilisée comme cible d'une SymLinkOption." + +#: creole/var_loader.py:485 +#, python-brace-format +msgid "Two containers with the same id ({0})" +msgstr "Deux conteneurs ont le même ID ({0})" + +#: creole/var_loader.py:487 +#, python-brace-format +msgid "Multiple ids for the container {0}" +msgstr "Le conteneur {0} possède plusieurs IDs" + +#: creole/var_loader.py:523 +msgid "Bridge IP network_br0 address" +msgstr "Adresse réseau du bridge br0" + +#: creole/var_loader.py:554 +#, python-brace-format +msgid "IP address of container {0}" +msgstr "Adresse IP du conteneur {0}" + +#: creole/var_loader.py:661 +#, python-brace-format +msgid "Two variables with the same name ({0})" +msgstr "Deux variables ont le même nom ({0})" + +#: creole/var_loader.py:663 +#, python-brace-format +msgid "Attempt to redefine unexistent variable: {0}." +msgstr "Tentative de redéfinition d'une variable inexistante : {0}." + +#: creole/var_loader.py:700 +#, python-brace-format +msgid "Redefining multi attribute is not allowed for variable {0}" +msgstr "Redéfinition de l'attribut multi interdit pour la variable {0}" + +#: creole/var_loader.py:703 +#, python-brace-format +msgid "Redefining type attribute is not allowed for variable {0}" +msgstr "Redéfinition de l'attribut type interdit pour la variable {0}" + +#: creole/var_loader.py:744 creole/var_loader.py:751 +#, python-brace-format +msgid "help already set for {0}" +msgstr "aide déjà existante pour : {0}" + +#: creole/var_loader.py:761 +#, python-brace-format +msgid "More than one separator for {0}" +msgstr "Plus d'un séparateur défini pour : {0}" + +#: creole/var_loader.py:800 +#, python-brace-format +msgid "Unknown condition type for {0}" +msgstr "Type de condition inconnu pour {0}" + +#: creole/var_loader.py:806 creole/var_loader.py:1530 +#, python-brace-format +msgid "Unknown type {0}" +msgstr "Type {0} inconnu" + +#: creole/var_loader.py:809 +#, python-brace-format +msgid "Unknown hidden {0}" +msgstr "« hidden » {0} inconnu" + +#: creole/var_loader.py:812 +#, python-brace-format +msgid "Unknown name {0}" +msgstr "Nom {0} inconnu" + +#: creole/var_loader.py:815 +#, python-brace-format +msgid "Unknown optional {0}" +msgstr "« optional » {0} inconnu" + +#: creole/var_loader.py:851 +#, python-brace-format +msgid "More than one function for target: {0}" +msgstr "Plus d'une fonction pour la cible {0}" + +#: creole/var_loader.py:856 +#, python-brace-format +msgid "Can not set level to {0} for this kind of callback" +msgstr "" +"Impossible de définir le niveau à {0} pour ce type de fonction de rappel." + +#: creole/var_loader.py:869 +msgid "Namespace different in param not allowed: {} - {}" +msgstr "Espaces de nom différents interdits dans les paramètres : {} - {}" + +#: creole/var_loader.py:885 +#, python-brace-format +msgid "Type {0} not yet implemented for {1} for {2}" +msgstr "Le type {0} n'est pas encore implémenté pour {1} pour {2}." + +#: creole/var_loader.py:901 +#, python-brace-format +msgid "Computing function already defined for {0}" +msgstr "Calcul déjà présent pour {0}" + +#: creole/var_loader.py:1071 +#, python-brace-format +msgid "File {0} does not exist" +msgstr "Le fichier {0} n'existe pas." + +#: creole/var_loader.py:1086 +msgid "Unable to run read_dir if Config already exists." +msgstr "Impossible de refaire une read_dir si la Config existe" + +#: creole/var_loader.py:1112 +#, python-brace-format +msgid "Unable to populate {0}: {1}" +msgstr "Impossible de remplir {0} : {1}" + +#: creole/var_loader.py:1215 +#, python-brace-format +msgid "Condition using unexistent variable {0} as parameter." +msgstr "Variable {0} inexistante utilisée en paramètre d'une condition." + +#: creole/var_loader.py:1246 +#, python-brace-format +msgid "Condition targetting unexistent variable {0}" +msgstr "Variable {0} inexistante utilisée comme cible d'une condition." + +#: creole/var_loader.py:1250 +#, python-brace-format +msgid "requires already set for this option preventing changing properties {0}" +msgstr "" +"« requires » déjà défini pour cette option et empêchant de modifier les " +"propriétés {0}." + +#: creole/var_loader.py:1254 +#, python-brace-format +msgid "requires already set for this option {0}" +msgstr "« requires » déjà défini pour l'option {0}." + +#: creole/var_loader.py:1345 +#, python-brace-format +msgid "Check using unexistent variable {0} as parameter." +msgstr "Variable {0} inexistante utilisée en paramètre d'un check." + +#: creole/var_loader.py:1386 +#, python-brace-format +msgid "unknown function {0} in eosfunc" +msgstr "fonction {0} inconnue dans eosfunc." + +#: creole/var_loader.py:1403 creole/var_loader.py:1416 +#, python-brace-format +msgid "Variable computing function using unknown variable {0}" +msgstr "Utilisation de la variable {0} non présente dans un calcul" + +#: creole/var_loader.py:1492 +msgid "Slave value length can not be greater than 1." +msgstr "Le nombre de valeurs d'une d'une esclave ne peut être supérieur à 1" + +#: creole/var_loader.py:1597 creole/var_loader.py:1605 +#, python-brace-format +msgid "{0} is auto, so must not be auto_freeze or auto_save" +msgstr "{0} est auto, donc ne doit pas être auto_freeze ou auto_save" + +#: creole/var_loader.py:1700 +#, python-brace-format +msgid "Unknown family {0} has requires" +msgstr "La famille inconnue {0} a des conditions" + +#: creole/xmlreflector.py:46 +msgid "not a valid xml file: {}" +msgstr "fichier XML invalide : {}" + +#~ msgid "Also update Envole packages" +#~ msgstr "Mettre à jour Envole." + +#~ msgid "Updating Envole packages ..." +#~ msgstr "Mise à jour des paquets Envole ..." + +#~ msgid "no" +#~ msgstr "non" + +#~ msgid "yes" +#~ msgstr "oui" + +#~ msgid "oui" +#~ msgstr "oui" + +#~ msgid "Reload config due to {0} on {1}" +#~ msgstr "Rechargement de la configuration suite à l'évènement {0} sur {1}" + +#~ msgid "Unable to connect to proxy {0}:{1}" +#~ msgstr "Impossible de se connecter au proxy {0}:{1}" + +#~ msgid "Error while loading CA to be sent to clients ({0}): {1}" +#~ msgstr "Erreur au chargement des CA à envoyer aux clients ({0}) : {1}" + +#~ msgid "infinite loop detect for {0}'s callback" +#~ msgstr "boucle infinie détectée pour le callback de {0}" + +#~ msgid "" +#~ "Raising release level will prevent lowering back to this stable version." +#~ msgstr "" +#~ "Augmenter de version mineure empêchera de revenir à cette version mineure " +#~ "stable." + +#~ msgid "Raising update level may prevent lowering back to stable version." +#~ msgstr "" +#~ "Augmenter de version mineure empêchera de revenir à cette version mineure " +#~ "stable." + +#~ msgid "use an higher release packages." +#~ msgstr "utiliser les paquets d'une version mineure supérieure." + +#~ msgid "valid_differ must have only eole variable" +#~ msgstr "valid_differ ne doit avoir que des variables eole." + +#~ msgid "cannot contact creoled" +#~ msgstr "ne peut contacter creoled" + +#~ msgid "cannot find configuration for container {0}" +#~ msgstr "impossible de trouver la configuration pour le conteneur {0}" + +#~ msgid "" +#~ "http://eole.ac-dijon.fr/materiel/ allows you to consult compatible " +#~ "hardware database." +#~ msgstr "" +#~ "http://eole.ac-dijon.fr/materiel/ vous permet de consulter une base des " +#~ "matériels compatibles" + +#~ msgid "" +#~ "Do you want to send this server hardware description to improve " +#~ "compatible hardware database." +#~ msgstr "" +#~ "Pour enrichir cette base, acceptez-vous l'envoi de la description " +#~ "matérielle de ce serveur ?" diff --git a/translation/fr/eole-schedule.po b/translation/fr/eole-schedule.po new file mode 100644 index 0000000..7be1114 --- /dev/null +++ b/translation/fr/eole-schedule.po @@ -0,0 +1,72 @@ +# French translations for eole-schedule package +# Traductions françaises du paquet eole-schedule. +# This file is put in the public domain. +# Benjamin Bohard , 2015. +# +msgid "" +msgstr "" +"Project-Id-Version: eole-schedule\n" +"Report-Msgid-Bugs-To: eole@ac-dijon.fr\n" +"POT-Creation-Date: 2017-06-22 10:30+0200\n" +"PO-Revision-Date: 2015-12-02 10:28+0100\n" +"Last-Translator: Benjamin Bohard \n" +"Language-Team: Équipe EOLE \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: schedule/schedule:69 +msgid "Starting {}" +msgstr "Démarrage de {}" + +#: schedule/schedule:106 +msgid "Error detected\n" +msgstr "Une erreur a été détectée\n" + +#: schedule/schedule:107 +msgid "{} exited with error return code" +msgstr "Sortie de {} avec un code d'erreur" + +#: schedule/schedule:110 +msgid "{} finished" +msgstr "{} accompli" + +#: schedule/schedule:126 +msgid "Job already running, cancelling" +msgstr "Tâche déjà en cours, annulation" + +#: schedule/schedule:140 +msgid "bareos is set for this day, cancelled" +msgstr "Une tâche bareos est programmée pour ce jour, annulation" + +#: schedule/schedule:156 +#, python-brace-format +msgid "Unknown job: {0}" +msgstr "Tâche inconnue : {0}" + +#: schedule/schedule:186 +#, python-brace-format +msgid "Too many arguments: {0}" +msgstr "Trop d'arguments : {0}" + +#: schedule/schedule:195 +#, python-brace-format +msgid "Not enough arguments: {0}" +msgstr "Pas assez d'arguments : {0}" + +#: schedule/schedule:199 +#, python-brace-format +msgid "Second argument must be pre or post: {0}" +msgstr "Le second argument doit être pre ou post : {0}" + +#: schedule/schedule:210 +#, python-brace-format +msgid "Too many arguments for cron: {0}" +msgstr "Trop d'arguments pour cron : {0}" + +#: schedule/schedule:215 +#, python-brace-format +msgid "Unknown schedule type : {0}" +msgstr "Type de schedule inconnu : {0}" diff --git a/translation/fr/update-manager.po b/translation/fr/update-manager.po new file mode 100644 index 0000000..83df19f --- /dev/null +++ b/translation/fr/update-manager.po @@ -0,0 +1,275 @@ +# French translations for update-manager package +# Traductions françaises du paquet update-manager. +# This file is put in the public domain. +# Benjamin Bohard , 2015. +# +msgid "" +msgstr "" +"Project-Id-Version: update-manager\n" +"Report-Msgid-Bugs-To: eole@ac-dijon.fr\n" +"POT-Creation-Date: 2016-04-08 17:19+0200\n" +"PO-Revision-Date: 2016-01-26 14:35+0100\n" +"Last-Translator: Benjamin Bohard \n" +"Language-Team: Équipe EOLE \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: upgrade/Upgrade-Auto:63 +msgid "Upgrade to a newer major version is not available" +msgstr "" +"La mise à niveau vers une nouvelle version majeure n'est pas disponible" + +#: upgrade/Upgrade-Auto:64 +msgid "Use Maj-Release script to upgrade to next minoir version" +msgstr "" +"Utilisez la commande Maj-Release pour changer de sous-version du serveur " +"EOLE." + +#: upgrade/Upgrade-Auto:98 +msgid "" +"Available choices:\n" +"{}\n" +msgstr "" +"Choix disponibles :\n" +"{}\n" + +#: upgrade/Upgrade-Auto:103 +msgid "Automatically selected first choice: {}\n" +msgstr "Premier choix sélectionné automatiquement : {}\n" + +#: upgrade/Upgrade-Auto:107 +msgid "" +"\n" +"[1]: " +msgstr "" +"\n" +"[1] : " + +#: upgrade/Upgrade-Auto:110 upgrade/Upgrade-Auto:594 +msgid "" +"\n" +"Upgrade aborted by user" +msgstr "" +"\n" +"Migration interrompue par l'utilisateur" + +#: upgrade/Upgrade-Auto:122 +msgid "Choice {} not available\n" +msgstr "Choix {} non disponible\n" + +#: upgrade/Upgrade-Auto:126 upgrade/Upgrade-Auto:495 +msgid "Upgrade cancelled by user" +msgstr "Migration annulée par l'utilisateur" + +#: upgrade/Upgrade-Auto:129 +msgid "Invalid input: {}\n" +msgstr "Saisie invalide : {}\n" + +#: upgrade/Upgrade-Auto:240 +#, python-brace-format +msgid "Verifying ISO image {iso}" +msgstr "Vérification de l'image ISO {iso}" + +#: upgrade/Upgrade-Auto:243 +msgid "Download SHA256SUMS file" +msgstr "Téléchargement du fichier SHA256SUMS" + +#: upgrade/Upgrade-Auto:247 +msgid "Download SHA256SUMS.gpg file" +msgstr "Téléchargement du fichier SHA256SUMS.gpg" + +#: upgrade/Upgrade-Auto:250 +msgid "Check SHA256SUMS file signature" +msgstr "Vérification de la signature du fichier SHA256SUMS" + +#: upgrade/Upgrade-Auto:258 +msgid "Check ISO SHA256..." +msgstr "Vérification de l'empreinte SHA256 de l'iso" + +#: upgrade/Upgrade-Auto:275 +msgid "OK" +msgstr "OK" + +#: upgrade/Upgrade-Auto:278 +msgid "Error" +msgstr "Erreur" + +#: upgrade/Upgrade-Auto:302 +#, python-brace-format +msgid "Error downloading {file} with wget from {url}" +msgstr "Erreur lors du téléchargement de {file} avec wget depuis {url}" + +#: upgrade/Upgrade-Auto:313 +msgid "Error downloading the image with zsync" +msgstr "Erreur lors du téléchargement de l'image avec zsync" + +#: upgrade/Upgrade-Auto:351 +#, python-brace-format +msgid "Unable to umount {cdrom}" +msgstr "Démontage de {cdrom} impossible" + +#: upgrade/Upgrade-Auto:383 +#, python-brace-format +msgid "Downloading ISO image for {release}" +msgstr "Téléchargement de l'image ISO pour {release}" + +#: upgrade/Upgrade-Auto:402 +msgid "No CDROM found" +msgstr "Aucun CDROM trouvé" + +#: upgrade/Upgrade-Auto:406 +#, python-brace-format +msgid "No such file: {iso}" +msgstr "Aucun fichier de ce nom : {iso}" + +#: upgrade/Upgrade-Auto:408 +#, python-brace-format +msgid "Unreadable file: {iso}" +msgstr "fichier illisible : {iso}" + +#: upgrade/Upgrade-Auto:414 +#, python-brace-format +msgid "Copying {source} to {iso}" +msgstr "Copie de {source} vers {iso}" + +#: upgrade/Upgrade-Auto:423 +#, python-brace-format +msgid "Error checking ISO after copy, remove {iso}" +msgstr "" +"Erreur lors de la vérification de l'ISO après copie ; suppression de {iso}" + +#: upgrade/Upgrade-Auto:436 +#, python-brace-format +msgid "Error checking ISO image after download, remove {iso}" +msgstr "" +"Erreur lors de la vérification de l'image ISO après le téléchargement ; " +"suppression de {iso}" + +#: upgrade/Upgrade-Auto:444 +msgid "EOLE distribution upgrade tool." +msgstr "Outil de montée de version de la distribution EOLE." + +#: upgrade/Upgrade-Auto:447 +msgid "Target release number" +msgstr "Numéro de la version cible" + +#: upgrade/Upgrade-Auto:450 +msgid "Only download the ISO image" +msgstr "Téléchargement de l'image ISO uniquement" + +#: upgrade/Upgrade-Auto:453 +msgid "Path to an ISO image" +msgstr "Chemin vers une image ISO" + +#: upgrade/Upgrade-Auto:456 +msgid "Use CDROM device instead of downloading ISO image" +msgstr "Utiliser le périphérique CDROM plutôt que de télécharger l'image ISO" + +#: upgrade/Upgrade-Auto:459 +msgid "Pass limit rate to wget. “0” to disable." +msgstr "" +"Fournir une limite de taux de transfert à wget. Utiliser « 0 » pour " +"désactiver." + +#: upgrade/Upgrade-Auto:462 +msgid "Do not ask confirmation" +msgstr "Ne pas demander de confirmation" + +#: upgrade/Upgrade-Auto:472 +msgid "This script will upgrade this server to a new release" +msgstr "" +"Ce script va effectuer la migration vers une nouvelle version de la " +"distribution" + +#: upgrade/Upgrade-Auto:473 +msgid "Modifications will be irreversible." +msgstr "Les modifications ne sont pas réversibles" + +#: upgrade/Upgrade-Auto:475 +msgid "Starting Upgrade-Auto ({})" +msgstr "Démarrage d'Upgrade-Auto ({})" + +#: upgrade/Upgrade-Auto:480 +#, python-brace-format +msgid "Invalid release {version} use: {values}" +msgstr "Version {version} invalide, utiliser {values}" + +#: upgrade/Upgrade-Auto:487 +msgid "Choose which version you want to upgrade to\n" +msgstr "Choisir la version vers laquelle migrer\n" + +#: upgrade/Upgrade-Auto:488 +msgid "Which version do you want to upgrade to (or 'q' to quit)?" +msgstr "Vers quelle version choisissez-vous de migrer (ou 'q' pour quitter) ?" + +#: upgrade/Upgrade-Auto:493 +msgid "Do you really want to upgrade to version {}?" +msgstr "Voulez-vous vraiment migrer vers la version {} ?" + +#: upgrade/Upgrade-Auto:504 +msgid "Check update status" +msgstr "Vérification de l'état de mise à jour" + +#: upgrade/Upgrade-Auto:513 +msgid "Some packages are not up-to-date!" +msgstr "Des paquets ne sont pas à jour !" + +#: upgrade/Upgrade-Auto:516 +msgid "Update this server (Maj-Auto) before another attempt to upgrade" +msgstr "Effectuez une mise à jour (Maj-Auto) avant de relancer ce script" + +#: upgrade/Upgrade-Auto:519 +msgid "Server is up-to-date" +msgstr "Le serveur est à jour" + +#: upgrade/Upgrade-Auto:522 +msgid "" +"In order to upgrade, most recent kernel endorsed for this release must be " +"used" +msgstr "" +"Pour cette opération, vous devez impérativement être sur le dernier noyau " +"disponible pour cette version !" + +#: upgrade/Upgrade-Auto:527 +msgid "This server uses most recent kernel" +msgstr "Le serveur utilise le dernier noyau" + +#: upgrade/Upgrade-Auto:532 +msgid "Download only detected, stop" +msgstr "Arrêt : téléchargement demandé uniquement" + +#: upgrade/Upgrade-Auto:537 +msgid "Copying upgrade scripts" +msgstr "Copie des scripts de migration" + +#: upgrade/Upgrade-Auto:539 +#, python-brace-format +msgid "Directory {0} already exists" +msgstr "Le répertoire {0} existe déjà" + +#: upgrade/Upgrade-Auto:547 +msgid "Configuring upgrade" +msgstr "Configuration de la migration" + +#: upgrade/Upgrade-Auto:563 +msgid "Module specific commands" +msgstr "Instructions préalables spécifiques au module" + +#: upgrade/Upgrade-Auto:566 +#, python-brace-format +msgid "Error {0}" +msgstr "Erreur {0}" + +#: upgrade/Upgrade-Auto:586 +msgid "Upgrading server" +msgstr "Migration du serveur" + +#~ msgid "" +#~ "Select target version:\n" +#~ "{}\n" +#~ msgstr "" +#~ "Sélectionner la version cible :\n" +#~ "{}\n" diff --git a/translation/update-manager.pot b/translation/update-manager.pot new file mode 100644 index 0000000..943e904 --- /dev/null +++ b/translation/update-manager.pot @@ -0,0 +1,249 @@ +# SOME DESCRIPTIVE TITLE. +# This file is put in the public domain. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: update-manager\n" +"Report-Msgid-Bugs-To: eole@ac-dijon.fr\n" +"POT-Creation-Date: 2017-12-11 10:20+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: upgrade/Upgrade-Auto:63 +msgid "Upgrade to a newer major version is not available" +msgstr "" + +#: upgrade/Upgrade-Auto:64 +msgid "Use Maj-Release script to upgrade to next minoir version" +msgstr "" + +#: upgrade/Upgrade-Auto:98 +msgid "" +"Available choices:\n" +"{}\n" +msgstr "" + +#: upgrade/Upgrade-Auto:103 +msgid "Automatically selected first choice: {}\n" +msgstr "" + +#: upgrade/Upgrade-Auto:107 +msgid "" +"\n" +"[1]: " +msgstr "" + +#: upgrade/Upgrade-Auto:110 upgrade/Upgrade-Auto:594 +msgid "" +"\n" +"Upgrade aborted by user" +msgstr "" + +#: upgrade/Upgrade-Auto:122 +msgid "Choice {} not available\n" +msgstr "" + +#: upgrade/Upgrade-Auto:126 upgrade/Upgrade-Auto:495 +msgid "Upgrade cancelled by user" +msgstr "" + +#: upgrade/Upgrade-Auto:129 +msgid "Invalid input: {}\n" +msgstr "" + +#: upgrade/Upgrade-Auto:240 +#, python-brace-format +msgid "Verifying ISO image {iso}" +msgstr "" + +#: upgrade/Upgrade-Auto:243 +msgid "Download SHA256SUMS file" +msgstr "" + +#: upgrade/Upgrade-Auto:247 +msgid "Download SHA256SUMS.gpg file" +msgstr "" + +#: upgrade/Upgrade-Auto:250 +msgid "Check SHA256SUMS file signature" +msgstr "" + +#: upgrade/Upgrade-Auto:258 +msgid "Check ISO SHA256..." +msgstr "" + +#: upgrade/Upgrade-Auto:275 +msgid "OK" +msgstr "" + +#: upgrade/Upgrade-Auto:278 +msgid "Error" +msgstr "" + +#: upgrade/Upgrade-Auto:302 +#, python-brace-format +msgid "Error downloading {file} with wget from {url}" +msgstr "" + +#: upgrade/Upgrade-Auto:313 +msgid "Error downloading the image with zsync" +msgstr "" + +#: upgrade/Upgrade-Auto:351 +#, python-brace-format +msgid "Unable to umount {cdrom}" +msgstr "" + +#: upgrade/Upgrade-Auto:383 +#, python-brace-format +msgid "Downloading ISO image for {release}" +msgstr "" + +#: upgrade/Upgrade-Auto:402 +msgid "No CDROM found" +msgstr "" + +#: upgrade/Upgrade-Auto:406 +#, python-brace-format +msgid "No such file: {iso}" +msgstr "" + +#: upgrade/Upgrade-Auto:408 +#, python-brace-format +msgid "Unreadable file: {iso}" +msgstr "" + +#: upgrade/Upgrade-Auto:414 +#, python-brace-format +msgid "Copying {source} to {iso}" +msgstr "" + +#: upgrade/Upgrade-Auto:423 +#, python-brace-format +msgid "Error checking ISO after copy, remove {iso}" +msgstr "" + +#: upgrade/Upgrade-Auto:436 +#, python-brace-format +msgid "Error checking ISO image after download, remove {iso}" +msgstr "" + +#: upgrade/Upgrade-Auto:444 +msgid "EOLE distribution upgrade tool." +msgstr "" + +#: upgrade/Upgrade-Auto:447 +msgid "Target release number" +msgstr "" + +#: upgrade/Upgrade-Auto:450 +msgid "Only download the ISO image" +msgstr "" + +#: upgrade/Upgrade-Auto:453 +msgid "Path to an ISO image" +msgstr "" + +#: upgrade/Upgrade-Auto:456 +msgid "Use CDROM device instead of downloading ISO image" +msgstr "" + +#: upgrade/Upgrade-Auto:459 +msgid "Pass limit rate to wget. “0” to disable." +msgstr "" + +#: upgrade/Upgrade-Auto:462 +msgid "Do not ask confirmation" +msgstr "" + +#: upgrade/Upgrade-Auto:472 +msgid "This script will upgrade this server to a new release" +msgstr "" + +#: upgrade/Upgrade-Auto:473 +msgid "Modifications will be irreversible." +msgstr "" + +#: upgrade/Upgrade-Auto:475 +msgid "Starting Upgrade-Auto ({})" +msgstr "" + +#: upgrade/Upgrade-Auto:480 +#, python-brace-format +msgid "Invalid release {version} use: {values}" +msgstr "" + +#: upgrade/Upgrade-Auto:487 +msgid "Choose which version you want to upgrade to\n" +msgstr "" + +#: upgrade/Upgrade-Auto:488 +msgid "Which version do you want to upgrade to (or 'q' to quit)?" +msgstr "" + +#: upgrade/Upgrade-Auto:493 +msgid "Do you really want to upgrade to version {}?" +msgstr "" + +#: upgrade/Upgrade-Auto:504 +msgid "Check update status" +msgstr "" + +#: upgrade/Upgrade-Auto:513 +msgid "Some packages are not up-to-date!" +msgstr "" + +#: upgrade/Upgrade-Auto:516 +msgid "Update this server (Maj-Auto) before another attempt to upgrade" +msgstr "" + +#: upgrade/Upgrade-Auto:519 +msgid "Server is up-to-date" +msgstr "" + +#: upgrade/Upgrade-Auto:522 +msgid "" +"In order to upgrade, most recent kernel endorsed for this release must be " +"used" +msgstr "" + +#: upgrade/Upgrade-Auto:527 +msgid "This server uses most recent kernel" +msgstr "" + +#: upgrade/Upgrade-Auto:532 +msgid "Download only detected, stop" +msgstr "" + +#: upgrade/Upgrade-Auto:537 +msgid "Copying upgrade scripts" +msgstr "" + +#: upgrade/Upgrade-Auto:539 +#, python-brace-format +msgid "Directory {0} already exists" +msgstr "" + +#: upgrade/Upgrade-Auto:547 +msgid "Configuring upgrade" +msgstr "" + +#: upgrade/Upgrade-Auto:563 +msgid "Module specific commands" +msgstr "" + +#: upgrade/Upgrade-Auto:566 +#, python-brace-format +msgid "Error {0}" +msgstr "" + +#: upgrade/Upgrade-Auto:586 +msgid "Upgrading server" +msgstr "" diff --git a/upgrade/DistUpgradeViewEOLE.py b/upgrade/DistUpgradeViewEOLE.py new file mode 100644 index 0000000..14e496a --- /dev/null +++ b/upgrade/DistUpgradeViewEOLE.py @@ -0,0 +1,27 @@ +from __future__ import absolute_import, print_function +from .DistUpgradeViewNonInteractive import DistUpgradeViewNonInteractive +z_proc = "UPGRADE" +try: + from pyeole.ansiprint import print_red +except: + print_red = print +try: + # import zephir logger if registered + from zephir.zephir_conf.zephir_conf import id_serveur + from zephir.lib_zephir import log as zlog + import time +except: + zlog = None + +class DistUpgradeViewEOLE(DistUpgradeViewNonInteractive): + def error(self, summary, msg, extended_msg=None): + " display an error " + print_red("Une erreur est survenue : %s %s (%s)" % (summary, msg, extended_msg)) + if zlog is not None: + zlog(z_proc, -2, "Une erreur est survenue : %s" % summary, str(time.ctime())) + super(DistUpgradeViewEOLE, self).error(summary, msg, extended_msg) + def abort(self): + if zlog is not None: + zlog(z_proc, 1, "Une erreur fatale est survenue Vous trouverez plus d'informations dans les journaux : /var/log/dist-upgrade/", str(time.ctime())) + print_red("Une erreur fatale est survenue. Vous trouverez plus d'informations dans les journaux : /var/log/dist-upgrade/") + super(DistUpgradeViewEOLE, self).abort() diff --git a/upgrade/EOLEPostInstallScripts.py b/upgrade/EOLEPostInstallScripts.py new file mode 100755 index 0000000..917e549 --- /dev/null +++ b/upgrade/EOLEPostInstallScripts.py @@ -0,0 +1,37 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +from os import system +from os.path import join +from pyeole.ihm import print_title, print_red +from creole.fonctionseole import zephir + +POST_UPGRADE = 'post_upgrade' +# nom de procédure pour les logs Zéphir +z_proc = "UPGRADE" + +# Variable déclarée en double (cf Upgrade-Auto) +RUNPARTS_CMD = u'/bin/run-parts --exit-on-error -v {directory}' + +if __name__ == "__main__": + #FIXME + tmp_dir = '/tmp/Upgrade-Auto' + post_upgrade = join(tmp_dir, POST_UPGRADE) + print_title("Instructions préalables spécifiques au module") + system('/usr/share/creole/gen_certif.py') + code = system(RUNPARTS_CMD.format(directory=post_upgrade)) + if code != 0: + zephir("ERR", u'Erreur dans un script post_upgrade)', z_proc) + print_red((u'Erreur {0}').format(post_upgrade)) + exit(1) + #Ne pas faire d'import ... doit être celui de la version de destination + #FIXME +# echo "EOLE \l +# Serveur migré de 2.3 vers $NEW_VERS +# " > /etc/issue + #FIXME apt-get clean ? + print_title("Mise à jour des informations dans l'application Zéphir ...") + #Ne pas faire d'import ... doit être celui de la version de destination + system('/usr/share/zephir/scripts/upgrade_distrib.py') + zephir("FIN", 'procédure Upgrade-Auto terminée avec succès', z_proc) + diff --git a/upgrade/Upgrade-Auto b/upgrade/Upgrade-Auto new file mode 100755 index 0000000..c7cb662 --- /dev/null +++ b/upgrade/Upgrade-Auto @@ -0,0 +1,596 @@ +#!/usr/bin/python -u +# -*- coding: utf-8 -*- +# +########################################################################## +# Maj-Auto - Manage automatique update of EOLE server +# Copyright © 2015 Pôle de compétences EOLE +# +# License CeCILL: +# * in french: http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html +# * in english http://www.cecill.info/licences/Licence_CeCILL_V2-en.html +########################################################################## + +import sys + +import warnings +import apt + +import atexit + +from argparse import ArgumentParser +import locale +from pyeole.i18n import i18n +from pyeole import lock +from pyeole.process import system_code +from pyeole.ihm import print_title, print_red, print_green +from pyeole.ihm import question_ouinon +from creole.config import configeoldir + +from os import system +from os import access +from os import R_OK +from os import mkdir +from os import unlink +from os.path import join +from os.path import isfile +from os.path import isdir + +import time +import re +from shutil import copytree +from shutil import copy +from pyeole.pkg import EolePkg, _configure_sources_mirror +from creole.fonctionseole import controle_kernel, zephir +from creole.config import eoledir +from creole.config import templatedir +from creole.config import vareole +from creole.template import CreoleTemplateEngine +from creole.client import CreoleClient + +from glob import glob +import hashlib +from urllib2 import urlopen +from urllib2 import ProxyHandler +from urllib2 import build_opener +from HTMLParser import HTMLParser + +warnings.filterwarnings("ignore", "apt API not stable yet", FutureWarning) + +_ = i18n('update-manager') + +if not isfile(join(configeoldir, '.upgrade_available')): + print "" + print_red(_(u'Upgrade to a newer major version is not available')) + print _(u'Use Maj-Release script to upgrade to next minoir version') + print "" + sys.exit(1) + +from UpdateManager.Core.MetaRelease import MetaReleaseCore +from UpdateManager.Core.DistUpgradeFetcherCore import DistUpgradeFetcherCore +from DistUpgrade.utils import init_proxy + +quit_re = re.compile(r'q|(quit)|(exit)|(abort)', re.I) + +tmp_dir = '/tmp/Upgrade-Auto' + +def release_lock(): + if lock.is_locked('upgrade-auto', level='system'): + lock.release('upgrade-auto', level='system') + + +class EOLEDistUpgradeFetcherCore(DistUpgradeFetcherCore): + def verifyDistUprader(self, *args, **kwargs): + copy(join(tmp_dir, 'DistUpgradeViewEOLE.py'), self.tmpdir) + return super(EOLEDistUpgradeFetcherCore, self).verifyDistUprader(*args, **kwargs) + + +def cli_choice(alternatives, prompt, title=None, guess=False): + """ + Display choices in terminal and return chosen one + :param alternatives: choices proposed to user + :type alternatives: list + :param guess: wether to guess choice + :type guess: boolean + """ + def default_input(alt_mapping, prompt, title=None, guess=False): + choices = "\n".join(["[{0}] {1}".format(alt[0], alt[1]) + for alt in alt_mapping.items()]) + choices = _(u"Available choices:\n{}\n").format(choices) + if title is not None: + print_green(title) + print choices + if guess is True and len(alt_mapping) < 2: + print_green(_(u"Automatically selected first choice: {}\n").format(alt_mapping[1])) + choice = "1" + else: + try: + prompt = prompt + _(u"\n[1]: ") + choice = raw_input(prompt) + except KeyboardInterrupt, EOFError: + print _("\nUpgrade aborted by user") + sys.exit(0) + if choice == '': + choice = "1" + return choice + + alt_mapping = {num + 1: choice for num, choice in enumerate(alternatives)} + choice = default_input(alt_mapping, prompt, title=title, guess=guess) + if choice not in alt_mapping.values(): + try: + choice = alt_mapping[int(choice)] + except KeyError: + print _("Choice {} not available\n").format(choice) + choice = cli_choice(alternatives, prompt, guess=guess) + except ValueError: + if quit_re.match(choice): + print _("Upgrade cancelled by user") + sys.exit(0) + else: + print _("Invalid input: {}\n").format(choice) + choice = cli_choice(alternatives, prompt, guess=guess) + return choice + + +def upgrade_container_source(container): + """Edit source list in container + :param container: container name + :type container: str + """ + print 'changement des sources.list pour le conteneur ', container + source_list = '/opt/lxc/{}/rootfs/etc/apt/sources.list'.format(container) + with open(source_list) as old_source: + sources = old_source.read() + with open(source_list, 'w') as new_source: + new_source.write(sources.replace('precise', 'trusty')) + cmd = ['apt-get', 'update'] + code = system_code(cmd, container=container) + return code + + +ALTERNATIVES = ("2.5.1", ) +RUNPARTS_CMD = u'/bin/run-parts --exit-on-error -v {directory}' +PRE_DOWNLOAD = 'pre_download' +UPGRADE_DIR = join(eoledir, 'upgrade') +ISO_DIR = join(vareole, 'iso') +ISO_URL_BASE = 'http://eole.ac-dijon.fr/pub/iso' +z_proc = "UPGRADE" + +class ExtractEOLEVersions(HTMLParser): + """Extrat stable EOLE versions from HTML page + + Gathered versions are stored in ``self.versions``. + + """ + + def __init__(self, version): + HTMLParser.__init__(self) + self.version = version + self.versions = [] + self.process_a = False + + def handle_starttag(self, tag, attrs): + if tag != 'a': + self.process_a = False + return + self.process_a = True + + + def handle_data(self, data): + if not self.process_a: + return + + # Strip not matching and pre stable versions + if data.lower().startswith(self.version) and '-' not in data: + self.versions.append(data.rstrip('/')) + + +def get_most_recent_version(match, url, proxy=None): + """Get the most recent matching version + + """ + if proxy is not None: + proxy_handler = ProxyHandler({'http': proxy, + 'https': proxy}) + else: + proxy_handler = ProxyHandler({}) + + opener = build_opener(proxy_handler) + http_request = opener.open(url) + html_parser = ExtractEOLEVersions(match) + html_parser.feed(http_request.read()) + html_parser.versions.sort() + return html_parser.versions[-1] + + +def build_iso_name(version): + """Build ISO name for version + + """ + arch = apt.apt_pkg.config.get('APT::Architecture') + iso_name = 'eole-{version}-alternate-{arch}.iso'.format(version=version, + arch=arch) + return iso_name + + +def build_release_url(version, proxy=None): + """Build the URL of latest release of a version + + """ + version_url = ISO_URL_BASE + '/EOLE-' + '.'.join(version.split('.')[0:2]) + latest_version = get_most_recent_version(version, version_url, proxy) + release_url = '{base}/{release}'.format(base=version_url, + release=latest_version) + return release_url + + +def check_iso(iso_name, path, release_url, proxy=None): + """Verify checksum and signature + + """ + sha256_file = join(ISO_DIR, 'SHA256SUMS') + sha256_url = release_url + '/SHA256SUMS' + + sha256_gpg_file = join(ISO_DIR, 'SHA256SUMS.gpg') + sha256_gpg_url = sha256_url + '.gpg' + + sha256 = hashlib.sha256() + + iso_ok = False + + print _(u"Verifying ISO image {iso}").format(iso=path) + + if not isfile(sha256_file): + print _(u"Download SHA256SUMS file") + download_with_wget(sha256_file, sha256_url, proxy) + + if not isfile(sha256_gpg_file): + print _(u"Download SHA256SUMS.gpg file") + download_with_wget(sha256_gpg_file, sha256_gpg_url, proxy) + + print _(u"Check SHA256SUMS file signature") + + gpg_cmd = ['gpgv', '-q', '--keyring', + '/etc/apt/trusted.gpg.d/eole-archive-keyring.gpg', + sha256_gpg_file, sha256_file] + + ret = system_code(gpg_cmd) + if ret == 0: + print _(u"Check ISO SHA256..."), + sha_fh = open(sha256_file, 'r') + for line in sha_fh: + sha, filename = line.split() + if filename != '*{iso_name}'.format(iso_name=iso_name): + continue + + with open(path, 'rb') as iso_fh: + while True: + block = iso_fh.read(2**10) + if not block: + break + + sha256.update(block) + + iso_ok = sha == sha256.hexdigest() + if iso_ok: + print _(u'OK') + return True + + print _(u'Error') + + + # Default + return False + + +def download_with_wget(out_file, url, proxy=None, limit_rate="0"): + """Use wget to download a file with a progress bar and rate limit + + """ + wcmd = ['wget', '-c', '--progress', 'dot:giga'] + if limit_rate != '0': + wcmd.extend(['--limit-rate', limit_rate]) + + wcmd.extend(['-O', out_file, url]) + + if proxy is not None: + env = {'http_proxy': proxy, + 'https_proxy': proxy} + else: + env = {} + + if not system_code(wcmd, env=env) == 0: + err_msg = _("Error downloading {file} with wget from {url}") + err_msg = err_msg.format(file=out_file, url=url) + zephir("ERR", err_msg, z_proc) + raise SystemError(err_msg) + +def download_iso_with_zsync(iso_file, iso_url): + """Use zsync to download the ISO + + """ + zcmd = ['zsync', '-o', iso_file, iso_url + '.zsync'] + if not system_code(zcmd) == 0: + err_msg = _("Error downloading the image with zsync") + zephir("ERR", err_msg, z_proc) + raise SystemError(err_msg) + +def clean_iso_dir(iso_file=None): + """Clean ISO directory + + If :data:`iso_file` is not `None`, it's keept + + """ + # Remove any file other than targeted release ISO + # This permit to resume download + for filename in glob('{iso_dir}/*'.format(iso_dir=ISO_DIR)): + if filename == iso_file: + continue + + unlink(filename) + +def get_cdrom_device(): + device = None + client = CreoleClient() + mount_point = '/media/cdrom' + mounted = False + if not isdir(mount_point): + mkdir(mount_point) + + for cdrom in client.get_creole('cdrom_devices'): + cmd = ['/bin/mount', cdrom, mount_point, '-o', 'ro'] + if system_code(cmd) != 0: + continue + + mounted = True + + if isdir('{0}/dists'.format(mount_point)): + device = cdrom + + cmd = ['/bin/umount', mount_point] + if system_code(cmd) != 0: + err_msg = _("Unable to umount {cdrom}").format(cdrom=cdrom) + zephir("ERR", err_msg, z_proc) + raise SystemError(err_msg) + + if device is not None: + break + + return device + + +def download_iso(args): + """Download ISO image + + Download an ISO image from internet or copy one from :data:`path`. + + :parameter path: path of an existing ISO image + :type path: `str` + + """ + proxy = None + client = CreoleClient() + + if client.get_creole('activer_proxy_client') == u'oui': + address = client.get_creole('proxy_client_adresse') + port = client.get_creole('proxy_client_port') + proxy = 'http://{address}:{port}'.format(address=address, port=port) + + release_url = build_release_url(args.release, proxy) + iso_name = build_iso_name(args.release) + iso_file = join(ISO_DIR, iso_name) + iso_url = '{url}/{iso}'.format(url=release_url, iso=iso_name) + + print_title(_(u"Downloading ISO image for {release}").format(release=args.release)) + + if not isdir(ISO_DIR): + mkdir(ISO_DIR) + + if isfile(iso_file) and check_iso(iso_name, iso_file, release_url, proxy): + # ISO is downloaded and verified + return True + + # Remove SHA265SUMS* files + # Keep ISO to resume download if possible + clean_iso_dir(iso_file) + err_msg = None + + if args.cdrom or args.iso is not None: + + if args.cdrom: + path = get_cdrom_device() + if path is None: + err_msg = _("No CDROM found") + else: + path = args.iso + if not isfile(path): + err_msg = _("No such file: {iso}").format(iso=path) + elif not access(path, R_OK): + err_msg = _("Unreadable file: {iso}").format(iso=path) + if err_msg is None: + # Should we also check source image before copying? + # elif not check_iso(iso_name, path, release_url): + # raise SystemError("ISO image is not valid for {iso}".format(iso=path)) + + print _("Copying {source} to {iso}").format(source=path, iso=iso_file) + + copy(path, iso_file) + + if not check_iso(iso_name, iso_file, release_url, proxy): + # Copy was OK but check fails + # Remove copied ISO as it may be corrupted and prevent + # futur download + clean_iso_dir() + msg = _("Error checking ISO after copy, remove {iso}") + err_msg = msg.format(iso=iso_file) + + else: + # Try resuming download + download_with_wget(iso_file, iso_url, proxy, args.limit_rate) + # download_iso_with_zsync(iso_file, iso_url) + + if not check_iso(iso_name, iso_file, release_url, proxy): + # Download was OK but check fails + # Remove downloaded ISO as it may be fully downloaded but + # corrupted and prevent futur download + clean_iso_dir() + msg = _(u"Error checking ISO image after download, remove {iso}") + err_msg = msg.format(iso=iso_file) + + if err_msg: + zephir('ERR', err_msg, z_proc) + raise SystemError(err_msg) + +def main(): + args_parser = ArgumentParser(description=_("EOLE distribution upgrade tool.")) + + args_parser.add_argument('--release', + help=_(u"Target release number")) + + args_parser.add_argument('--download', action='store_true', + help=_(u"Only download the ISO image")) + + args_parser.add_argument('--iso', metavar=u'PATH', + help=_(u"Path to an ISO image")) + + args_parser.add_argument('--cdrom', action='store_true', + help=_(u"Use CDROM device instead of downloading ISO image")) + + args_parser.add_argument('--limit-rate', metavar=u'BANDWIDTH', default='120k', + help=_(u"Pass limit rate to wget. “0” to disable.")) + + args_parser.add_argument('-f', '--force', action='store_true', + help=_(u"Do not ask confirmation")) + + args = args_parser.parse_args() + + + try: + locale.setlocale(locale.LC_ALL, "") + except: + pass + + print_red(_(u"This script will upgrade this server to a new release")) + print_red(_(u"Modifications will be irreversible.")) + init_proxy() + zephir("INIT", _(u"Starting Upgrade-Auto ({})").format(" ".join(sys.argv[1:])), z_proc) + + # Ask for release if none provided on command line + if args.release is not None: + if args.release not in ALTERNATIVES: + msg = _(u"Invalid release {version} use: {values}") + err_msg = msg.format(version=args.release, + values=', '.join(ALTERNATIVES)) + zephir("ERR", err_msg, z_proc) + print err_msg + sys.exit(1) + else: + title = _(u"Choose which version you want to upgrade to\n") + prompt = _(u"Which version do you want to upgrade to (or 'q' to quit)?") + args.release = cli_choice(ALTERNATIVES, prompt, title=title, guess=False) + + + if not args.force: + confirmation_msg = _(u"Do you really want to upgrade to version {}?") + if question_ouinon(confirmation_msg.format(args.release)) != 'oui': + end_msg = _(u'Upgrade cancelled by user') + zephir("FIN", end_msg, z_proc) + print end_msg + sys.exit(0) + + lock.acquire('upgrade-auto', valid=False, level='system') + atexit.register(release_lock) + + if not args.download: + print_title(_("Check update status")) + PKGMGR = EolePkg('apt', ignore=False) + PKGMGR.set_option('APT::Get::Simulate', 'true') + _configure_sources_mirror(PKGMGR.pkgmgr) + PKGMGR.update(silent=True) + upgrades = PKGMGR.get_upgradable_list() + + for container, packages in upgrades.items(): + if packages: + err_msg = _(u"Some packages are not up-to-date!") + zephir("ERR", err_msg, z_proc) + print_red(err_msg) + print_red(_(u"Update this server (Maj-Auto) before another attempt to upgrade")) + sys.exit(1) + + print_green(_(u'Server is up-to-date')) + + if controle_kernel(): + err_msg = _(u"In order to upgrade, most recent kernel endorsed for this release must be used") + zephir("ERR", err_msg, z_proc) + print_red(err_msg) + sys.exit(1) + + print_green(_(u'This server uses most recent kernel')) + + download_iso(args) + + if args.download: + end_msg = _(u"Download only detected, stop") + print_green(end_msg) + zephir("FIN", end_msg, z_proc) + sys.exit(0) + + print_title(_("Copying upgrade scripts")) + if isdir(tmp_dir): + err_msg = _(u"Directory {0} already exists").format(tmp_dir) + zephir("ERR", err_msg, z_proc) + print_red(err_msg) + sys.exit(1) + + copytree(UPGRADE_DIR, tmp_dir) + pre_download = join(tmp_dir, PRE_DOWNLOAD) + + print_title(_("Configuring upgrade")) + engine = CreoleTemplateEngine() + rootctx = {u'name': u'root', u'path': u''} + + file_info = {'name': '/etc/update-manager/release-upgrades.d/eole.cfg', + 'source': join(templatedir, 'eole.cfg'), + 'full_name': '/etc/update-manager/release-upgrades.d/eole.cfg', + 'activate' : True, + 'del_comment': u'', + 'mkdir' : False, + 'rm' : False} + engine.prepare_template(file_info) + engine.process(file_info, rootctx) + + _configure_sources_mirror(PKGMGR.pkgmgr, eole_release=args.release) + + print_title(_("Module specific commands")) + code = system(RUNPARTS_CMD.format(directory=pre_download)) + if code != 0: + err_msg = _(u'Error {0}').format(pre_download) + print_red(err_msg) + zephir("ERR", err_msg, z_proc) + sys.exit(1) + + for container in (cont for cont in upgrades if cont != 'root'): + upgrade_container_source(container) + PKGMGR.dist_upgrade(container=container, silent=False) + + m = MetaReleaseCore(useDevelopmentRelease=False, + useProposed=False) + # this will timeout eventually + while m.downloading: + time.sleep(0.5) + progress = apt.progress.text.AcquireProgress() + fetcher = EOLEDistUpgradeFetcherCore(new_dist=m.new_dist, + progress=progress) + fetcher.run_options += ["--mode=server", + "--frontend=DistUpgradeViewEOLE", + ] + print_title(_("Upgrading server")) + fetcher.run() + # all lines below will not be executed + +if __name__ == "__main__": + try: + main() + except (KeyboardInterrupt, EOFError): + print_red(_("\nUpgrade aborted by user")) + exit(0) + diff --git a/upgrade/post_upgrade/00-common b/upgrade/post_upgrade/00-common new file mode 100755 index 0000000..ad6e105 --- /dev/null +++ b/upgrade/post_upgrade/00-common @@ -0,0 +1,9 @@ +#!/bin/bash + +#suppression des fichiers du type : /usr/share/eole/mysql_pwd.pyc +find /usr/share/eole -name "*.pyc" -delete + +#suppression du lien symbolique ajouté pour Upgrade-Auto 2.4 +[ -L /usr/bin/Upgrade-Auto ] && rm -f /usr/bin/Upgrade-Auto + +exit 0 diff --git a/upgrade/post_upgrade/01-amon b/upgrade/post_upgrade/01-amon new file mode 100755 index 0000000..c9a1d23 --- /dev/null +++ b/upgrade/post_upgrade/01-amon @@ -0,0 +1,29 @@ +#!/bin/bash + +initfile="$(CreoleGet container_path_proxy '')/etc/init.d/winbind" +# Utilisation du script d'init fourni par le paquet (#14608) +if [ -f ${initfile}.dpkg-dist ];then + mv -f ${initfile}.dpkg-dist ${initfile} +fi + +# Restauration des bases de filtres obligatoires (#8621) +DB="$(CreoleGet container_path_proxy '')/var/lib/blacklists/db" +if [ -d /tmp/db ];then + for filter in 'adult' 'redirector';do + mkdir -p $DB/$filter + if [ -f /tmp/db/$filter/urls ];then + cp -f /tmp/db/$filter/urls $DB/$filter/urls + fi + if [ -f /tmp/db/$filter/domains ];then + cp -f /tmp/db/$filter/domains $DB/$filter/domains + fi + done +fi + +# Suppression des restrictions pour squid (#15760) +[ -f /etc/apparmor.d/usr.sbin.squid ] && ln -nsf /etc/apparmor.d/usr.sbin.squid /etc/apparmor.d/disable/ + +# Suppression des configurations fournies par le paquet freeradius (#16147) +rm -f /etc/freeradius/modules/*.dpkg-dist + +exit 0 diff --git a/upgrade/post_upgrade/01-bacula b/upgrade/post_upgrade/01-bacula new file mode 100755 index 0000000..d338217 --- /dev/null +++ b/upgrade/post_upgrade/01-bacula @@ -0,0 +1,6 @@ +#!/bin/bash + +# Purge des paquets bacula (#14933) +if [ -n "$(dpkg -l eole-bacula | grep ^rc)" ];then + apt-get remove --purge -y --force-yes bacula-common bacula-common-sqlite3 bacula-console bacula-director-common bacula-director-sqlite3 bacula-fd bacula-sd eole-bacula +fi diff --git a/upgrade/post_upgrade/01-horus b/upgrade/post_upgrade/01-horus new file mode 100755 index 0000000..6b53096 --- /dev/null +++ b/upgrade/post_upgrade/01-horus @@ -0,0 +1,9 @@ +#!/bin/bash + +# Restauration des fichiers Interbase (#11070) +if [ -d /tmp/interbase ];then + cp -f /tmp/interbase/isc4.gdb /opt/interbase/isc4.gdb + cp -f /tmp/interbase/ib_license.dat /opt/interbase/ib_license.dat 2>/dev/null +fi + +exit 0 diff --git a/upgrade/post_upgrade/03-zephir-client b/upgrade/post_upgrade/03-zephir-client new file mode 100755 index 0000000..ab514ea --- /dev/null +++ b/upgrade/post_upgrade/03-zephir-client @@ -0,0 +1,19 @@ +#!/bin/bash + +BACKUP_DIR=/var/lib/zephir_backup +OLD_DIR=/usr/lib/python2.6/dist-packages/zephir + +if [ -f $BACKUP_DIR/zephir_conf.py ] +then + # mise en place de la configuration uucp + cp -rpf $BACKUP_DIR/.ssh /var/spool/uucp/ + cp -pf $BACKUP_DIR/uucp/* /etc/uucp/ + # mise en place de la configuration d'enregistrement (python 2.7) + mv -f $BACKUP_DIR/zephir_conf.py /usr/lib/python2.7/dist-packages/zephir/zephir_conf/ + rm -rf $BACKUP_DIR + # suppression anciens fichier python2.6 + if [ -d $OLD_DIR ] + then + rm -rf $OLD_DIR + fi +fi diff --git a/upgrade/post_upgrade/10-apache b/upgrade/post_upgrade/10-apache new file mode 100755 index 0000000..46c673c --- /dev/null +++ b/upgrade/post_upgrade/10-apache @@ -0,0 +1,13 @@ +#!/bin/sh + +PACKAGES="apache2-mpm-prefork apache2-utils apache2.2-bin" +MODULES="alias auth_basic authn_file authz_host authz_user autoindex deflate dir env negotiation status" + +if CreoleGet container_ip_reseau > /dev/null 2>&1 +then + # Remove unwanted packages + CreoleRun "apt-eole remove ${PACKAGES}" reseau + + # Enable required modules + CreoleRun "a2enmod ${MODULES}" reseau +fi diff --git a/upgrade/post_upgrade/90-delete-iso b/upgrade/post_upgrade/90-delete-iso new file mode 100755 index 0000000..c05718b --- /dev/null +++ b/upgrade/post_upgrade/90-delete-iso @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "Remove ISO directory /var/lib/eole/iso" +rm -rf /var/lib/eole/iso diff --git a/upgrade/post_upgrade/99-grub b/upgrade/post_upgrade/99-grub new file mode 100755 index 0000000..2a3bd21 --- /dev/null +++ b/upgrade/post_upgrade/99-grub @@ -0,0 +1,16 @@ +#!/bin/bash + +bootdevice=$(mount | awk '/ \/boot / {gsub(/[0-9]/,"",$1);print $1}') +rootdevice=$(mount | awk '/ \/ / {gsub(/[0-9]/,"",$1);print $1}') +if [[ -n "${bootdevice}" ]] +then + grub-install ${bootdevice} + exit $? +elif [[ -n "${rootdevice}" ]] +then + grub-install ${rootdevice} + exit $? +else + echo "Le disque d'installation de grub ne peut pas être déterminé." + exit 127 +fi diff --git a/upgrade/post_upgrade/99-unlock b/upgrade/post_upgrade/99-unlock new file mode 100755 index 0000000..2b75279 --- /dev/null +++ b/upgrade/post_upgrade/99-unlock @@ -0,0 +1,8 @@ +#!/bin/bash + +python -c 'from pyeole.lock import release; release("upgrade-auto", force=True, level="system")' + +# Unlock instance +echo '2.4.2' >| /etc/eole/.upgrade-auto + +exit 0 diff --git a/upgrade/post_upgrade/99-upgrade_eole b/upgrade/post_upgrade/99-upgrade_eole new file mode 100755 index 0000000..24cb905 --- /dev/null +++ b/upgrade/post_upgrade/99-upgrade_eole @@ -0,0 +1,5 @@ +#!/bin/bash + +[[ -f /etc/apt/apt.conf.d/99upgradeEOLE ]] && rm -f /etc/apt/apt.conf.d/99upgradeEOLE + +exit 0 diff --git a/upgrade/pre_download/00-common b/upgrade/pre_download/00-common new file mode 100755 index 0000000..f6acc4c --- /dev/null +++ b/upgrade/pre_download/00-common @@ -0,0 +1,28 @@ +#!/bin/bash + +BACKUP_DIR="/var/backup/creolelocal" +echo -e "\n# personnalisations locales (dictionnaires/patch/templates)" +echo -e " Sauvegarde dans ${BACKUP_DIR}" +mkdir -p ${BACKUP_DIR}/distrib +mkdir -p ${BACKUP_DIR}/dicos +mkdir -p ${BACKUP_DIR}/patch +# dictionnaires locaux +/bin/cp -rf /usr/share/eole/creole/dicos/local/*.xml ${BACKUP_DIR}/dicos/ >/dev/null 2>&1 +# si enregistré sur Zéphir : suppression des dictionnaires locaux/de variante +# limite les problèmes avec creoled (cf https://dev-eole.ac-dijon.fr/issues/9787) +/usr/bin/enregistrement_zephir --check >/dev/null +if [ $? -eq 0 ] +then + /bin/rm -f /usr/share/eole/creole/dicos/local/*.xml + /bin/rm -f /usr/share/eole/creole/dicos/variante/*.xml +fi +# patchs +/bin/cp -rf /usr/share/eole/creole/patch/*.patch ${BACKUP_DIR}/patch/ >/dev/null 2>&1 +# templates non installés par un paquet (variante et locaux) +for TMPL in `ls /usr/share/eole/creole/distrib/*` +do + dpkg -S $TMPL >/dev/null 2>&1 + if [ $? -ne 0 ];then + /bin/cp -rf $TMPL ${BACKUP_DIR}/distrib/ + fi +done diff --git a/upgrade/pre_download/00-dpkg_options b/upgrade/pre_download/00-dpkg_options new file mode 100755 index 0000000..32b477b --- /dev/null +++ b/upgrade/pre_download/00-dpkg_options @@ -0,0 +1,3 @@ +#!/bin/bash + +echo 'Dpkg::Options {"--force-confdef"; "--force-confmiss";};' > /etc/apt/apt.conf.d/99upgradeEOLE diff --git a/upgrade/pre_download/01-amon b/upgrade/pre_download/01-amon new file mode 100755 index 0000000..adeb84b --- /dev/null +++ b/upgrade/pre_download/01-amon @@ -0,0 +1,10 @@ +#!/bin/bash +# Sauvegarde des bases de filtres obligatoires (#8621) +DB="$(CreoleGet container_path_proxy '')/var/lib/blacklists/db" +for filter in 'adult' 'redirector';do + if [ -d $DB/$filter ];then + mkdir -p /tmp/db/$filter + cp -f $DB/$filter/urls /tmp/db/$filter/urls + cp -f $DB/$filter/domains /tmp/db/$filter/domains + fi +done diff --git a/upgrade/pre_download/01-bacula b/upgrade/pre_download/01-bacula new file mode 100755 index 0000000..c24450a --- /dev/null +++ b/upgrade/pre_download/01-bacula @@ -0,0 +1,6 @@ +#!/bin/bash + +# Suppression des anciens fichiers bacula (#14933) +if [ -d /etc/bacula/baculafichiers.d ];then + rm -rf /etc/bacula/baculafichiers.d +fi diff --git a/upgrade/pre_download/01-horus b/upgrade/pre_download/01-horus new file mode 100755 index 0000000..1763491 --- /dev/null +++ b/upgrade/pre_download/01-horus @@ -0,0 +1,27 @@ +#!/bin/bash + +if dpkg-query -s eole-horus-backend > /dev/null 2>&1;then + python -c """import sys +from horus import backend +from ldap import INVALID_CREDENTIALS +try: + for user in backend.ldapsearch('(&%s(sambaLogonScript=*))' % backend.user_filters): + print 'correction du compte %s' % user[1]['uid'][0] + backend.ldapmodify(user[0], 'sambaLogonScript', '') +except INVALID_CREDENTIALS: + print + print 'Erreur le mot de passe ldap est désynchronisé' + print 'Relancer un reconfigure pour corriger' + print + sys.exit(1) +""" +fi + +# Sauvegarde des fichiers Interbase (#11070) +if [ -f /opt/interbase/isc4.gdb ];then + mkdir -p /tmp/interbase + cp -f /opt/interbase/isc4.gdb /tmp/interbase + cp -f /opt/interbase/ib_license.dat /tmp/interbase 2>/dev/null +fi + +exit 0 diff --git a/upgrade/pre_download/03-zephir-client b/upgrade/pre_download/03-zephir-client new file mode 100755 index 0000000..ddc3e45 --- /dev/null +++ b/upgrade/pre_download/03-zephir-client @@ -0,0 +1,16 @@ +#!/bin/bash + +/usr/bin/enregistrement_zephir --check >/dev/null 2>&1 + +if [ $? -eq 0 ] +then + BACKUP_DIR=/var/lib/zephir_backup/ + mkdir -p $BACKUP_DIR + # copie temporaire de la configuration d'enregistrement + cp -f /usr/lib/python2.7/dist-packages/zephir/zephir_conf/zephir_conf.py $BACKUP_DIR + # configuration ssh de l'utilisateur uucp + cp -rpf /var/spool/uucp/.ssh $BACKUP_DIR + cp -rpf /etc/uucp $BACKUP_DIR +fi + +exit 0 diff --git a/upgrade/pre_download/10-rsyslog b/upgrade/pre_download/10-rsyslog new file mode 100755 index 0000000..01841f9 --- /dev/null +++ b/upgrade/pre_download/10-rsyslog @@ -0,0 +1,18 @@ +#!/bin/sh + +# Remove autogenerated configuration files +DO_NOT_TOUCH_REGEXP='eole_templates\|default' + +for conf in $(find /etc/rsyslog.d/ -type f -name '*.conf') +do + if echo "${conf}" | grep -qs "${DO_NOT_TOUCH_REGEXP}" + then + # Do nothing + continue + fi + if ! dpkg -S "${conf}" > /dev/null 2>&1 + then + echo "Remove generated rsyslog configuration file: “${conf}”" + rm -f "${conf}" + fi +done diff --git a/upgrade/pre_download/10-sympa b/upgrade/pre_download/10-sympa new file mode 100755 index 0000000..a1e94ba --- /dev/null +++ b/upgrade/pre_download/10-sympa @@ -0,0 +1,6 @@ +#!/bin/sh + +if CreoleGet container_ip_reseau > /dev/null 2>&1 +then + CreoleRun 'rm -f /etc/apache2/conf.d/sympa' reseau +fi diff --git a/upgrade/pre_download/90-fill-apt-cache b/upgrade/pre_download/90-fill-apt-cache new file mode 100755 index 0000000..d08b324 --- /dev/null +++ b/upgrade/pre_download/90-fill-apt-cache @@ -0,0 +1,107 @@ +#!/bin/sh + +set -e + +ISO_DIR='/var/lib/eole/iso' + +ISO_IMAGE=$(ls -1 ${ISO_DIR}/*.iso 2>/dev/null || true) + +APT_CACHER_DIR='/var/cache/apt-cacher-ng' +APT_DIR='/var/cache/apt/archives' + +MOUNT_POINT= + +## Called at the end of the file +main() { + if [ $(echo "${ISO_IMAGE}" | wc -l) -gt 1 ] + then + die "more than one ISO image detected: ${ISO_IMAGE}" + fi + + if [ -d "${APT_CACHER_DIR}" ] + then + populate_apt_cacher_cache + else + populate_apt_cache + fi +} + +populate_apt_cache() { + MOUNT_POINT='/media/cdrom' + mount_iso "${ISO_IMAGE}" "${MOUNT_POINT}" + + if find "${MOUNT_POINT}" -type f -name '*.deb' | xargs -I{} cp {} "${APT_DIR}" + then + echo "APT cache directory populated" + else + die "unablo to populate APT cache" + fi +} + +populate_apt_cacher_cache() { + + MOUNT_POINT="${APT_CACHER_DIR}/_import" + mount_iso "${ISO_IMAGE}" "${MOUNT_POINT}" + APT_CACHER_IMPORT_LOG=/tmp/apt-cacher-import.log + APT_CACHER_PORT=$(CreoleGet apt_cacher_port) + + CURRENT_DISTRIB=$(lsb_release --codename --short) + NEXT_DISTRIB=$(awk '/^Suite:/ {print $2}' "${MOUNT_POINT}/dists/stable/Release") + TMP_SL=/tmp/next-apt-sources.list + + # Build a temporary sources.list + # EOLE references are OK + cp /etc/apt/sources.list ${TMP_SL} + sed -i -e "s,${CURRENT_DISTRIB},${NEXT_DISTRIB}," ${TMP_SL} + + # Clean apt cache + rm -f /var/cache/apt/*cache.bin + rm -f /var/lib/apt/lists/*Packages + rm -f /var/lib/apt/lists/*Sources + + apt-get -o Dir::Etc::SourceList=${TMP_SL} update + + IMPORT_URL="http://localhost:${APT_CACHER_PORT}/acng-report.html?abortOnErrors=aOe&doImport=Start+Import&calcSize=cs&asNeeded=an" + + ERROR_PATTERN='(No appropriate files found in the _import directory|color=red)' + wget -O "${APT_CACHER_IMPORT_LOG}" -q "${IMPORT_URL}" + ERRORS=$(sed -n -E "/${ERROR_PATTERN}/ s,<[^>]*>,,gp" "${APT_CACHER_IMPORT_LOG}") + if [ -n "${ERRORS}" ] + then + die "import log contains errors: ${ERRORS}" + else + echo "APT-CACHER cache populated" + fi +} + +mount_iso() { + ISO="${1}" + MOUNT_POINT="$2" + + [ -d "${MOUNT_POINT}" ] || mkdir "${MOUNT_POINT}" + + if ! mount -o loop,ro "${ISO}" "${MOUNT_POINT}" + then + die "unable to mount “${ISO}”" + fi +} + +die(){ echo 'Error:' $@ >&2; exit 1; } + +_clean() { + EXIT_CODE=$? + + # Do not abort on failure as we are in SIGHANDLER + set +e + + # Make script idempotent + umount "${MOUNT_POINT}" 2> /dev/null + rmdir "${MOUNT_POINT}" 2> /dev/null + + # Use main script exit code + return ${EXIT_CODE} +} + +trap _clean EXIT + +main $@