for creole's zephir2 branch
This commit is contained in:
1750
creole/var_loader.py
Normal file
1750
creole/var_loader.py
Normal file
@ -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_<conteneur>
|
||||
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_<conteneur>
|
||||
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_<conteneur>
|
||||
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_<conteneur>
|
||||
# adresse_ip_<container> 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
|
Reference in New Issue
Block a user