diff options
-rw-r--r-- | python/vyos/dicts.py | 50 | ||||
-rw-r--r-- | python/vyos/ifconfig/dhcp.py | 222 | ||||
-rw-r--r-- | python/vyos/ifconfig/interface.py | 22 | ||||
-rw-r--r-- | python/vyos/ifconfig_vlan.py | 22 | ||||
-rwxr-xr-x | src/conf_mode/interfaces-bonding.py | 22 | ||||
-rwxr-xr-x | src/conf_mode/interfaces-bridge.py | 22 | ||||
-rwxr-xr-x | src/conf_mode/interfaces-ethernet.py | 22 | ||||
-rwxr-xr-x | src/conf_mode/interfaces-pseudo-ethernet.py | 22 | ||||
-rwxr-xr-x | src/conf_mode/interfaces-tunnel.py | 36 | ||||
-rwxr-xr-x | src/conf_mode/interfaces-wireless.py | 22 |
10 files changed, 192 insertions, 270 deletions
diff --git a/python/vyos/dicts.py b/python/vyos/dicts.py new file mode 100644 index 000000000..79cab4a08 --- /dev/null +++ b/python/vyos/dicts.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +class FixedDict(dict): + """ + FixedDict: A dictionnary not allowing new keys to be created after initialisation. + + >>> f = FixedDict(**{'count':1}) + >>> f['count'] = 2 + >>> f['king'] = 3 + File "...", line ..., in __setitem__ + raise ConfigError(f'Option "{k}" has no defined default') + """ + + def __init__(self, **options): + self._allowed = options.keys() + super().__init__(**options) + + def __setitem__(self, k, v): + """ + __setitem__ is a builtin which is called by python when setting dict values: + >>> d = dict() + >>> d['key'] = 'value' + >>> d + {'key': 'value'} + + is syntaxic sugar for + + >>> d = dict() + >>> d.__setitem__('key','value') + >>> d + {'key': 'value'} + """ + if k not in self._allowed: + raise ConfigError(f'Option "{k}" has no defined default') + super().__setitem__(k, v) diff --git a/python/vyos/ifconfig/dhcp.py b/python/vyos/ifconfig/dhcp.py index 8ec8263b5..5b0a0bf6a 100644 --- a/python/vyos/ifconfig/dhcp.py +++ b/python/vyos/ifconfig/dhcp.py @@ -16,103 +16,55 @@ import os import jinja2 +from vyos.dicts import FixedDict from vyos.ifconfig.control import Control -template_v4 = """ -# generated by ifconfig.py -option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; -timeout 60; -retry 300; - -interface "{{ intf }}" { - send host-name "{{ hostname }}"; - {% if client_id -%} - send dhcp-client-identifier "{{ client_id }}"; - {% endif -%} - {% if vendor_class_id -%} - send vendor-class-identifier "{{ vendor_class_id }}"; - {% endif -%} - request subnet-mask, broadcast-address, routers, domain-name-servers, - rfc3442-classless-static-routes, domain-name, interface-mtu; - require subnet-mask; -} - -""" - -template_v6 = """ -# generated by ifconfig.py -interface "{{ intf }}" { - request routers, domain-name-servers, domain-name; -} - -""" - -class DHCP (Control): + +class _DHCP (Control): client_base = r'/var/lib/dhcp/dhclient_' - def __init__ (self, ifname, **kargs): + def __init__(self, ifname, version, **kargs): super().__init__(**kargs) - - # per interface DHCP config files - self._dhcp = { - 4: { - 'ifname': ifname, - 'conf': self.client_base + ifname + '.conf', - 'pid': self.client_base + ifname + '.pid', - 'lease': self.client_base + ifname + '.leases', - 'options': { - 'intf': ifname, - 'hostname': '', - 'client_id': '', - 'vendor_class_id': '' - }, - }, - 6: { - 'ifname': ifname, - 'conf': self.client_base + ifname + '.v6conf', - 'pid': self.client_base + ifname + '.v6pid', - 'lease': self.client_base + ifname + '.v6leases', - 'accept_ra': f'/proc/sys/net/ipv6/conf/{ifname}/accept_ra', - 'options': { - 'intf': ifname, - 'dhcpv6_prm_only': False, - 'dhcpv6_temporary': False - }, - }, + self.version = version + self.file = { + 'ifname': ifname, + 'conf': self.client_base + ifname + '.' + version + 'conf', + 'pid': self.client_base + ifname + '.' + version + 'pid', + 'lease': self.client_base + ifname + '.' + version + 'leases', } - def get_dhcp_options(self): - """ - Return dictionary with supported DHCP options. - - Dictionary should be altered and send back via set_dhcp_options() - so those options are applied when DHCP is run. - """ - return self._dhcp[4]['options'] - - def set_dhcp_options(self, options): - """ - Store new DHCP options used by next run of DHCP client. - """ - self._dhcp[4]['options'] = options - - def get_dhcpv6_options(self): - """ - Return dictionary with supported DHCPv6 options. - - Dictionary should be altered and send back via set_dhcp_options() - so those options are applied when DHCP is run. - """ - return self._dhcp[6]['options'] - - def set_dhcpv6_options(self, options): - """ - Store new DHCP options used by next run of DHCP client. - """ - self._dhcp[6]['options'] = options +class _DHCPv4 (_DHCP): + template = """\ + # generated by ifconfig.py + option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; + timeout 60; + retry 300; + + interface "{{ ifname }}" { + send host-name "{{ hostname }}"; + {% if client_id -%} + send dhcp-client-identifier "{{ client_id }}"; + {% endif -%} + {% if vendor_class_id -%} + send vendor-class-identifier "{{ vendor_class_id }}"; + {% endif -%} + request subnet-mask, broadcast-address, routers, domain-name-servers, + rfc3442-classless-static-routes, domain-name, interface-mtu; + require subnet-mask; + } + """.replace(' ', '') + + def __init__(self, ifname): + super().__init__(ifname, '') + self.options = FixedDict(**{ + 'ifname': ifname, + 'hostname': '', + 'client_id': '', + 'vendor_class_id': '' + }) # replace dhcpv4/v6 with systemd.networkd? - def _set_dhcp(self): + def set(self): """ Configure interface as DHCP client. The dhclient binary is automatically started in background! @@ -121,21 +73,19 @@ class DHCP (Control): >>> from vyos.ifconfig import Interface >>> j = Interface('eth0') - >>> j.set_dhcp() + >>> j.dhcp.v4.set() """ - dhcp = self.get_dhcp_options() - if not dhcp['hostname']: + if not self.options['hostname']: # read configured system hostname. # maybe change to vyos hostd client ??? with open('/etc/hostname', 'r') as f: - dhcp['hostname'] = f.read().rstrip('\n') + self.options['hostname'] = f.read().rstrip('\n') # render DHCP configuration - tmpl = jinja2.Template(template_v4) - dhcp_text = tmpl.render(dhcp) - with open(self._dhcp[4]['conf'], 'w') as f: - f.write(dhcp_text) + tmpl = jinja2.Template(self.template) + with open(self.file['conf'], 'w') as f: + f.write(tmpl.render(self.options)) cmd = 'start-stop-daemon' cmd += ' --start' @@ -146,9 +96,9 @@ class DHCP (Control): cmd += ' --' # now pass arguments to dhclient binary cmd += ' -4 -nw -cf {conf} -pf {pid} -lf {lease} {ifname}' - return self._cmd(cmd.format(**self._dhcp[4])) + return self._cmd(cmd.format(**self.file)) - def _del_dhcp(self): + def delete(self): """ De-configure interface as DHCP clinet. All auto generated files like pid, config and lease will be removed. @@ -157,14 +107,14 @@ class DHCP (Control): >>> from vyos.ifconfig import Interface >>> j = Interface('eth0') - >>> j.del_dhcp() + >>> j.dhcp.v4.delete() """ - if not os.path.isfile(self._dhcp[4]['pid']): + if not os.path.isfile(self.file['pid']): self._debug_msg('No DHCP client PID found') return None - # with open(self._dhcp[4]['pid'], 'r') as f: - # pid = int(f.read()) + # with open(self.file['pid'], 'r') as f: + # pid = int(f.read()) # stop dhclient, we need to call dhclient and tell it should release the # aquired IP address. tcpdump tells me: @@ -178,14 +128,35 @@ class DHCP (Control): # Hostname Option 12, length 10: "vyos" # cmd = '/sbin/dhclient -cf {conf} -pf {pid} -lf {lease} -r {ifname}' - self._cmd(cmd.format(**self._dhcp[4])) + self._cmd(cmd.format(**self.file)) # cleanup old config files for name in ('conf', 'pid', 'lease'): - if os.path.isfile(self._dhcp[4][name]): - os.remove(self._dhcp[4][name]) + if os.path.isfile(self.file[name]): + os.remove(self.file[name]) - def _set_dhcpv6(self): + +class _DHCPv6 (_DHCP): + template = """\ + # generated by ifconfig.py + interface "{{ ifname }}" { + request routers, domain-name-servers, domain-name; + } + + """.replace(' ', '') + + def __init__(self, ifname): + super().__init__(ifname, 'v6') + self.options = FixedDict(**{ + 'ifname': ifname, + 'dhcpv6_prm_only': False, + 'dhcpv6_temporary': False, + }) + self.file.update({ + 'accept_ra': f'/proc/sys/net/ipv6/conf/{ifname}/accept_ra', + }) + + def set(self): """ Configure interface as DHCPv6 client. The dhclient binary is automatically started in background! @@ -196,22 +167,20 @@ class DHCP (Control): >>> j = Interface('eth0') >>> j.set_dhcpv6() """ - dhcpv6 = self.get_dhcpv6_options() # better save then sorry .. should be checked in interface script # but if you missed it we are safe! - if dhcpv6['dhcpv6_prm_only'] and dhcpv6['dhcpv6_temporary']: + if self.options['dhcpv6_prm_only'] and self.options['dhcpv6_temporary']: raise Exception( 'DHCPv6 temporary and parameters-only options are mutually exclusive!') # render DHCP configuration - tmpl = jinja2.Template(template_v6) - dhcpv6_text = tmpl.render(dhcpv6) - with open(self._dhcp[6]['conf'], 'w') as f: - f.write(dhcpv6_text) + tmpl = jinja2.Template(self.template) + with open(self.file['conf'], 'w') as f: + f.write(tmpl.render(self.options)) # no longer accept router announcements on this interface - self._write_sysfs(self._dhcp[6]['accept_ra'], 0) + self._write_sysfs(self.file['accept_ra'], 0) # assemble command-line to start DHCPv6 client (dhclient) cmd = 'start-stop-daemon' @@ -224,15 +193,15 @@ class DHCP (Control): # now pass arguments to dhclient binary cmd += ' -6 -nw -cf {conf} -pf {pid} -lf {lease}' # add optional arguments - if dhcpv6['dhcpv6_prm_only']: + if self.options['dhcpv6_prm_only']: cmd += ' -S' - if dhcpv6['dhcpv6_temporary']: + if self.options['dhcpv6_temporary']: cmd += ' -T' cmd += ' {ifname}' - return self._cmd(cmd.format(**self._dhcp[6])) + return self._cmd(cmd.format(**self.file)) - def _del_dhcpv6(self): + def delete(self): """ De-configure interface as DHCPv6 clinet. All auto generated files like pid, config and lease will be removed. @@ -243,12 +212,12 @@ class DHCP (Control): >>> j = Interface('eth0') >>> j.del_dhcpv6() """ - if not os.path.isfile(self._dhcp[6]['pid']): + if not os.path.isfile(self.file['pid']): self._debug_msg('No DHCPv6 client PID found') return None - # with open(self._dhcp[6]['pid'], 'r') as f: - # pid = int(f.read()) + # with open(self.file['pid'], 'r') as f: + # pid = int(f.read()) # stop dhclient cmd = 'start-stop-daemon' @@ -256,13 +225,18 @@ class DHCP (Control): cmd += ' --oknodo' cmd += ' --quiet' cmd += ' --pidfile {pid}' - self._cmd(cmd.format(**self._dhcp[6])) + self._cmd(cmd.format(**self.file)) # accept router announcements on this interface - self._write_sysfs(self._dhcp[6]['accept_ra'], 1) + self._write_sysfs(self.options['accept_ra'], 1) # cleanup old config files for name in ('conf', 'pid', 'lease'): - if os.path.isfile(self._dhcp[6][name]): - os.remove(self._dhcp[6][name]) + if os.path.isfile(self.file[name]): + os.remove(self.file[name]) + +class DHCP (object): + def __init__(self, ifname): + self.v4 = _DHCPv4(ifname) + self.v6 = _DHCPv6(ifname) diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 22c71a464..43f823eca 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -41,8 +41,10 @@ from vyos.validate import assert_mtu from vyos.validate import assert_positive from vyos.validate import assert_range +from vyos.ifconfig.control import Control -class Interface(DHCP): + +class Interface(Control): options = [] required = [] default = { @@ -181,7 +183,8 @@ class Interface(DHCP): self.config['ifname'] = ifname # we must have updated config before initialising the Interface - super().__init__(ifname, **kargs) + super().__init__(**kargs) + self.dhcp = DHCP(ifname) if not os.path.exists('/sys/class/net/{}'.format(self.config['ifname'])): # Any instance of Interface, such as Interface('eth0') @@ -224,8 +227,8 @@ class Interface(DHCP): >>> i.remove() """ # stop DHCP(v6) if running - self._del_dhcp() - self._del_dhcpv6() + self.dhcp.v4.delete() + self.dhcp.v6.delete() # remove all assigned IP addresses from interface - this is a bit redundant # as the kernel will remove all addresses on interface deletion, but we @@ -668,12 +671,13 @@ class Interface(DHCP): # do not change below 'if' ordering esle you will get an exception as: # ValueError: 'dhcp' does not appear to be an IPv4 or IPv6 address if addr != 'dhcp' and is_ipv4(addr): - raise ConfigError("Can't configure both static IPv4 and DHCP address on the same interface") + raise ConfigError( + "Can't configure both static IPv4 and DHCP address on the same interface") if addr == 'dhcp': - self._set_dhcp() + self.dhcp.v4.set() elif addr == 'dhcpv6': - self._set_dhcpv6() + self.dhcp.v6.set() else: if not is_intf_addr_assigned(self.config['ifname'], addr): cmd = 'ip addr add "{}" dev "{}"'.format(addr, self.config['ifname']) @@ -702,9 +706,9 @@ class Interface(DHCP): ['2001:db8::ffff/64'] """ if addr == 'dhcp': - self._del_dhcp() + self.dhcp.v4.delete() elif addr == 'dhcpv6': - self._del_dhcpv6() + self.dhcp.v6.delete() else: if is_intf_addr_assigned(self.config['ifname'], addr): cmd = 'ip addr del "{}" dev "{}"'.format(addr, self.config['ifname']) diff --git a/python/vyos/ifconfig_vlan.py b/python/vyos/ifconfig_vlan.py index ed22646c1..899fd17da 100644 --- a/python/vyos/ifconfig_vlan.py +++ b/python/vyos/ifconfig_vlan.py @@ -25,32 +25,20 @@ def apply_vlan_config(vlan, config): if not vlan.definition['vlan']: raise TypeError() - # get DHCP config dictionary and update values - opt = vlan.get_dhcp_options() - if config['dhcp_client_id']: - opt['client_id'] = config['dhcp_client_id'] + vlan.dhcp.v4.options['client_id'] = config['dhcp_client_id'] if config['dhcp_hostname']: - opt['hostname'] = config['dhcp_hostname'] + vlan.dhcp.v4.options['hostname'] = config['dhcp_hostname'] if config['dhcp_vendor_class_id']: - opt['vendor_class_id'] = config['dhcp_vendor_class_id'] - - # store DHCP config dictionary - used later on when addresses are aquired - vlan.set_dhcp_options(opt) - - # get DHCPv6 config dictionary and update values - opt = vlan.get_dhcpv6_options() + vlan.dhcp.v4.options['vendor_class_id'] = config['dhcp_vendor_class_id'] if config['dhcpv6_prm_only']: - opt['dhcpv6_prm_only'] = True + vlan.dhcp.v6.options['dhcpv6_prm_only'] = True if config['dhcpv6_temporary']: - opt['dhcpv6_temporary'] = True - - # store DHCPv6 config dictionary - used later on when addresses are aquired - vlan.set_dhcpv6_options(opt) + vlan.dhcp.v6.options['dhcpv6_temporary'] = True # update interface description used e.g. within SNMP vlan.set_alias(config['description']) diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py index 32aa2826b..fd1f218d1 100755 --- a/src/conf_mode/interfaces-bonding.py +++ b/src/conf_mode/interfaces-bonding.py @@ -399,32 +399,20 @@ def apply(bond): # update interface description used e.g. within SNMP b.set_alias(bond['description']) - # get DHCP config dictionary and update values - opt = b.get_dhcp_options() - if bond['dhcp_client_id']: - opt['client_id'] = bond['dhcp_client_id'] + b.dhcp.v4.options['client_id'] = bond['dhcp_client_id'] if bond['dhcp_hostname']: - opt['hostname'] = bond['dhcp_hostname'] + b.dhcp.v4.options['hostname'] = bond['dhcp_hostname'] if bond['dhcp_vendor_class_id']: - opt['vendor_class_id'] = bond['dhcp_vendor_class_id'] - - # store DHCP config dictionary - used later on when addresses are aquired - b.set_dhcp_options(opt) - - # get DHCPv6 config dictionary and update values - opt = b.get_dhcpv6_options() + b.dhcp.v4.options['vendor_class_id'] = bond['dhcp_vendor_class_id'] if bond['dhcpv6_prm_only']: - opt['dhcpv6_prm_only'] = True + b.dhcp.v6.options['dhcpv6_prm_only'] = True if bond['dhcpv6_temporary']: - opt['dhcpv6_temporary'] = True - - # store DHCPv6 config dictionary - used later on when addresses are required - b.set_dhcpv6_options(opt) + b.dhcp.v6.options['dhcpv6_temporary'] = True # ignore link state changes b.set_link_detect(bond['disable_link_detect']) diff --git a/src/conf_mode/interfaces-bridge.py b/src/conf_mode/interfaces-bridge.py index 79247ee51..93c6db97e 100755 --- a/src/conf_mode/interfaces-bridge.py +++ b/src/conf_mode/interfaces-bridge.py @@ -300,32 +300,20 @@ def apply(bridge): # update interface description used e.g. within SNMP br.set_alias(bridge['description']) - # get DHCP config dictionary and update values - opt = br.get_dhcp_options() - if bridge['dhcp_client_id']: - opt['client_id'] = bridge['dhcp_client_id'] + br.dhcp.v4.options['client_id'] = bridge['dhcp_client_id'] if bridge['dhcp_hostname']: - opt['hostname'] = bridge['dhcp_hostname'] + br.dhcp.v4.options['hostname'] = bridge['dhcp_hostname'] if bridge['dhcp_vendor_class_id']: - opt['vendor_class_id'] = bridge['dhcp_vendor_class_id'] - - # store DHCPv6 config dictionary - used later on when addresses are aquired - br.set_dhcp_options(opt) - - # get DHCPv6 config dictionary and update values - opt = br.get_dhcpv6_options() + br.dhcp.v4.options['vendor_class_id'] = bridge['dhcp_vendor_class_id'] if bridge['dhcpv6_prm_only']: - opt['dhcpv6_prm_only'] = True + br.dhcp.v6.options['dhcpv6_prm_only'] = True if bridge['dhcpv6_temporary']: - opt['dhcpv6_temporary'] = True - - # store DHCPv6 config dictionary - used later on when addresses are aquired - br.set_dhcpv6_options(opt) + br.dhcp.v6.options['dhcpv6_temporary'] = True # assign/remove VRF br.set_vrf(bridge['vrf']) diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py index 15e9b4185..5a977d797 100755 --- a/src/conf_mode/interfaces-ethernet.py +++ b/src/conf_mode/interfaces-ethernet.py @@ -301,32 +301,20 @@ def apply(eth): # update interface description used e.g. within SNMP e.set_alias(eth['description']) - # get DHCP config dictionary and update values - opt = e.get_dhcp_options() - if eth['dhcp_client_id']: - opt['client_id'] = eth['dhcp_client_id'] + e.dhcp.v4.options['client_id'] = eth['dhcp_client_id'] if eth['dhcp_hostname']: - opt['hostname'] = eth['dhcp_hostname'] + e.dhcp.v4.options['hostname'] = eth['dhcp_hostname'] if eth['dhcp_vendor_class_id']: - opt['vendor_class_id'] = eth['dhcp_vendor_class_id'] - - # store DHCP config dictionary - used later on when addresses are aquired - e.set_dhcp_options(opt) - - # get DHCPv6 config dictionary and update values - opt = e.get_dhcpv6_options() + e.dhcp.v4.options['vendor_class_id'] = eth['dhcp_vendor_class_id'] if eth['dhcpv6_prm_only']: - opt['dhcpv6_prm_only'] = True + e.dhcp.v6.options['dhcpv6_prm_only'] = True if eth['dhcpv6_temporary']: - opt['dhcpv6_temporary'] = True - - # store DHCPv6 config dictionary - used later on when addresses are aquired - e.set_dhcpv6_options(opt) + e.dhcp.v6.options['dhcpv6_temporary'] = True # ignore link state changes e.set_link_detect(eth['disable_link_detect']) diff --git a/src/conf_mode/interfaces-pseudo-ethernet.py b/src/conf_mode/interfaces-pseudo-ethernet.py index ce3d472c4..655006146 100755 --- a/src/conf_mode/interfaces-pseudo-ethernet.py +++ b/src/conf_mode/interfaces-pseudo-ethernet.py @@ -281,32 +281,20 @@ def apply(peth): # update interface description used e.g. within SNMP p.set_alias(peth['description']) - # get DHCP config dictionary and update values - opt = p.get_dhcp_options() - if peth['dhcp_client_id']: - opt['client_id'] = peth['dhcp_client_id'] + p.dhcp.v4.options['client_id'] = peth['dhcp_client_id'] if peth['dhcp_hostname']: - opt['hostname'] = peth['dhcp_hostname'] + p.dhcp.v4.options['hostname'] = peth['dhcp_hostname'] if peth['dhcp_vendor_class_id']: - opt['vendor_class_id'] = peth['dhcp_vendor_class_id'] - - # store DHCP config dictionary - used later on when addresses are aquired - p.set_dhcp_options(opt) - - # get DHCPv6 config dictionary and update values - opt = p.get_dhcpv6_options() + p.dhcp.v4.options['vendor_class_id'] = peth['dhcp_vendor_class_id'] if peth['dhcpv6_prm_only']: - opt['dhcpv6_prm_only'] = True + p.dhcp.v6.options['dhcpv6_prm_only'] = True if peth['dhcpv6_temporary']: - opt['dhcpv6_temporary'] = True - - # store DHCPv6 config dictionary - used later on when addresses are aquired - p.set_dhcpv6_options(opt) + p.dhcp.v6.options['dhcpv6_temporary'] = True # ignore link state changes p.set_link_detect(peth['disable_link_detect']) diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py index 28b1cf60f..19538da72 100755 --- a/src/conf_mode/interfaces-tunnel.py +++ b/src/conf_mode/interfaces-tunnel.py @@ -26,41 +26,7 @@ from vyos.ifconfig.afi import IP4, IP6 from vyos.configdict import list_diff from vyos.validate import is_ipv4, is_ipv6 from vyos import ConfigError - - -class FixedDict(dict): - """ - FixedDict: A dictionnary not allowing new keys to be created after initialisation. - - >>> f = FixedDict(**{'count':1}) - >>> f['count'] = 2 - >>> f['king'] = 3 - File "...", line ..., in __setitem__ - raise ConfigError(f'Option "{k}" has no defined default') - """ - def __init__ (self, **options): - self._allowed = options.keys() - super().__init__(**options) - - def __setitem__ (self, k, v): - """ - __setitem__ is a builtin which is called by python when setting dict values: - >>> d = dict() - >>> d['key'] = 'value' - >>> d - {'key': 'value'} - - is syntaxic sugar for - - >>> d = dict() - >>> d.__setitem__('key','value') - >>> d - {'key': 'value'} - """ - if k not in self._allowed: - raise ConfigError(f'Option "{k}" has no defined default') - super().__setitem__(k, v) - +from vyos.dicts import FixedDict class ConfigurationState(Config): """ diff --git a/src/conf_mode/interfaces-wireless.py b/src/conf_mode/interfaces-wireless.py index 138f27755..07c4537b4 100755 --- a/src/conf_mode/interfaces-wireless.py +++ b/src/conf_mode/interfaces-wireless.py @@ -722,32 +722,20 @@ def apply(wifi): # update interface description used e.g. within SNMP w.set_alias(wifi['description']) - # get DHCP config dictionary and update values - opt = w.get_dhcp_options() - if wifi['dhcp_client_id']: - opt['client_id'] = wifi['dhcp_client_id'] + w.dhcp.v4.options['client_id'] = wifi['dhcp_client_id'] if wifi['dhcp_hostname']: - opt['hostname'] = wifi['dhcp_hostname'] + w.dhcp.v4.options['hostname'] = wifi['dhcp_hostname'] if wifi['dhcp_vendor_class_id']: - opt['vendor_class_id'] = wifi['dhcp_vendor_class_id'] - - # store DHCP config dictionary - used later on when addresses are aquired - w.set_dhcp_options(opt) - - # get DHCPv6 config dictionary and update values - opt = w.get_dhcpv6_options() + w.dhcp.v4.options['vendor_class_id'] = wifi['dhcp_vendor_class_id'] if wifi['dhcpv6_prm_only']: - opt['dhcpv6_prm_only'] = True + w.dhcp.v6.options['dhcpv6_prm_only'] = True if wifi['dhcpv6_temporary']: - opt['dhcpv6_temporary'] = True - - # store DHCPv6 config dictionary - used later on when addresses are aquired - w.set_dhcpv6_options(opt) + w.dhcp.v6.options['dhcpv6_temporary'] = True # ignore link state changes w.set_link_detect(wifi['disable_link_detect']) |