masters shall have the same names as groups
This commit is contained in:
parent
6a3b7102b5
commit
a404c4c992
4 changed files with 35 additions and 237 deletions
|
@ -82,69 +82,21 @@ def test_iter_on_empty_group():
|
|||
pass
|
||||
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():
|
||||
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é")
|
||||
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])
|
||||
interface1 = OptionDescription('interface1', '', [master])
|
||||
interface1.set_group_type(groups.group, master='interface1')
|
||||
def test_master_not_valid_name():
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé")
|
||||
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,
|
||||
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_group_is_master():
|
||||
descr = make_master_group2()
|
||||
conf = Config(descr)
|
||||
interface1 = conf.creole.interface1
|
||||
assert interface1._cfgimpl_descr.get_master_name() == "interface1"
|
||||
def test_sub_group_in_master_group():
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé")
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau")
|
||||
subgroup = OptionDescription("subgroup", '', [])
|
||||
invalid_group = OptionDescription('ip_admin_eth0', '', [subgroup, ip_admin_eth0, netmask_admin_eth0])
|
||||
raises(ConfigError, "invalid_group.set_group_type(groups.master)")
|
||||
|
|
|
@ -74,10 +74,8 @@ class Config(object):
|
|||
for child in self._cfgimpl_descr._children:
|
||||
if isinstance(child, Option):
|
||||
if child.is_multi():
|
||||
#force_append to load values without append value to
|
||||
#child/master
|
||||
childdef = Multi(copy(child.getdefault()), config=self,
|
||||
opt=child, force_append=False)
|
||||
opt=child)
|
||||
max_len_child = max(max_len_child, len(childdef))
|
||||
self._cfgimpl_values[child._name] = childdef
|
||||
self._cfgimpl_previous_values[child._name] = list(childdef)
|
||||
|
@ -90,25 +88,6 @@ class Config(object):
|
|||
self._validate_duplicates(child._children)
|
||||
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):
|
||||
"""dynamically adds `Option()` or `OptionDescription()`
|
||||
"""
|
||||
|
@ -181,53 +160,12 @@ class Config(object):
|
|||
def __getattr__(self, 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):
|
||||
"""fills a multi option with default and calculated values
|
||||
"""
|
||||
value = self._cfgimpl_values[name]
|
||||
master_len = self._get_master_len(name)
|
||||
if not isinstance(result, list):
|
||||
if master_len is None:
|
||||
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)
|
||||
_result = [result]
|
||||
else:
|
||||
_result = result
|
||||
return Multi(_result, value.config, opt=value.opt)
|
||||
|
@ -268,7 +206,6 @@ class Config(object):
|
|||
if (not opt_or_descr.is_frozen() or \
|
||||
not opt_or_descr.is_forced_on_freeze()) and \
|
||||
not opt_or_descr.is_default_owner(self):
|
||||
self._valid_len(name, value)
|
||||
return value
|
||||
try:
|
||||
result = opt_or_descr.getcallback_value(
|
||||
|
@ -301,7 +238,6 @@ class Config(object):
|
|||
opt_or_descr.setowner(self, owners.default)
|
||||
self._test_mandatory(name, opt_or_descr)
|
||||
value = self._cfgimpl_values[name]
|
||||
self._valid_len(name, value)
|
||||
return value
|
||||
|
||||
def unwrap_from_name(self, name):
|
||||
|
@ -351,7 +287,6 @@ class Config(object):
|
|||
value = self.fill_multi(name, child.getdefault(),
|
||||
use_default_multi=True,
|
||||
default_multi=child.getdefault_multi())
|
||||
self._valid_len(name, value)
|
||||
if not isinstance(who, owners.Owner):
|
||||
raise TypeError("invalid owner [{0}] for option: {1}".format(
|
||||
str(who), name))
|
||||
|
|
|
@ -42,61 +42,24 @@ for act1, act2 in requires_actions:
|
|||
class Multi(list):
|
||||
"""multi options values container
|
||||
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 config: the parent config
|
||||
: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.opt = opt
|
||||
if force_append and self.opt.is_master(config):
|
||||
# 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)
|
||||
super(Multi, self).__init__(lst)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
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)
|
||||
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:
|
||||
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)
|
||||
self._setvalue(value, who=settings.get_owner())
|
||||
|
||||
def _setvalue(self, value, key=None, who=None):
|
||||
if value != None:
|
||||
|
@ -123,35 +86,7 @@ class Multi(list):
|
|||
:return: the requested element
|
||||
|
||||
"""
|
||||
try:
|
||||
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.opt.setowner(self.config, settings.get_owner())
|
||||
self.config._cfgimpl_previous_values[self.opt._name] = list(self)
|
||||
return super(Multi, self).pop(key)
|
||||
# ____________________________________________________________
|
||||
|
@ -382,13 +317,6 @@ class Option(HiddenBaseType, DisabledBaseType):
|
|||
|
||||
def getkey(self, 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"
|
||||
def freeze(self):
|
||||
|
@ -498,9 +426,6 @@ class OptionDescription(HiddenBaseType, DisabledBaseType):
|
|||
self._requires = requires
|
||||
self._build()
|
||||
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):
|
||||
return self.doc
|
||||
|
@ -551,7 +476,7 @@ class OptionDescription(HiddenBaseType, DisabledBaseType):
|
|||
paths.append('.'.join(currpath + [attr]))
|
||||
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
|
||||
|
||||
:param group_type: an instance of `GroupType` or `MasterGroupType`
|
||||
|
@ -560,28 +485,21 @@ class OptionDescription(HiddenBaseType, DisabledBaseType):
|
|||
if isinstance(group_type, groups.GroupType):
|
||||
self.group_type = group_type
|
||||
if isinstance(group_type, groups.MasterGroupType):
|
||||
if master is None:
|
||||
raise ConfigError('this group type ({0}) needs a master '
|
||||
'for OptionDescription {1}'.format(group_type,
|
||||
self._name))
|
||||
else:
|
||||
if master is not None:
|
||||
raise ConfigError("this group type ({0}) doesn't need a "
|
||||
"master for OptionDescription {1}".format(
|
||||
group_type, self._name))
|
||||
self.master = master
|
||||
identical_master_child_name = False
|
||||
for child in self._children:
|
||||
if isinstance(child, OptionDescription):
|
||||
raise ConfigError("master group {} shall not have "
|
||||
"a subgroup".format(self._name))
|
||||
if child._name == self._name:
|
||||
identical_master_child_name = True
|
||||
if not identical_master_child_name:
|
||||
raise ConfigError("the master group: {} has not any "
|
||||
"master child".format(self._name))
|
||||
else:
|
||||
raise ConfigError('not allowed group_type : {0}'.format(group_type))
|
||||
|
||||
def get_group_type(self):
|
||||
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"
|
||||
def hide(self):
|
||||
|
|
|
@ -56,17 +56,10 @@ groups = GroupModule()
|
|||
|
||||
def populate_groups():
|
||||
"populates the available groups in the appropriate namespaces"
|
||||
_available_group_names = ('default', 'family', 'group')
|
||||
_available_groups_with_a_master = ('group', )
|
||||
_available_default_groups = ('default', )
|
||||
# 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))
|
||||
groups.master = groups.MasterGroupType('master')
|
||||
groups.default = groups.DefaultGroupType('default')
|
||||
groups.family = groups.GroupType('family')
|
||||
|
||||
# names are in the module now
|
||||
populate_groups()
|
||||
# ____________________________________________________________
|
||||
|
|
Loading…
Reference in a new issue