masters shall have the same names as groups
This commit is contained in:
parent
6a3b7102b5
commit
a404c4c992
|
@ -82,69 +82,21 @@ def test_iter_on_empty_group():
|
||||||
pass
|
pass
|
||||||
assert [] == list(config)
|
assert [] == list(config)
|
||||||
|
|
||||||
def make_master_group():
|
|
||||||
numero_etab = StrOption('numero_etab', "identifiant de l'établissement")
|
|
||||||
nom_machine = StrOption('nom_machine', "nom de la machine", default="eoleng")
|
|
||||||
nombre_interfaces = IntOption('nombre_interfaces', "nombre d'interfaces à activer",
|
|
||||||
default=1)
|
|
||||||
activer_proxy_client = BoolOption('activer_proxy_client', "utiliser un proxy",
|
|
||||||
default=False)
|
|
||||||
mode_conteneur_actif = BoolOption('mode_conteneur_actif', "le serveur est en mode conteneur",
|
|
||||||
default=False)
|
|
||||||
adresse_serveur_ntp = StrOption('serveur_ntp', "adresse serveur ntp", multi=True)
|
|
||||||
time_zone = ChoiceOption('time_zone', 'fuseau horaire du serveur',
|
|
||||||
['Paris', 'Londres'], 'Paris')
|
|
||||||
|
|
||||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé")
|
|
||||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau")
|
|
||||||
|
|
||||||
master = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
|
||||||
interface1 = OptionDescription('interface1', '', [master])
|
|
||||||
interface1.set_group_type('toto', master='interface1')
|
|
||||||
|
|
||||||
general = OptionDescription('general', '', [numero_etab, nom_machine,
|
|
||||||
nombre_interfaces, activer_proxy_client,
|
|
||||||
mode_conteneur_actif, adresse_serveur_ntp,
|
|
||||||
time_zone])
|
|
||||||
general.set_group_type(groups.family)
|
|
||||||
creole = OptionDescription('creole', 'first tiramisu configuration', [general, interface1])
|
|
||||||
descr = OptionDescription('baseconfig', 'baseconifgdescr', [creole] )
|
|
||||||
return descr
|
|
||||||
|
|
||||||
def test_allowed_groups():
|
def test_allowed_groups():
|
||||||
raises(ConfigError, "descr = make_master_group()")
|
|
||||||
|
|
||||||
def make_master_group2():
|
|
||||||
numero_etab = StrOption('numero_etab', "identifiant de l'établissement")
|
|
||||||
nom_machine = StrOption('nom_machine', "nom de la machine", default="eoleng")
|
|
||||||
nombre_interfaces = IntOption('nombre_interfaces', "nombre d'interfaces à activer",
|
|
||||||
default=1)
|
|
||||||
activer_proxy_client = BoolOption('activer_proxy_client', "utiliser un proxy",
|
|
||||||
default=False)
|
|
||||||
mode_conteneur_actif = BoolOption('mode_conteneur_actif', "le serveur est en mode conteneur",
|
|
||||||
default=False)
|
|
||||||
adresse_serveur_ntp = StrOption('serveur_ntp', "adresse serveur ntp", multi=True)
|
|
||||||
time_zone = ChoiceOption('time_zone', 'fuseau horaire du serveur',
|
|
||||||
['Paris', 'Londres'], 'Paris')
|
|
||||||
|
|
||||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé")
|
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé")
|
||||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau")
|
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau")
|
||||||
|
interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||||
|
raises(ConfigError, "interface1.set_group_type('toto')")
|
||||||
|
|
||||||
master = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
def test_master_not_valid_name():
|
||||||
interface1 = OptionDescription('interface1', '', [master])
|
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé")
|
||||||
interface1.set_group_type(groups.group, master='interface1')
|
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau")
|
||||||
|
invalid_group = OptionDescription('interface1', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||||
|
raises(ConfigError, "invalid_group.set_group_type(groups.master)")
|
||||||
|
|
||||||
general = OptionDescription('general', '', [numero_etab, nom_machine,
|
def test_sub_group_in_master_group():
|
||||||
nombre_interfaces, activer_proxy_client,
|
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé")
|
||||||
mode_conteneur_actif, adresse_serveur_ntp,
|
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau")
|
||||||
time_zone])
|
subgroup = OptionDescription("subgroup", '', [])
|
||||||
general.set_group_type(groups.family)
|
invalid_group = OptionDescription('ip_admin_eth0', '', [subgroup, ip_admin_eth0, netmask_admin_eth0])
|
||||||
creole = OptionDescription('creole', 'first tiramisu configuration', [general, interface1])
|
raises(ConfigError, "invalid_group.set_group_type(groups.master)")
|
||||||
descr = OptionDescription('baseconfig', 'baseconifgdescr', [creole] )
|
|
||||||
return descr
|
|
||||||
|
|
||||||
def test_group_is_master():
|
|
||||||
descr = make_master_group2()
|
|
||||||
conf = Config(descr)
|
|
||||||
interface1 = conf.creole.interface1
|
|
||||||
assert interface1._cfgimpl_descr.get_master_name() == "interface1"
|
|
||||||
|
|
|
@ -74,10 +74,8 @@ class Config(object):
|
||||||
for child in self._cfgimpl_descr._children:
|
for child in self._cfgimpl_descr._children:
|
||||||
if isinstance(child, Option):
|
if isinstance(child, Option):
|
||||||
if child.is_multi():
|
if child.is_multi():
|
||||||
#force_append to load values without append value to
|
|
||||||
#child/master
|
|
||||||
childdef = Multi(copy(child.getdefault()), config=self,
|
childdef = Multi(copy(child.getdefault()), config=self,
|
||||||
opt=child, force_append=False)
|
opt=child)
|
||||||
max_len_child = max(max_len_child, len(childdef))
|
max_len_child = max(max_len_child, len(childdef))
|
||||||
self._cfgimpl_values[child._name] = childdef
|
self._cfgimpl_values[child._name] = childdef
|
||||||
self._cfgimpl_previous_values[child._name] = list(childdef)
|
self._cfgimpl_previous_values[child._name] = list(childdef)
|
||||||
|
@ -90,25 +88,6 @@ class Config(object):
|
||||||
self._validate_duplicates(child._children)
|
self._validate_duplicates(child._children)
|
||||||
self._cfgimpl_values[child._name] = Config(child, parent=self)
|
self._cfgimpl_values[child._name] = Config(child, parent=self)
|
||||||
|
|
||||||
try:
|
|
||||||
master = self._cfgimpl_descr.get_master_name()
|
|
||||||
except TypeError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
#if master/slave group, add default_multi value if length of value
|
|
||||||
#is inferior of length's group
|
|
||||||
for child in self._cfgimpl_descr._children:
|
|
||||||
if isinstance(child, Option):
|
|
||||||
value = self._cfgimpl_values[child._name]
|
|
||||||
if value is None:
|
|
||||||
len_child = 0
|
|
||||||
value = Multi([], config=self, opt=child, force_append=False)
|
|
||||||
else:
|
|
||||||
len_child = len(value)
|
|
||||||
if len_child < max_len_child:
|
|
||||||
for num in range(len_child, max_len_child):
|
|
||||||
value._append_default()
|
|
||||||
|
|
||||||
def cfgimpl_update(self):
|
def cfgimpl_update(self):
|
||||||
"""dynamically adds `Option()` or `OptionDescription()`
|
"""dynamically adds `Option()` or `OptionDescription()`
|
||||||
"""
|
"""
|
||||||
|
@ -181,53 +160,12 @@ class Config(object):
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
return self._getattr(name)
|
return self._getattr(name)
|
||||||
|
|
||||||
def _get_master_len(self, slave_name):
|
|
||||||
try:
|
|
||||||
master_name = self._cfgimpl_descr.get_master_name()
|
|
||||||
if master_name == slave_name:
|
|
||||||
return None
|
|
||||||
master_value = self._cfgimpl_values[master_name]
|
|
||||||
return len(master_value)
|
|
||||||
except TypeError, err:
|
|
||||||
# in this case we just don't care about the len
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _valid_len(self, slave_name, slave_value):
|
|
||||||
master_len = self._get_master_len(slave_name)
|
|
||||||
if master_len == None:
|
|
||||||
return True
|
|
||||||
if master_len != len(slave_value):
|
|
||||||
master_name = self._cfgimpl_descr.get_master_name()
|
|
||||||
master_value = self._cfgimpl_values[master_name]
|
|
||||||
raise ValueError("invalid len of '{0}={1}' for the group of"
|
|
||||||
" '{2}={3}'".format(slave_name,
|
|
||||||
slave_value,
|
|
||||||
master_name,
|
|
||||||
master_value))
|
|
||||||
|
|
||||||
def fill_multi(self, name, result, use_default_multi=False, default_multi=None):
|
def fill_multi(self, name, result, use_default_multi=False, default_multi=None):
|
||||||
"""fills a multi option with default and calculated values
|
"""fills a multi option with default and calculated values
|
||||||
"""
|
"""
|
||||||
value = self._cfgimpl_values[name]
|
value = self._cfgimpl_values[name]
|
||||||
master_len = self._get_master_len(name)
|
|
||||||
if not isinstance(result, list):
|
if not isinstance(result, list):
|
||||||
if master_len is None:
|
_result = [result]
|
||||||
master_len = 1
|
|
||||||
# a list is built with the same len as the master
|
|
||||||
_result = []
|
|
||||||
for i in range(master_len):
|
|
||||||
_result.append(result)
|
|
||||||
elif use_default_multi != False:
|
|
||||||
_result = result
|
|
||||||
if master_len != None:
|
|
||||||
slave_len = len(result)
|
|
||||||
if slave_len > master_len:
|
|
||||||
raise ValueError("invalid value's len for"
|
|
||||||
"the option: {1}".format(name))
|
|
||||||
if slave_len != master_len:
|
|
||||||
delta_len = master_len - len(result)
|
|
||||||
for i in range(delta_len):
|
|
||||||
_result.append(default_multi)
|
|
||||||
else:
|
else:
|
||||||
_result = result
|
_result = result
|
||||||
return Multi(_result, value.config, opt=value.opt)
|
return Multi(_result, value.config, opt=value.opt)
|
||||||
|
@ -268,7 +206,6 @@ class Config(object):
|
||||||
if (not opt_or_descr.is_frozen() or \
|
if (not opt_or_descr.is_frozen() or \
|
||||||
not opt_or_descr.is_forced_on_freeze()) and \
|
not opt_or_descr.is_forced_on_freeze()) and \
|
||||||
not opt_or_descr.is_default_owner(self):
|
not opt_or_descr.is_default_owner(self):
|
||||||
self._valid_len(name, value)
|
|
||||||
return value
|
return value
|
||||||
try:
|
try:
|
||||||
result = opt_or_descr.getcallback_value(
|
result = opt_or_descr.getcallback_value(
|
||||||
|
@ -301,7 +238,6 @@ class Config(object):
|
||||||
opt_or_descr.setowner(self, owners.default)
|
opt_or_descr.setowner(self, owners.default)
|
||||||
self._test_mandatory(name, opt_or_descr)
|
self._test_mandatory(name, opt_or_descr)
|
||||||
value = self._cfgimpl_values[name]
|
value = self._cfgimpl_values[name]
|
||||||
self._valid_len(name, value)
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def unwrap_from_name(self, name):
|
def unwrap_from_name(self, name):
|
||||||
|
@ -351,7 +287,6 @@ class Config(object):
|
||||||
value = self.fill_multi(name, child.getdefault(),
|
value = self.fill_multi(name, child.getdefault(),
|
||||||
use_default_multi=True,
|
use_default_multi=True,
|
||||||
default_multi=child.getdefault_multi())
|
default_multi=child.getdefault_multi())
|
||||||
self._valid_len(name, value)
|
|
||||||
if not isinstance(who, owners.Owner):
|
if not isinstance(who, owners.Owner):
|
||||||
raise TypeError("invalid owner [{0}] for option: {1}".format(
|
raise TypeError("invalid owner [{0}] for option: {1}".format(
|
||||||
str(who), name))
|
str(who), name))
|
||||||
|
|
|
@ -42,61 +42,24 @@ for act1, act2 in requires_actions:
|
||||||
class Multi(list):
|
class Multi(list):
|
||||||
"""multi options values container
|
"""multi options values container
|
||||||
that support item notation for the values of multi options"""
|
that support item notation for the values of multi options"""
|
||||||
def __init__(self, lst, config, opt, force_append=True):
|
def __init__(self, lst, config, opt):
|
||||||
"""
|
"""
|
||||||
:param lst: the Multi wraps a list value
|
:param lst: the Multi wraps a list value
|
||||||
:param config: the parent config
|
:param config: the parent config
|
||||||
:param opt: the option object that have this Multi value
|
:param opt: the option object that have this Multi value
|
||||||
:param force_append: - True to append child value with master's one
|
|
||||||
- False to force lst value
|
|
||||||
"""
|
"""
|
||||||
self.config = config
|
self.config = config
|
||||||
self.opt = opt
|
self.opt = opt
|
||||||
if force_append and self.opt.is_master(config):
|
super(Multi, self).__init__(lst)
|
||||||
# we pass the list at the list type's init
|
|
||||||
# because a normal init cannot return anything
|
|
||||||
super(Multi, self).__init__(lst)
|
|
||||||
# we add the slaves without modifying the master
|
|
||||||
for l in lst:
|
|
||||||
self.append(l, add_master=False)
|
|
||||||
else:
|
|
||||||
if force_append:
|
|
||||||
self.config._valid_len(self.opt._name, lst)
|
|
||||||
super(Multi, self).__init__(lst)
|
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
self._setvalue(value, key, who=settings.get_owner())
|
self._setvalue(value, key, who=settings.get_owner())
|
||||||
|
|
||||||
def append(self, value, add_master=True):
|
def append(self, value):
|
||||||
"""the list value can be updated (appened)
|
"""the list value can be updated (appened)
|
||||||
only if the option is a master
|
only if the option is a master
|
||||||
:param add_master: adds slaves without modifiying the master option
|
|
||||||
if True, adds slaves **and** the master option
|
|
||||||
"""
|
"""
|
||||||
try:
|
self._setvalue(value, who=settings.get_owner())
|
||||||
master = self.config._cfgimpl_descr.get_master_name()
|
|
||||||
if master != self.opt._name:
|
|
||||||
raise IndexError("in a group with a master, you mustn't add "
|
|
||||||
"a value in a slave's Multi value")
|
|
||||||
except TypeError:
|
|
||||||
# Not a master/slaves
|
|
||||||
self._setvalue(value, who=settings.get_owner())
|
|
||||||
return
|
|
||||||
|
|
||||||
multis = []
|
|
||||||
for opt in self.config._cfgimpl_descr._children:
|
|
||||||
if isinstance(opt, OptionDescription):
|
|
||||||
continue
|
|
||||||
multi = self.config._cfgimpl_values[opt._name]
|
|
||||||
if master == multi.opt._name:
|
|
||||||
if add_master:
|
|
||||||
multi._setvalue(value, who=settings.get_owner())
|
|
||||||
elif len(multi) == 0 or len(multi) < len(self):
|
|
||||||
multi._append_default()
|
|
||||||
|
|
||||||
def _append_default(self):
|
|
||||||
default_value = self.opt.getdefault_multi()
|
|
||||||
self._setvalue(default_value)
|
|
||||||
|
|
||||||
def _setvalue(self, value, key=None, who=None):
|
def _setvalue(self, value, key=None, who=None):
|
||||||
if value != None:
|
if value != None:
|
||||||
|
@ -123,35 +86,7 @@ class Multi(list):
|
||||||
:return: the requested element
|
:return: the requested element
|
||||||
|
|
||||||
"""
|
"""
|
||||||
try:
|
self.opt.setowner(self.config, settings.get_owner())
|
||||||
master = self.config._cfgimpl_descr.get_master_name()
|
|
||||||
if master != self.opt._name:
|
|
||||||
raise IndexError("in a group with a master, you mustn't remove "
|
|
||||||
"a value in a slave's Multi value")
|
|
||||||
except TypeError:
|
|
||||||
return self._pop(key)
|
|
||||||
|
|
||||||
multis = []
|
|
||||||
for name, multi in self.config:
|
|
||||||
multis.append(multi)
|
|
||||||
for multi in multis:
|
|
||||||
if master == multi.opt._name:
|
|
||||||
ret = multi._pop(key)
|
|
||||||
else:
|
|
||||||
change_who = False
|
|
||||||
# the value owner has to be updated because
|
|
||||||
# the default value doesn't have the same length
|
|
||||||
# of the new value
|
|
||||||
if len(multi.opt.getdefault()) >= len(multi):
|
|
||||||
change_who = True
|
|
||||||
multi._pop(key, change_who=change_who)
|
|
||||||
if ret not in locals():
|
|
||||||
raise ConfigError('Unexpected multi pop error: ret must be defined')
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def _pop(self, key, change_who=True):
|
|
||||||
if change_who:
|
|
||||||
self.opt.setowner(self.config, settings.get_owner())
|
|
||||||
self.config._cfgimpl_previous_values[self.opt._name] = list(self)
|
self.config._cfgimpl_previous_values[self.opt._name] = list(self)
|
||||||
return super(Multi, self).pop(key)
|
return super(Multi, self).pop(key)
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
@ -382,13 +317,6 @@ class Option(HiddenBaseType, DisabledBaseType):
|
||||||
|
|
||||||
def getkey(self, value):
|
def getkey(self, value):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def is_master(self, config):
|
|
||||||
try:
|
|
||||||
self.master = config._cfgimpl_descr.get_master_name()
|
|
||||||
except TypeError:
|
|
||||||
return False
|
|
||||||
return self.master is not None and self.master == self._name
|
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
"freeze utility"
|
"freeze utility"
|
||||||
def freeze(self):
|
def freeze(self):
|
||||||
|
@ -498,9 +426,6 @@ class OptionDescription(HiddenBaseType, DisabledBaseType):
|
||||||
self._requires = requires
|
self._requires = requires
|
||||||
self._build()
|
self._build()
|
||||||
self.properties = [] # 'hidden', 'disabled'...
|
self.properties = [] # 'hidden', 'disabled'...
|
||||||
# if this group is a master group, master is set
|
|
||||||
# to the master option name. it's just a ref to a name
|
|
||||||
self.master = None
|
|
||||||
|
|
||||||
def getdoc(self):
|
def getdoc(self):
|
||||||
return self.doc
|
return self.doc
|
||||||
|
@ -551,7 +476,7 @@ class OptionDescription(HiddenBaseType, DisabledBaseType):
|
||||||
paths.append('.'.join(currpath + [attr]))
|
paths.append('.'.join(currpath + [attr]))
|
||||||
return paths
|
return paths
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
def set_group_type(self, group_type, master=None):
|
def set_group_type(self, group_type):
|
||||||
"""sets a given group object to an OptionDescription
|
"""sets a given group object to an OptionDescription
|
||||||
|
|
||||||
:param group_type: an instance of `GroupType` or `MasterGroupType`
|
:param group_type: an instance of `GroupType` or `MasterGroupType`
|
||||||
|
@ -560,28 +485,21 @@ class OptionDescription(HiddenBaseType, DisabledBaseType):
|
||||||
if isinstance(group_type, groups.GroupType):
|
if isinstance(group_type, groups.GroupType):
|
||||||
self.group_type = group_type
|
self.group_type = group_type
|
||||||
if isinstance(group_type, groups.MasterGroupType):
|
if isinstance(group_type, groups.MasterGroupType):
|
||||||
if master is None:
|
identical_master_child_name = False
|
||||||
raise ConfigError('this group type ({0}) needs a master '
|
for child in self._children:
|
||||||
'for OptionDescription {1}'.format(group_type,
|
if isinstance(child, OptionDescription):
|
||||||
self._name))
|
raise ConfigError("master group {} shall not have "
|
||||||
else:
|
"a subgroup".format(self._name))
|
||||||
if master is not None:
|
if child._name == self._name:
|
||||||
raise ConfigError("this group type ({0}) doesn't need a "
|
identical_master_child_name = True
|
||||||
"master for OptionDescription {1}".format(
|
if not identical_master_child_name:
|
||||||
group_type, self._name))
|
raise ConfigError("the master group: {} has not any "
|
||||||
self.master = master
|
"master child".format(self._name))
|
||||||
else:
|
else:
|
||||||
raise ConfigError('not allowed group_type : {0}'.format(group_type))
|
raise ConfigError('not allowed group_type : {0}'.format(group_type))
|
||||||
|
|
||||||
def get_group_type(self):
|
def get_group_type(self):
|
||||||
return self.group_type
|
return self.group_type
|
||||||
|
|
||||||
def get_master_name(self):
|
|
||||||
if self.master is None:
|
|
||||||
raise TypeError('get_master_name() shall not be called in case of '
|
|
||||||
'non-master OptionDescription')
|
|
||||||
return self.master
|
|
||||||
|
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
"actions API"
|
"actions API"
|
||||||
def hide(self):
|
def hide(self):
|
||||||
|
|
|
@ -56,17 +56,10 @@ groups = GroupModule()
|
||||||
|
|
||||||
def populate_groups():
|
def populate_groups():
|
||||||
"populates the available groups in the appropriate namespaces"
|
"populates the available groups in the appropriate namespaces"
|
||||||
_available_group_names = ('default', 'family', 'group')
|
groups.master = groups.MasterGroupType('master')
|
||||||
_available_groups_with_a_master = ('group', )
|
groups.default = groups.DefaultGroupType('default')
|
||||||
_available_default_groups = ('default', )
|
groups.family = groups.GroupType('family')
|
||||||
# populates normal or master groups
|
|
||||||
for grp in _available_group_names:
|
|
||||||
if grp in _available_groups_with_a_master:
|
|
||||||
setattr(groups, grp, groups.MasterGroupType(grp))
|
|
||||||
elif grp in _available_default_groups:
|
|
||||||
setattr(groups, grp, groups.DefaultGroupType(grp))
|
|
||||||
else:
|
|
||||||
setattr(groups, grp, groups.GroupType(grp))
|
|
||||||
# names are in the module now
|
# names are in the module now
|
||||||
populate_groups()
|
populate_groups()
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
|
|
Loading…
Reference in New Issue