diff options
| author | John Estabrook <jestabro@vyos.io> | 2024-01-22 21:01:00 -0600 | 
|---|---|---|
| committer | John Estabrook <jestabro@vyos.io> | 2024-01-23 10:32:15 -0600 | 
| commit | 1b1569d5b88a20994fc65fd529f8103db371bf3f (patch) | |
| tree | f661f4782f27c9ea03c49fcabe288e4e361cc4bd /python | |
| parent | 4c2d4519277bc4cbe964a37160b93c31cdc77309 (diff) | |
| download | vyos-1x-1b1569d5b88a20994fc65fd529f8103db371bf3f.tar.gz vyos-1x-1b1569d5b88a20994fc65fd529f8103db371bf3f.zip | |
image-tools: T5980: add support for configurable kernel boot options
Diffstat (limited to 'python')
| -rw-r--r-- | python/vyos/system/compat.py | 8 | ||||
| -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 | 
4 files changed, 104 insertions, 8 deletions
| diff --git a/python/vyos/system/compat.py b/python/vyos/system/compat.py index 436da14e8..626ce0067 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 @@ -246,13 +246,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 | 
