diff options
20 files changed, 221 insertions, 110 deletions
diff --git a/op-mode-definitions/system-image.xml.in b/op-mode-definitions/system-image.xml.in index 463b985d6..c131087be 100644 --- a/op-mode-definitions/system-image.xml.in +++ b/op-mode-definitions/system-image.xml.in @@ -17,7 +17,7 @@ <list>/path/to/vyos-image.iso "http://example.com/vyos-image.iso"</list> </completionHelp> </properties> - <command>sudo ${vyos_op_scripts_dir}/image_installer.py --action add --image_path "${4}"</command> + <command>sudo ${vyos_op_scripts_dir}/image_installer.py --action add --image-path "${4}"</command> <children> <tagNode name="vrf"> <properties> @@ -26,7 +26,7 @@ <path>vrf name</path> </completionHelp> </properties> - <command>sudo ${vyos_op_scripts_dir}/image_installer.py --action add --image_path "${4}" --vrf "${6}"</command> + <command>sudo ${vyos_op_scripts_dir}/image_installer.py --action add --image-path "${4}" --vrf "${6}"</command> <children> <tagNode name="username"> <properties> @@ -37,7 +37,7 @@ <properties> <help>Password to use with authentication</help> </properties> - <command>sudo ${vyos_op_scripts_dir}/image_installer.py --action add --image_path "${4}" --vrf "${6}" --username "${8}" --password "${10}"</command> + <command>sudo ${vyos_op_scripts_dir}/image_installer.py --action add --image-path "${4}" --vrf "${6}" --username "${8}" --password "${10}"</command> </tagNode> </children> </tagNode> @@ -52,7 +52,7 @@ <properties> <help>Password to use with authentication</help> </properties> - <command>sudo ${vyos_op_scripts_dir}/image_installer.py --action add --image_path "${4}" --username "${6}" --password "${8}"</command> + <command>sudo ${vyos_op_scripts_dir}/image_installer.py --action add --image-path "${4}" --username "${6}" --password "${8}"</command> </tagNode> </children> </tagNode> @@ -90,7 +90,7 @@ <script>sudo ${vyos_op_scripts_dir}/image_manager.py --action list</script> </completionHelp> </properties> - <command>sudo ${vyos_op_scripts_dir}/image_manager.py --action set --image_name "${5}"</command> + <command>sudo ${vyos_op_scripts_dir}/image_manager.py --action set --image-name "${5}"</command> </tagNode> </children> </node> @@ -134,7 +134,7 @@ <script>sudo ${vyos_op_scripts_dir}/image_manager.py --action list</script> </completionHelp> </properties> - <command>sudo ${vyos_op_scripts_dir}/image_manager.py --action delete --image_name "${4}"</command> + <command>sudo ${vyos_op_scripts_dir}/image_manager.py --action delete --image-name "${4}"</command> </tagNode> </children> </node> @@ -162,7 +162,7 @@ <properties> <help>A new name for an image</help> </properties> - <command>sudo ${vyos_op_scripts_dir}/image_manager.py --action rename --image_name "${4}" --image_new_name "${6}"</command> + <command>sudo ${vyos_op_scripts_dir}/image_manager.py --action rename --image-name "${4}" --image-new-name "${6}"</command> </tagNode> </children> </tagNode> diff --git a/python/vyos/configsession.py b/python/vyos/configsession.py index 9802ebae4..90842b749 100644 --- a/python/vyos/configsession.py +++ b/python/vyos/configsession.py @@ -30,8 +30,10 @@ SHOW_CONFIG = ['/bin/cli-shell-api', 'showConfig'] LOAD_CONFIG = ['/bin/cli-shell-api', 'loadFile'] MIGRATE_LOAD_CONFIG = ['/usr/libexec/vyos/vyos-load-config.py'] SAVE_CONFIG = ['/usr/libexec/vyos/vyos-save-config.py'] -INSTALL_IMAGE = ['/opt/vyatta/sbin/install-image', '--url'] -REMOVE_IMAGE = ['/opt/vyatta/bin/vyatta-boot-image.pl', '--del'] +INSTALL_IMAGE = ['/usr/libexec/vyos/op_mode/image_installer.py', + '--action', 'add', '--no-prompt', '--image-path'] +REMOVE_IMAGE = ['/usr/libexec/vyos/op_mode/image_manager.py', + '--action', 'delete', '--no-prompt', '--image-name'] GENERATE = ['/opt/vyatta/bin/vyatta-op-cmd-wrapper', 'generate'] SHOW = ['/opt/vyatta/bin/vyatta-op-cmd-wrapper', 'show'] RESET = ['/opt/vyatta/bin/vyatta-op-cmd-wrapper', 'reset'] diff --git a/python/vyos/remote.py b/python/vyos/remote.py index 8b90e4530..fec44b571 100644 --- a/python/vyos/remote.py +++ b/python/vyos/remote.py @@ -46,17 +46,6 @@ from vyos.version import get_version CHUNK_SIZE = 8192 -@contextmanager -def umask(mask: int): - """ - Context manager that temporarily sets the process umask. - """ - oldmask = os.umask(mask) - try: - yield - finally: - os.umask(oldmask) - class InteractivePolicy(MissingHostKeyPolicy): """ Paramiko policy for interactively querying the user on whether to proceed @@ -88,6 +77,17 @@ class SourceAdapter(HTTPAdapter): num_pools=connections, maxsize=maxsize, block=block, source_address=self._source_pair) +@contextmanager +def umask(mask: int): + """ + Context manager that temporarily sets the process umask. + """ + import os + oldmask = os.umask(mask) + try: + yield + finally: + os.umask(oldmask) def check_storage(path, size): """ @@ -436,8 +436,8 @@ def urlc(urlstring, *args, **kwargs): except KeyError: raise ValueError(f'Unsupported URL scheme: "{scheme}"') -def download(local_path, urlstring, progressbar=False, raise_error=False, check_space=False, - source_host='', source_port=0, timeout=10.0): +def download(local_path, urlstring, progressbar=False, check_space=False, + source_host='', source_port=0, timeout=10.0, raise_error=False): try: progressbar = progressbar and is_interactive() urlc(urlstring, progressbar, check_space, source_host, source_port, timeout).download(local_path) @@ -448,14 +448,12 @@ def download(local_path, urlstring, progressbar=False, raise_error=False, check_ except KeyboardInterrupt: print_error('\nDownload aborted by user.') -def upload(local_path, urlstring, progressbar=False, raise_error=False, +def upload(local_path, urlstring, progressbar=False, source_host='', source_port=0, timeout=10.0): try: progressbar = progressbar and is_interactive() urlc(urlstring, progressbar, source_host, source_port, timeout).upload(local_path) except Exception as err: - if raise_error: - raise print_error(f'Unable to upload "{urlstring}": {err}') except KeyboardInterrupt: print_error('\nUpload aborted by user.') diff --git a/python/vyos/system/image.py b/python/vyos/system/image.py index 6c4e3bba5..c03ce02d5 100644 --- a/python/vyos/system/image.py +++ b/python/vyos/system/image.py @@ -261,3 +261,8 @@ def is_live_boot() -> bool: if boot_type == 'live': return True return False + +def is_running_as_container() -> bool: + if Path('/.dockerenv').exists(): + return True + return False diff --git a/python/vyos/utils/network.py b/python/vyos/utils/network.py index 6a5de5423..2a0808fca 100644 --- a/python/vyos/utils/network.py +++ b/python/vyos/utils/network.py @@ -61,14 +61,17 @@ def get_vrf_members(vrf: str) -> list: """ import json from vyos.utils.process import cmd - if not interface_exists(vrf): - raise ValueError(f'VRF "{vrf}" does not exist!') - output = cmd(f'ip --json --brief link show master {vrf}') - answer = json.loads(output) interfaces = [] - for data in answer: - if 'ifname' in data: - interfaces.append(data.get('ifname')) + try: + if not interface_exists(vrf): + raise ValueError(f'VRF "{vrf}" does not exist!') + output = cmd(f'ip --json --brief link show vrf {vrf}') + answer = json.loads(output) + for data in answer: + if 'ifname' in data: + interfaces.append(data.get('ifname')) + except: + pass return interfaces def get_interface_vrf(interface): diff --git a/smoketest/scripts/cli/test_protocols_bfd.py b/smoketest/scripts/cli/test_protocols_bfd.py index 451565664..f209eae3a 100755 --- a/smoketest/scripts/cli/test_protocols_bfd.py +++ b/smoketest/scripts/cli/test_protocols_bfd.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 VyOS maintainers and contributors +# Copyright (C) 2021-2023 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 @@ -77,11 +77,23 @@ profiles = { } class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase): + @classmethod + def setUpClass(cls): + super(TestProtocolsBFD, cls).setUpClass() + + # Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same + cls.daemon_pid = process_named_running(PROCESS_NAME) + + # 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)) + + # check process health and continuity + self.assertEqual(self.daemon_pid, process_named_running(PROCESS_NAME)) def test_bfd_peer(self): self.cli_set(['vrf', 'name', vrf_name, 'table', '1000']) diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 23e138ebe..71e2142f9 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -174,9 +174,16 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): def setUpClass(cls): super(TestProtocolsBGP, cls).setUpClass() + # Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same + cls.daemon_pid = process_named_running(PROCESS_NAME) + # 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_delete(cls, ['policy', 'route-map']) + cls.cli_delete(cls, ['policy', 'prefix-list']) + cls.cli_delete(cls, ['policy', 'prefix-list6']) + cls.cli_delete(cls, ['vrf']) 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']) @@ -192,18 +199,23 @@ class TestProtocolsBGP(VyOSUnitTestSHIM.TestCase): @classmethod def tearDownClass(cls): - cls.cli_delete(cls, ['policy']) + cls.cli_delete(cls, ['policy', 'route-map']) + cls.cli_delete(cls, ['policy', 'prefix-list']) + cls.cli_delete(cls, ['policy', 'prefix-list6']) def setUp(self): self.cli_set(base_path + ['system-as', ASN]) def tearDown(self): + # cleanup any possible VRF mess self.cli_delete(['vrf']) + # always destrox the entire bgpd configuration to make the processes + # life as hard as possible self.cli_delete(base_path) self.cli_commit() - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + # check process health and continuity + self.assertEqual(self.daemon_pid, process_named_running(PROCESS_NAME)) def create_bgp_instances_for_import_test(self): table = '1000' diff --git a/smoketest/scripts/cli/test_protocols_igmp-proxy.py b/smoketest/scripts/cli/test_protocols_igmp-proxy.py index a75003b12..df10442ea 100755 --- a/smoketest/scripts/cli/test_protocols_igmp-proxy.py +++ b/smoketest/scripts/cli/test_protocols_igmp-proxy.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2019-2020 VyOS maintainers and contributors +# Copyright (C) 2019-2023 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 @@ -29,14 +29,32 @@ upstream_if = 'eth1' downstream_if = 'eth2' class TestProtocolsIGMPProxy(VyOSUnitTestSHIM.TestCase): - def setUp(self): - self.cli_set(['interfaces', 'ethernet', upstream_if, 'address', '172.16.1.1/24']) + @classmethod + def setUpClass(cls): + # call base-classes classmethod + super(TestProtocolsIGMPProxy, 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, ['interfaces', 'ethernet', upstream_if, 'address', '172.16.1.1/24']) + + @classmethod + def tearDownClass(cls): + cls.cli_delete(cls, ['interfaces', 'ethernet', upstream_if, 'address']) + + # call base-classes classmethod + super(TestProtocolsIGMPProxy, cls).tearDownClass() def tearDown(self): - self.cli_delete(['interfaces', 'ethernet', upstream_if, 'address']) + # Check for running process + self.assertTrue(process_named_running(PROCESS_NAME)) + self.cli_delete(base_path) self.cli_commit() + # Check for no longer running process + self.assertFalse(process_named_running(PROCESS_NAME)) + def test_igmpproxy(self): threshold = '20' altnet = '192.0.2.0/24' @@ -74,8 +92,5 @@ class TestProtocolsIGMPProxy(VyOSUnitTestSHIM.TestCase): self.assertIn(f'whitelist {whitelist}', config) self.assertIn(f'phyint {downstream_if} downstream ratelimit 0 threshold 1', config) - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) - 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 8b423dbea..aa5f2f38c 100755 --- a/smoketest/scripts/cli/test_protocols_isis.py +++ b/smoketest/scripts/cli/test_protocols_isis.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021-2022 VyOS maintainers and contributors +# Copyright (C) 2021-2023 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -31,20 +31,25 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase): @classmethod def setUpClass(cls): cls._interfaces = Section.interfaces('ethernet') - # call base-classes classmethod super(TestProtocolsISIS, cls).setUpClass() - + # Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same + cls.daemon_pid = process_named_running(PROCESS_NAME) # 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_delete(cls, ['vrf']) def tearDown(self): + # cleanup any possible VRF mess + self.cli_delete(['vrf']) + # always destrox the entire isisd configuration to make the processes + # life as hard as possible self.cli_delete(base_path) self.cli_commit() - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + # check process health and continuity + self.assertEqual(self.daemon_pid, process_named_running(PROCESS_NAME)) def isis_base_config(self): self.cli_set(base_path + ['net', net]) @@ -333,7 +338,7 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['interface', interface]) self.cli_set(['policy', 'prefix-list', prefix_list, 'rule', '1', 'action', 'permit']) self.cli_set(['policy', 'prefix-list', prefix_list, 'rule', '1', 'prefix', prefix_list_address]) - + # Commit main ISIS changes self.cli_commit() @@ -385,4 +390,4 @@ class TestProtocolsISIS(VyOSUnitTestSHIM.TestCase): self.cli_commit() 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_mpls.py b/smoketest/scripts/cli/test_protocols_mpls.py index 06f21c6e1..0c1599f9b 100755 --- a/smoketest/scripts/cli/test_protocols_mpls.py +++ b/smoketest/scripts/cli/test_protocols_mpls.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 VyOS maintainers and contributors +# Copyright (C) 2021-2023 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 @@ -70,6 +70,9 @@ class TestProtocolsMPLS(VyOSUnitTestSHIM.TestCase): def setUpClass(cls): super(TestProtocolsMPLS, cls).setUpClass() + # Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same + cls.daemon_pid = process_named_running(PROCESS_NAME) + # ensure we can also run this test on a live system - so lets clean # out the current configuration :) cls.cli_delete(cls, base_path) @@ -77,8 +80,9 @@ class TestProtocolsMPLS(VyOSUnitTestSHIM.TestCase): def tearDown(self): self.cli_delete(base_path) self.cli_commit() - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + + # check process health and continuity + self.assertEqual(self.daemon_pid, process_named_running(PROCESS_NAME)) def test_mpls_basic(self): router_id = '1.2.3.4' diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py index a6850db71..6bffc7c45 100755 --- a/smoketest/scripts/cli/test_protocols_ospf.py +++ b/smoketest/scripts/cli/test_protocols_ospf.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021-2022 VyOS maintainers and contributors +# Copyright (C) 2021-2023 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -32,6 +32,9 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): def setUpClass(cls): super(TestProtocolsOSPF, cls).setUpClass() + # Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same + cls.daemon_pid = process_named_running(PROCESS_NAME) + 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']) @@ -45,11 +48,12 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase): super(TestProtocolsOSPF, cls).tearDownClass() def tearDown(self): - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) self.cli_delete(base_path) self.cli_commit() + # check process health and continuity + self.assertEqual(self.daemon_pid, process_named_running(PROCESS_NAME)) + def test_ospf_01_defaults(self): # commit changes self.cli_set(base_path) diff --git a/smoketest/scripts/cli/test_protocols_ospfv3.py b/smoketest/scripts/cli/test_protocols_ospfv3.py index 0d6c6c691..4ae7f05d9 100755 --- a/smoketest/scripts/cli/test_protocols_ospfv3.py +++ b/smoketest/scripts/cli/test_protocols_ospfv3.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021-2022 VyOS maintainers and contributors +# Copyright (C) 2021-2023 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -35,6 +35,9 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase): def setUpClass(cls): super(TestProtocolsOSPFv3, cls).setUpClass() + # Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same + cls.daemon_pid = process_named_running(PROCESS_NAME) + 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']) @@ -48,11 +51,12 @@ class TestProtocolsOSPFv3(VyOSUnitTestSHIM.TestCase): super(TestProtocolsOSPFv3, cls).tearDownClass() def tearDown(self): - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) self.cli_delete(base_path) self.cli_commit() + # check process health and continuity + self.assertEqual(self.daemon_pid, process_named_running(PROCESS_NAME)) + def test_ospfv3_01_basic(self): seq = '10' prefix = '2001:db8::/32' diff --git a/smoketest/scripts/cli/test_protocols_pim6.py b/smoketest/scripts/cli/test_protocols_pim6.py index e22a7c722..ba24edca2 100755 --- a/smoketest/scripts/cli/test_protocols_pim6.py +++ b/smoketest/scripts/cli/test_protocols_pim6.py @@ -25,15 +25,22 @@ PROCESS_NAME = 'pim6d' base_path = ['protocols', 'pim6'] class TestProtocolsPIMv6(VyOSUnitTestSHIM.TestCase): - def tearDown(self): - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + @classmethod + def setUpClass(cls): + # call base-classes classmethod + super(TestProtocolsPIMv6, cls).setUpClass() + # Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same + cls.daemon_pid = process_named_running(PROCESS_NAME) + # 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)) + # check process health and continuity + self.assertEqual(self.daemon_pid, process_named_running(PROCESS_NAME)) def test_pim6_01_mld_simple(self): # commit changes diff --git a/smoketest/scripts/cli/test_protocols_rip.py b/smoketest/scripts/cli/test_protocols_rip.py index 925499fc8..bfc327fd4 100755 --- a/smoketest/scripts/cli/test_protocols_rip.py +++ b/smoketest/scripts/cli/test_protocols_rip.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 VyOS maintainers and contributors +# Copyright (C) 2021-2023 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 @@ -34,7 +34,8 @@ class TestProtocolsRIP(VyOSUnitTestSHIM.TestCase): @classmethod def setUpClass(cls): super(TestProtocolsRIP, cls).setUpClass() - + # Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same + cls.daemon_pid = process_named_running(PROCESS_NAME) # ensure we can also run this test on a live system - so lets clean # out the current configuration :) cls.cli_delete(cls, base_path) @@ -65,8 +66,8 @@ class TestProtocolsRIP(VyOSUnitTestSHIM.TestCase): self.cli_delete(base_path) self.cli_commit() - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + # check process health and continuity + self.assertEqual(self.daemon_pid, process_named_running(PROCESS_NAME)) def test_rip_01_parameters(self): distance = '40' diff --git a/smoketest/scripts/cli/test_protocols_ripng.py b/smoketest/scripts/cli/test_protocols_ripng.py index 0a8ce7eef..0cfb065c6 100755 --- a/smoketest/scripts/cli/test_protocols_ripng.py +++ b/smoketest/scripts/cli/test_protocols_ripng.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 VyOS maintainers and contributors +# Copyright (C) 2021-2023 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -31,28 +31,43 @@ route_map = 'FooBar123' base_path = ['protocols', 'ripng'] class TestProtocolsRIPng(VyOSUnitTestSHIM.TestCase): - def setUp(self): - self.cli_set(['policy', 'access-list6', acl_in, 'rule', '10', 'action', 'permit']) - self.cli_set(['policy', 'access-list6', acl_in, 'rule', '10', 'source', 'any']) - self.cli_set(['policy', 'access-list6', acl_out, 'rule', '20', 'action', 'deny']) - self.cli_set(['policy', 'access-list6', acl_out, 'rule', '20', 'source', 'any']) - self.cli_set(['policy', 'prefix-list6', prefix_list_in, 'rule', '100', 'action', 'permit']) - self.cli_set(['policy', 'prefix-list6', prefix_list_in, 'rule', '100', 'prefix', '2001:db8::/32']) - self.cli_set(['policy', 'prefix-list6', prefix_list_out, 'rule', '200', 'action', 'deny']) - self.cli_set(['policy', 'prefix-list6', prefix_list_out, 'rule', '200', 'prefix', '2001:db8::/32']) - self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit']) + @classmethod + def setUpClass(cls): + # call base-classes classmethod + super(TestProtocolsRIPng, cls).setUpClass() + # Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same + cls.daemon_pid = process_named_running(PROCESS_NAME) + # 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', 'access-list6', acl_in, 'rule', '10', 'action', 'permit']) + cls.cli_set(cls, ['policy', 'access-list6', acl_in, 'rule', '10', 'source', 'any']) + cls.cli_set(cls, ['policy', 'access-list6', acl_out, 'rule', '20', 'action', 'deny']) + cls.cli_set(cls, ['policy', 'access-list6', acl_out, 'rule', '20', 'source', 'any']) + cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_in, 'rule', '100', 'action', 'permit']) + cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_in, 'rule', '100', 'prefix', '2001:db8::/32']) + cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_out, 'rule', '200', 'action', 'deny']) + cls.cli_set(cls, ['policy', 'prefix-list6', prefix_list_out, 'rule', '200', 'prefix', '2001:db8::/32']) + cls.cli_set(cls, ['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit']) + + @classmethod + def tearDownClass(cls): + # call base-classes classmethod + super(TestProtocolsRIPng, cls).tearDownClass() + + cls.cli_delete(cls, ['policy', 'access-list6', acl_in]) + cls.cli_delete(cls, ['policy', 'access-list6', acl_out]) + cls.cli_delete(cls, ['policy', 'prefix-list6', prefix_list_in]) + cls.cli_delete(cls, ['policy', 'prefix-list6', prefix_list_out]) + cls.cli_delete(cls, ['policy', 'route-map', route_map]) def tearDown(self): self.cli_delete(base_path) - self.cli_delete(['policy', 'access-list6', acl_in]) - self.cli_delete(['policy', 'access-list6', acl_out]) - self.cli_delete(['policy', 'prefix-list6', prefix_list_in]) - self.cli_delete(['policy', 'prefix-list6', prefix_list_out]) - self.cli_delete(['policy', 'route-map', route_map]) self.cli_commit() - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + # check process health and continuity + self.assertEqual(self.daemon_pid, process_named_running(PROCESS_NAME)) def test_ripng_01_parameters(self): metric = '8' diff --git a/smoketest/scripts/cli/test_protocols_rpki.py b/smoketest/scripts/cli/test_protocols_rpki.py index f4aedcbc3..ab3f076ac 100755 --- a/smoketest/scripts/cli/test_protocols_rpki.py +++ b/smoketest/scripts/cli/test_protocols_rpki.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 VyOS maintainers and contributors +# Copyright (C) 2021-2023 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -31,6 +31,16 @@ rpki_ssh_key = '/config/auth/id_rsa_rpki' rpki_ssh_pub = f'{rpki_ssh_key}.pub' class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase): + @classmethod + def setUpClass(cls): + # call base-classes classmethod + super(TestProtocolsRPKI, cls).setUpClass() + # Retrieve FRR daemon PID - it is not allowed to crash, thus PID must remain the same + cls.daemon_pid = process_named_running(PROCESS_NAME) + # 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() @@ -39,8 +49,8 @@ class TestProtocolsRPKI(VyOSUnitTestSHIM.TestCase): # frrconfig = self.getFRRconfig('rpki') # self.assertNotIn('rpki', frrconfig) - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + # check process health and continuity + self.assertEqual(self.daemon_pid, process_named_running(PROCESS_NAME)) def test_rpki(self): polling = '7200' diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py index 0f658f366..bb91eddea 100755 --- a/smoketest/scripts/cli/test_vrf.py +++ b/smoketest/scripts/cli/test_vrf.py @@ -489,4 +489,4 @@ class VRFTest(VyOSUnitTestSHIM.TestCase): if __name__ == '__main__': - unittest.main(verbosity=2, failfast=True) + unittest.main(verbosity=2) diff --git a/src/op_mode/image_installer.py b/src/op_mode/image_installer.py index aa4cf301b..df5d897b7 100755 --- a/src/op_mode/image_installer.py +++ b/src/op_mode/image_installer.py @@ -376,7 +376,7 @@ def validate_signature(file_path: str, sign_type: str) -> None: print('Signature is valid') -def image_fetch(image_path: str) -> Path: +def image_fetch(image_path: str, no_prompt: bool = False) -> Path: """Fetch an ISO image Args: @@ -389,13 +389,14 @@ def image_fetch(image_path: str) -> Path: # check a type of path if urlparse(image_path).scheme: # download an image - download(ISO_DOWNLOAD_PATH, image_path, True, True) + download(ISO_DOWNLOAD_PATH, image_path, True, True, + raise_error=True) # download a signature sign_file = (False, '') for sign_type in ['minisig', 'asc']: try: download(f'{ISO_DOWNLOAD_PATH}.{sign_type}', - f'{image_path}.{sign_type}') + f'{image_path}.{sign_type}', raise_error=True) sign_file = (True, sign_type) break except Exception: @@ -404,7 +405,8 @@ def image_fetch(image_path: str) -> Path: if sign_file[0]: validate_signature(ISO_DOWNLOAD_PATH, sign_file[1]) else: - if not ask_yes_no(MSG_WARN_ISO_SIGN_UNAVAL, default=False): + if (not no_prompt and + not ask_yes_no(MSG_WARN_ISO_SIGN_UNAVAL, default=False)): cleanup() exit(MSG_INFO_INSTALL_EXIT) @@ -629,7 +631,7 @@ def install_image() -> None: @compat.grub_cfg_update -def add_image(image_path: str) -> None: +def add_image(image_path: str, no_prompt: bool = False) -> None: """Add a new image Args: @@ -639,7 +641,7 @@ def add_image(image_path: str) -> None: exit(MSG_ERR_LIVE) # fetch an image - iso_path: Path = image_fetch(image_path) + iso_path: Path = image_fetch(image_path, no_prompt) try: # mount an ISO Path(DIR_ISO_MOUNT).mkdir(mode=0o755, parents=True) @@ -668,8 +670,12 @@ def add_image(image_path: str) -> None: raise compat.DowngradingImageTools( f'Adding image would downgrade image tools to v.{cfg_ver}; disallowed') - image_name: str = ask_input(MSG_INPUT_IMAGE_NAME, version_name) - set_as_default: bool = ask_yes_no(MSG_INPUT_IMAGE_DEFAULT, default=True) + if not no_prompt: + image_name: str = ask_input(MSG_INPUT_IMAGE_NAME, version_name) + set_as_default: bool = ask_yes_no(MSG_INPUT_IMAGE_DEFAULT, default=True) + else: + image_name: str = version_name + set_as_default: bool = True # find target directory root_dir: str = disk.find_persistence() @@ -678,7 +684,7 @@ def add_image(image_path: str) -> None: # create all the rest in a single step target_config_dir: str = f'{root_dir}/boot/{image_name}/rw/opt/vyatta/etc/config/' # copy config - if migrate_config(): + if no_prompt or migrate_config(): print('Copying configuration directory') # copytree preserves perms but not ownership: Path(target_config_dir).mkdir(parents=True) @@ -727,8 +733,10 @@ def parse_arguments() -> Namespace: choices=['install', 'add'], required=True, help='action to perform with an image') + parser.add_argument('--no-prompt', action='store_true', + help='perform action non-interactively') parser.add_argument( - '--image_path', + '--image-path', help='a path (HTTP or local file) to an image that needs to be installed' ) # parser.add_argument('--image_new_name', help='a new name for image') @@ -746,7 +754,7 @@ if __name__ == '__main__': if args.action == 'install': install_image() if args.action == 'add': - add_image(args.image_path) + add_image(args.image_path, args.no_prompt) exit() diff --git a/src/op_mode/image_manager.py b/src/op_mode/image_manager.py index e4b2f4833..e75485f9f 100755 --- a/src/op_mode/image_manager.py +++ b/src/op_mode/image_manager.py @@ -36,7 +36,7 @@ MSG_DELETE_IMAGE_DEFAULT: str = 'Default image cannot be deleted; set another im @compat.grub_cfg_update def delete_image(image_name: Optional[str] = None, - prompt: bool = True) -> None: + no_prompt: bool = False) -> None: """Remove installed image files and boot entry Args: @@ -44,7 +44,7 @@ def delete_image(image_name: Optional[str] = None, """ available_images: list[str] = grub.version_list() if image_name is None: - if not prompt: + if no_prompt: exit('An image name is required for delete action') else: image_name = select_entry(available_images, @@ -60,8 +60,9 @@ def delete_image(image_name: Optional[str] = None, if not persistence_storage: exit('Persistence storage cannot be found') - if not ask_yes_no(f'Do you really want to delete the image {image_name}?', - default=False): + if (not no_prompt and + not ask_yes_no(f'Do you really want to delete the image {image_name}?', + default=False)): exit() # remove files and menu entry @@ -171,11 +172,13 @@ def parse_arguments() -> Namespace: choices=['delete', 'set', 'rename', 'list'], required=True, help='action to perform with an image') + parser.add_argument('--no-prompt', action='store_true', + help='perform action non-interactively') parser.add_argument( - '--image_name', + '--image-name', help= 'a name of an image to add, delete, install, rename, or set as default') - parser.add_argument('--image_new_name', help='a new name for image') + parser.add_argument('--image-new-name', help='a new name for image') args: Namespace = parser.parse_args() # Validate arguments if args.action == 'rename' and (not args.image_name or @@ -189,7 +192,7 @@ if __name__ == '__main__': try: args: Namespace = parse_arguments() if args.action == 'delete': - delete_image(args.image_name) + delete_image(args.image_name, args.no_prompt) if args.action == 'set': set_image(args.image_name) if args.action == 'rename': diff --git a/src/system/grub_update.py b/src/system/grub_update.py index 366a85344..3c851f0e0 100644 --- a/src/system/grub_update.py +++ b/src/system/grub_update.py @@ -41,6 +41,9 @@ if __name__ == '__main__': if image.is_live_boot(): exit(0) + if image.is_running_as_container(): + exit(0) + # Skip everything if update is not required if not cfg_check_update(): exit(0) |