summaryrefslogtreecommitdiff
path: root/smoketest/scripts/cli
diff options
context:
space:
mode:
Diffstat (limited to 'smoketest/scripts/cli')
-rw-r--r--smoketest/scripts/cli/base_accel_ppp_test.py41
-rwxr-xr-xsmoketest/scripts/cli/test_cgnat.py138
-rwxr-xr-xsmoketest/scripts/cli/test_container.py16
-rwxr-xr-xsmoketest/scripts/cli/test_load-balancing_reverse-proxy.py78
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_isis.py17
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_ospf.py3
-rwxr-xr-xsmoketest/scripts/cli/test_qos.py116
-rwxr-xr-xsmoketest/scripts/cli/test_service_dns_forwarding.py10
-rwxr-xr-xsmoketest/scripts/cli/test_service_https.py41
-rwxr-xr-xsmoketest/scripts/cli/test_service_upnp.py103
-rwxr-xr-xsmoketest/scripts/cli/test_vpn_l2tp.py23
11 files changed, 481 insertions, 105 deletions
diff --git a/smoketest/scripts/cli/base_accel_ppp_test.py b/smoketest/scripts/cli/base_accel_ppp_test.py
index 383adc445..212dc58ab 100644
--- a/smoketest/scripts/cli/base_accel_ppp_test.py
+++ b/smoketest/scripts/cli/base_accel_ppp_test.py
@@ -367,6 +367,27 @@ class BasicAccelPPPTest:
]
)
+ self.set(
+ [
+ "authentication",
+ "radius",
+ "server",
+ radius_server,
+ "backup",
+ ]
+ )
+
+ self.set(
+ [
+ "authentication",
+ "radius",
+ "server",
+ radius_server,
+ "priority",
+ "10",
+ ]
+ )
+
# commit changes
self.cli_commit()
@@ -379,6 +400,8 @@ class BasicAccelPPPTest:
self.assertEqual(f"acct-port=0", server[3])
self.assertEqual(f"req-limit=0", server[4])
self.assertEqual(f"fail-time=0", server[5])
+ self.assertIn('weight=10', server)
+ self.assertIn('backup', server)
def test_accel_ipv4_pool(self):
self.basic_config(is_gateway=False, is_client_pool=False)
@@ -605,3 +628,21 @@ delegate={delegate_2_prefix},{delegate_mask},name={pool_name}"""
self.assertEqual(conf['connlimit']['limit'], limits)
self.assertEqual(conf['connlimit']['burst'], burst)
self.assertEqual(conf['connlimit']['timeout'], timeout)
+
+ def test_accel_log_level(self):
+ self.basic_config()
+ self.cli_commit()
+
+ # check default value
+ conf = ConfigParser(allow_no_value=True)
+ conf.read(self._config_file)
+ self.assertEqual(conf['log']['level'], '3')
+
+ for log_level in range(0, 5):
+ self.set(['log', 'level', str(log_level)])
+ self.cli_commit()
+ # Validate configuration values
+ conf = ConfigParser(allow_no_value=True)
+ conf.read(self._config_file)
+
+ self.assertEqual(conf['log']['level'], str(log_level))
diff --git a/smoketest/scripts/cli/test_cgnat.py b/smoketest/scripts/cli/test_cgnat.py
new file mode 100755
index 000000000..02dad3de5
--- /dev/null
+++ b/smoketest/scripts/cli/test_cgnat.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2024 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 os
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+from vyos.configsession import ConfigSessionError
+
+
+base_path = ['nat', 'cgnat']
+nftables_cgnat_config = '/run/nftables-cgnat.nft'
+
+
+class TestCGNAT(VyOSUnitTestSHIM.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ super(TestCGNAT, 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()
+ self.assertFalse(os.path.exists(nftables_cgnat_config))
+
+ def test_cgnat(self):
+ internal_name = 'vyos-int-01'
+ external_name = 'vyos-ext-01'
+ internal_net = '100.64.0.0/29'
+ external_net = '192.0.2.1-192.0.2.2'
+ external_ports = '40000-60000'
+ ports_per_subscriber = '5000'
+ rule = '100'
+
+ nftables_search = [
+ ['map tcp_nat_map'],
+ ['map udp_nat_map'],
+ ['map icmp_nat_map'],
+ ['map other_nat_map'],
+ ['100.64.0.0 : 192.0.2.1 . 40000-44999'],
+ ['100.64.0.1 : 192.0.2.1 . 45000-49999'],
+ ['100.64.0.2 : 192.0.2.1 . 50000-54999'],
+ ['100.64.0.3 : 192.0.2.1 . 55000-59999'],
+ ['100.64.0.4 : 192.0.2.2 . 40000-44999'],
+ ['100.64.0.5 : 192.0.2.2 . 45000-49999'],
+ ['100.64.0.6 : 192.0.2.2 . 50000-54999'],
+ ['100.64.0.7 : 192.0.2.2 . 55000-59999'],
+ ['chain POSTROUTING'],
+ ['type nat hook postrouting priority srcnat'],
+ ['ip protocol tcp counter snat ip to ip saddr map @tcp_nat_map'],
+ ['ip protocol udp counter snat ip to ip saddr map @udp_nat_map'],
+ ['ip protocol icmp counter snat ip to ip saddr map @icmp_nat_map'],
+ ['counter snat ip to ip saddr map @other_nat_map'],
+ ]
+
+ self.cli_set(base_path + ['pool', 'external', external_name, 'external-port-range', external_ports])
+ self.cli_set(base_path + ['pool', 'external', external_name, 'range', external_net])
+
+ # allocation out of the available ports
+ with self.assertRaises(ConfigSessionError):
+ self.cli_set(base_path + ['pool', 'external', external_name, 'per-user-limit', 'port', '8000'])
+ self.cli_commit()
+ self.cli_set(base_path + ['pool', 'external', external_name, 'per-user-limit', 'port', ports_per_subscriber])
+
+ # internal pool not set
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_set(base_path + ['pool', 'internal', internal_name, 'range', internal_net])
+
+ self.cli_set(base_path + ['rule', rule, 'source', 'pool', internal_name])
+ # non-exist translation pool
+ with self.assertRaises(ConfigSessionError):
+ self.cli_set(base_path + ['rule', rule, 'translation', 'pool', 'fake-pool'])
+ self.cli_commit()
+
+ self.cli_set(base_path + ['rule', rule, 'translation', 'pool', external_name])
+ self.cli_commit()
+
+ self.verify_nftables(nftables_search, 'ip cgnat', inverse=False, args='-s')
+
+
+ def test_cgnat_sequence(self):
+ internal_name = 'earth'
+ external_name = 'milky_way'
+ internal_net = '100.64.0.0/28'
+
+ ext_addr_alpha_proxima = '192.0.2.121/32'
+ ext_addr_beta_cygni = '198.51.100.23/32'
+ ext_addr_gamma_leonis = '203.0.113.102/32'
+
+ ext_seq_beta_cygni = '3'
+ ext_seq_gamma_leonis = '10'
+
+ external_ports = '1024-65535'
+ ports_per_subscriber = '10000'
+ rule = '100'
+
+ nftables_search = [
+ ['100.64.0.0 : 198.51.100.23 . 1024-11023, 100.64.0.1 : 198.51.100.23 . 11024-21023'],
+ ['100.64.0.4 : 198.51.100.23 . 41024-51023, 100.64.0.5 : 198.51.100.23 . 51024-61023'],
+ ['100.64.0.6 : 203.0.113.102 . 1024-11023, 100.64.0.7 : 203.0.113.102 . 11024-21023'],
+ ['100.64.0.8 : 203.0.113.102 . 21024-31023, 100.64.0.9 : 203.0.113.102 . 31024-41023'],
+ ['100.64.0.10 : 203.0.113.102 . 41024-51023, 100.64.0.11 : 203.0.113.102 . 51024-61023'],
+ ['100.64.0.12 : 192.0.2.121 . 1024-11023, 100.64.0.13 : 192.0.2.121 . 11024-21023'],
+ ['100.64.0.14 : 192.0.2.121 . 21024-31023, 100.64.0.15 : 192.0.2.121 . 31024-41023'],
+ ]
+
+ self.cli_set(base_path + ['pool', 'external', external_name, 'external-port-range', external_ports])
+ self.cli_set(base_path + ['pool', 'external', external_name, 'per-user-limit', 'port', ports_per_subscriber])
+ self.cli_set(base_path + ['pool', 'external', external_name, 'range', ext_addr_alpha_proxima])
+ self.cli_set(base_path + ['pool', 'external', external_name, 'range', ext_addr_beta_cygni, 'seq', ext_seq_beta_cygni])
+ self.cli_set(base_path + ['pool', 'external', external_name, 'range', ext_addr_gamma_leonis, 'seq', ext_seq_gamma_leonis])
+ self.cli_set(base_path + ['pool', 'internal', internal_name, 'range', internal_net])
+ self.cli_set(base_path + ['rule', rule, 'source', 'pool', internal_name])
+ self.cli_set(base_path + ['rule', rule, 'translation', 'pool', external_name])
+ self.cli_commit()
+
+ self.verify_nftables(nftables_search, 'ip cgnat', inverse=False, args='-s')
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_container.py b/smoketest/scripts/cli/test_container.py
index 3201883b8..90f821c60 100755
--- a/smoketest/scripts/cli/test_container.py
+++ b/smoketest/scripts/cli/test_container.py
@@ -91,6 +91,22 @@ class TestContainer(VyOSUnitTestSHIM.TestCase):
# Check for running process
self.assertEqual(process_named_running(PROCESS_NAME), pid)
+ def test_cpu_limit(self):
+ cont_name = 'c2'
+
+ self.cli_set(base_path + ['name', cont_name, 'allow-host-networks'])
+ self.cli_set(base_path + ['name', cont_name, 'image', cont_image])
+ self.cli_set(base_path + ['name', cont_name, 'cpu-quota', '1.25'])
+
+ self.cli_commit()
+
+ pid = 0
+ with open(PROCESS_PIDFILE.format(cont_name), 'r') as f:
+ pid = int(f.read())
+
+ # Check for running process
+ self.assertEqual(process_named_running(PROCESS_NAME), pid)
+
def test_ipv4_network(self):
prefix = '192.0.2.0/24'
base_name = 'ipv4'
diff --git a/smoketest/scripts/cli/test_load-balancing_reverse-proxy.py b/smoketest/scripts/cli/test_load-balancing_reverse-proxy.py
index c8b17316f..aa796f59f 100755
--- a/smoketest/scripts/cli/test_load-balancing_reverse-proxy.py
+++ b/smoketest/scripts/cli/test_load-balancing_reverse-proxy.py
@@ -218,7 +218,7 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase):
# Frontend
self.assertIn(f'frontend {frontend}', config)
- self.assertIn(f'bind :::{front_port} v4v6', config)
+ self.assertIn(f'bind [::]:{front_port} v4v6', config)
self.assertIn(f'mode {mode}', config)
for domain in domains_bk_first:
self.assertIn(f'acl {rule_ten} hdr(host) -i {domain}', config)
@@ -338,6 +338,11 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase):
self.assertIn('http-check send meth GET uri /health', config)
self.assertIn('http-check expect string success', config)
+ # Test configuring both http-check & health-check fails validation script
+ self.cli_set(base_path + ['backend', 'bk-01', 'health-check', 'ldap'])
+ with self.assertRaises(ConfigSessionError) as e:
+ self.cli_commit()
+
def test_06_lb_reverse_proxy_tcp_mode(self):
frontend = 'tcp_8443'
mode = 'tcp'
@@ -371,7 +376,7 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase):
# Frontend
self.assertIn(f'frontend {frontend}', config)
- self.assertIn(f'bind :::{front_port} v4v6', config)
+ self.assertIn(f'bind [::]:{front_port} v4v6', config)
self.assertIn(f'mode {mode}', config)
self.assertIn(f'tcp-request inspect-delay {tcp_request_delay}', config)
@@ -385,5 +390,74 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase):
self.assertIn(f'mode {mode}', config)
self.assertIn(f'server {bk_name} {bk_server}:{bk_server_port}', config)
+ def test_07_lb_reverse_proxy_http_response_headers(self):
+ # Setup base
+ self.configure_pki()
+ self.base_config()
+
+ # Set example headers in both frontend and backend
+ self.cli_set(base_path + ['service', 'https_front', 'http-response-headers', 'Cache-Control', 'value', 'max-age=604800'])
+ self.cli_set(base_path + ['backend', 'bk-01', 'http-response-headers', 'Proxy-Backend-ID', 'value', 'bk-01'])
+ self.cli_commit()
+
+ # Test headers are present in generated configuration file
+ config = read_file(HAPROXY_CONF)
+ self.assertIn('http-response set-header Cache-Control \'max-age=604800\'', config)
+ self.assertIn('http-response set-header Proxy-Backend-ID \'bk-01\'', config)
+
+ # Test setting alongside modes other than http is blocked by validation conditions
+ self.cli_set(base_path + ['service', 'https_front', 'mode', 'tcp'])
+ with self.assertRaises(ConfigSessionError) as e:
+ self.cli_commit()
+
+ def test_08_lb_reverse_proxy_tcp_health_checks(self):
+ # Setup PKI
+ self.configure_pki()
+
+ # Define variables
+ frontend = 'fe_ldaps'
+ mode = 'tcp'
+ health_check = 'ldap'
+ front_port = '636'
+ bk_name = 'bk_ldap'
+ bk_servers = ['192.0.2.11', '192.0.2.12']
+ bk_server_port = '389'
+
+ # Configure frontend
+ self.cli_set(base_path + ['service', frontend, 'mode', mode])
+ self.cli_set(base_path + ['service', frontend, 'port', front_port])
+ self.cli_set(base_path + ['service', frontend, 'ssl', 'certificate', 'smoketest'])
+
+ # Configure backend
+ self.cli_set(base_path + ['backend', bk_name, 'mode', mode])
+ self.cli_set(base_path + ['backend', bk_name, 'health-check', health_check])
+ for index, bk_server in enumerate(bk_servers):
+ self.cli_set(base_path + ['backend', bk_name, 'server', f'srv-{index}', 'address', bk_server])
+ self.cli_set(base_path + ['backend', bk_name, 'server', f'srv-{index}', 'port', bk_server_port])
+
+ # Commit & read config
+ self.cli_commit()
+ config = read_file(HAPROXY_CONF)
+
+ # Validate Frontend
+ self.assertIn(f'frontend {frontend}', config)
+ self.assertIn(f'bind [::]:{front_port} v4v6 ssl crt /run/haproxy/smoketest.pem', config)
+ self.assertIn(f'mode {mode}', config)
+ self.assertIn(f'backend {bk_name}', config)
+
+ # Validate Backend
+ self.assertIn(f'backend {bk_name}', config)
+ self.assertIn(f'option {health_check}-check', config)
+ self.assertIn(f'mode {mode}', config)
+ for index, bk_server in enumerate(bk_servers):
+ self.assertIn(f'server srv-{index} {bk_server}:{bk_server_port}', config)
+
+ # Validate SMTP option renders correctly
+ self.cli_set(base_path + ['backend', bk_name, 'health-check', 'smtp'])
+ self.cli_commit()
+ config = read_file(HAPROXY_CONF)
+ self.assertIn(f'option smtpchk', config)
+
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_isis.py b/smoketest/scripts/cli/test_protocols_isis.py
index 0fd18a6da..769f3dd33 100755
--- a/smoketest/scripts/cli/test_protocols_isis.py
+++ b/smoketest/scripts/cli/test_protocols_isis.py
@@ -60,6 +60,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
prefix_list = 'EXPORT-ISIS'
route_map = 'EXPORT-ISIS'
rule = '10'
+ metric_style = 'transition'
self.cli_set(['policy', 'prefix-list', prefix_list, 'rule', rule, 'action', 'permit'])
self.cli_set(['policy', 'prefix-list', prefix_list, 'rule', rule, 'prefix', '203.0.113.0/24'])
@@ -80,6 +81,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
self.cli_set(base_path + ['redistribute', 'ipv4', 'connected', 'level-2', 'route-map', route_map])
+ self.cli_set(base_path + ['metric-style', metric_style])
self.cli_set(base_path + ['log-adjacency-changes'])
# Commit all changes
@@ -88,6 +90,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
# Verify all changes
tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd')
self.assertIn(f' net {net}', tmp)
+ self.assertIn(f' metric-style {metric_style}', tmp)
self.assertIn(f' log-adjacency-changes', tmp)
self.assertIn(f' redistribute ipv4 connected level-2 route-map {route_map}', tmp)
@@ -395,5 +398,19 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase):
self.cli_delete(['policy', 'prefix-list', prefix_list])
self.cli_commit()
+ def test_isis_10_topology(self):
+ topologies = ['ipv4-multicast', 'ipv4-mgmt', 'ipv6-unicast', 'ipv6-multicast', 'ipv6-mgmt']
+ interface = 'lo'
+
+ # Set a basic IS-IS config
+ self.cli_set(base_path + ['net', net])
+ self.cli_set(base_path + ['interface', interface])
+ for topology in topologies:
+ self.cli_set(base_path + ['topology', topology])
+ self.cli_commit()
+ tmp = self.getFRRconfig(f'router isis {domain}', daemon='isisd')
+ self.assertIn(f' net {net}', tmp)
+ self.assertIn(f' topology {topology}', tmp)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py
index 1b9cc50fe..585c1dc89 100755
--- a/smoketest/scripts/cli/test_protocols_ospf.py
+++ b/smoketest/scripts/cli/test_protocols_ospf.py
@@ -16,6 +16,7 @@
import unittest
+from time import sleep
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
@@ -480,6 +481,8 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
# Commit main OSPF changes
self.cli_commit()
+ sleep(10)
+
# Verify main OSPF changes
frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
self.assertIn(f'router ospf', frrconfig)
diff --git a/smoketest/scripts/cli/test_qos.py b/smoketest/scripts/cli/test_qos.py
index bcf5139c7..b98c0e9b7 100755
--- a/smoketest/scripts/cli/test_qos.py
+++ b/smoketest/scripts/cli/test_qos.py
@@ -738,6 +738,122 @@ class TestQoS(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
self.assertEqual('', cmd(f'tc filter show dev {interface}'))
+ def test_14_policy_limiter_marked_traffic(self):
+ policy_name = 'smoke_test'
+ base_policy_path = ['qos', 'policy', 'limiter', policy_name]
+
+ self.cli_set(['qos', 'interface', self._interfaces[0], 'ingress', policy_name])
+ self.cli_set(base_policy_path + ['class', '100', 'bandwidth', '20gbit'])
+ self.cli_set(base_policy_path + ['class', '100', 'burst', '3760k'])
+ self.cli_set(base_policy_path + ['class', '100', 'match', 'INTERNAL', 'mark', '100'])
+ self.cli_set(base_policy_path + ['class', '100', 'priority', '20'])
+ self.cli_set(base_policy_path + ['default', 'bandwidth', '1gbit'])
+ self.cli_set(base_policy_path + ['default', 'burst', '125000000b'])
+ self.cli_commit()
+
+ tc_filters = cmd(f'tc filter show dev {self._interfaces[0]} ingress')
+ # class 100
+ self.assertIn('filter parent ffff: protocol all pref 20 fw chain 0', tc_filters)
+ self.assertIn('action order 1: police 0x1 rate 20Gbit burst 3847500b mtu 2Kb action drop overhead 0b', tc_filters)
+ # default
+ self.assertIn('filter parent ffff: protocol all pref 255 basic chain 0', tc_filters)
+ self.assertIn('action order 1: police 0x2 rate 1Gbit burst 125000000b mtu 2Kb action drop overhead 0b', tc_filters)
+
+ def test_15_traffic_match_group(self):
+ interface = self._interfaces[0]
+ self.cli_set(['qos', 'interface', interface, 'egress', 'VyOS-HTB'])
+ base_policy_path = ['qos', 'policy', 'shaper', 'VyOS-HTB']
+
+ #old syntax
+ self.cli_set(base_policy_path + ['bandwidth', '100mbit'])
+ self.cli_set(base_policy_path + ['class', '10', 'bandwidth', '40%'])
+ self.cli_set(base_policy_path + ['class', '10', 'match', 'AF11', 'ip', 'dscp', 'AF11'])
+ self.cli_set(base_policy_path + ['class', '10', 'match', 'AF41', 'ip', 'dscp', 'AF41'])
+ self.cli_set(base_policy_path + ['class', '10', 'match', 'AF43', 'ip', 'dscp', 'AF43'])
+ self.cli_set(base_policy_path + ['class', '10', 'match', 'CS4', 'ip', 'dscp', 'CS4'])
+ self.cli_set(base_policy_path + ['class', '10', 'priority', '1'])
+ self.cli_set(base_policy_path + ['class', '10', 'queue-type', 'fair-queue'])
+ self.cli_set(base_policy_path + ['class', '20', 'bandwidth', '30%'])
+ self.cli_set(base_policy_path + ['class', '20', 'match', 'EF', 'ip', 'dscp', 'EF'])
+ self.cli_set(base_policy_path + ['class', '20', 'match', 'CS5', 'ip', 'dscp', 'CS5'])
+ self.cli_set(base_policy_path + ['class', '20', 'priority', '2'])
+ self.cli_set(base_policy_path + ['class', '20', 'queue-type', 'fair-queue'])
+ self.cli_set(base_policy_path + ['default', 'bandwidth', '20%'])
+ self.cli_set(base_policy_path + ['default', 'queue-type', 'fair-queue'])
+ self.cli_commit()
+
+ tc_filters_old = cmd(f'tc -details filter show dev {interface}')
+ self.assertIn('match 00280000/00ff0000', tc_filters_old)
+ self.assertIn('match 00880000/00ff0000', tc_filters_old)
+ self.assertIn('match 00980000/00ff0000', tc_filters_old)
+ self.assertIn('match 00800000/00ff0000', tc_filters_old)
+ self.assertIn('match 00a00000/00ff0000', tc_filters_old)
+ self.assertIn('match 00b80000/00ff0000', tc_filters_old)
+ # delete config by old syntax
+ self.cli_delete(base_policy_path)
+ self.cli_delete(['qos', 'interface', interface, 'egress', 'VyOS-HTB'])
+ self.cli_commit()
+ self.assertEqual('', cmd(f'tc -s filter show dev {interface}'))
+
+ self.cli_set(['qos', 'interface', interface, 'egress', 'VyOS-HTB'])
+ # prepare traffic match group
+ self.cli_set(['qos', 'traffic-match-group', 'VOICE', 'description', 'voice shaper'])
+ self.cli_set(['qos', 'traffic-match-group', 'VOICE', 'match', 'EF', 'ip', 'dscp', 'EF'])
+ self.cli_set(['qos', 'traffic-match-group', 'VOICE', 'match', 'CS5', 'ip', 'dscp', 'CS5'])
+
+ self.cli_set(['qos', 'traffic-match-group', 'REAL_TIME_COMMON', 'description', 'real time common filters'])
+ self.cli_set(['qos', 'traffic-match-group', 'REAL_TIME_COMMON', 'match', 'AF43', 'ip', 'dscp', 'AF43'])
+ self.cli_set(['qos', 'traffic-match-group', 'REAL_TIME_COMMON', 'match', 'CS4', 'ip', 'dscp', 'CS4'])
+
+ self.cli_set(['qos', 'traffic-match-group', 'REAL_TIME', 'description', 'real time shaper'])
+ self.cli_set(['qos', 'traffic-match-group', 'REAL_TIME', 'match', 'AF41', 'ip', 'dscp', 'AF41'])
+ self.cli_set(['qos', 'traffic-match-group', 'REAL_TIME', 'match-group', 'REAL_TIME_COMMON'])
+
+ # new syntax
+ self.cli_set(base_policy_path + ['bandwidth', '100mbit'])
+ self.cli_set(base_policy_path + ['class', '10', 'bandwidth', '40%'])
+ self.cli_set(base_policy_path + ['class', '10', 'match', 'AF11', 'ip', 'dscp', 'AF11'])
+ self.cli_set(base_policy_path + ['class', '10', 'match-group', 'REAL_TIME'])
+ self.cli_set(base_policy_path + ['class', '10', 'priority', '1'])
+ self.cli_set(base_policy_path + ['class', '10', 'queue-type', 'fair-queue'])
+ self.cli_set(base_policy_path + ['class', '20', 'bandwidth', '30%'])
+ self.cli_set(base_policy_path + ['class', '20', 'match-group', 'VOICE'])
+ self.cli_set(base_policy_path + ['class', '20', 'priority', '2'])
+ self.cli_set(base_policy_path + ['class', '20', 'queue-type', 'fair-queue'])
+ self.cli_set(base_policy_path + ['default', 'bandwidth', '20%'])
+ self.cli_set(base_policy_path + ['default', 'queue-type', 'fair-queue'])
+ self.cli_commit()
+
+ self.assertEqual(tc_filters_old, cmd(f'tc -details filter show dev {interface}'))
+
+ def test_16_wrong_traffic_match_group(self):
+ interface = self._interfaces[0]
+ self.cli_set(['qos', 'interface', interface])
+
+ # Can not use both IPv6 and IPv4 in one match
+ self.cli_set(['qos', 'traffic-match-group', '1', 'match', 'one', 'ip', 'dscp', 'EF'])
+ self.cli_set(['qos', 'traffic-match-group', '1', 'match', 'one', 'ipv6', 'dscp', 'EF'])
+ with self.assertRaises(ConfigSessionError) as e:
+ self.cli_commit()
+
+ # check contain itself, should commit success
+ self.cli_delete(['qos', 'traffic-match-group', '1', 'match', 'one', 'ipv6'])
+ self.cli_set(['qos', 'traffic-match-group', '1', 'match-group', '1'])
+ self.cli_commit()
+
+ # check cycle dependency, should commit success
+ self.cli_set(['qos', 'traffic-match-group', '1', 'match-group', '3'])
+ self.cli_set(['qos', 'traffic-match-group', '2', 'match', 'one', 'ip', 'dscp', 'CS4'])
+ self.cli_set(['qos', 'traffic-match-group', '2', 'match-group', '1'])
+
+ self.cli_set(['qos', 'traffic-match-group', '3', 'match', 'one', 'ipv6', 'dscp', 'CS4'])
+ self.cli_set(['qos', 'traffic-match-group', '3', 'match-group', '2'])
+ self.cli_commit()
+
+ # inherit from non exist group, should commit success with warning
+ self.cli_set(['qos', 'traffic-match-group', '3', 'match-group', 'unexpected'])
+ self.cli_commit()
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_dns_forwarding.py b/smoketest/scripts/cli/test_service_dns_forwarding.py
index 079c584ba..4db1d7495 100755
--- a/smoketest/scripts/cli/test_service_dns_forwarding.py
+++ b/smoketest/scripts/cli/test_service_dns_forwarding.py
@@ -291,5 +291,15 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase):
tmp = get_config_value('edns-subnet-allow-list')
self.assertEqual(tmp, ','.join(options))
+ def test_multiple_ns_records(self):
+ test_zone = 'example.com'
+ self.cli_set(base_path + ['authoritative-domain', test_zone, 'records', 'ns', 'test', 'target', f'ns1.{test_zone}'])
+ self.cli_set(base_path + ['authoritative-domain', test_zone, 'records', 'ns', 'test', 'target', f'ns2.{test_zone}'])
+ self.cli_commit()
+ zone_config = read_file(f'{PDNS_REC_RUN_DIR}/zone.{test_zone}.conf')
+ self.assertRegex(zone_config, fr'test\s+\d+\s+NS\s+ns1\.{test_zone}\.')
+ self.assertRegex(zone_config, fr'test\s+\d+\s+NS\s+ns2\.{test_zone}\.')
+
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_service_https.py b/smoketest/scripts/cli/test_service_https.py
index f2a64627f..8a6386e4f 100755
--- a/smoketest/scripts/cli/test_service_https.py
+++ b/smoketest/scripts/cli/test_service_https.py
@@ -412,6 +412,47 @@ class TestHTTPSService(VyOSUnitTestSHIM.TestCase):
self.assertEqual(r.status_code, 200)
@ignore_warning(InsecureRequestWarning)
+ def test_api_image(self):
+ address = '127.0.0.1'
+ key = 'VyOS-key'
+ url = f'https://{address}/image'
+ headers = {}
+
+ self.cli_set(base_path + ['api', 'keys', 'id', 'key-01', 'key', key])
+ self.cli_commit()
+
+ payload = {
+ 'data': '{"op": "add"}',
+ 'key': f'{key}',
+ }
+ r = request('POST', url, verify=False, headers=headers, data=payload)
+ self.assertEqual(r.status_code, 400)
+ self.assertIn('Missing required field "url"', r.json().get('error'))
+
+ payload = {
+ 'data': '{"op": "delete"}',
+ 'key': f'{key}',
+ }
+ r = request('POST', url, verify=False, headers=headers, data=payload)
+ self.assertEqual(r.status_code, 400)
+ self.assertIn('Missing required field "name"', r.json().get('error'))
+
+ payload = {
+ 'data': '{"op": "set_default"}',
+ 'key': f'{key}',
+ }
+ r = request('POST', url, verify=False, headers=headers, data=payload)
+ self.assertEqual(r.status_code, 400)
+ self.assertIn('Missing required field "name"', r.json().get('error'))
+
+ payload = {
+ 'data': '{"op": "show"}',
+ 'key': f'{key}',
+ }
+ r = request('POST', url, verify=False, headers=headers, data=payload)
+ self.assertEqual(r.status_code, 200)
+
+ @ignore_warning(InsecureRequestWarning)
def test_api_config_file_load_http(self):
# Test load config from HTTP URL
address = '127.0.0.1'
diff --git a/smoketest/scripts/cli/test_service_upnp.py b/smoketest/scripts/cli/test_service_upnp.py
deleted file mode 100755
index fd67b0ced..000000000
--- a/smoketest/scripts/cli/test_service_upnp.py
+++ /dev/null
@@ -1,103 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2021-2024 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.template import ip_from_cidr
-from vyos.utils.file import read_file
-from vyos.utils.process import process_named_running
-
-UPNP_CONF = '/run/upnp/miniupnp.conf'
-DAEMON = 'miniupnpd'
-interface = 'eth0'
-base_path = ['service', 'upnp']
-address_base = ['interfaces', 'ethernet', interface, 'address']
-
-ipv4_addr = '100.64.0.1/24'
-ipv6_addr = '2001:db8::1/64'
-
-class TestServiceUPnP(VyOSUnitTestSHIM.TestCase):
- @classmethod
- def setUpClass(cls):
- super(TestServiceUPnP, 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, address_base + [ipv4_addr])
- cls.cli_set(cls, address_base + [ipv6_addr])
-
- @classmethod
- def tearDownClass(cls):
- cls.cli_delete(cls, address_base)
- cls._session.commit()
-
- super(TestServiceUPnP, cls).tearDownClass()
-
- def tearDown(self):
- # Check for running process
- self.assertTrue(process_named_running(DAEMON))
-
- self.cli_delete(base_path)
- self.cli_commit()
-
- # Check for running process
- self.assertFalse(process_named_running(DAEMON))
-
- def test_ipv4_base(self):
- self.cli_set(base_path + ['nat-pmp'])
- self.cli_set(base_path + ['listen', interface])
-
- # check validate() - WAN interface is mandatory
- with self.assertRaises(ConfigSessionError):
- self.cli_commit()
- self.cli_set(base_path + ['wan-interface', interface])
-
- self.cli_commit()
-
- config = read_file(UPNP_CONF)
- self.assertIn(f'ext_ifname={interface}', config)
- self.assertIn(f'listening_ip={interface}', config)
- self.assertIn(f'enable_natpmp=yes', config)
- self.assertIn(f'enable_upnp=yes', config)
-
- def test_ipv6_base(self):
- v6_addr = ip_from_cidr(ipv6_addr)
-
- self.cli_set(base_path + ['nat-pmp'])
- self.cli_set(base_path + ['listen', interface])
- self.cli_set(base_path + ['listen', v6_addr])
-
- # check validate() - WAN interface is mandatory
- with self.assertRaises(ConfigSessionError):
- self.cli_commit()
- self.cli_set(base_path + ['wan-interface', interface])
-
- self.cli_commit()
-
- config = read_file(UPNP_CONF)
- self.assertIn(f'ext_ifname={interface}', config)
- self.assertIn(f'listening_ip={interface}', config)
- self.assertIn(f'ipv6_listening_ip={v6_addr}', config)
- self.assertIn(f'enable_natpmp=yes', config)
- self.assertIn(f'enable_upnp=yes', config)
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_vpn_l2tp.py b/smoketest/scripts/cli/test_vpn_l2tp.py
index 8c4e53895..07a7e2906 100755
--- a/smoketest/scripts/cli/test_vpn_l2tp.py
+++ b/smoketest/scripts/cli/test_vpn_l2tp.py
@@ -95,6 +95,29 @@ class TestVPNL2TPServer(BasicAccelPPPTest.TestCase):
self.cli_set(base_path + ['authentication', 'protocols', 'chap'])
self.cli_commit()
+ def test_l2tp_radius_server(self):
+ base_path = ['vpn', 'l2tp', 'remote-access']
+ radius_server = "192.0.2.22"
+ radius_key = "secretVyOS"
+
+ self.cli_set(base_path + ['authentication', 'mode', 'radius'])
+ self.cli_set(base_path + ['gateway-address', '192.0.2.1'])
+ self.cli_set(base_path + ['client-ip-pool', 'SIMPLE-POOL', 'range', '192.0.2.0/24'])
+ self.cli_set(base_path + ['default-pool', 'SIMPLE-POOL'])
+ self.cli_set(base_path + ['authentication', 'radius', 'server', radius_server, 'key', radius_key])
+ self.cli_set(base_path + ['authentication', 'radius', 'server', radius_server, 'priority', '10'])
+ self.cli_set(base_path + ['authentication', 'radius', 'server', radius_server, 'backup'])
+
+ # commit changes
+ self.cli_commit()
+
+ # Validate configuration values
+ conf = ConfigParser(allow_no_value=True)
+ conf.read(self._config_file)
+ server = conf["radius"]["server"].split(",")
+ self.assertIn('weight=10', server)
+ self.assertIn('backup', server)
+
if __name__ == '__main__':
unittest.main(verbosity=2)