diff options
-rw-r--r-- | data/templates/frr/bfdd.frr.j2 | 6 | ||||
-rw-r--r-- | data/templates/grub/grub_vyos_version.j2 | 9 | ||||
-rw-r--r-- | interface-definitions/include/bfd/common.xml.i | 12 | ||||
-rw-r--r-- | interface-definitions/system_option.xml.in | 13 | ||||
-rw-r--r-- | python/vyos/ifconfig/ethernet.py | 2 | ||||
-rw-r--r-- | python/vyos/remote.py | 2 | ||||
-rw-r--r-- | python/vyos/system/compat.py | 15 | ||||
-rw-r--r-- | python/vyos/system/grub.py | 61 | ||||
-rw-r--r-- | python/vyos/system/grub_util.py | 30 | ||||
-rw-r--r-- | python/vyos/system/image.py | 13 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_protocols_bfd.py | 10 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_service_dhcp-server.py | 3 | ||||
-rwxr-xr-x | src/conf_mode/protocols_bfd.py | 3 | ||||
-rwxr-xr-x | src/conf_mode/service_dhcp-server.py | 28 | ||||
-rwxr-xr-x | src/conf_mode/system_option.py | 11 | ||||
-rwxr-xr-x | src/migration-scripts/https/5-to-6 | 4 | ||||
-rwxr-xr-x | src/op_mode/image_installer.py | 12 | ||||
-rwxr-xr-x | src/op_mode/show_openvpn.py | 6 |
18 files changed, 203 insertions, 37 deletions
diff --git a/data/templates/frr/bfdd.frr.j2 b/data/templates/frr/bfdd.frr.j2 index c4adeb402..f3303e401 100644 --- a/data/templates/frr/bfdd.frr.j2 +++ b/data/templates/frr/bfdd.frr.j2 @@ -13,6 +13,9 @@ bfd {% if profile_config.echo_mode is vyos_defined %} echo-mode {% endif %} +{% if profile_config.minimum_ttl is vyos_defined %} + minimum-ttl {{ profile_config.minimum_ttl }} +{% endif %} {% if profile_config.passive is vyos_defined %} passive-mode {% endif %} @@ -38,6 +41,9 @@ bfd {% if peer_config.echo_mode is vyos_defined %} echo-mode {% endif %} +{% if peer_config.minimum_ttl is vyos_defined %} + minimum-ttl {{ peer_config.minimum_ttl }} +{% endif %} {% if peer_config.passive is vyos_defined %} passive-mode {% endif %} diff --git a/data/templates/grub/grub_vyos_version.j2 b/data/templates/grub/grub_vyos_version.j2 index 62688e68b..de85f1419 100644 --- a/data/templates/grub/grub_vyos_version.j2 +++ b/data/templates/grub/grub_vyos_version.j2 @@ -1,5 +1,10 @@ -{% set boot_opts_default = "boot=live rootdelay=5 noautologin net.ifnames=0 biosdevname=0 vyos-union=/boot/" + version_name %} -{% if boot_opts != '' %} +{% if boot_opts_config is vyos_defined %} +{% if boot_opts_config %} +{% set boot_opts_rendered = boot_opts_default + " " + boot_opts_config %} +{% else %} +{% set boot_opts_rendered = boot_opts_default %} +{% endif %} +{% elif boot_opts != '' %} {% set boot_opts_rendered = boot_opts %} {% else %} {% set boot_opts_rendered = boot_opts_default %} diff --git a/interface-definitions/include/bfd/common.xml.i b/interface-definitions/include/bfd/common.xml.i index 126ab9b9a..8e6999d28 100644 --- a/interface-definitions/include/bfd/common.xml.i +++ b/interface-definitions/include/bfd/common.xml.i @@ -63,6 +63,18 @@ </leafNode> </children> </node> +<leafNode name="minimum-ttl"> + <properties> + <help>Expect packets with at least this TTL</help> + <valueHelp> + <format>u32:1-254</format> + <description>Minimum TTL expected</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-254"/> + </constraint> + </properties> +</leafNode> <leafNode name="passive"> <properties> <help>Do not attempt to start sessions</help> diff --git a/interface-definitions/system_option.xml.in b/interface-definitions/system_option.xml.in index adb45bdcc..602d7d100 100644 --- a/interface-definitions/system_option.xml.in +++ b/interface-definitions/system_option.xml.in @@ -32,6 +32,19 @@ <constraintErrorMessage>Must be ignore, reboot, or poweroff</constraintErrorMessage> </properties> </leafNode> + <node name="kernel"> + <properties> + <help>Kernel boot parameters</help> + </properties> + <children> + <leafNode name="disable-mitigations"> + <properties> + <help>Disable all optional CPU mitigations</help> + <valueless/> + </properties> + </leafNode> + </children> + </node> <leafNode name="keyboard-layout"> <properties> <help>System keyboard layout, type ISO2</help> diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py index dde87149d..c3f5bbf47 100644 --- a/python/vyos/ifconfig/ethernet.py +++ b/python/vyos/ifconfig/ethernet.py @@ -452,7 +452,7 @@ class EthernetIf(Interface): self.set_gso(dict_search('offload.gso', config) != None) # GSO (generic segmentation offload) - self.set_hw_tc_offload(dict_search('offload.hw-tc-offload', config) != None) + self.set_hw_tc_offload(dict_search('offload.hw_tc_offload', config) != None) # LRO (large receive offload) self.set_lro(dict_search('offload.lro', config) != None) diff --git a/python/vyos/remote.py b/python/vyos/remote.py index b1efcd10b..830770d11 100644 --- a/python/vyos/remote.py +++ b/python/vyos/remote.py @@ -148,7 +148,7 @@ class FtpC: # Almost all FTP servers support the `SIZE' command. size = conn.size(self.path) if self.check_space: - check_storage(path, size) + check_storage(location, size) # No progressbar if we can't determine the size or if the file is too small. if self.progressbar and size and size > CHUNK_SIZE: with Progressbar(CHUNK_SIZE / size) as p: diff --git a/python/vyos/system/compat.py b/python/vyos/system/compat.py index 436da14e8..37b834ad6 100644 --- a/python/vyos/system/compat.py +++ b/python/vyos/system/compat.py @@ -1,4 +1,4 @@ -# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -170,9 +170,12 @@ def prune_vyos_versions(root_dir: str = '') -> None: if not root_dir: root_dir = disk.find_persistence() - for version in grub.version_list(): + version_files = Path(f'{root_dir}/{grub.GRUB_DIR_VYOS_VERS}').glob('*.cfg') + + for file in version_files: + version = Path(file).stem if not Path(f'{root_dir}/boot/{version}').is_dir(): - grub.version_del(version) + grub.version_del(version, root_dir) def update_cfg_ver(root_dir:str = '') -> int: @@ -246,13 +249,17 @@ def update_version_list(root_dir: str = '') -> list[dict]: menu_entries = list(filter(lambda x: x.get('version') != ver, menu_entries)) + # reset boot_opts in case of config update + for entry in menu_entries: + entry['boot_opts'] = grub.get_boot_opts(entry['version']) + add = list(set(current_versions) - set(menu_versions)) for ver in add: last = menu_entries[0].get('version') new = deepcopy(list(filter(lambda x: x.get('version') == last, menu_entries))) for e in new: - boot_opts = e.get('boot_opts').replace(last, ver) + boot_opts = grub.get_boot_opts(ver) e.update({'version': ver, 'boot_opts': boot_opts}) menu_entries = new + menu_entries diff --git a/python/vyos/system/grub.py b/python/vyos/system/grub.py index 781962dd0..2e8b20972 100644 --- a/python/vyos/system/grub.py +++ b/python/vyos/system/grub.py @@ -1,4 +1,4 @@ -# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -45,10 +45,14 @@ TMPL_GRUB_MODULES: str = 'grub/grub_modules.j2' TMPL_GRUB_OPTS: str = 'grub/grub_options.j2' TMPL_GRUB_COMMON: str = 'grub/grub_common.j2' +# default boot options +BOOT_OPTS_STEM: str = 'boot=live rootdelay=5 noautologin net.ifnames=0 biosdevname=0 vyos-union=/boot/' + # prepare regexes REGEX_GRUB_VARS: str = r'^set (?P<variable_name>.+)=[\'"]?(?P<variable_value>.*)(?<![\'"])[\'"]?$' REGEX_GRUB_MODULES: str = r'^insmod (?P<module_name>.+)$' REGEX_KERNEL_CMDLINE: str = r'^BOOT_IMAGE=/(?P<boot_type>boot|live)/((?P<image_version>.+)/)?vmlinuz.*$' +REGEX_GRUB_BOOT_OPTS: str = r'^\s*set boot_opts="(?P<boot_opts>[^$]+)"$' def install(drive_path: str, boot_dir: str, efi_dir: str, id: str = 'VyOS') -> None: @@ -95,7 +99,8 @@ def gen_version_uuid(version_name: str) -> str: def version_add(version_name: str, root_dir: str = '', - boot_opts: str = '') -> None: + boot_opts: str = '', + boot_opts_config = None) -> None: """Add a new VyOS version to GRUB loader configuration Args: @@ -112,7 +117,9 @@ def version_add(version_name: str, version_config, TMPL_VYOS_VERSION, { 'version_name': version_name, 'version_uuid': gen_version_uuid(version_name), - 'boot_opts': boot_opts + 'boot_opts_default': BOOT_OPTS_STEM + version_name, + 'boot_opts': boot_opts, + 'boot_opts_config': boot_opts_config }) @@ -294,12 +301,43 @@ def vars_write(grub_cfg: str, grub_vars: dict[str, str]) -> None: """ render(grub_cfg, TMPL_GRUB_VARS, {'vars': grub_vars}) +def get_boot_opts(version_name: str, root_dir: str = '') -> str: + """Read boot_opts setting from version file; return default setting on + any failure. + + Args: + version_name (str): version name + root_dir (str, optional): an optional path to the root directory. + Defaults to empty. + """ + if not root_dir: + root_dir = disk.find_persistence() + + boot_opts_default: str = BOOT_OPTS_STEM + version_name + boot_opts: str = '' + regex_filter = re_compile(REGEX_GRUB_BOOT_OPTS) + version_config: str = f'{root_dir}/{GRUB_DIR_VYOS_VERS}/{version_name}.cfg' + try: + config_text: list[str] = Path(version_config).read_text().splitlines() + except FileNotFoundError: + return boot_opts_default + for line in config_text: + search_result = regex_filter.fullmatch(line) + if search_result: + search_dict = search_result.groupdict() + boot_opts = search_dict.get('boot_opts', '') + break + + if not boot_opts: + boot_opts = boot_opts_default + + return boot_opts def set_default(version_name: str, root_dir: str = '') -> None: """Set version as default boot entry Args: - version_name (str): versio name + version_name (str): version name root_dir (str, optional): an optional path to the root directory. Defaults to empty. """ @@ -369,3 +407,18 @@ def set_console_speed(console_speed: str, root_dir: str = '') -> None: vars_current: dict[str, str] = vars_read(vars_file) vars_current['console_speed'] = str(console_speed) vars_write(vars_file, vars_current) + +def set_kernel_cmdline_options(cmdline_options: str, version_name: str, + root_dir: str = '') -> None: + """Write additional cmdline options to GRUB configuration + + Args: + cmdline_options (str): cmdline options to add to default boot line + version_name (str): image version name + root_dir (str, optional): an optional path to the root directory. + """ + if not root_dir: + root_dir = disk.find_persistence() + + version_add(version_name=version_name, root_dir=root_dir, + boot_opts_config=cmdline_options) diff --git a/python/vyos/system/grub_util.py b/python/vyos/system/grub_util.py index 9e79d41d4..4a3d8795e 100644 --- a/python/vyos/system/grub_util.py +++ b/python/vyos/system/grub_util.py @@ -13,7 +13,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with this library. If not, see <http://www.gnu.org/licenses/>. -from vyos.system import disk, grub, compat +from vyos.system import disk, grub, image, compat @compat.grub_cfg_update def set_console_speed(console_speed: str, root_dir: str = '') -> None: @@ -29,6 +29,7 @@ def set_console_speed(console_speed: str, root_dir: str = '') -> None: grub.set_console_speed(console_speed, root_dir) +@image.if_not_live_boot def update_console_speed(console_speed: str, root_dir: str = '') -> None: """Update console_speed if different from current value""" @@ -40,3 +41,30 @@ def update_console_speed(console_speed: str, root_dir: str = '') -> None: console_speed_current = vars_current.get('console_speed', None) if console_speed != console_speed_current: set_console_speed(console_speed, root_dir) + +@compat.grub_cfg_update +def set_kernel_cmdline_options(cmdline_options: str, version: str = '', + root_dir: str = '') -> None: + """Write Kernel CLI cmdline options to GRUB configuration""" + if not root_dir: + root_dir = disk.find_persistence() + + if not version: + version = image.get_running_image() + + grub.set_kernel_cmdline_options(cmdline_options, version, root_dir) + +@image.if_not_live_boot +def update_kernel_cmdline_options(cmdline_options: str, + root_dir: str = '') -> None: + """Update Kernel custom cmdline options""" + if not root_dir: + root_dir = disk.find_persistence() + + version = image.get_running_image() + + boot_opts_current = grub.get_boot_opts(version, root_dir) + boot_opts_proposed = grub.BOOT_OPTS_STEM + f'{version} {cmdline_options}' + + if boot_opts_proposed != boot_opts_current: + set_kernel_cmdline_options(cmdline_options, version, root_dir) diff --git a/python/vyos/system/image.py b/python/vyos/system/image.py index 514275654..5460e6a36 100644 --- a/python/vyos/system/image.py +++ b/python/vyos/system/image.py @@ -1,4 +1,4 @@ -# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -15,6 +15,7 @@ from pathlib import Path from re import compile as re_compile +from functools import wraps from tempfile import TemporaryDirectory from typing import TypedDict @@ -262,6 +263,16 @@ def is_live_boot() -> bool: return True return False +def if_not_live_boot(func): + """Decorator to call function only if not live boot""" + @wraps(func) + def wrapper(*args, **kwargs): + if not is_live_boot(): + ret = func(*args, **kwargs) + return ret + return None + return wrapper + def is_running_as_container() -> bool: if Path('/.dockerenv').exists(): return True diff --git a/smoketest/scripts/cli/test_protocols_bfd.py b/smoketest/scripts/cli/test_protocols_bfd.py index f209eae3a..716d0a806 100755 --- a/smoketest/scripts/cli/test_protocols_bfd.py +++ b/smoketest/scripts/cli/test_protocols_bfd.py @@ -32,6 +32,7 @@ peers = { 'multihop' : '', 'source_addr': '192.0.2.254', 'profile' : 'foo-bar-baz', + 'minimum_ttl': '20', }, '192.0.2.20' : { 'echo_mode' : '', @@ -63,6 +64,7 @@ profiles = { 'intv_rx' : '222', 'intv_tx' : '333', 'shutdown' : '', + 'minimum_ttl': '40', }, 'foo-bar-baz' : { 'intv_mult' : '4', @@ -109,6 +111,8 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['peer', peer, 'interval', 'receive', peer_config["intv_rx"]]) if 'intv_tx' in peer_config: self.cli_set(base_path + ['peer', peer, 'interval', 'transmit', peer_config["intv_tx"]]) + if 'minimum_ttl' in peer_config: + self.cli_set(base_path + ['peer', peer, 'minimum-ttl', peer_config["minimum_ttl"]]) if 'multihop' in peer_config: self.cli_set(base_path + ['peer', peer, 'multihop']) if 'passive' in peer_config: @@ -152,6 +156,8 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase): self.assertIn(f'receive-interval {peer_config["intv_rx"]}', peerconfig) if 'intv_tx' in peer_config: self.assertIn(f'transmit-interval {peer_config["intv_tx"]}', peerconfig) + if 'minimum_ttl' in peer_config: + self.assertIn(f'minimum-ttl {peer_config["minimum_ttl"]}', peerconfig) if 'passive' in peer_config: self.assertIn(f'passive-mode', peerconfig) if 'shutdown' in peer_config: @@ -173,6 +179,8 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['profile', profile, 'interval', 'receive', profile_config["intv_rx"]]) if 'intv_tx' in profile_config: self.cli_set(base_path + ['profile', profile, 'interval', 'transmit', profile_config["intv_tx"]]) + if 'minimum_ttl' in profile_config: + self.cli_set(base_path + ['profile', profile, 'minimum-ttl', profile_config["minimum_ttl"]]) if 'passive' in profile_config: self.cli_set(base_path + ['profile', profile, 'passive']) if 'shutdown' in profile_config: @@ -210,6 +218,8 @@ class TestProtocolsBFD(VyOSUnitTestSHIM.TestCase): 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) + if 'minimum_ttl' in profile_config: + self.assertIn(f' minimum-ttl {profile_config["minimum_ttl"]}', config) if 'passive' in profile_config: self.assertIn(f' passive-mode', config) if 'shutdown' in profile_config: diff --git a/smoketest/scripts/cli/test_service_dhcp-server.py b/smoketest/scripts/cli/test_service_dhcp-server.py index 849a411f1..194289567 100755 --- a/smoketest/scripts/cli/test_service_dhcp-server.py +++ b/smoketest/scripts/cli/test_service_dhcp-server.py @@ -387,6 +387,9 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): self.cli_set(pool + ['static-mapping', 'dupe1', 'ip-address', inc_ip(subnet, 10)]) with self.assertRaises(ConfigSessionError): self.cli_commit() + # Should allow disabled duplicate + self.cli_set(pool + ['static-mapping', 'dupe1', 'disable']) + self.cli_commit() self.cli_delete(pool + ['static-mapping', 'dupe1']) # cannot have mappings with duplicate MAC addresses diff --git a/src/conf_mode/protocols_bfd.py b/src/conf_mode/protocols_bfd.py index dab784662..37421efb4 100755 --- a/src/conf_mode/protocols_bfd.py +++ b/src/conf_mode/protocols_bfd.py @@ -72,6 +72,9 @@ def verify(bfd): if 'source' in peer_config and 'interface' in peer_config['source']: raise ConfigError('BFD multihop and source interface cannot be used together') + if 'minimum_ttl' in peer_config and 'multihop' not in peer_config: + raise ConfigError('Minimum TTL is only available for multihop BFD sessions!') + if 'profile' in peer_config: profile_name = peer_config['profile'] if 'profile' not in bfd or profile_name not in bfd['profile']: diff --git a/src/conf_mode/service_dhcp-server.py b/src/conf_mode/service_dhcp-server.py index 9632b91fc..91ea354b6 100755 --- a/src/conf_mode/service_dhcp-server.py +++ b/src/conf_mode/service_dhcp-server.py @@ -246,19 +246,21 @@ def verify(dhcp): raise ConfigError(f'Either MAC address or Client identifier (DUID) is required for ' f'static mapping "{mapping}" within shared-network "{network}, {subnet}"!') - if mapping_config['ip_address'] in used_ips: - raise ConfigError(f'Configured IP address for static mapping "{mapping}" already exists on another static mapping') - used_ips.append(mapping_config['ip_address']) - - if 'mac' in mapping_config: - if mapping_config['mac'] in used_mac: - raise ConfigError(f'Configured MAC address for static mapping "{mapping}" already exists on another static mapping') - used_mac.append(mapping_config['mac']) - - if 'duid' in mapping_config: - if mapping_config['duid'] in used_duid: - raise ConfigError(f'Configured DUID for static mapping "{mapping}" already exists on another static mapping') - used_duid.append(mapping_config['duid']) + if 'disable' not in mapping_config: + if mapping_config['ip_address'] in used_ips: + raise ConfigError(f'Configured IP address for static mapping "{mapping}" already exists on another static mapping') + used_ips.append(mapping_config['ip_address']) + + if 'disable' not in mapping_config: + if 'mac' in mapping_config: + if mapping_config['mac'] in used_mac: + raise ConfigError(f'Configured MAC address for static mapping "{mapping}" already exists on another static mapping') + used_mac.append(mapping_config['mac']) + + if 'duid' in mapping_config: + if mapping_config['duid'] in used_duid: + raise ConfigError(f'Configured DUID for static mapping "{mapping}" already exists on another static mapping') + used_duid.append(mapping_config['duid']) # There must be one subnet connected to a listen interface. # This only counts if the network itself is not disabled! diff --git a/src/conf_mode/system_option.py b/src/conf_mode/system_option.py index d92121b3d..3b5b67437 100755 --- a/src/conf_mode/system_option.py +++ b/src/conf_mode/system_option.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2019-2023 VyOS maintainers and contributors +# Copyright (C) 2019-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 @@ -22,6 +22,7 @@ from time import sleep from vyos.config import Config from vyos.configverify import verify_source_interface +from vyos.system import grub_util from vyos.template import render from vyos.utils.process import cmd from vyos.utils.process import is_systemd_service_running @@ -39,7 +40,6 @@ time_format_to_locale = { '24-hour': 'en_GB.UTF-8' } - def get_config(config=None): if config: conf = config @@ -87,6 +87,13 @@ def verify(options): def generate(options): render(curlrc_config, 'system/curlrc.j2', options) render(ssh_config, 'system/ssh_config.j2', options) + + cmdline_options = [] + if 'kernel' in options: + if 'disable_mitigations' in options['kernel']: + cmdline_options.append('mitigations=off') + grub_util.update_kernel_cmdline_options(' '.join(cmdline_options)) + return None def apply(options): diff --git a/src/migration-scripts/https/5-to-6 b/src/migration-scripts/https/5-to-6 index 6d6efd32c..0090adccb 100755 --- a/src/migration-scripts/https/5-to-6 +++ b/src/migration-scripts/https/5-to-6 @@ -43,11 +43,11 @@ if not config.exists(base): # Nothing to do sys.exit(0) -if config.exists(base + ['certificates']): +if config.exists(base + ['certificates', 'certbot']): # both domain-name and email must be set on CLI - ensured by previous verify() domain_names = config.return_values(base + ['certificates', 'certbot', 'domain-name']) email = config.return_value(base + ['certificates', 'certbot', 'email']) - config.delete(base + ['certificates']) + config.delete(base + ['certificates', 'certbot']) # Set default certname based on domain-name cert_name = 'https-' + domain_names[0].split('.')[0] diff --git a/src/op_mode/image_installer.py b/src/op_mode/image_installer.py index fad6face7..501e9b804 100755 --- a/src/op_mode/image_installer.py +++ b/src/op_mode/image_installer.py @@ -69,8 +69,8 @@ MSG_WARN_ISO_SIGN_INVALID: str = 'Signature is not valid. Do you want to continu MSG_WARN_ISO_SIGN_UNAVAL: str = 'Signature is not available. Do you want to continue with installation?' MSG_WARN_ROOT_SIZE_TOOBIG: str = 'The size is too big. Try again.' MSG_WARN_ROOT_SIZE_TOOSMALL: str = 'The size is too small. Try again' -MSG_WARN_IMAGE_NAME_WRONG: str = 'The suggested name is unsupported!\n' -'It must be between 1 and 32 characters long and contains only the next characters: .+-_ a-z A-Z 0-9' +MSG_WARN_IMAGE_NAME_WRONG: str = 'The suggested name is unsupported!\n'\ +'It must be between 1 and 64 characters long and contains only the next characters: .+-_ a-z A-Z 0-9' CONST_MIN_DISK_SIZE: int = 2147483648 # 2 GB CONST_MIN_ROOT_SIZE: int = 1610612736 # 1.5 GB # a reserved space: 2MB for header, 1 MB for BIOS partition, 256 MB for EFI @@ -812,7 +812,11 @@ def add_image(image_path: str, vrf: str = None, username: str = '', f'Adding image would downgrade image tools to v.{cfg_ver}; disallowed') if not no_prompt: - image_name: str = ask_input(MSG_INPUT_IMAGE_NAME, version_name) + while True: + image_name: str = ask_input(MSG_INPUT_IMAGE_NAME, version_name) + if image.validate_name(image_name): + break + print(MSG_WARN_IMAGE_NAME_WRONG) set_as_default: bool = ask_yes_no(MSG_INPUT_IMAGE_DEFAULT, default=True) else: image_name: str = version_name @@ -867,7 +871,7 @@ def add_image(image_path: str, vrf: str = None, username: str = '', except Exception as err: # unmount an ISO and cleanup cleanup([str(iso_path)]) - exit(f'Whooops: {err}') + exit(f'Error: {err}') def parse_arguments() -> Namespace: diff --git a/src/op_mode/show_openvpn.py b/src/op_mode/show_openvpn.py index e29e594a5..6abafc8b6 100755 --- a/src/op_mode/show_openvpn.py +++ b/src/op_mode/show_openvpn.py @@ -63,9 +63,11 @@ def get_vpn_tunnel_address(peer, interface): # filter out subnet entries lst = [l for l in lst[1:] if '/' not in l.split(',')[0]] - tunnel_ip = lst[0].split(',')[0] + if lst: + tunnel_ip = lst[0].split(',')[0] + return tunnel_ip - return tunnel_ip + return 'n/a' def get_status(mode, interface): status_file = '/var/run/openvpn/{}.status'.format(interface) |