requires for a master is a required for the masterslaves + remove cache from masterslaves too

This commit is contained in:
Emmanuel Garette 2018-09-02 11:55:19 +02:00
parent 71ec5b7148
commit 122796bd19
9 changed files with 101 additions and 25 deletions

View File

@ -446,8 +446,7 @@ def test_cache_master_and_slaves_master():
compare(cfg._config.cfgimpl_get_values()._p_.get_cached(), {'val1.val1': {None: ([], None)}}) compare(cfg._config.cfgimpl_get_values()._p_.get_cached(), {'val1.val1': {None: ([], None)}})
# #
cfg.option('val1.val1').value.set([undefined]) cfg.option('val1.val1').value.set([undefined])
compare(cfg._config.cfgimpl_get_settings()._p_.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings']), None)}, compare(cfg._config.cfgimpl_get_settings()._p_.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings']), None)}})
'val1': {None: (set([]), None)}})
assert cfg._config.cfgimpl_get_values()._p_.get_cached() == {} assert cfg._config.cfgimpl_get_values()._p_.get_cached() == {}
cfg.config.dict() cfg.config.dict()
if TIRAMISU_VERSION == 2: if TIRAMISU_VERSION == 2:
@ -467,8 +466,7 @@ def test_cache_master_and_slaves_master():
cfg.option('val1.val1').value.set([undefined, undefined]) cfg.option('val1.val1').value.set([undefined, undefined])
cfg.config.dict() cfg.config.dict()
cfg.option('val1.val2', 1).value.set('oui') cfg.option('val1.val2', 1).value.set('oui')
compare(cfg._config.cfgimpl_get_settings()._p_.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings']), None)}, compare(cfg._config.cfgimpl_get_settings()._p_.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings']), None)}})
'val1': {None: (set([]), None)}})
assert cfg._config.cfgimpl_get_values()._p_.get_cached() == {} assert cfg._config.cfgimpl_get_values()._p_.get_cached() == {}
if TIRAMISU_VERSION == 2: if TIRAMISU_VERSION == 2:
val1_val2_props = {None: (set([]), None), 0: (set([]), None), 1: (set([]), None)} val1_val2_props = {None: (set([]), None), 0: (set([]), None), 1: (set([]), None)}
@ -520,8 +518,7 @@ def test_cache_master_callback():
'val1.val2': {None: (val1_val2_props, None)}}) 'val1.val2': {None: (val1_val2_props, None)}})
compare(cfg._config.cfgimpl_get_values()._p_.get_cached(), {'val1.val1': {None: ([], None)}}) compare(cfg._config.cfgimpl_get_values()._p_.get_cached(), {'val1.val1': {None: ([], None)}})
cfg.option('val1.val1').value.set([undefined]) cfg.option('val1.val1').value.set([undefined])
compare(cfg._config.cfgimpl_get_settings()._p_.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings']), None)}, compare(cfg._config.cfgimpl_get_settings()._p_.get_cached(), {None: {None: (set(['cache', 'disabled', 'frozen', 'hidden', 'validator', 'warnings']), None)}})
'val1': {None: (set([]), None)}})
assert cfg._config.cfgimpl_get_values()._p_.get_cached() == {} assert cfg._config.cfgimpl_get_values()._p_.get_cached() == {}
cfg.config.dict() cfg.config.dict()

View File

@ -970,6 +970,62 @@ def test_master_slave_requires():
assert isinstance(ret['ip_admin_eth0.netmask_admin_eth0'][1], PropertiesOptionError) assert isinstance(ret['ip_admin_eth0.netmask_admin_eth0'][1], PropertiesOptionError)
def test_master_slave_requires_master():
activate = BoolOption('activate', "Activer l'accès au réseau", True)
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True,
requires=[{'option': activate, 'expected': False, 'action': 'disabled'}])
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])
maconfig = OptionDescription('toto', '', [activate, interface1])
api = Config(maconfig)
api.property.read_write()
#
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2'])
assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == ['192.168.1.2']
#
api.option('activate').value.set(False)
raises(PropertiesOptionError, "api.option('ip_admin_eth0.ip_admin_eth0').value.get()")
raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()")
#
api.option('activate').value.set(True)
assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None
#
api.option('activate').value.set(False)
raises(PropertiesOptionError, "api.option('ip_admin_eth0.ip_admin_eth0').value.get()")
raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()")
assert api.config.dict() == {'activate': False}
def test_master_slave_requires_masterslaves():
activate = BoolOption('activate', "Activer l'accès au réseau", True)
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],
requires=[{'option': activate, 'expected': False, 'action': 'disabled'}])
maconfig = OptionDescription('toto', '', [activate, interface1])
api = Config(maconfig)
api.property.read_write()
#
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2'])
assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == ['192.168.1.2']
#
api.option('activate').value.set(False)
raises(PropertiesOptionError, "api.option('ip_admin_eth0.ip_admin_eth0').value.get()")
raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()")
#
api.option('activate').value.set(True)
assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None
#
api.option('activate').value.set(False)
raises(PropertiesOptionError, "api.option('ip_admin_eth0.ip_admin_eth0').value.get()")
raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()")
assert api.config.dict() == {'activate': False}
def test_master_slave_requires_no_master(): def test_master_slave_requires_no_master():
activate = BoolOption('activate', "Activer l'accès au réseau", True) activate = BoolOption('activate', "Activer l'accès au réseau", True)
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)

View File

@ -24,9 +24,7 @@ from copy import copy
from .error import PropertiesOptionError, ConfigError, ConflictError, SlaveError from .error import PropertiesOptionError, ConfigError, ConflictError, SlaveError
from .option.syndynoptiondescription import SynDynOptionDescription from .option import SynDynOptionDescription, DynOptionDescription, MasterSlaves
from .option.dynoptiondescription import DynOptionDescription
from .option.masterslave import MasterSlaves
from .option.baseoption import BaseOption, valid_name from .option.baseoption import BaseOption, valid_name
from .setting import OptionBag, ConfigBag, groups, Settings, undefined from .setting import OptionBag, ConfigBag, groups, Settings, undefined
from .storage import get_storages, get_default_values_storages from .storage import get_storages, get_default_values_storages

View File

@ -1,7 +1,7 @@
from .optiondescription import OptionDescription from .optiondescription import OptionDescription
from .dynoptiondescription import DynOptionDescription from .dynoptiondescription import DynOptionDescription
from .syndynoptiondescription import SynDynOptionDescription from .syndynoptiondescription import SynDynOptionDescription
from .masterslave import MasterSlaves from .masterslaves import MasterSlaves
from .baseoption import submulti from .baseoption import submulti
from .symlinkoption import SymLinkOption from .symlinkoption import SymLinkOption
from .dynsymlinkoption import DynSymLinkOption from .dynsymlinkoption import DynSymLinkOption

View File

@ -98,11 +98,7 @@ class Base(object):
raise TypeError(_('invalid properties type {0} for {1},' raise TypeError(_('invalid properties type {0} for {1},'
' must be a frozenset').format(type(properties), ' must be a frozenset').format(type(properties),
name)) name))
if calc_properties != frozenset([]) and properties: self.validate_properties(name, calc_properties, properties)
set_forbidden_properties = calc_properties & properties
if set_forbidden_properties != frozenset():
raise ValueError(_('conflict: properties already set in '
'requirement {0}').format(display_list(list(set_forbidden_properties))))
_setattr = object.__setattr__ _setattr = object.__setattr__
_setattr(self, '_name', name) _setattr(self, '_name', name)
_setattr(self, '_informations', {'doc': doc}) _setattr(self, '_informations', {'doc': doc})
@ -113,6 +109,13 @@ class Base(object):
if properties: if properties:
_setattr(self, '_properties', properties) _setattr(self, '_properties', properties)
def validate_properties(self, name, calc_properties, properties):
set_forbidden_properties = calc_properties & properties
if set_forbidden_properties != frozenset():
raise ValueError(_('conflict: properties already set in requirement {0} for {1}'
'').format(display_list(list(set_forbidden_properties)),
name))
def _get_function_args(self, def _get_function_args(self,
function): function):
args = set() args = set()

View File

@ -111,7 +111,7 @@ class IPOption(Option):
raise ValueError(msg.format(network, raise ValueError(msg.format(network,
netmask, netmask,
opts[1].impl_get_display_name(), opts[1].impl_get_display_name(),
opts[2].impl_getname(), opts[2].impl_get_display_name(),
ip)) ip))
# test if ip is not network/broadcast IP # test if ip is not network/broadcast IP
opts[2]._cons_ip_netmask(current_opt, opts[2]._cons_ip_netmask(current_opt,

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"master slave support" "master slaves support"
# Copyright (C) 2014-2018 Team tiramisu (see AUTHORS for all contributors) # Copyright (C) 2014-2018 Team tiramisu (see AUTHORS for all contributors)
# #
# This program is free software: you can redistribute it and/or modify it # This program is free software: you can redistribute it and/or modify it
@ -27,7 +27,7 @@ from ..i18n import _
from ..setting import groups, undefined, OptionBag from ..setting import groups, undefined, OptionBag
from .optiondescription import OptionDescription from .optiondescription import OptionDescription
from .option import Option from .option import Option
from ..error import SlaveError, PropertiesOptionError from ..error import SlaveError, PropertiesOptionError, RequirementError
from ..function import ParamOption from ..function import ParamOption
@ -69,9 +69,9 @@ class MasterSlaves(OptionDescription):
self.impl_get_display_name())) self.impl_get_display_name()))
# no empty property for save # no empty property for save
if idx != 0: if idx != 0:
properties = list(child._properties) child_properties = list(child._properties)
properties.remove('empty') child_properties.remove('empty')
child._properties = frozenset(properties) child._properties = frozenset(child_properties)
slaves.append(child) slaves.append(child)
child._add_dependency(self) child._add_dependency(self)
child._master_slaves = weakref.ref(self) child._master_slaves = weakref.ref(self)
@ -82,6 +82,21 @@ class MasterSlaves(OptionDescription):
if callbk.option in slaves: if callbk.option in slaves:
raise ValueError(_("callback of master's option shall " raise ValueError(_("callback of master's option shall "
"not refered a slave's ones")) "not refered a slave's ones"))
# master should not have requires, only MasterSlaves should have
# so move requires to MasterSlaves
# if MasterSlaves has requires to, cannot manage the move so raises
master_requires = getattr(master, '_requires', None)
if master_requires:
if self.impl_getrequires():
raise RequirementError(_('master {} in MasterSlaves {} cannot have both requirement'
'').format(master.impl_getname(),
self.impl_getname()))
master_calproperties = getattr(master, '_calc_properties', None)
if master_calproperties:
if properties is not None:
self.validate_properties(name, master_calproperties, frozenset(properties))
setattr(self, '_calc_properties', master_calproperties)
setattr(self, '_requires', master_requires)
def is_master(self, opt): def is_master(self, opt):
master = self._children[0][0] master = self._children[0][0]
@ -158,18 +173,24 @@ class MasterSlaves(OptionDescription):
resetted_opts): resetted_opts):
master = self.getmaster() master = self.getmaster()
slaves = self.getslaves() slaves = self.getslaves()
self._reset_cache(master, self._reset_cache(path,
master,
slaves, slaves,
values, values,
settings, settings,
resetted_opts) resetted_opts)
def _reset_cache(self, def _reset_cache(self,
path,
master, master,
slaves, slaves,
values, values,
settings, settings,
resetted_opts): resetted_opts):
super().reset_cache(path,
values,
settings,
resetted_opts)
context = values._getcontext() context = values._getcontext()
mpath = master.impl_getpath(context) mpath = master.impl_getpath(context)
master.reset_cache(mpath, master.reset_cache(mpath,

View File

@ -673,9 +673,9 @@ class Option(OnlyOption):
log.debug(_('_cons_not_equal: {} are not different').format(display_list(equal))) log.debug(_('_cons_not_equal: {} are not different').format(display_list(equal)))
if is_current: if is_current:
if warnings_only: if warnings_only:
msg = _('should be different from the value of {}') msg = _('should be different from the value of "{}"')
else: else:
msg = _('must be different from the value of {}') msg = _('must be different from the value of "{}"')
else: else:
if warnings_only: if warnings_only:
msg = _('value for {} should be different') msg = _('value for {} should be different')

View File

@ -103,7 +103,8 @@ class SynDynOptionDescription(object):
if self.impl_get_group_type() == groups.master: if self.impl_get_group_type() == groups.master:
master = self.getmaster() master = self.getmaster()
slaves = self.getslaves() slaves = self.getslaves()
self._reset_cache(master, self._reset_cache(path,
master,
slaves, slaves,
values, values,
settings, settings,