From b8b0d7f6ed3ef4a60fa8200b44938fc4b3a1f49b Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Thu, 19 Apr 2018 08:19:03 +0200 Subject: [PATCH] support symlink with a slave --- test/test_masterslaves.py | 11 +++++++++ test/test_symlink.py | 47 +++++++++++++++++++++++++++++++++++++++ tiramisu/api.py | 23 ++++++++----------- tiramisu/config.py | 15 ++++++++++--- 4 files changed, 79 insertions(+), 17 deletions(-) diff --git a/test/test_masterslaves.py b/test/test_masterslaves.py index 4a17196..f10ad49 100644 --- a/test/test_masterslaves.py +++ b/test/test_masterslaves.py @@ -200,6 +200,17 @@ def test_groups_with_master_in_config(): assert interface1.impl_get_group_type() == groups.master +def test_groups_with_master_make_dict(): + ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) + netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True) + interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) + od = OptionDescription('root', '', [interface1]) + api = getapi(Config(od)) + assert api.option.make_dict() == {'ip_admin_eth0.ip_admin_eth0': [], 'ip_admin_eth0.netmask_admin_eth0': []} + api.option('ip_admin_eth0.ip_admin_eth0').value.set(['ip1', 'ip2']) + assert api.option.make_dict() == {'ip_admin_eth0.ip_admin_eth0': ['ip1', 'ip2'], 'ip_admin_eth0.netmask_admin_eth0': [None, None]} + + def test_groups_with_master_hidden_in_config(): ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True, properties=('hidden',)) netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True, properties=('hidden',)) diff --git a/test/test_symlink.py b/test/test_symlink.py index 548b3e2..1cbb7ae 100644 --- a/test/test_symlink.py +++ b/test/test_symlink.py @@ -200,6 +200,43 @@ def test_symlink_slaves(): raises(ValueError, "MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])") +def test_symlink_with_master(): + ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) + netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True) + interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) + master = SymLinkOption('master', ip_admin_eth0) + od = OptionDescription('root', '', [interface1, master]) + api = getapi(Config(od)) + assert api.option.make_dict() == {'ip_admin_eth0.ip_admin_eth0': [], 'ip_admin_eth0.netmask_admin_eth0': [], 'master': []} + api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val1', 'val2']) + assert api.option.make_dict() == {'ip_admin_eth0.ip_admin_eth0': ['val1', 'val2'], 'ip_admin_eth0.netmask_admin_eth0': [None, None], 'master': ['val1', 'val2']} + + +def test_symlink_with_slave(): + ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) + netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True) + interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) + slave = SymLinkOption('slave', netmask_admin_eth0) + od = OptionDescription('root', '', [interface1, slave]) + api = getapi(Config(od)) + assert api.option.make_dict() == {'ip_admin_eth0.ip_admin_eth0': [], 'ip_admin_eth0.netmask_admin_eth0': [], 'slave': []} + api.option('ip_admin_eth0.ip_admin_eth0').value.set(['val1', 'val2']) + assert api.option.make_dict() == {'ip_admin_eth0.ip_admin_eth0': ['val1', 'val2'], 'ip_admin_eth0.netmask_admin_eth0': [None, None], 'slave': [None, None]} + # + assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == None + assert api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == None + assert api.option('slave', 0).value.get() == None + assert api.option('slave', 1).value.get() == None + # + api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('val3') + assert api.option.make_dict() == {'ip_admin_eth0.ip_admin_eth0': ['val1', 'val2'], 'ip_admin_eth0.netmask_admin_eth0': [None, 'val3'], 'slave': [None, 'val3']} + # + assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() == None + assert api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == 'val3' + assert api.option('slave', 0).value.get() == None + assert api.option('slave', 1).value.get() == 'val3' + + #____________________________________________________________ def test_symlink_dependency(): boolopt = BoolOption("b", "", default=False) @@ -211,3 +248,13 @@ def test_symlink_dependency(): assert api.option('c').option.has_dependency() is True assert api.option('s1.b').option.has_dependency(False) is True assert api.option('c').option.has_dependency(False) is False + +def test_symlink_makedict(): + boolopt = BoolOption("b", "", default=False) + linkopt = SymLinkOption("c", boolopt) + descr = OptionDescription("opt", "", + [linkopt, OptionDescription("s1", "", [boolopt])]) + api = getapi(Config(descr)) + assert api.option.make_dict() == {'c': False, 's1.b': False} + api.option('s1.b').value.set(True) + assert api.option.make_dict() == {'c': True, 's1.b': True} diff --git a/tiramisu/api.py b/tiramisu/api.py index a99cb41..1a2c1e8 100644 --- a/tiramisu/api.py +++ b/tiramisu/api.py @@ -168,11 +168,12 @@ class CommonTiramisu(TiramisuHelp): if self.index is not None: if option.impl_is_optiondescription() or not option.impl_is_master_slaves('slave'): raise APIError('index must be set only with a slave option') - if self.index >= self.subconfig.cfgimpl_get_length(): + self._length = self.subconfig.cfgimpl_get_length_slave(option, self.config_bag) + if self.index >= self._length: raise SlaveError(_('index "{}" is higher than the master length "{}" ' 'for option "{}"').format(self.index, - self.subconfig.cfgimpl_get_length(), - option.impl_get_display_name())) + self._length, + option.impl_get_display_name())) if not self.allow_optiondescription and option.impl_is_optiondescription(): raise APIError(_('option must not be an optiondescription')) return option @@ -573,17 +574,11 @@ class TiramisuOptionValue(CommonTiramisuOption): @count def _len(self): """length of slave option (only for slave option)""" - self._get_option() - subconfig_path = self._path.rsplit('.', 1)[0] - if self.config_bag.setting_properties is not None: - self.config_bag.config.cfgimpl_get_settings().validate_properties(self._path, - self.index, - self.config_bag) - config_bag = self.config_bag.copy('nooption') - subconfig = config_bag.config.getattr(subconfig_path, - None, - config_bag) - return subconfig.cfgimpl_get_length() + option = self._get_option() + # for example if index is None + if '_length' not in vars(self): + self._length = self.subconfig.cfgimpl_get_length_slave(option, self.config_bag) + return self._length def __getattr__(self, name): if name == 'list' and isinstance(self._get_option(), ChoiceOption): diff --git a/tiramisu/config.py b/tiramisu/config.py index fa389a4..9154eb1 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -83,6 +83,16 @@ class SubConfig(object): def cfgimpl_get_length(self): return self._impl_length + def cfgimpl_get_length_slave(self, option, config_bag): + if option.impl_is_symlinkoption(): + context = self.cfgimpl_get_context() + sconfig_bag = config_bag.copy('nooption') + subconfig, _ = context.cfgimpl_get_home_by_path(option.impl_getopt().impl_getpath(context), + sconfig_bag) + return subconfig.cfgimpl_get_length() + else: + return self.cfgimpl_get_length() + def reset_one_option_cache(self, desc, values, @@ -354,7 +364,7 @@ class SubConfig(object): subpath) if option.impl_is_master_slaves('slave'): - length = self.cfgimpl_get_length() + length = self.cfgimpl_get_length_slave(option, config_bag) slave_len = self.cfgimpl_get_values()._p_.get_max_length(subpath) if slave_len > length: raise SlaveError(_('slave option "{}" has higher length "{}" than the master ' @@ -364,7 +374,6 @@ class SubConfig(object): subpath)) if option.impl_is_master_slaves('slave') and index is None: value = [] - length = self.cfgimpl_get_length() for idx in range(length): config_bag.properties = None value.append(self.getattr(name, @@ -551,7 +560,7 @@ class SubConfig(object): option = config_bag.option if not option.impl_is_optiondescription() and option.impl_is_master_slaves('slave'): ret = [] - length = self.cfgimpl_get_length() + length = self.cfgimpl_get_length_slave(option, config_bag) if length: for idx in range(length): config_bag.properties = None