diff options
Diffstat (limited to 'smoketest/scripts')
-rw-r--r-- | smoketest/scripts/cli/base_interfaces_test.py | 39 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_configd_init.py | 38 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_netns.py | 83 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_vxlan.py | 35 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_protocols_bfd.py | 64 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_protocols_bgp.py | 135 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_protocols_isis.py | 6 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_protocols_mpls.py | 117 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_protocols_ospf.py | 28 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_protocols_ospfv3.py | 77 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_service_snmp.py | 102 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_system_flow-accounting.py | 154 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_system_logs.py | 117 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_vpn_ipsec.py | 32 |
14 files changed, 940 insertions, 87 deletions
diff --git a/smoketest/scripts/cli/base_interfaces_test.py b/smoketest/scripts/cli/base_interfaces_test.py index 447c1db30..9de961249 100644 --- a/smoketest/scripts/cli/base_interfaces_test.py +++ b/smoketest/scripts/cli/base_interfaces_test.py @@ -171,10 +171,10 @@ class BasicInterfaceTest: def test_add_multiple_ip_addresses(self): # Add address for intf in self._interfaces: + for option in self._options.get(intf, []): + self.cli_set(self._base_path + [intf] + option.split()) for addr in self._test_addr: self.cli_set(self._base_path + [intf, 'address', addr]) - for option in self._options.get(intf, []): - self.cli_set(self._base_path + [intf] + option.split()) self.cli_commit() @@ -297,6 +297,23 @@ class BasicInterfaceTest: self.assertEqual(Interface(vif).get_admin_state(), 'up') + # T4064: Delete interface addresses, keep VLAN interface + for interface in self._interfaces: + base = self._base_path + [interface] + for vlan in self._vlan_range: + base = self._base_path + [interface, 'vif', vlan] + self.cli_delete(base + ['address']) + + self.cli_commit() + + # Verify no IP address is assigned + for interface in self._interfaces: + for vlan in self._vlan_range: + vif = f'{intf}.{vlan}' + for address in self._test_addr: + self.assertFalse(is_intf_addr_assigned(vif, address)) + + def test_vif_8021q_mtu_limits(self): # XXX: This testcase is not allowed to run as first testcase, reason # is the Wireless test will first load the wifi kernel hwsim module @@ -493,6 +510,24 @@ class BasicInterfaceTest: tmp = get_interface_config(vif) self.assertEqual(tmp['mtu'], int(self._mtu)) + + # T4064: Delete interface addresses, keep VLAN interface + for interface in self._interfaces: + base = self._base_path + [interface] + for vif_s in self._qinq_range: + for vif_c in self._vlan_range: + self.cli_delete(self._base_path + [interface, 'vif-s', vif_s, 'vif-c', vif_c, 'address']) + + self.cli_commit() + # Verify no IP address is assigned + for interface in self._interfaces: + base = self._base_path + [interface] + for vif_s in self._qinq_range: + for vif_c in self._vlan_range: + vif = f'{interface}.{vif_s}.{vif_c}' + for address in self._test_addr: + self.assertFalse(is_intf_addr_assigned(vif, address)) + # T3972: remove vif-c interfaces from vif-s for interface in self._interfaces: base = self._base_path + [interface] diff --git a/smoketest/scripts/cli/test_configd_init.py b/smoketest/scripts/cli/test_configd_init.py new file mode 100755 index 000000000..5dec89963 --- /dev/null +++ b/smoketest/scripts/cli/test_configd_init.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 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 +# 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/>. + +import unittest +from time import sleep + +from vyos.util import cmd, is_systemd_service_running + +class TestConfigdInit(unittest.TestCase): + def setUp(self): + self.running_state = is_systemd_service_running('vyos-configd.service') + + def test_configd_init(self): + if not self.running_state: + cmd('sudo systemctl start vyos-configd.service') + # allow time for init to succeed/fail + sleep(2) + self.assertTrue(is_systemd_service_running('vyos-configd.service')) + + def tearDown(self): + if not self.running_state: + cmd('sudo systemctl stop vyos-configd.service') + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_interfaces_netns.py b/smoketest/scripts/cli/test_interfaces_netns.py new file mode 100755 index 000000000..9975a6b09 --- /dev/null +++ b/smoketest/scripts/cli/test_interfaces_netns.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 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 +# 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/>. + +import re +import os +import json +import unittest + +from netifaces import interfaces +from base_vyostest_shim import VyOSUnitTestSHIM + +from vyos.configsession import ConfigSession +from vyos.configsession import ConfigSessionError +from vyos.ifconfig import Interface +from vyos.ifconfig import Section +from vyos.util import cmd + +base_path = ['netns'] +namespaces = ['mgmt', 'front', 'back', 'ams-ix'] + +class NETNSTest(VyOSUnitTestSHIM.TestCase): + + def setUp(self): + self._interfaces = ['dum10', 'dum12', 'dum50'] + + def test_create_netns(self): + for netns in namespaces: + base = base_path + ['name', netns] + self.cli_set(base) + + # commit changes + self.cli_commit() + + netns_list = cmd('ip netns ls') + + # Verify NETNS configuration + for netns in namespaces: + self.assertTrue(netns in netns_list) + + + def test_netns_assign_interface(self): + netns = 'foo' + self.cli_set(['netns', 'name', netns]) + + # Set + for iface in self._interfaces: + self.cli_set(['interfaces', 'dummy', iface, 'netns', netns]) + + # commit changes + self.cli_commit() + + netns_iface_list = cmd(f'sudo ip netns exec {netns} ip link show') + + for iface in self._interfaces: + self.assertTrue(iface in netns_iface_list) + + # Delete + for iface in self._interfaces: + self.cli_delete(['interfaces', 'dummy', iface, 'netns', netns]) + + # commit changes + self.cli_commit() + + netns_iface_list = cmd(f'sudo ip netns exec {netns} ip link show') + + for iface in self._interfaces: + self.assertNotIn(iface, netns_iface_list) + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_interfaces_vxlan.py b/smoketest/scripts/cli/test_interfaces_vxlan.py index f63c850d8..9278adadd 100755 --- a/smoketest/scripts/cli/test_interfaces_vxlan.py +++ b/smoketest/scripts/cli/test_interfaces_vxlan.py @@ -16,6 +16,7 @@ import unittest +from vyos.configsession import ConfigSessionError from vyos.ifconfig import Interface from vyos.util import get_interface_config @@ -78,6 +79,9 @@ class VXLANInterfaceTest(BasicInterfaceTest.TestCase): label = options['linkinfo']['info_data']['label'] self.assertIn(f'parameters ipv6 flowlabel {label}', self._options[interface]) + if any('external' in s for s in self._options[interface]): + self.assertTrue(options['linkinfo']['info_data']['external']) + self.assertEqual('vxlan', options['linkinfo']['info_kind']) self.assertEqual('set', options['linkinfo']['info_data']['df']) self.assertEqual(f'0x{tos}', options['linkinfo']['info_data']['tos']) @@ -85,5 +89,36 @@ class VXLANInterfaceTest(BasicInterfaceTest.TestCase): self.assertEqual(Interface(interface).get_admin_state(), 'up') ttl += 10 + def test_vxlan_external(self): + interface = 'vxlan0' + source_address = '192.0.2.1' + self.cli_set(self._base_path + [interface, 'external']) + self.cli_set(self._base_path + [interface, 'source-address', source_address]) + + # Both 'VNI' and 'external' can not be specified at the same time. + self.cli_set(self._base_path + [interface, 'vni', '111']) + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_delete(self._base_path + [interface, 'vni']) + + # Now add some more interfaces - this must fail and a CLI error needs + # to be generated as Linux can only handle one VXLAN tunnel when using + # external mode. + for intf in self._interfaces: + for option in self._options.get(intf, []): + self.cli_set(self._base_path + [intf] + option.split()) + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + # Remove those test interfaces again + for intf in self._interfaces: + self.cli_delete(self._base_path + [intf]) + + self.cli_commit() + + options = get_interface_config(interface) + self.assertTrue(options['linkinfo']['info_data']['external']) + self.assertEqual('vxlan', options['linkinfo']['info_kind']) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_bfd.py b/smoketest/scripts/cli/test_protocols_bfd.py index d33a64301..fdc254a05 100755 --- a/smoketest/scripts/cli/test_protocols_bfd.py +++ b/smoketest/scripts/cli/test_protocols_bfd.py @@ -31,7 +31,8 @@ peers = { 'intv_tx' : '600', 'multihop' : '', 'source_addr': '192.0.2.254', - }, + 'profile' : 'foo-bar-baz', + }, '192.0.2.20' : { 'echo_mode' : '', 'intv_echo' : '100', @@ -40,16 +41,18 @@ peers = { 'intv_tx' : '333', 'passive' : '', 'shutdown' : '', + 'profile' : 'foo', 'source_intf': dum_if, - }, - '2001:db8::a' : { + }, + '2001:db8::1000:1' : { 'source_addr': '2001:db8::1', 'vrf' : vrf_name, - }, - '2001:db8::b' : { + }, + '2001:db8::2000:1' : { 'source_addr': '2001:db8::1', 'multihop' : '', - }, + 'profile' : 'baz_foo', + }, } profiles = { @@ -61,7 +64,12 @@ profiles = { 'intv_tx' : '333', 'shutdown' : '', }, - 'bar' : { + 'foo-bar-baz' : { + 'intv_mult' : '4', + 'intv_rx' : '400', + 'intv_tx' : '400', + }, + 'baz_foo' : { 'intv_mult' : '102', 'intv_rx' : '444', 'passive' : '', @@ -106,7 +114,7 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase): self.cli_commit() # Verify FRR bgpd configuration - frrconfig = self.getFRRconfig('bfd') + frrconfig = self.getFRRconfig('bfd', daemon=PROCESS_NAME) for peer, peer_config in peers.items(): tmp = f'peer {peer}' if 'multihop' in peer_config: @@ -119,7 +127,7 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase): tmp += f' vrf {peer_config["vrf"]}' self.assertIn(tmp, frrconfig) - peerconfig = self.getFRRconfig(f' peer {peer}', end='') + peerconfig = self.getFRRconfig(f' peer {peer}', end='', daemon=PROCESS_NAME) if 'echo_mode' in peer_config: self.assertIn(f'echo-mode', peerconfig) @@ -142,8 +150,6 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase): self.cli_delete(['vrf', 'name', vrf_name]) def test_bfd_profile(self): - peer = '192.0.2.10' - for profile, profile_config in profiles.items(): if 'echo_mode' in profile_config: self.cli_set(base_path + ['profile', profile, 'echo-mode']) @@ -160,7 +166,20 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase): if 'shutdown' in profile_config: self.cli_set(base_path + ['profile', profile, 'shutdown']) - self.cli_set(base_path + ['peer', peer, 'profile', list(profiles)[0]]) + for peer, peer_config in peers.items(): + if 'profile' in peer_config: + self.cli_set(base_path + ['peer', peer, 'profile', peer_config["profile"] + 'wrong']) + if 'source_addr' in peer_config: + self.cli_set(base_path + ['peer', peer, 'source', 'address', peer_config["source_addr"]]) + if 'source_intf' in peer_config: + self.cli_set(base_path + ['peer', peer, 'source', 'interface', peer_config["source_intf"]]) + + # BFD profile does not exist! + with self.assertRaises(ConfigSessionError): + self.cli_commit() + for peer, peer_config in peers.items(): + if 'profile' in peer_config: + self.cli_set(base_path + ['peer', peer, 'profile', peer_config["profile"]]) # commit changes self.cli_commit() @@ -169,22 +188,27 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase): for profile, profile_config in profiles.items(): config = self.getFRRconfig(f' profile {profile}', endsection='^ !') if 'echo_mode' in profile_config: - self.assertIn(f'echo-mode', config) + self.assertIn(f' echo-mode', config) if 'intv_echo' in profile_config: - self.assertIn(f'echo receive-interval {profile_config["intv_echo"]}', config) - self.assertIn(f'echo transmit-interval {profile_config["intv_echo"]}', config) + self.assertIn(f' echo receive-interval {profile_config["intv_echo"]}', config) + self.assertIn(f' echo transmit-interval {profile_config["intv_echo"]}', config) if 'intv_mult' in profile_config: - self.assertIn(f'detect-multiplier {profile_config["intv_mult"]}', config) + self.assertIn(f' detect-multiplier {profile_config["intv_mult"]}', config) if 'intv_rx' in profile_config: - self.assertIn(f'receive-interval {profile_config["intv_rx"]}', config) + self.assertIn(f' receive-interval {profile_config["intv_rx"]}', config) if 'intv_tx' in profile_config: - self.assertIn(f'transmit-interval {profile_config["intv_tx"]}', config) + self.assertIn(f' transmit-interval {profile_config["intv_tx"]}', config) if 'passive' in profile_config: - self.assertIn(f'passive-mode', config) + self.assertIn(f' passive-mode', config) if 'shutdown' in profile_config: - self.assertIn(f'shutdown', config) + self.assertIn(f' shutdown', config) else: self.assertNotIn(f'shutdown', config) + for peer, peer_config in peers.items(): + peerconfig = self.getFRRconfig(f' peer {peer}', end='', daemon=PROCESS_NAME) + if 'profile' in peer_config: + self.assertIn(f' profile {peer_config["profile"]}', peerconfig) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 16284ed01..d7230baf4 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -32,9 +32,11 @@ prefix_list_in = 'pfx-foo-in' prefix_list_out = 'pfx-foo-out' prefix_list_in6 = 'pfx-foo-in6' prefix_list_out6 = 'pfx-foo-out6' +bfd_profile = 'foo-bar-baz' neighbor_config = { '192.0.2.1' : { + 'bfd' : '', 'cap_dynamic' : '', 'cap_ext_next' : '', 'remote_as' : '100', @@ -51,23 +53,30 @@ neighbor_config = { 'addpath_all' : '', }, '192.0.2.2' : { + 'bfd_profile' : bfd_profile, 'remote_as' : '200', 'shutdown' : '', 'no_cap_nego' : '', 'port' : '667', 'cap_strict' : '', + 'advertise_map': route_map_in, + 'non_exist_map': route_map_out, 'pfx_list_in' : prefix_list_in, 'pfx_list_out' : prefix_list_out, 'no_send_comm_std' : '', }, '192.0.2.3' : { + 'advertise_map': route_map_in, 'description' : 'foo bar baz', 'remote_as' : '200', 'passive' : '', 'multi_hop' : '5', 'update_src' : 'lo', + 'peer_group' : 'foo', }, '2001:db8::1' : { + 'advertise_map': route_map_in, + 'exist_map' : route_map_out, 'cap_dynamic' : '', 'cap_ext_next' : '', 'remote_as' : '123', @@ -83,6 +92,7 @@ neighbor_config = { 'route_map_out': route_map_out, 'no_send_comm_std' : '', 'addpath_per_as' : '', + 'peer_group' : 'foo-bar', }, '2001:db8::2' : { 'remote_as' : '456', @@ -93,11 +103,15 @@ neighbor_config = { 'pfx_list_in' : prefix_list_in6, 'pfx_list_out' : prefix_list_out6, 'no_send_comm_ext' : '', + 'peer_group' : 'foo-bar_baz', }, } peer_group_config = { 'foo' : { + 'advertise_map': route_map_in, + 'exist_map' : route_map_out, + 'bfd' : '', 'remote_as' : '100', 'passive' : '', 'password' : 'VyOS-Secure123', @@ -105,7 +119,8 @@ peer_group_config = { 'cap_over' : '', 'ttl_security': '5', }, - 'bar' : { + 'foo-bar' : { + 'advertise_map': route_map_in, 'description' : 'foo peer bar group', 'remote_as' : '200', 'shutdown' : '', @@ -115,7 +130,10 @@ peer_group_config = { 'pfx_list_out' : prefix_list_out, 'no_send_comm_ext' : '', }, - 'baz' : { + 'foo-bar_baz' : { + 'advertise_map': route_map_in, + 'non_exist_map': route_map_out, + 'bfd_profile' : bfd_profile, 'cap_dynamic' : '', 'cap_ext_next' : '', 'remote_as' : '200', @@ -128,23 +146,34 @@ peer_group_config = { } class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): - def setUp(self): - self.cli_set(['policy', 'route-map', route_map_in, 'rule', '10', 'action', 'permit']) - self.cli_set(['policy', 'route-map', route_map_out, 'rule', '10', 'action', 'permit']) - self.cli_set(['policy', 'prefix-list', prefix_list_in, 'rule', '10', 'action', 'permit']) - self.cli_set(['policy', 'prefix-list', prefix_list_in, 'rule', '10', 'prefix', '192.0.2.0/25']) - self.cli_set(['policy', 'prefix-list', prefix_list_out, 'rule', '10', 'action', 'permit']) - self.cli_set(['policy', 'prefix-list', prefix_list_out, 'rule', '10', 'prefix', '192.0.2.128/25']) - - self.cli_set(['policy', 'prefix-list6', prefix_list_in6, 'rule', '10', 'action', 'permit']) - self.cli_set(['policy', 'prefix-list6', prefix_list_in6, 'rule', '10', 'prefix', '2001:db8:1000::/64']) - self.cli_set(['policy', 'prefix-list6', prefix_list_out6, 'rule', '10', 'action', 'deny']) - self.cli_set(['policy', 'prefix-list6', prefix_list_out6, 'rule', '10', 'prefix', '2001:db8:2000::/64']) + @classmethod + def setUpClass(cls): + super(cls, cls).setUpClass() + + # ensure we can also run this test on a live system - so lets clean + # out the current configuration :) + cls.cli_delete(cls, base_path) + + cls.cli_set(cls, ['policy', 'route-map', route_map_in, 'rule', '10', 'action', 'permit']) + cls.cli_set(cls, ['policy', 'route-map', route_map_out, 'rule', '10', 'action', 'permit']) + cls.cli_set(cls, ['policy', 'prefix-list', prefix_list_in, 'rule', '10', 'action', 'permit']) + cls.cli_set(cls, ['policy', 'prefix-list', prefix_list_in, 'rule', '10', 'prefix', '192.0.2.0/25']) + cls.cli_set(cls, ['policy', 'prefix-list', prefix_list_out, 'rule', '10', 'action', 'permit']) + cls.cli_set(cls, ['policy', 'prefix-list', prefix_list_out, 'rule', '10', 'prefix', '192.0.2.128/25']) + + cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_in6, 'rule', '10', 'action', 'permit']) + cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_in6, 'rule', '10', 'prefix', '2001:db8:1000::/64']) + cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_out6, 'rule', '10', 'action', 'deny']) + cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_out6, 'rule', '10', 'prefix', '2001:db8:2000::/64']) + + @classmethod + def tearDownClass(cls): + cls.cli_delete(cls, ['policy']) + def setUp(self): self.cli_set(base_path + ['local-as', ASN]) def tearDown(self): - self.cli_delete(['policy']) self.cli_delete(['vrf']) self.cli_delete(base_path) self.cli_commit() @@ -154,6 +183,11 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): def verify_frr_config(self, peer, peer_config, frrconfig): # recurring patterns to verify for both a simple neighbor and a peer-group + if 'bfd' in peer_config: + self.assertIn(f' neighbor {peer} bfd', frrconfig) + if 'bfd_profile' in peer_config: + self.assertIn(f' neighbor {peer} bfd profile {peer_config["bfd_profile"]}', frrconfig) + self.assertIn(f' neighbor {peer} bfd check-control-plane-failure', frrconfig) if 'cap_dynamic' in peer_config: self.assertIn(f' neighbor {peer} capability dynamic', frrconfig) if 'cap_ext_next' in peer_config: @@ -198,7 +232,13 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(f' neighbor {peer} addpath-tx-all-paths', frrconfig) if 'addpath_per_as' in peer_config: self.assertIn(f' neighbor {peer} addpath-tx-bestpath-per-AS', frrconfig) - + if 'advertise_map' in peer_config: + base = f' neighbor {peer} advertise-map {peer_config["advertise_map"]}' + if 'exist_map' in peer_config: + base = f'{base} exist-map {peer_config["exist_map"]}' + if 'non_exist_map' in peer_config: + base = f'{base} non-exist-map {peer_config["non_exist_map"]}' + self.assertIn(base, frrconfig) def test_bgp_01_simple(self): router_id = '127.0.0.1' @@ -208,6 +248,8 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): max_path_v4ibgp = '4' max_path_v6 = '8' max_path_v6ibgp = '16' + cond_adv_timer = '30' + min_hold_time = '2' self.cli_set(base_path + ['parameters', 'router-id', router_id]) self.cli_set(base_path + ['parameters', 'log-neighbor-changes']) @@ -229,6 +271,13 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['parameters', 'bestpath', 'bandwidth', 'default-weight-for-missing']) self.cli_set(base_path + ['parameters', 'bestpath', 'compare-routerid']) + self.cli_set(base_path + ['parameters', 'conditional-advertisement', 'timer', cond_adv_timer]) + self.cli_set(base_path + ['parameters', 'fast-convergence']) + self.cli_set(base_path + ['parameters', 'minimum-holdtime', min_hold_time]) + self.cli_set(base_path + ['parameters', 'reject-as-sets']) + self.cli_set(base_path + ['parameters', 'shutdown']) + self.cli_set(base_path + ['parameters', 'suppress-fib-pending']) + # AFI maximum path support self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'maximum-paths', 'ebgp', max_path_v4]) self.cli_set(base_path + ['address-family', 'ipv4-unicast', 'maximum-paths', 'ibgp', max_path_v4ibgp]) @@ -244,11 +293,17 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(f' bgp router-id {router_id}', frrconfig) self.assertIn(f' bgp log-neighbor-changes', frrconfig) self.assertIn(f' bgp default local-preference {local_pref}', frrconfig) + self.assertIn(f' bgp conditional-advertisement timer {cond_adv_timer}', frrconfig) + self.assertIn(f' bgp fast-convergence', frrconfig) self.assertIn(f' bgp graceful-restart stalepath-time {stalepath_time}', frrconfig) self.assertIn(f' bgp graceful-shutdown', frrconfig) self.assertIn(f' bgp bestpath as-path multipath-relax', frrconfig) self.assertIn(f' bgp bestpath bandwidth default-weight-for-missing', frrconfig) self.assertIn(f' bgp bestpath compare-routerid', frrconfig) + self.assertIn(f' bgp minimum-holdtime {min_hold_time}', frrconfig) + self.assertIn(f' bgp reject-as-sets', frrconfig) + self.assertIn(f' bgp shutdown', frrconfig) + self.assertIn(f' bgp suppress-fib-pending', frrconfig) self.assertNotIn(f'bgp ebgp-requires-policy', frrconfig) afiv4_config = self.getFRRconfig(' address-family ipv4 unicast') @@ -270,6 +325,11 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): if 'adv_interv' in peer_config: self.cli_set(base_path + ['neighbor', peer, 'advertisement-interval', peer_config["adv_interv"]]) + if 'bfd' in peer_config: + self.cli_set(base_path + ['neighbor', peer, 'bfd']) + if 'bfd_profile' in peer_config: + self.cli_set(base_path + ['neighbor', peer, 'bfd', 'profile', peer_config["bfd_profile"]]) + self.cli_set(base_path + ['neighbor', peer, 'bfd', 'check-control-plane-failure']) if 'cap_dynamic' in peer_config: self.cli_set(base_path + ['neighbor', peer, 'capability', 'dynamic']) if 'cap_ext_next' in peer_config: @@ -319,6 +379,20 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): if 'addpath_per_as' in peer_config: self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'addpath-tx-per-as']) + # Conditional advertisement + if 'advertise_map' in peer_config: + self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'conditionally-advertise', 'advertise-map', peer_config["advertise_map"]]) + # Either exist-map or non-exist-map needs to be specified + if 'exist_map' not in peer_config and 'non_exist_map' not in peer_config: + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'conditionally-advertise', 'exist-map', route_map_in]) + + if 'exist_map' in peer_config: + self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'conditionally-advertise', 'exist-map', peer_config["exist_map"]]) + if 'non_exist_map' in peer_config: + self.cli_set(base_path + ['neighbor', peer, 'address-family', afi, 'conditionally-advertise', 'non-exist-map', peer_config["non_exist_map"]]) + # commit changes self.cli_commit() @@ -339,6 +413,11 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): def test_bgp_03_peer_groups(self): # Test out individual peer-group configuration items for peer_group, config in peer_group_config.items(): + if 'bfd' in config: + self.cli_set(base_path + ['peer-group', peer_group, 'bfd']) + if 'bfd_profile' in config: + self.cli_set(base_path + ['peer-group', peer_group, 'bfd', 'profile', config["bfd_profile"]]) + self.cli_set(base_path + ['peer-group', peer_group, 'bfd', 'check-control-plane-failure']) if 'cap_dynamic' in config: self.cli_set(base_path + ['peer-group', peer_group, 'capability', 'dynamic']) if 'cap_ext_next' in config: @@ -382,6 +461,24 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): if 'addpath_per_as' in config: self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'addpath-tx-per-as']) + # Conditional advertisement + if 'advertise_map' in config: + self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'conditionally-advertise', 'advertise-map', config["advertise_map"]]) + # Either exist-map or non-exist-map needs to be specified + if 'exist_map' not in config and 'non_exist_map' not in config: + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'conditionally-advertise', 'exist-map', route_map_in]) + + if 'exist_map' in config: + self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'conditionally-advertise', 'exist-map', config["exist_map"]]) + if 'non_exist_map' in config: + self.cli_set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'conditionally-advertise', 'non-exist-map', config["non_exist_map"]]) + + for peer, peer_config in neighbor_config.items(): + if 'peer_group' in peer_config: + self.cli_set(base_path + ['neighbor', peer, 'peer-group', peer_config['peer_group']]) + # commit changes self.cli_commit() @@ -393,6 +490,10 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(f' neighbor {peer_group} peer-group', frrconfig) self.verify_frr_config(peer, peer_config, frrconfig) + for peer, peer_config in neighbor_config.items(): + if 'peer_group' in peer_config: + self.assertIn(f' neighbor {peer} peer-group {peer_config["peer_group"]}', frrconfig) + def test_bgp_04_afi_ipv4(self): networks = { @@ -753,4 +854,4 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): self.assertIn(f' exit-address-family', afi_config) if __name__ == '__main__': - unittest.main(verbosity=2)
\ No newline at end of file + unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_isis.py b/smoketest/scripts/cli/test_protocols_isis.py index e42040025..7f51c7178 100755 --- a/smoketest/scripts/cli/test_protocols_isis.py +++ b/smoketest/scripts/cli/test_protocols_isis.py @@ -198,17 +198,19 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase): self.assertIn(f' area-password clear {password}', tmp) - def test_isis_06_spf_delay(self): + def test_isis_06_spf_delay_bfd(self): network = 'point-to-point' holddown = '10' init_delay = '50' long_delay = '200' short_delay = '100' time_to_learn = '75' + bfd_profile = 'isis-bfd' self.cli_set(base_path + ['net', net]) for interface in self._interfaces: self.cli_set(base_path + ['interface', interface, 'network', network]) + self.cli_set(base_path + ['interface', interface, 'bfd', 'profile', bfd_profile]) self.cli_set(base_path + ['spf-delay-ietf', 'holddown', holddown]) # verify() - All types of spf-delay must be configured @@ -244,6 +246,8 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase): self.assertIn(f' ip router isis {domain}', tmp) self.assertIn(f' ipv6 router isis {domain}', tmp) self.assertIn(f' isis network {network}', tmp) + self.assertIn(f' isis bfd', tmp) + self.assertIn(f' isis bfd profile {bfd_profile}', tmp) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_mpls.py b/smoketest/scripts/cli/test_protocols_mpls.py new file mode 100755 index 000000000..13d38d01b --- /dev/null +++ b/smoketest/scripts/cli/test_protocols_mpls.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 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 +# 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/>. + +import unittest + +from base_vyostest_shim import VyOSUnitTestSHIM +from vyos.configsession import ConfigSessionError +from vyos.ifconfig import Section +from vyos.util import process_named_running + +PROCESS_NAME = 'ldpd' +base_path = ['protocols', 'mpls', 'ldp'] + +peers = { + '192.0.2.10' : { + 'intv_rx' : '500', + 'intv_tx' : '600', + 'multihop' : '', + 'source_addr': '192.0.2.254', + }, + '192.0.2.20' : { + 'echo_mode' : '', + 'intv_echo' : '100', + 'intv_mult' : '100', + 'intv_rx' : '222', + 'intv_tx' : '333', + 'passive' : '', + 'shutdown' : '', + }, + '2001:db8::a' : { + 'source_addr': '2001:db8::1', + }, + '2001:db8::b' : { + 'source_addr': '2001:db8::1', + 'multihop' : '', + }, +} + +profiles = { + 'foo' : { + 'echo_mode' : '', + 'intv_echo' : '100', + 'intv_mult' : '101', + 'intv_rx' : '222', + 'intv_tx' : '333', + 'shutdown' : '', + }, + 'bar' : { + 'intv_mult' : '102', + 'intv_rx' : '444', + 'passive' : '', + }, +} + +class TestProtocolsMPLS(VyOSUnitTestSHIM.TestCase): + @classmethod + def setUpClass(cls): + super(cls, cls).setUpClass() + + # ensure we can also run this test on a live system - so lets clean + # out the current configuration :) + cls.cli_delete(cls, base_path) + + def tearDown(self): + self.cli_delete(base_path) + self.cli_commit() + # Check for running process + self.assertTrue(process_named_running(PROCESS_NAME)) + + def test_mpls_basic(self): + self.debug = True + router_id = '1.2.3.4' + transport_ipv4_addr = '5.6.7.8' + interfaces = Section.interfaces('ethernet') + + self.cli_set(base_path + ['router-id', router_id]) + + # At least one LDP interface must be configured + with self.assertRaises(ConfigSessionError): + self.cli_commit() + for interface in interfaces: + self.cli_set(base_path + ['interface', interface]) + + # LDP transport address missing + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_set(base_path + ['discovery', 'transport-ipv4-address', transport_ipv4_addr]) + + # Commit changes + self.cli_commit() + + # Validate configuration + frrconfig = self.getFRRconfig('mpls ldp', daemon=PROCESS_NAME) + self.assertIn(f'mpls ldp', frrconfig) + self.assertIn(f' router-id {router_id}', frrconfig) + + # Validate AFI IPv4 + afiv4_config = self.getFRRconfig(' address-family ipv4', daemon=PROCESS_NAME) + self.assertIn(f' discovery transport-address {transport_ipv4_addr}', afiv4_config) + for interface in interfaces: + self.assertIn(f' interface {interface}', afiv4_config) + +if __name__ == '__main__': + unittest.main(verbosity=2, failfast=True) diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py index 04853c5fe..ee58b0fe2 100755 --- a/smoketest/scripts/cli/test_protocols_ospf.py +++ b/smoketest/scripts/cli/test_protocols_ospf.py @@ -33,14 +33,21 @@ route_map = 'foo-bar-baz10' log = logging.getLogger('TestProtocolsOSPF') class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): - def setUp(self): - self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit']) - self.cli_set(['policy', 'route-map', route_map, 'rule', '20', 'action', 'permit']) + @classmethod + def setUpClass(cls): + super(cls, cls).setUpClass() + + cls.cli_set(cls, ['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit']) + cls.cli_set(cls, ['policy', 'route-map', route_map, 'rule', '20', 'action', 'permit']) + + @classmethod + def tearDownClass(cls): + cls.cli_delete(cls, ['policy', 'route-map', route_map]) + super(cls, cls).tearDownClass() def tearDown(self): # Check for running process self.assertTrue(process_named_running(PROCESS_NAME)) - self.cli_delete(['policy', 'route-map', route_map]) self.cli_delete(base_path) self.cli_commit() @@ -199,9 +206,15 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['redistribute', protocol, 'route-map', route_map]) self.cli_set(base_path + ['redistribute', protocol, 'metric-type', metric_type]) + # enable FRR debugging to find the root cause of failing testcases + cmd('touch /tmp/vyos.frr.debug') + # commit changes self.cli_commit() + # disable FRR debugging + cmd('rm -f /tmp/vyos.frr.debug') + # Verify FRR ospfd configuration frrconfig = self.getFRRconfig('router ospf') try: @@ -210,8 +223,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): self.assertIn(f' redistribute {protocol} metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig) except: log.debug(frrconfig) - log.debug(cmd('sudo cat /var/log/messages')) - log.debug(cmd('vtysh -c "show run"')) + log.debug(cmd('sudo cat /tmp/vyos-configd-script-stdout')) self.fail('Now we can hopefully see why OSPF fails!') def test_ospf_08_virtual_link(self): @@ -251,13 +263,14 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): cost = '150' network = 'point-to-point' priority = '200' + bfd_profile = 'vyos-test' self.cli_set(base_path + ['passive-interface', 'default']) for interface in interfaces: base_interface = base_path + ['interface', interface] self.cli_set(base_interface + ['authentication', 'plaintext-password', password]) self.cli_set(base_interface + ['bandwidth', bandwidth]) - self.cli_set(base_interface + ['bfd']) + self.cli_set(base_interface + ['bfd', 'profile', bfd_profile]) self.cli_set(base_interface + ['cost', cost]) self.cli_set(base_interface + ['mtu-ignore']) self.cli_set(base_interface + ['network', network]) @@ -272,6 +285,7 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): self.assertIn(f'interface {interface}', config) self.assertIn(f' ip ospf authentication-key {password}', config) self.assertIn(f' ip ospf bfd', config) + self.assertIn(f' ip ospf bfd profile {bfd_profile}', config) self.assertIn(f' ip ospf cost {cost}', config) self.assertIn(f' ip ospf mtu-ignore', config) self.assertIn(f' ip ospf network {network}', config) diff --git a/smoketest/scripts/cli/test_protocols_ospfv3.py b/smoketest/scripts/cli/test_protocols_ospfv3.py index f0557f640..1327fd910 100755 --- a/smoketest/scripts/cli/test_protocols_ospfv3.py +++ b/smoketest/scripts/cli/test_protocols_ospfv3.py @@ -18,16 +18,31 @@ import unittest from base_vyostest_shim import VyOSUnitTestSHIM +from vyos.configsession import ConfigSessionError from vyos.ifconfig import Section from vyos.util import process_named_running PROCESS_NAME = 'ospf6d' base_path = ['protocols', 'ospfv3'] +route_map = 'foo-bar-baz-0815' + router_id = '192.0.2.1' default_area = '0' class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase): + @classmethod + def setUpClass(cls): + super(cls, cls).setUpClass() + + cls.cli_set(cls, ['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit']) + cls.cli_set(cls, ['policy', 'route-map', route_map, 'rule', '20', 'action', 'permit']) + + @classmethod + def tearDownClass(cls): + cls.cli_delete(cls, ['policy', 'route-map', route_map]) + super(cls, cls).tearDownClass() + def tearDown(self): # Check for running process self.assertTrue(process_named_running(PROCESS_NAME)) @@ -109,7 +124,9 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase): for protocol in redistribute: self.assertIn(f' redistribute {protocol} route-map {route_map}', frrconfig) + def test_ospfv3_04_interfaces(self): + bfd_profile = 'vyos-ipv6' self.cli_set(base_path + ['parameters', 'router-id', router_id]) self.cli_set(base_path + ['area', default_area]) @@ -119,7 +136,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase): interfaces = Section.interfaces('ethernet') for interface in interfaces: if_base = base_path + ['interface', interface] - self.cli_set(if_base + ['bfd']) + self.cli_set(if_base + ['bfd', 'profile', bfd_profile]) self.cli_set(if_base + ['cost', cost]) self.cli_set(if_base + ['instance-id', '0']) self.cli_set(if_base + ['mtu-ignore']) @@ -142,6 +159,7 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase): if_config = self.getFRRconfig(f'interface {interface}') self.assertIn(f'interface {interface}', if_config) self.assertIn(f' ipv6 ospf6 bfd', if_config) + self.assertIn(f' ipv6 ospf6 bfd profile {bfd_profile}', if_config) self.assertIn(f' ipv6 ospf6 cost {cost}', if_config) self.assertIn(f' ipv6 ospf6 mtu-ignore', if_config) self.assertIn(f' ipv6 ospf6 network point-to-point', if_config) @@ -168,7 +186,60 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase): self.assertIn(f' area {area_stub_nosum} stub no-summary', frrconfig) - def test_ospfv3_06_vrfs(self): + def test_ospfv3_06_area_nssa(self): + area_nssa = '1.1.1.1' + area_nssa_nosum = '2.2.2.2' + area_nssa_default = '3.3.3.3' + + self.cli_set(base_path + ['area', area_nssa, 'area-type', 'nssa']) + self.cli_set(base_path + ['area', area_nssa, 'area-type', 'stub']) + # can only set one area-type per OSPFv3 area + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_delete(base_path + ['area', area_nssa, 'area-type', 'stub']) + + self.cli_set(base_path + ['area', area_nssa_nosum, 'area-type', 'nssa', 'no-summary']) + self.cli_set(base_path + ['area', area_nssa_nosum, 'area-type', 'nssa', 'default-information-originate']) + self.cli_set(base_path + ['area', area_nssa_default, 'area-type', 'nssa', 'default-information-originate']) + + # commit changes + self.cli_commit() + + # Verify FRR ospfd configuration + frrconfig = self.getFRRconfig('router ospf6') + self.assertIn(f'router ospf6', frrconfig) + self.assertIn(f' area {area_nssa} nssa', frrconfig) + self.assertIn(f' area {area_nssa_nosum} nssa default-information-originate no-summary', frrconfig) + self.assertIn(f' area {area_nssa_default} nssa default-information-originate', frrconfig) + + + def test_ospfv3_07_default_originate(self): + seq = '100' + metric = '50' + metric_type = '1' + + self.cli_set(base_path + ['default-information', 'originate', 'metric', metric]) + self.cli_set(base_path + ['default-information', 'originate', 'metric-type', metric_type]) + self.cli_set(base_path + ['default-information', 'originate', 'route-map', route_map]) + + # commit changes + self.cli_commit() + + # Verify FRR ospfd configuration + frrconfig = self.getFRRconfig('router ospf6') + self.assertIn(f'router ospf6', frrconfig) + self.assertIn(f' default-information originate metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig) + + # Now set 'always' + self.cli_set(base_path + ['default-information', 'originate', 'always']) + self.cli_commit() + + # Verify FRR ospfd configuration + frrconfig = self.getFRRconfig('router ospf6') + self.assertIn(f' default-information originate always metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig) + + + def test_ospfv3_08_vrfs(self): # It is safe to assume that when the basic VRF test works, all # other OSPF related features work, as we entirely inherit the CLI # templates and Jinja2 FRR template. @@ -207,4 +278,4 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase): self.cli_delete(['interfaces', 'ethernet', vrf_iface, 'vrf']) if __name__ == '__main__': - unittest.main(verbosity=2) + unittest.main(verbosity=2, failfast=True) diff --git a/smoketest/scripts/cli/test_service_snmp.py b/smoketest/scripts/cli/test_service_snmp.py index 058835c72..fc24fd54e 100755 --- a/smoketest/scripts/cli/test_service_snmp.py +++ b/smoketest/scripts/cli/test_service_snmp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2019-2020 VyOS maintainers and contributors +# Copyright (C) 2019-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 @@ -22,14 +22,25 @@ from base_vyostest_shim import VyOSUnitTestSHIM from vyos.configsession import ConfigSessionError from vyos.template import is_ipv4 from vyos.template import address_from_cidr +from vyos.util import call +from vyos.util import DEVNULL from vyos.util import read_file from vyos.util import process_named_running +from vyos.version import get_version_data PROCESS_NAME = 'snmpd' SNMPD_CONF = '/etc/snmp/snmpd.conf' base_path = ['service', 'snmp'] +snmpv3_group = 'default_group' +snmpv3_view = 'default_view' +snmpv3_view_oid = '1' +snmpv3_user = 'vyos' +snmpv3_auth_pw = 'vyos12345678' +snmpv3_priv_pw = 'vyos87654321' +snmpv3_engine_id = '000000000000000000000002' + def get_config_value(key): tmp = read_file(SNMPD_CONF) tmp = re.findall(r'\n?{}\s+(.*)'.format(key), tmp) @@ -45,13 +56,22 @@ class TestSNMPService(VyOSUnitTestSHIM.TestCase): cls.cli_delete(cls, base_path) def tearDown(self): + # Check for running process + self.assertTrue(process_named_running(PROCESS_NAME)) + # delete testing SNMP config self.cli_delete(base_path) self.cli_commit() + # Check for running process + self.assertFalse(process_named_running(PROCESS_NAME)) + def test_snmp_basic(self): dummy_if = 'dum7312' dummy_addr = '100.64.0.1/32' + contact = 'maintainers@vyos.io' + location = 'QEMU' + self.cli_set(['interfaces', 'dummy', dummy_if, 'address', dummy_addr]) # Check if SNMP can be configured and service runs @@ -71,8 +91,8 @@ class TestSNMPService(VyOSUnitTestSHIM.TestCase): for addr in listen: self.cli_set(base_path + ['listen-address', addr, 'port', port]) - self.cli_set(base_path + ['contact', 'maintainers@vyos.io']) - self.cli_set(base_path + ['location', 'qemu']) + self.cli_set(base_path + ['contact', contact]) + self.cli_set(base_path + ['location', location]) self.cli_commit() @@ -82,7 +102,6 @@ class TestSNMPService(VyOSUnitTestSHIM.TestCase): config = get_config_value('agentaddress') expected = 'unix:/run/snmpd.socket' self.assertIn(expected, config) - for addr in listen: if is_ipv4(addr): expected = f'udp:{addr}:{port}' @@ -90,6 +109,16 @@ class TestSNMPService(VyOSUnitTestSHIM.TestCase): expected = f'udp6:[{addr}]:{port}' self.assertIn(expected, config) + config = get_config_value('sysDescr') + version_data = get_version_data() + self.assertEqual('VyOS ' + version_data['version'], config) + + config = get_config_value('SysContact') + self.assertEqual(contact, config) + + config = get_config_value('SysLocation') + self.assertEqual(location, config) + # Check for running process self.assertTrue(process_named_running(PROCESS_NAME)) self.cli_delete(['interfaces', 'dummy', dummy_if]) @@ -98,8 +127,7 @@ class TestSNMPService(VyOSUnitTestSHIM.TestCase): def test_snmpv3_sha(self): # Check if SNMPv3 can be configured with SHA authentication # and service runs - - self.cli_set(base_path + ['v3', 'engineid', '000000000000000000000002']) + self.cli_set(base_path + ['v3', 'engineid', snmpv3_engine_id]) self.cli_set(base_path + ['v3', 'group', 'default', 'mode', 'ro']) # check validate() - a view must be created before this can be committed with self.assertRaises(ConfigSessionError): @@ -109,46 +137,52 @@ class TestSNMPService(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['v3', 'group', 'default', 'view', 'default']) # create user - self.cli_set(base_path + ['v3', 'user', 'vyos', 'auth', 'plaintext-password', 'vyos12345678']) - self.cli_set(base_path + ['v3', 'user', 'vyos', 'auth', 'type', 'sha']) - self.cli_set(base_path + ['v3', 'user', 'vyos', 'privacy', 'plaintext-password', 'vyos12345678']) - self.cli_set(base_path + ['v3', 'user', 'vyos', 'privacy', 'type', 'aes']) - self.cli_set(base_path + ['v3', 'user', 'vyos', 'group', 'default']) + self.cli_set(base_path + ['v3', 'user', snmpv3_user, 'auth', 'plaintext-password', snmpv3_auth_pw]) + self.cli_set(base_path + ['v3', 'user', snmpv3_user, 'auth', 'type', 'sha']) + self.cli_set(base_path + ['v3', 'user', snmpv3_user, 'privacy', 'plaintext-password', snmpv3_priv_pw]) + self.cli_set(base_path + ['v3', 'user', snmpv3_user, 'privacy', 'type', 'aes']) + self.cli_set(base_path + ['v3', 'user', snmpv3_user, 'group', 'default']) self.cli_commit() # commit will alter the CLI values - check if they have been updated: hashed_password = '4e52fe55fd011c9c51ae2c65f4b78ca93dcafdfe' - tmp = self._session.show_config(base_path + ['v3', 'user', 'vyos', 'auth', 'encrypted-password']).split()[1] + tmp = self._session.show_config(base_path + ['v3', 'user', snmpv3_user, 'auth', 'encrypted-password']).split()[1] self.assertEqual(tmp, hashed_password) - tmp = self._session.show_config(base_path + ['v3', 'user', 'vyos', 'privacy', 'encrypted-password']).split()[1] + hashed_password = '54705c8de9e81fdf61ad7ac044fa8fe611ddff6b' + tmp = self._session.show_config(base_path + ['v3', 'user', snmpv3_user, 'privacy', 'encrypted-password']).split()[1] self.assertEqual(tmp, hashed_password) # TODO: read in config file and check values - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + # Try SNMPv3 connection + tmp = call(f'snmpwalk -v 3 -u {snmpv3_user} -a SHA -A {snmpv3_auth_pw} -x AES -X {snmpv3_priv_pw} -l authPriv 127.0.0.1', stdout=DEVNULL) + self.assertEqual(tmp, 0) def test_snmpv3_md5(self): # Check if SNMPv3 can be configured with MD5 authentication # and service runs + self.cli_set(base_path + ['v3', 'engineid', snmpv3_engine_id]) - self.cli_set(base_path + ['v3', 'engineid', '000000000000000000000002']) - self.cli_set(base_path + ['v3', 'group', 'default', 'mode', 'ro']) - # check validate() - a view must be created before this can be comitted + # create user + self.cli_set(base_path + ['v3', 'user', snmpv3_user, 'auth', 'plaintext-password', snmpv3_auth_pw]) + self.cli_set(base_path + ['v3', 'user', snmpv3_user, 'auth', 'type', 'md5']) + self.cli_set(base_path + ['v3', 'user', snmpv3_user, 'privacy', 'plaintext-password', snmpv3_priv_pw]) + self.cli_set(base_path + ['v3', 'user', snmpv3_user, 'privacy', 'type', 'des']) + + # check validate() - user requires a group to be created with self.assertRaises(ConfigSessionError): self.cli_commit() + self.cli_set(base_path + ['v3', 'user', 'vyos', 'group', snmpv3_group]) - self.cli_set(base_path + ['v3', 'view', 'default', 'oid', '1']) - self.cli_set(base_path + ['v3', 'group', 'default', 'view', 'default']) + self.cli_set(base_path + ['v3', 'group', snmpv3_group, 'mode', 'ro']) + # check validate() - a view must be created before this can be comitted + with self.assertRaises(ConfigSessionError): + self.cli_commit() - # create user - self.cli_set(base_path + ['v3', 'user', 'vyos', 'auth', 'plaintext-password', 'vyos12345678']) - self.cli_set(base_path + ['v3', 'user', 'vyos', 'auth', 'type', 'md5']) - self.cli_set(base_path + ['v3', 'user', 'vyos', 'privacy', 'plaintext-password', 'vyos12345678']) - self.cli_set(base_path + ['v3', 'user', 'vyos', 'privacy', 'type', 'des']) - self.cli_set(base_path + ['v3', 'user', 'vyos', 'group', 'default']) + self.cli_set(base_path + ['v3', 'view', snmpv3_view, 'oid', snmpv3_view_oid]) + self.cli_set(base_path + ['v3', 'group', snmpv3_group, 'view', snmpv3_view]) self.cli_commit() @@ -157,13 +191,21 @@ class TestSNMPService(VyOSUnitTestSHIM.TestCase): tmp = self._session.show_config(base_path + ['v3', 'user', 'vyos', 'auth', 'encrypted-password']).split()[1] self.assertEqual(tmp, hashed_password) + hashed_password = 'e11c83f2c510540a3c4de84ee66de440' tmp = self._session.show_config(base_path + ['v3', 'user', 'vyos', 'privacy', 'encrypted-password']).split()[1] self.assertEqual(tmp, hashed_password) - # TODO: read in config file and check values - - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + tmp = read_file(SNMPD_CONF) + # views + self.assertIn(f'view {snmpv3_view} included .{snmpv3_view_oid}', tmp) + # group + self.assertIn(f'group {snmpv3_group} usm {snmpv3_user}', tmp) + # access + self.assertIn(f'access {snmpv3_group} "" usm auth exact {snmpv3_view} none none', tmp) + + # Try SNMPv3 connection + tmp = call(f'snmpwalk -v 3 -u {snmpv3_user} -a MD5 -A {snmpv3_auth_pw} -x DES -X {snmpv3_priv_pw} -l authPriv 127.0.0.1', stdout=DEVNULL) + self.assertEqual(tmp, 0) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_system_flow-accounting.py b/smoketest/scripts/cli/test_system_flow-accounting.py index dfbfba94e..857df1be6 100755 --- a/smoketest/scripts/cli/test_system_flow-accounting.py +++ b/smoketest/scripts/cli/test_system_flow-accounting.py @@ -27,7 +27,7 @@ from vyos.util import read_file PROCESS_NAME = 'uacctd' base_path = ['system', 'flow-accounting'] -uacctd_conf = '/etc/pmacct/uacctd.conf' +uacctd_conf = '/run/pmacct/uacctd.conf' class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase): @classmethod @@ -47,7 +47,10 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase): def test_basic(self): buffer_size = '5' # MiB + syslog = 'all' + self.cli_set(base_path + ['buffer-size', buffer_size]) + self.cli_set(base_path + ['syslog-facility', syslog]) # You need to configure at least one interface for flow-accounting with self.assertRaises(ConfigSessionError): @@ -84,8 +87,153 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase): tmp //= 1000 self.assertIn(f'plugin_buffer_size: {tmp}', uacctd) - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + # when 'disable-imt' is not configured on the CLI it must be present + self.assertIn(f'imt_path: /tmp/uacctd.pipe', uacctd) + self.assertIn(f'imt_mem_pools_number: 169', uacctd) + self.assertIn(f'syslog: {syslog}', uacctd) + self.assertIn(f'plugins: memory', uacctd) + + def test_sflow(self): + sampling_rate = '4000' + source_address = '192.0.2.1' + dummy_if = 'dum3841' + agent_address = '192.0.2.2' + + sflow_server = { + '1.2.3.4' : { + }, + '5.6.7.8' : { + 'port' : '6000' + } + } + + self.cli_set(['interfaces', 'dummy', dummy_if, 'address', agent_address + '/32']) + self.cli_set(base_path + ['disable-imt']) + + # You need to configure at least one interface for flow-accounting + with self.assertRaises(ConfigSessionError): + self.cli_commit() + for interface in Section.interfaces('ethernet'): + self.cli_set(base_path + ['interface', interface]) + + + # You need to configure at least one sFlow or NetFlow protocol, or not + # set "disable-imt" for flow-accounting + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + self.cli_set(base_path + ['sflow', 'agent-address', agent_address]) + self.cli_set(base_path + ['sflow', 'sampling-rate', sampling_rate]) + self.cli_set(base_path + ['sflow', 'source-address', source_address]) + for server, server_config in sflow_server.items(): + self.cli_set(base_path + ['sflow', 'server', server]) + if 'port' in server_config: + self.cli_set(base_path + ['sflow', 'server', server, 'port', server_config['port']]) + + # commit changes + self.cli_commit() + + uacctd = read_file(uacctd_conf) + + # when 'disable-imt' is not configured on the CLI it must be present + self.assertNotIn(f'imt_path: /tmp/uacctd.pipe', uacctd) + self.assertNotIn(f'imt_mem_pools_number: 169', uacctd) + self.assertNotIn(f'plugins: memory', uacctd) + + for server, server_config in sflow_server.items(): + if 'port' in server_config: + self.assertIn(f'sfprobe_receiver[sf_{server}]: {server}', uacctd) + else: + self.assertIn(f'sfprobe_receiver[sf_{server}]: {server}:6343', uacctd) + + self.assertIn(f'sfprobe_agentip[sf_{server}]: {agent_address}', uacctd) + self.assertIn(f'sampling_rate[sf_{server}]: {sampling_rate}', uacctd) + self.assertIn(f'sfprobe_source_ip[sf_{server}]: {source_address}', uacctd) + + self.cli_delete(['interfaces', 'dummy', dummy_if]) + + def test_netflow(self): + engine_id = '33' + max_flows = '667' + sampling_rate = '100' + source_address = '192.0.2.1' + dummy_if = 'dum3842' + agent_address = '192.0.2.10' + version = '10' + tmo_expiry = '120' + tmo_flow = '1200' + tmo_icmp = '60' + tmo_max = '50000' + tmo_tcp_fin = '100' + tmo_tcp_generic = '120' + tmo_tcp_rst = '99' + tmo_udp = '10' + + netflow_server = { + '11.22.33.44' : { + }, + '55.66.77.88' : { + 'port' : '6000' + } + } + + self.cli_set(['interfaces', 'dummy', dummy_if, 'address', agent_address + '/32']) + + for interface in Section.interfaces('ethernet'): + self.cli_set(base_path + ['interface', interface]) + + self.cli_set(base_path + ['netflow', 'engine-id', engine_id]) + self.cli_set(base_path + ['netflow', 'max-flows', max_flows]) + self.cli_set(base_path + ['netflow', 'sampling-rate', sampling_rate]) + self.cli_set(base_path + ['netflow', 'source-address', source_address]) + self.cli_set(base_path + ['netflow', 'version', version]) + + # timeouts + self.cli_set(base_path + ['netflow', 'timeout', 'expiry-interval', tmo_expiry]) + self.cli_set(base_path + ['netflow', 'timeout', 'flow-generic', tmo_flow]) + self.cli_set(base_path + ['netflow', 'timeout', 'icmp', tmo_icmp]) + self.cli_set(base_path + ['netflow', 'timeout', 'max-active-life', tmo_max]) + self.cli_set(base_path + ['netflow', 'timeout', 'tcp-fin', tmo_tcp_fin]) + self.cli_set(base_path + ['netflow', 'timeout', 'tcp-generic', tmo_tcp_generic]) + self.cli_set(base_path + ['netflow', 'timeout', 'tcp-rst', tmo_tcp_rst]) + self.cli_set(base_path + ['netflow', 'timeout', 'udp', tmo_udp]) + + # You need to configure at least one netflow server + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + for server, server_config in netflow_server.items(): + self.cli_set(base_path + ['netflow', 'server', server]) + if 'port' in server_config: + self.cli_set(base_path + ['netflow', 'server', server, 'port', server_config['port']]) + + # commit changes + self.cli_commit() + + uacctd = read_file(uacctd_conf) + + tmp = [] + tmp.append('memory') + for server, server_config in netflow_server.items(): + tmp.append(f'nfprobe[nf_{server}]') + self.assertIn('plugins: ' + ','.join(tmp), uacctd) + + for server, server_config in netflow_server.items(): + self.assertIn(f'nfprobe_engine[nf_{server}]: {engine_id}', uacctd) + self.assertIn(f'nfprobe_maxflows[nf_{server}]: {max_flows}', uacctd) + self.assertIn(f'sampling_rate[nf_{server}]: {sampling_rate}', uacctd) + self.assertIn(f'nfprobe_source_ip[nf_{server}]: {source_address}', uacctd) + self.assertIn(f'nfprobe_version[nf_{server}]: {version}', uacctd) + + if 'port' in server_config: + self.assertIn(f'nfprobe_receiver[nf_{server}]: {server}', uacctd) + else: + self.assertIn(f'nfprobe_receiver[nf_{server}]: {server}:2055', uacctd) + + self.assertIn(f'nfprobe_timeouts[nf_{server}]: expint={tmo_expiry}:general={tmo_flow}:icmp={tmo_icmp}:maxlife={tmo_max}:tcp.fin={tmo_tcp_fin}:tcp={tmo_tcp_generic}:tcp.rst={tmo_tcp_rst}:udp={tmo_udp}', uacctd) + + + self.cli_delete(['interfaces', 'dummy', dummy_if]) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_system_logs.py b/smoketest/scripts/cli/test_system_logs.py new file mode 100755 index 000000000..0c11c4663 --- /dev/null +++ b/smoketest/scripts/cli/test_system_logs.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 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 +# 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/>. + +import re +import unittest +from base_vyostest_shim import VyOSUnitTestSHIM +from vyos.util import read_file + +# path to logrotate configs +logrotate_atop_file = '/etc/logrotate.d/vyos-atop' +logrotate_rsyslog_file = '/etc/logrotate.d/vyos-rsyslog' +# default values +default_atop_maxsize = '10M' +default_atop_rotate = '10' +default_rsyslog_size = '1M' +default_rsyslog_rotate = '10' + +base_path = ['system', 'logs'] + + +def logrotate_config_parse(file_path): + # read the file + logrotate_config = read_file(file_path) + # create regex for parsing options + regex_options = re.compile( + r'(^\s+(?P<option_name_script>postrotate|prerotate|firstaction|lastaction|preremove)\n(?P<option_value_script>((?!endscript).)*)\n\s+endscript\n)|(^\s+(?P<option_name>[\S]+)([ \t]+(?P<option_value>\S+))*$)', + re.M | re.S) + # create empty dict for config + logrotate_config_dict = {} + # fill dictionary with actual config + for option in regex_options.finditer(logrotate_config): + option_name = option.group('option_name') + option_value = option.group('option_value') + option_name_script = option.group('option_name_script') + option_value_script = option.group('option_value_script') + if option_name: + logrotate_config_dict[option_name] = option_value + if option_name_script: + logrotate_config_dict[option_name_script] = option_value_script + + # return config dictionary + return (logrotate_config_dict) + + +class TestSystemLogs(VyOSUnitTestSHIM.TestCase): + + def tearDown(self): + self.cli_delete(base_path) + self.cli_commit() + + def test_logs_defaults(self): + # test with empty section for default values + self.cli_set(base_path) + self.cli_commit() + + # read the config file and check content + logrotate_config_atop = logrotate_config_parse(logrotate_atop_file) + logrotate_config_rsyslog = logrotate_config_parse( + logrotate_rsyslog_file) + self.assertEqual(logrotate_config_atop['maxsize'], default_atop_maxsize) + self.assertEqual(logrotate_config_atop['rotate'], default_atop_rotate) + self.assertEqual(logrotate_config_rsyslog['size'], default_rsyslog_size) + self.assertEqual(logrotate_config_rsyslog['rotate'], + default_rsyslog_rotate) + + def test_logs_atop_maxsize(self): + # test for maxsize option + self.cli_set(base_path + ['logrotate', 'atop', 'max-size', '50']) + self.cli_commit() + + # read the config file and check content + logrotate_config = logrotate_config_parse(logrotate_atop_file) + self.assertEqual(logrotate_config['maxsize'], '50M') + + def test_logs_atop_rotate(self): + # test for rotate option + self.cli_set(base_path + ['logrotate', 'atop', 'rotate', '50']) + self.cli_commit() + + # read the config file and check content + logrotate_config = logrotate_config_parse(logrotate_atop_file) + self.assertEqual(logrotate_config['rotate'], '50') + + def test_logs_rsyslog_size(self): + # test for size option + self.cli_set(base_path + ['logrotate', 'messages', 'max-size', '50']) + self.cli_commit() + + # read the config file and check content + logrotate_config = logrotate_config_parse(logrotate_rsyslog_file) + self.assertEqual(logrotate_config['size'], '50M') + + def test_logs_rsyslog_rotate(self): + # test for rotate option + self.cli_set(base_path + ['logrotate', 'messages', 'rotate', '50']) + self.cli_commit() + + # read the config file and check content + logrotate_config = logrotate_config_parse(logrotate_rsyslog_file) + self.assertEqual(logrotate_config['rotate'], '50') + + +if __name__ == '__main__': + unittest.main(verbosity=2, failfast=True) diff --git a/smoketest/scripts/cli/test_vpn_ipsec.py b/smoketest/scripts/cli/test_vpn_ipsec.py index c710aec6e..1433c7329 100755 --- a/smoketest/scripts/cli/test_vpn_ipsec.py +++ b/smoketest/scripts/cli/test_vpn_ipsec.py @@ -111,9 +111,22 @@ rgiyCHemtMepq57Pl1Nmj49eEA== """ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase): - def setUp(self): - self.cli_set(base_path + ['interface', f'{interface}.{vif}']) + @classmethod + def setUpClass(cls): + super(cls, cls).setUpClass() + # ensure we can also run this test on a live system - so lets clean + # out the current configuration :) + cls.cli_delete(cls, base_path) + + cls.cli_set(cls, base_path + ['interface', f'{interface}.{vif}']) + + @classmethod + def tearDownClass(cls): + super(cls, cls).tearDownClass() + + cls.cli_delete(cls, base_path + ['interface', f'{interface}.{vif}']) + def setUp(self): # Set IKE/ESP Groups self.cli_set(base_path + ['esp-group', esp_group, 'proposal', '1', 'encryption', 'aes128']) self.cli_set(base_path + ['esp-group', esp_group, 'proposal', '1', 'hash', 'sha1']) @@ -127,7 +140,6 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase): self.cli_delete(base_path) self.cli_delete(tunnel_path) - self.cli_delete(ethernet_path) self.cli_commit() # Check for no longer running process @@ -158,6 +170,7 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase): # Site to site local_address = '192.0.2.10' + priority = '20' peer_base_path = base_path + ['site-to-site', 'peer', peer_ip] self.cli_set(peer_base_path + ['authentication', 'mode', 'pre-shared-secret']) @@ -173,6 +186,10 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase): self.cli_set(peer_base_path + ['tunnel', '1', 'remote', 'prefix', '172.17.11.0/24']) self.cli_set(peer_base_path + ['tunnel', '1', 'remote', 'port', '443']) + self.cli_set(peer_base_path + ['tunnel', '2', 'local', 'prefix', '10.1.0.0/16']) + self.cli_set(peer_base_path + ['tunnel', '2', 'remote', 'prefix', '10.2.0.0/16']) + self.cli_set(peer_base_path + ['tunnel', '2', 'priority', priority]) + self.cli_commit() # Verify strongSwan configuration @@ -187,8 +204,15 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase): f'local_addrs = {local_address} # dhcp:no', f'remote_addrs = {peer_ip}', f'mode = tunnel', + f'peer_{peer_ip.replace(".","-")}_tunnel_1', f'local_ts = 172.16.10.0/24[tcp/443],172.16.11.0/24[tcp/443]', - f'remote_ts = 172.17.10.0/24[tcp/443],172.17.11.0/24[tcp/443]' + f'remote_ts = 172.17.10.0/24[tcp/443],172.17.11.0/24[tcp/443]', + f'mode = tunnel', + f'peer_{peer_ip.replace(".","-")}_tunnel_2', + f'local_ts = 10.1.0.0/16', + f'remote_ts = 10.2.0.0/16', + f'priority = {priority}', + f'mode = tunnel', ] for line in swanctl_conf_lines: self.assertIn(line, swanctl_conf) |