summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Poessinger <christian@poessinger.com>2020-06-30 20:28:39 +0200
committerGitHub <noreply@github.com>2020-06-30 20:28:39 +0200
commit6d3da454f1fe0f1970ce16440c519867ede56ae0 (patch)
treeac94366b7931fd428eb4fbb03a35ba942cd9b7b9
parent628ba49dd655c9003fb65e25aba145c1a6349181 (diff)
parent987cfd15db91a14df944a4c3174a094ff756cdd0 (diff)
downloadvyos-1x-6d3da454f1fe0f1970ce16440c519867ede56ae0.tar.gz
vyos-1x-6d3da454f1fe0f1970ce16440c519867ede56ae0.zip
Merge pull request #484 from thomas-mangin/T2649
tunnel: T2649: ConfigurationState, do not inherit from Config
-rwxr-xr-xsrc/conf_mode/interfaces-tunnel.py118
1 files changed, 74 insertions, 44 deletions
diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py
index c13f77d91..ea15a7fb7 100755
--- a/src/conf_mode/interfaces-tunnel.py
+++ b/src/conf_mode/interfaces-tunnel.py
@@ -32,7 +32,8 @@ from vyos.dicts import FixedDict
from vyos import airbag
airbag.enable()
-class ConfigurationState(Config):
+
+class ConfigurationState(object):
"""
The current API require a dict to be generated by get_config()
which is then consumed by verify(), generate() and apply()
@@ -40,7 +41,7 @@ class ConfigurationState(Config):
ConfiguartionState is an helper class wrapping Config and providing
an common API to this dictionary structure
- Its to_dict() function return a dictionary containing three fields,
+ Its to_api() function return a dictionary containing three fields,
each a dict, called options, changes, actions.
options:
@@ -84,16 +85,16 @@ class ConfigurationState(Config):
which for each field represent how it was modified since the last commit
"""
- def __init__ (self, section, default):
+ def __init__(self, configuration, section, default):
"""
initialise the class for a given configuration path:
- >>> conf = ConfigurationState('interfaces ethernet eth1')
+ >>> conf = ConfigurationState(conf, 'interfaces ethernet eth1')
all further references to get_value(s) and get_effective(s)
will be for this part of the configuration (eth1)
"""
- super().__init__()
- self.section = section
+ self._conf = configuration
+
self.default = deepcopy(default)
self.options = FixedDict(**default)
self.actions = {
@@ -104,13 +105,19 @@ class ConfigurationState(Config):
'delete': [], # the key was present and was deleted
}
self.changes = {}
- if not self.exists(section):
+ if not self._conf.exists(section):
self.changes['section'] = 'delete'
- elif self.exists_effective(section):
+ elif self._conf.exists_effective(section):
self.changes['section'] = 'modify'
else:
self.changes['section'] = 'create'
+ self.set_level(section)
+
+ def set_level(self, lpath):
+ self.section = lpath
+ self._conf.set_level(lpath)
+
def _act(self, section):
"""
Returns for a given configuration field determine what happened to it
@@ -121,18 +128,18 @@ class ConfigurationState(Config):
'delete': it was present but was removed from the configuration
'absent': it was not and is not present
"""
- if self.exists(section):
- if self.exists_effective(section):
- if self.return_value(section) != self.return_effective_value(section):
+ if self._conf.exists(section):
+ if self._conf.exists_effective(section):
+ if self._conf.return_value(section) != self._conf.return_effective_value(section):
return 'modify'
return 'static'
return 'create'
else:
- if self.exists_effective(section):
+ if self._conf.exists_effective(section):
return 'delete'
return 'absent'
- def _action (self, name, key):
+ def _action(self, name, key):
action = self._act(key)
self.changes[name] = action
self.actions[action].append(name)
@@ -157,18 +164,28 @@ class ConfigurationState(Config):
"""
if self._action(name, key) in ('delete', 'absent'):
return
- return self._get(name, key, default, self.return_value)
+ return self._get(name, key, default, self._conf.return_value)
def get_values(self, name, key, default=None):
"""
- >>> conf.get_values('addresses-add', 'address')
- will place a list made of the IP present in 'interface dummy dum1 address'
- into the dictionnary entry 'addr' using Config.return_values
- (the data in the configuration to apply)
+ >>> conf.get_values('addresses', 'address')
+ will place a list of the new IP present in 'interface dummy dum1 address'
+ into the dictionnary entry "-add" (here 'addresses-add') using
+ Config.return_values and will add the the one which were removed in into
+ the entry "-del" (here addresses-del')
"""
- if self._action(name, key) in ('delete', 'absent'):
+ add_name = f'{name}-add'
+
+ if self._action(add_name, key) in ('delete', 'absent'):
return
- return self._get(name, key, default, self.return_values)
+
+ self._get(add_name, key, default, self._conf.return_values)
+
+ # get the effective values to determine which data is no longer valid
+ self.options['addresses-del'] = list_diff(
+ self._conf.return_effective_values('address'),
+ self.options['addresses-add']
+ )
def get_effective(self, name, key, default=None):
"""
@@ -178,7 +195,7 @@ class ConfigurationState(Config):
(the data in the configuration to apply)
"""
self._action(name, key)
- return self._get(name, key, default, self.return_effective_value)
+ return self._get(name, key, default, self._conf.return_effective_value)
def get_effectives(self, name, key, default=None):
"""
@@ -188,7 +205,7 @@ class ConfigurationState(Config):
(the data in the un-modified configuration)
"""
self._action(name, key)
- return self._get(name, key, default, self.return_effectives_value)
+ return self._get(name, key, default, self._conf.return_effectives_value)
def load(self, mapping):
"""
@@ -220,16 +237,35 @@ class ConfigurationState(Config):
else:
self.get_value(local_name, config_name, default)
- def remove_default (self,*options):
+ def remove_default(self,*options):
"""
remove all the values which were not changed from the default
"""
for option in options:
- if self.exists(option) and self.self_return_value(option) != self.default[option]:
+ if not self._conf.exists(option):
+ del self.options[option]
continue
- del self.options[option]
- def to_dict (self):
+ if self._conf.return_value(option) == self.default[option]:
+ del self.options[option]
+ continue
+
+ if self._conf.return_values(option) == self.default[option]:
+ del self.options[option]
+ continue
+
+ def as_dict(self, lpath):
+ l = self._conf.get_level()
+ self._conf.set_level([])
+ d = self._conf.get_config_dict(lpath)
+ # XXX: that not what I would have expected from get_config_dict
+ if lpath:
+ d = d[lpath[-1]]
+ # XXX: it should have provided me the content and not the key
+ self._conf.set_level(l)
+ return d
+
+ def to_api(self):
"""
provide a dictionary with the generated data for the configuration
options: the configuration value for the key
@@ -243,6 +279,7 @@ class ConfigurationState(Config):
'actions': self.actions,
}
+
default_config_data = {
# interface definition
'vrf': '',
@@ -288,6 +325,7 @@ default_config_data = {
'6rd-relay-prefix': '',
}
+
# dict name -> config name, multiple values, default
mapping = {
'type': ('encapsulation', False, None),
@@ -310,7 +348,7 @@ mapping = {
'state': ('disable', False, 'down'),
'link_detect': ('disable-link-detect', False, 2),
'vrf': ('vrf', False, None),
- 'addresses-add': ('address', True, None),
+ 'addresses': ('address', True, None),
'arp_filter': ('ip disable-arp-filter', False, 0),
'arp_accept': ('ip enable-arp-accept', False, 1),
'arp_announce': ('ip enable-arp-announce', False, 1),
@@ -320,6 +358,7 @@ mapping = {
'ipv6_dad_transmits:': ('ipv6 dup-addr-detect-transmits', False, None)
}
+
def get_class (options):
dispatch = {
'gre': GREIf,
@@ -363,19 +402,17 @@ def get_config():
if not ifname:
raise ConfigError('Interface not specified')
- conf = ConfigurationState('interfaces tunnel ' + ifname, default_config_data)
+ config = Config()
+ conf = ConfigurationState(config, ['interfaces', 'tunnel ', ifname], default_config_data)
options = conf.options
changes = conf.changes
options['ifname'] = ifname
- # set new configuration level
- conf.set_level(conf.section)
-
if changes['section'] == 'delete':
conf.get_effective('type', mapping['type'][0])
- conf.set_level('protocols nhrp tunnel')
- options['nhrp'] = conf.list_nodes('')
- return conf.to_dict()
+ config.set_level(['protocols', 'nhrp', 'tunnel'])
+ options['nhrp'] = config.list_nodes('')
+ return conf.to_api()
# load all the configuration option according to the mapping
conf.load(mapping)
@@ -407,12 +444,6 @@ def get_config():
options['local'] = picked
options['dhcp-interface'] = ''
- # get interface addresses (currently effective) - to determine which
- # address is no longer valid and needs to be removed
- # could be done within ConfigurationState
- eff_addr = conf.return_effective_values('address')
- options['addresses-del'] = list_diff(eff_addr, options['addresses-add'])
-
# to make IPv6 SLAAC and DHCPv6 work with forwarding=1,
# accept_ra must be 2
if options['ipv6_autoconf'] or 'dhcpv6' in options['addresses-add']:
@@ -422,12 +453,11 @@ def get_config():
options['allmulticast'] = options['multicast']
# check that per encapsulation all local-remote pairs are unique
- conf.set_level('interfaces tunnel')
- ct = conf.get_config_dict()['tunnel']
+ ct = conf.as_dict(['interfaces', 'tunnel'])
options['tunnel'] = {}
# check for bridges
- options['bridge'] = is_member(conf, ifname, 'bridge')
+ options['bridge'] = is_member(config, ifname, 'bridge')
options['interfaces'] = interfaces()
for name in ct:
@@ -440,7 +470,7 @@ def get_config():
pair = f'{local}-{remote}'
options['tunnel'][encap][pair] = options['tunnel'].setdefault(encap, {}).get(pair, 0) + 1
- return conf.to_dict()
+ return conf.to_api()
def verify(conf):