consistancies can have more than one option
add _cons_broadcast
This commit is contained in:
parent
2490d00935
commit
482dfec7f2
|
@ -4,7 +4,7 @@ from py.test import raises
|
|||
from tiramisu.setting import owners, groups
|
||||
from tiramisu.config import Config
|
||||
from tiramisu.option import IPOption, NetworkOption, NetmaskOption, IntOption,\
|
||||
SymLinkOption, OptionDescription
|
||||
BroadcastOption, SymLinkOption, OptionDescription
|
||||
|
||||
|
||||
def test_consistency_not_equal():
|
||||
|
@ -159,3 +159,22 @@ def test_consistency_network_netmask_multi_master():
|
|||
c.a = ['192.168.1.0']
|
||||
c.b = ['255.255.255.0']
|
||||
raises(ValueError, "c.a = ['192.168.1.1']")
|
||||
|
||||
|
||||
def test_consistency_broadcast():
|
||||
a = NetworkOption('a', '', multi=True)
|
||||
b = NetmaskOption('b', '', multi=True)
|
||||
c = BroadcastOption('c', '', multi=True)
|
||||
od = OptionDescription('a', '', [a, b, c])
|
||||
od.impl_set_group_type(groups.master)
|
||||
b.impl_add_consistency('network_netmask', a)
|
||||
c.impl_add_consistency('broadcast', a, b)
|
||||
c = Config(od)
|
||||
c.a = ['192.168.1.0']
|
||||
c.b = ['255.255.255.0']
|
||||
c.c = ['192.168.1.255']
|
||||
raises(ValueError, "c.a = ['192.168.1.1']")
|
||||
c.a = ['192.168.1.0', '192.168.2.128']
|
||||
c.b = ['255.255.255.0', '255.255.255.128']
|
||||
c.c = ['192.168.1.255', '192.168.2.255']
|
||||
raises(ValueError, "c.c[1] = '192.168.2.128'")
|
||||
|
|
|
@ -72,7 +72,8 @@ def _diff_opt(opt1, opt2):
|
|||
if isinstance(val1, list):
|
||||
for index, consistency in enumerate(val1):
|
||||
assert consistency[0] == val2[index][0]
|
||||
assert consistency[1]._name == val2[index][1]._name
|
||||
for idx, opt in enumerate(consistency[1]):
|
||||
assert opt._name == val2[index][1][idx]._name
|
||||
elif attr == '_callback':
|
||||
assert val1[0] == val2[0]
|
||||
if val1[1] is not None:
|
||||
|
|
|
@ -27,7 +27,7 @@ from types import FunctionType
|
|||
from IPy import IP
|
||||
import warnings
|
||||
|
||||
from tiramisu.error import ConflictError, ValueWarning
|
||||
from tiramisu.error import ConfigError, ConflictError, ValueWarning
|
||||
from tiramisu.setting import groups, multitypes
|
||||
from tiramisu.i18n import _
|
||||
from tiramisu.autolib import carry_out_calculation
|
||||
|
@ -172,14 +172,13 @@ class BaseOption(object):
|
|||
if isinstance(consistencies, list):
|
||||
new_value = []
|
||||
for consistency in consistencies:
|
||||
if load:
|
||||
new_value.append((consistency[0],
|
||||
descr.impl_get_opt_by_path(
|
||||
consistency[1])))
|
||||
else:
|
||||
new_value.append((consistency[0],
|
||||
descr.impl_get_path_by_opt(
|
||||
consistency[1])))
|
||||
values = []
|
||||
for obj in consistency[1]:
|
||||
if load:
|
||||
values.append(descr.impl_get_opt_by_path(obj))
|
||||
else:
|
||||
values.append(descr.impl_get_path_by_opt(obj))
|
||||
new_value.append((consistency[0], tuple(values)))
|
||||
|
||||
else:
|
||||
new_value = {}
|
||||
|
@ -395,50 +394,62 @@ class Option(BaseOption):
|
|||
self.impl_validate(default)
|
||||
self._default = default
|
||||
|
||||
def _launch_consistency(self, func, opt, vals, context, index, opt_):
|
||||
def _launch_consistency(self, func, right_opt, right_val, context, index,
|
||||
left_opts):
|
||||
if context is not None:
|
||||
descr = context.cfgimpl_get_description()
|
||||
if opt is self:
|
||||
#values are for self, search opt_ values
|
||||
values = vals
|
||||
if context is not None:
|
||||
path = descr.impl_get_path_by_opt(opt_)
|
||||
values_ = context._getattr(path, validate=False)
|
||||
#right_opt is also in left_opts
|
||||
if right_opt not in left_opts:
|
||||
raise ConfigError(_('right_opt not in left_opts'))
|
||||
|
||||
left_vals = []
|
||||
for opt in left_opts:
|
||||
if right_opt == opt:
|
||||
value = right_val
|
||||
else:
|
||||
if context is not None:
|
||||
path = descr.impl_get_path_by_opt(opt)
|
||||
value = context._getattr(path, validate=False)
|
||||
else:
|
||||
value = opt.impl_getdefault()
|
||||
if index is None:
|
||||
#could be multi or not
|
||||
left_vals.append(value)
|
||||
else:
|
||||
values_ = opt_.impl_getdefault()
|
||||
if index is not None:
|
||||
#value is not already set, could be higher
|
||||
try:
|
||||
values_ = values_[index]
|
||||
if right_opt == opt:
|
||||
val = value
|
||||
else:
|
||||
val = value[index]
|
||||
if val is None:
|
||||
#no value so no consistencies
|
||||
return
|
||||
left_vals.append(val)
|
||||
except IndexError:
|
||||
values_ = None
|
||||
else:
|
||||
#values are for opt_, search self values
|
||||
values_ = vals
|
||||
if context is not None:
|
||||
path = descr.impl_get_path_by_opt(self)
|
||||
values = context._getattr(path, validate=False)
|
||||
#so return if no value
|
||||
return
|
||||
|
||||
if self.impl_is_multi():
|
||||
if index is None:
|
||||
for idx, right_v in enumerate(right_val):
|
||||
try:
|
||||
left_v = []
|
||||
for left_val in left_vals:
|
||||
left_v.append(left_val[idx])
|
||||
if None in left_v:
|
||||
continue
|
||||
except IndexError:
|
||||
continue
|
||||
getattr(self, func)(left_opts, left_v)
|
||||
else:
|
||||
values = self.impl_getdefault()
|
||||
if index is not None:
|
||||
#value is not already set, could be higher
|
||||
try:
|
||||
values = values[index]
|
||||
except IndexError:
|
||||
values = None
|
||||
if index is None and self.impl_is_multi():
|
||||
for index in range(0, len(values)):
|
||||
try:
|
||||
value = values[index]
|
||||
value_ = values_[index]
|
||||
except IndexError:
|
||||
value = None
|
||||
value_ = None
|
||||
if None not in (value, value_):
|
||||
getattr(self, func)(opt_._name, value, value_)
|
||||
if None in left_vals:
|
||||
return
|
||||
getattr(self, func)(left_opts, left_vals)
|
||||
else:
|
||||
if None not in (values, values_):
|
||||
getattr(self, func)(opt_._name, values, values_)
|
||||
if None in left_vals:
|
||||
return
|
||||
getattr(self, func)(left_opts, left_vals)
|
||||
|
||||
def impl_validate(self, value, context=None, validate=True,
|
||||
force_no_multi=False):
|
||||
|
@ -550,29 +561,31 @@ class Option(BaseOption):
|
|||
def impl_is_multi(self):
|
||||
return self._multi
|
||||
|
||||
def impl_add_consistency(self, func, opt):
|
||||
def impl_add_consistency(self, func, *left_opts):
|
||||
if self._consistencies is None:
|
||||
self._consistencies = []
|
||||
if not isinstance(opt, Option):
|
||||
raise ValueError('consistency must be set with an option')
|
||||
if self is opt:
|
||||
raise ValueError('cannot add consistency with itself')
|
||||
if self.impl_is_multi() != opt.impl_is_multi():
|
||||
raise ValueError('options in consistency'
|
||||
' should be multi in two sides')
|
||||
for opt in left_opts:
|
||||
if not isinstance(opt, Option):
|
||||
raise ValueError(_('consistency should be set with an option'))
|
||||
if self is opt:
|
||||
raise ValueError(_('cannot add consistency with itself'))
|
||||
if self.impl_is_multi() != opt.impl_is_multi():
|
||||
raise ValueError(_('options in consistency should be multi in '
|
||||
'two sides'))
|
||||
func = '_cons_{0}'.format(func)
|
||||
self._launch_consistency(func,
|
||||
self,
|
||||
self.impl_getdefault(),
|
||||
None, None, opt)
|
||||
self._consistencies.append((func, opt))
|
||||
opts = tuple([self] + list(left_opts))
|
||||
self._launch_consistency(func, self, self.impl_getdefault(), None,
|
||||
None, opts)
|
||||
self._consistencies.append((func, opts))
|
||||
self.impl_validate(self.impl_getdefault())
|
||||
|
||||
def _cons_not_equal(self, optname, value, value_):
|
||||
if value == value_:
|
||||
def _cons_not_equal(self, opts, vals):
|
||||
if len(opts) != 2:
|
||||
raise ConfigError(_('invalid len for opts'))
|
||||
if vals[0] == vals[1]:
|
||||
raise ValueError(_("invalid value {0} for option {1} "
|
||||
"must be different as {2} option"
|
||||
"").format(value, self._name, optname))
|
||||
"").format(vals[0], self._name, opts[1]._name))
|
||||
|
||||
def _impl_convert_callbacks(self, descr, load=False):
|
||||
if not load and self._callback is None:
|
||||
|
@ -889,15 +902,17 @@ class NetmaskOption(Option):
|
|||
except ValueError:
|
||||
raise ValueError(_('invalid netmask address {0}').format(self._name))
|
||||
|
||||
def _cons_network_netmask(self, optname, value, value_):
|
||||
def _cons_network_netmask(self, opts, vals):
|
||||
#opts must be (netmask, network) options
|
||||
self.__cons_netmask(optname, value, value_, False)
|
||||
self.__cons_netmask(opts, vals[0], vals[1], False)
|
||||
|
||||
def _cons_ip_netmask(self, optname, value, value_):
|
||||
def _cons_ip_netmask(self, opts, vals):
|
||||
#opts must be (netmask, ip) options
|
||||
self.__cons_netmask(optname, value, value_, True)
|
||||
self.__cons_netmask(opts, vals[0], vals[1], True)
|
||||
|
||||
def __cons_netmask(self, optname, val_netmask, val_ipnetwork, make_net):
|
||||
def __cons_netmask(self, opts, val_netmask, val_ipnetwork, make_net):
|
||||
if len(opts) != 2:
|
||||
raise ConfigError(_('invalid len for opts'))
|
||||
msg = None
|
||||
try:
|
||||
ip = IP('{0}/{1}'.format(val_ipnetwork, val_netmask),
|
||||
|
@ -923,17 +938,30 @@ class NetmaskOption(Option):
|
|||
else:
|
||||
msg = _("invalid network {0} ({1}) with netmask {2} ({3})")
|
||||
if msg is not None:
|
||||
raise ValueError(msg.format(val_ipnetwork, optname,
|
||||
raise ValueError(msg.format(val_ipnetwork, opts[1]._name,
|
||||
val_netmask, self._name))
|
||||
|
||||
|
||||
class BroadcastOption(Option):
|
||||
__slots__ = tuple()
|
||||
_opt_type = 'broadcast'
|
||||
|
||||
def _validate(self, value):
|
||||
try:
|
||||
IP('{0}/32'.format(value))
|
||||
except ValueError:
|
||||
raise ValueError(_('invalid broadcast address {0}').format(self._name))
|
||||
|
||||
def _cons_broadcast(self, opts, vals):
|
||||
if len(vals) != 3:
|
||||
raise ConfigError(_('invalid len for vals'))
|
||||
broadcast, network, netmask = vals
|
||||
if IP('{0}/{1}'.format(network, netmask)).broadcast() != IP(broadcast):
|
||||
raise ValueError(_('invalid broadcast {0} ({1}) with network {2} '
|
||||
'({3}) and netmask {4} ({5})').format(
|
||||
broadcast, opts[0]._name, network,
|
||||
opts[1]._name, netmask, opts[2]._name))
|
||||
|
||||
|
||||
class DomainnameOption(Option):
|
||||
"represents the choice of a domain name"
|
||||
|
@ -1098,12 +1126,11 @@ class OptionDescription(BaseOption):
|
|||
if not force_no_consistencies and \
|
||||
option._consistencies is not None:
|
||||
for consistency in option._consistencies:
|
||||
func, opt = consistency
|
||||
opts = (option, opt)
|
||||
_consistencies.setdefault(opt,
|
||||
[]).append((func, opts))
|
||||
_consistencies.setdefault(option,
|
||||
[]).append((func, opts))
|
||||
func, left_opts = consistency
|
||||
for opt in left_opts:
|
||||
_consistencies.setdefault(opt,
|
||||
[]).append((func,
|
||||
left_opts))
|
||||
else:
|
||||
_currpath.append(attr)
|
||||
option.impl_build_cache(cache_path,
|
||||
|
@ -1186,17 +1213,15 @@ class OptionDescription(BaseOption):
|
|||
def impl_get_group_type(self):
|
||||
return self._group_type
|
||||
|
||||
def _valid_consistency(self, opt, value, context=None, index=None):
|
||||
consistencies = self._consistencies.get(opt)
|
||||
def _valid_consistency(self, right_opt, right_val, context=None, index=None):
|
||||
#[('_cons_not_equal', (opt1, opt2))]
|
||||
consistencies = self._consistencies.get(right_opt)
|
||||
if consistencies is not None:
|
||||
for consistency in consistencies:
|
||||
opt_ = consistency[1]
|
||||
ret = opt_[0]._launch_consistency(consistency[0],
|
||||
opt,
|
||||
value,
|
||||
context,
|
||||
index,
|
||||
opt_[1])
|
||||
for func, opts in consistencies:
|
||||
#opts[0] is the option where func is set
|
||||
#opts is left_opts
|
||||
ret = opts[0]._launch_consistency(func, right_opt, right_val,
|
||||
context, index, opts)
|
||||
if ret is False:
|
||||
return False
|
||||
return True
|
||||
|
|
Loading…
Reference in New Issue