diff options
author | Christian Poessinger <christian@poessinger.com> | 2021-01-26 20:07:21 +0100 |
---|---|---|
committer | Christian Poessinger <christian@poessinger.com> | 2021-01-27 18:51:06 +0000 |
commit | 788f741a0beb9a2dbf52f8c7b9d0b0903ec6a87c (patch) | |
tree | bb546fe276f4c9930360ea74a08203be78b2df1c /smoketest | |
parent | fb5a64a0a517291efe62185d053b437b62ef2921 (diff) | |
download | vyos-1x-788f741a0beb9a2dbf52f8c7b9d0b0903ec6a87c.tar.gz vyos-1x-788f741a0beb9a2dbf52f8c7b9d0b0903ec6a87c.zip |
smoketest: refactor setUp() for all interface based testcases
It does not make sense (at all!) to re-initialize the entire class with every
call to setUp(). We neither change the enabled/disabled tastcases dynamically,
not do we adjust the testinterfaces during a run.
Remove the runtime overhead and place one-time init calls into setUpClass()
instead.
(cherry picked from commit b48890396dcff074d1e9336ca1db9d3eafe2a12f)
Diffstat (limited to 'smoketest')
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_bonding.py | 38 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_bridge.py | 34 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_dummy.py | 8 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_ethernet.py | 44 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_geneve.py | 16 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_l2tpv3.py | 16 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_loopback.py | 18 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_macsec.py | 20 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py | 24 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_tunnel.py | 28 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_vxlan.py | 18 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_wireguard.py | 2 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_wireless.py | 14 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_wirelessmodem.py | 2 |
14 files changed, 135 insertions, 147 deletions
diff --git a/smoketest/scripts/cli/test_interfaces_bonding.py b/smoketest/scripts/cli/test_interfaces_bonding.py index 560bfb92b..234992b23 100755 --- a/smoketest/scripts/cli/test_interfaces_bonding.py +++ b/smoketest/scripts/cli/test_interfaces_bonding.py @@ -25,33 +25,31 @@ from vyos.configsession import ConfigSessionError from vyos.util import read_file class BondingInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._test_ipv6 = True - self._test_ipv6_pd = True - self._test_mtu = True - self._test_vlan = True - self._test_qinq = True - self._base_path = ['interfaces', 'bonding'] - self._interfaces = ['bond0'] - self._mirror_interfaces = ['dum21354'] - self._members = [] + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._test_ipv6_pd = True + cls._test_mtu = True + cls._test_vlan = True + cls._test_qinq = True + cls._base_path = ['interfaces', 'bonding'] + cls._interfaces = ['bond0'] + cls._mirror_interfaces = ['dum21354'] + cls._members = [] # we need to filter out VLAN interfaces identified by a dot (.) # in their name - just in case! if 'TEST_ETH' in os.environ: - self._members = os.environ['TEST_ETH'].split() + cls._members = os.environ['TEST_ETH'].split() else: - for tmp in Section.interfaces("ethernet"): + for tmp in Section.interfaces('ethernet'): if not '.' in tmp: - self._members.append(tmp) - - self._options['bond0'] = [] - for member in self._members: - self._options['bond0'].append(f'member interface {member}') - - super().setUp() + cls._members.append(tmp) + cls._options['bond0'] = [] + for member in cls._members: + cls._options['bond0'].append(f'member interface {member}') def test_add_single_ip_address(self): super().test_add_single_ip_address() diff --git a/smoketest/scripts/cli/test_interfaces_bridge.py b/smoketest/scripts/cli/test_interfaces_bridge.py index 464226b6f..854d870be 100755 --- a/smoketest/scripts/cli/test_interfaces_bridge.py +++ b/smoketest/scripts/cli/test_interfaces_bridge.py @@ -27,31 +27,29 @@ from vyos.util import cmd from vyos.util import read_file class BridgeInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._test_ipv6 = True - self._test_ipv6_pd = True - self._test_vlan = True - self._test_qinq = True - self._base_path = ['interfaces', 'bridge'] - self._mirror_interfaces = ['dum21354'] - self._members = [] + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._test_ipv6_pd = True + cls._test_vlan = True + cls._base_path = ['interfaces', 'bridge'] + cls._mirror_interfaces = ['dum21354'] + cls._members = [] # we need to filter out VLAN interfaces identified by a dot (.) # in their name - just in case! if 'TEST_ETH' in os.environ: - self._members = os.environ['TEST_ETH'].split() + cls._members = os.environ['TEST_ETH'].split() else: - for tmp in Section.interfaces("ethernet"): + for tmp in Section.interfaces('ethernet'): if not '.' in tmp: - self._members.append(tmp) + cls._members.append(tmp) - self._options['br0'] = [] - for member in self._members: - self._options['br0'].append(f'member interface {member}') - self._interfaces = list(self._options) - - super().setUp() + cls._options['br0'] = [] + for member in cls._members: + cls._options['br0'].append(f'member interface {member}') + cls._interfaces = list(cls._options) def test_add_remove_bridge_member(self): # Add member interfaces to bridge and set STP cost/priority diff --git a/smoketest/scripts/cli/test_interfaces_dummy.py b/smoketest/scripts/cli/test_interfaces_dummy.py index 60465a1d5..6e462bccf 100755 --- a/smoketest/scripts/cli/test_interfaces_dummy.py +++ b/smoketest/scripts/cli/test_interfaces_dummy.py @@ -19,10 +19,10 @@ import unittest from base_interfaces_test import BasicInterfaceTest class DummyInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._base_path = ['interfaces', 'dummy'] - self._interfaces = ['dum435', 'dum8677', 'dum0931', 'dum089'] - super().setUp() + @classmethod + def setUpClass(cls): + cls._base_path = ['interfaces', 'dummy'] + cls._interfaces = ['dum435', 'dum8677', 'dum0931', 'dum089'] if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_interfaces_ethernet.py b/smoketest/scripts/cli/test_interfaces_ethernet.py index 9d896f690..623a8887c 100755 --- a/smoketest/scripts/cli/test_interfaces_ethernet.py +++ b/smoketest/scripts/cli/test_interfaces_ethernet.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 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 @@ -35,37 +35,30 @@ def get_wpa_supplicant_value(interface, key): return tmp[0] class EthernetInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._test_ipv6 = True - self._test_ipv6_pd = True - self._test_mtu = True - self._test_vlan = True - self._test_qinq = True - self._base_path = ['interfaces', 'ethernet'] - self._mirror_interfaces = ['dum21354'] + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._test_ipv6_pd = True + cls._test_mtu = True + cls._test_vlan = True + cls._test_qinq = True + cls._base_path = ['interfaces', 'ethernet'] + cls._mirror_interfaces = ['dum21354'] # we need to filter out VLAN interfaces identified by a dot (.) # in their name - just in case! if 'TEST_ETH' in os.environ: tmp = os.environ['TEST_ETH'].split() - self._interfaces = tmp + cls._interfaces = tmp else: - for tmp in Section.interfaces("ethernet"): + for tmp in Section.interfaces('ethernet'): if not '.' in tmp: - self._interfaces.append(tmp) + cls._interfaces.append(tmp) - self._macs = {} - for interface in self._interfaces: - try: - mac = self.session.show_config(self._base_path + - [interface, 'hw-id']).split()[1] - except: - # during initial system startup there is no hw-id node - mac = read_file(f'/sys/class/net/{interface}/address') - self._macs[interface] = mac - - super().setUp() + cls._macs = {} + for interface in cls._interfaces: + cls._macs[interface] = read_file(f'/sys/class/net/{interface}/address') def tearDown(self): @@ -101,8 +94,7 @@ class EthernetInterfaceTest(BasicInterfaceTest.BaseTest): # Validate interface state for interface in self._interfaces: - with open(f'/sys/class/net/{interface}/flags', 'r') as f: - flags = f.read() + flags = read_file(f'/sys/class/net/{interface}/flags') self.assertEqual(int(flags, 16) & 1, 0) def test_offloading_rps(self): diff --git a/smoketest/scripts/cli/test_interfaces_geneve.py b/smoketest/scripts/cli/test_interfaces_geneve.py index 12cded400..b708b5437 100755 --- a/smoketest/scripts/cli/test_interfaces_geneve.py +++ b/smoketest/scripts/cli/test_interfaces_geneve.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 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 @@ -20,16 +20,16 @@ from vyos.configsession import ConfigSession from base_interfaces_test import BasicInterfaceTest class GeneveInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._test_ipv6 = True - self._base_path = ['interfaces', 'geneve'] - self._options = { + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._base_path = ['interfaces', 'geneve'] + cls._options = { 'gnv0': ['vni 10', 'remote 127.0.1.1'], 'gnv1': ['vni 20', 'remote 127.0.1.2'], } - self._interfaces = list(self._options) - super().setUp() + cls._interfaces = list(cls._options) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_interfaces_l2tpv3.py b/smoketest/scripts/cli/test_interfaces_l2tpv3.py index 81af6d7f4..a89895b92 100755 --- a/smoketest/scripts/cli/test_interfaces_l2tpv3.py +++ b/smoketest/scripts/cli/test_interfaces_l2tpv3.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 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 @@ -21,11 +21,12 @@ from base_interfaces_test import BasicInterfaceTest from vyos.util import cmd class GeneveInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._test_ipv6 = True - self._base_path = ['interfaces', 'l2tpv3'] - self._options = { + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._base_path = ['interfaces', 'l2tpv3'] + cls._options = { 'l2tpeth10': ['local-ip 127.0.0.1', 'remote-ip 127.10.10.10', 'tunnel-id 100', 'peer-tunnel-id 10', 'session-id 100', 'peer-session-id 10', @@ -35,8 +36,7 @@ class GeneveInterfaceTest(BasicInterfaceTest.BaseTest): 'session-id 20', 'tunnel-id 200', 'source-port 2020', 'destination-port 20202'], } - self._interfaces = list(self._options) - super().setUp() + cls._interfaces = list(cls._options) def test_add_single_ip_address(self): super().test_add_single_ip_address() diff --git a/smoketest/scripts/cli/test_interfaces_loopback.py b/smoketest/scripts/cli/test_interfaces_loopback.py index 36000c3ff..77dd4c1b5 100755 --- a/smoketest/scripts/cli/test_interfaces_loopback.py +++ b/smoketest/scripts/cli/test_interfaces_loopback.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 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 @@ -21,13 +21,13 @@ from netifaces import interfaces from vyos.validate import is_intf_addr_assigned +loopbacks = ['127.0.0.1', '::1'] + class LoopbackInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - super().setUp() - # these addresses are never allowed to be removed from the system - self._loopback_addresses = ['127.0.0.1', '::1'] - self._base_path = ['interfaces', 'loopback'] - self._interfaces = ['lo'] + @classmethod + def setUpClass(cls): + cls._base_path = ['interfaces', 'loopback'] + cls._interfaces = ['lo'] def tearDown(self): self.session.delete(self._base_path) @@ -40,12 +40,12 @@ class LoopbackInterfaceTest(BasicInterfaceTest.BaseTest): def test_add_single_ip_address(self): super().test_add_single_ip_address() - for addr in self._loopback_addresses: + for addr in loopbacks: self.assertTrue(is_intf_addr_assigned('lo', addr)) def test_add_multiple_ip_addresses(self): super().test_add_multiple_ip_addresses() - for addr in self._loopback_addresses: + for addr in loopbacks: self.assertTrue(is_intf_addr_assigned('lo', addr)) def test_interface_disable(self): diff --git a/smoketest/scripts/cli/test_interfaces_macsec.py b/smoketest/scripts/cli/test_interfaces_macsec.py index 89743e5fd..3a3e7bff3 100755 --- a/smoketest/scripts/cli/test_interfaces_macsec.py +++ b/smoketest/scripts/cli/test_interfaces_macsec.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 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 @@ -31,19 +31,19 @@ def get_config_value(interface, key): return tmp[0] class MACsecInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - super().setUp() - self._test_ip = True - self._test_ipv6 = True - self._base_path = ['interfaces', 'macsec'] - self._options = { 'macsec0': ['source-interface eth0', 'security cipher gcm-aes-128'] } + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._base_path = ['interfaces', 'macsec'] + cls._options = { 'macsec0': ['source-interface eth0', 'security cipher gcm-aes-128'] } # if we have a physical eth1 interface, add a second macsec instance - if 'eth1' in Section.interfaces("ethernet"): + if 'eth1' in Section.interfaces('ethernet'): macsec = { 'macsec1': [f'source-interface eth1', 'security cipher gcm-aes-128'] } - self._options.update(macsec) + cls._options.update(macsec) - self._interfaces = list(self._options) + cls._interfaces = list(cls._options) def test_macsec_encryption(self): # MACsec can be operating in authentication and encryption mode - both diff --git a/smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py b/smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py index 10bd7ca34..54cd8566b 100755 --- a/smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py +++ b/smoketest/scripts/cli/test_interfaces_pseudo_ethernet.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 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 @@ -19,20 +19,20 @@ import unittest from base_interfaces_test import BasicInterfaceTest class PEthInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._test_ipv6 = True - self._test_ipv6_pd = True - self._test_mtu = True - self._test_vlan = True - self._test_qinq = True - self._base_path = ['interfaces', 'pseudo-ethernet'] - self._options = { + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._test_ipv6_pd = True + cls._test_mtu = True + cls._test_vlan = True + cls._test_qinq = True + cls._base_path = ['interfaces', 'pseudo-ethernet'] + cls._options = { 'peth0': ['source-interface eth1'], 'peth1': ['source-interface eth1'], } - self._interfaces = list(self._options) - super().setUp() + cls._interfaces = list(cls._options) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_interfaces_tunnel.py b/smoketest/scripts/cli/test_interfaces_tunnel.py index f67b813af..5f3791655 100755 --- a/smoketest/scripts/cli/test_interfaces_tunnel.py +++ b/smoketest/scripts/cli/test_interfaces_tunnel.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 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 @@ -61,22 +61,22 @@ def tunnel_conf(interface): return json.loads(tmp)[0] class TunnelInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._test_ipv6 = True - self._test_mtu = True - self._base_path = ['interfaces', 'tunnel'] - self.local_v4 = '192.0.2.1' - self.local_v6 = '2001:db8::1' - - self._options = { - 'tun10': ['encapsulation ipip', 'remote-ip 192.0.2.10', 'local-ip ' + self.local_v4], - 'tun20': ['encapsulation gre', 'remote-ip 192.0.2.20', 'local-ip ' + self.local_v4], + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._test_mtu = True + cls._base_path = ['interfaces', 'tunnel'] + cls.local_v4 = '192.0.2.1' + cls.local_v6 = '2001:db8::1' + cls._options = { + 'tun10': ['encapsulation ipip', 'remote-ip 192.0.2.10', 'local-ip ' + cls.local_v4], + 'tun20': ['encapsulation gre', 'remote-ip 192.0.2.20', 'local-ip ' + cls.local_v4], } + cls._interfaces = list(cls._options) - self._interfaces = list(self._options) + def setUp(self): super().setUp() - self.session.set(['interfaces', 'dummy', source_if, 'address', self.local_v4 + '/32']) self.session.set(['interfaces', 'dummy', source_if, 'address', self.local_v6 + '/128']) diff --git a/smoketest/scripts/cli/test_interfaces_vxlan.py b/smoketest/scripts/cli/test_interfaces_vxlan.py index a726aa610..fcc1b15ce 100755 --- a/smoketest/scripts/cli/test_interfaces_vxlan.py +++ b/smoketest/scripts/cli/test_interfaces_vxlan.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 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 @@ -20,17 +20,17 @@ from vyos.configsession import ConfigSession, ConfigSessionError from base_interfaces_test import BasicInterfaceTest class VXLANInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._test_ipv6 = True - self._test_mtu = True - self._base_path = ['interfaces', 'vxlan'] - self._options = { + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._test_ipv6 = True + cls._test_mtu = True + cls._base_path = ['interfaces', 'vxlan'] + cls._options = { 'vxlan0': ['vni 10', 'remote 127.0.0.2'], 'vxlan1': ['vni 20', 'group 239.1.1.1', 'source-interface eth0'], } - self._interfaces = list(self._options) - super().setUp() + cls._interfaces = list(cls._options) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_interfaces_wireguard.py b/smoketest/scripts/cli/test_interfaces_wireguard.py index d9a51b146..e70324f96 100755 --- a/smoketest/scripts/cli/test_interfaces_wireguard.py +++ b/smoketest/scripts/cli/test_interfaces_wireguard.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 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 diff --git a/smoketest/scripts/cli/test_interfaces_wireless.py b/smoketest/scripts/cli/test_interfaces_wireless.py index 51d97f032..39e8cd5b8 100755 --- a/smoketest/scripts/cli/test_interfaces_wireless.py +++ b/smoketest/scripts/cli/test_interfaces_wireless.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 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 @@ -32,10 +32,11 @@ def get_config_value(interface, key): return tmp[0] class WirelessInterfaceTest(BasicInterfaceTest.BaseTest): - def setUp(self): - self._test_ip = True - self._base_path = ['interfaces', 'wireless'] - self._options = { + @classmethod + def setUpClass(cls): + cls._test_ip = True + cls._base_path = ['interfaces', 'wireless'] + cls._options = { 'wlan0': ['physical-device phy0', 'ssid VyOS-WIFI-0', 'type station', 'address 192.0.2.1/30'], 'wlan1': ['physical-device phy0', 'ssid VyOS-WIFI-1', 'country-code se', @@ -45,8 +46,7 @@ class WirelessInterfaceTest(BasicInterfaceTest.BaseTest): 'wlan11': ['physical-device phy1', 'ssid VyOS-WIFI-3', 'country-code se', 'type access-point', 'address 192.0.2.13/30', 'channel 0'], } - self._interfaces = list(self._options) - super().setUp() + cls._interfaces = list(cls._options) def test_wireless_add_single_ip_address(self): # derived method to check if member interfaces are enslaved properly diff --git a/smoketest/scripts/cli/test_interfaces_wirelessmodem.py b/smoketest/scripts/cli/test_interfaces_wirelessmodem.py index 696a6946b..023f57305 100755 --- a/smoketest/scripts/cli/test_interfaces_wirelessmodem.py +++ b/smoketest/scripts/cli/test_interfaces_wirelessmodem.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2021 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 |