From be1ba5be08a329a040485eb9ef8360f1ed8370b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hozza?= Date: Mon, 19 Feb 2024 17:34:12 +0100 Subject: [PATCH] Stages/grub2: extend default config options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the stage to allow explicitly configuring more grub2 default config options. Preserve the defaults for options which were previously hard-coded. Extend the stage unit test to verify setting of the new grub2 default config options. Related to https://issues.redhat.com/browse/RHEL-19583 Signed-off-by: Tomáš Hozza --- stages/org.osbuild.grub2 | 47 +++++++++++++++++++++++++++++++++++++-- stages/test/test_grub2.py | 34 ++++++++++++++++++++++++---- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/stages/org.osbuild.grub2 b/stages/org.osbuild.grub2 index 72e6e1a0..5fb784fe 100755 --- a/stages/org.osbuild.grub2 +++ b/stages/org.osbuild.grub2 @@ -202,11 +202,24 @@ SCHEMA = """ "description": "Default boot entry", "type": "string" }, + "disable_recovery": { + "type": "boolean" + }, + "disable_submenu": { + "type": "boolean" + }, + "distributor": { + "description": "Name of the distributor", + "type": "string" + }, + "terminal": { + "$ref": "#/definitions/terminal" + }, "terminal_input": { - "$ref": "#/definitions/terminal" + "$ref": "#/definitions/terminal" }, "terminal_output": { - "$ref": "#/definitions/terminal" + "$ref": "#/definitions/terminal" }, "timeout": { "description": "Timeout in seconds", @@ -214,6 +227,10 @@ SCHEMA = """ "minimum": 0, "default": 0 }, + "timeout_style": { + "type": "string", + "enum": ["hidden", "menu", "countdown"] + }, "serial": { "description": "The command to configure the serial console", "type": "string" @@ -371,10 +388,15 @@ class GrubConfig: self.ignition = False self.greenboot = False self.kernel_opts = "" + self.disable_recovery = None + self.disable_submenu = None + self.distributor = None self.serial = "" + self.terminal = None self.terminal_input = None self.terminal_output = None self.timeout = 0 + self.timeout_style = None @property def grubfs(self): @@ -472,9 +494,22 @@ class GrubConfig: "GRUB_ENABLE_BLSCFG=true\n" ) + if self.disable_recovery is not None: + data += f"GRUB_DISABLE_RECOVERY={str(self.disable_recovery).lower()}\n" + + if self.disable_submenu is not None: + data += f"GRUB_DISABLE_SUBMENU={str(self.disable_submenu).lower()}\n" + + if self.distributor: + data += f'GRUB_DISTRIBUTOR="{self.distributor}"\n' + if self.serial: data += f'GRUB_SERIAL_COMMAND="{self.serial}"\n' + if self.terminal: + val = " ".join(self.terminal) + data += f'GRUB_TERMINAL="{val}"\n' + if self.terminal_input: val = " ".join(self.terminal_input) data += f'GRUB_TERMINAL_INPUT="{val}"\n' @@ -483,6 +518,9 @@ class GrubConfig: val = " ".join(self.terminal_output) data += f'GRUB_TERMINAL_OUTPUT="{val}"\n' + if self.timeout_style: + data += f'GRUB_TIMEOUT_STYLE={self.timeout_style}\n' + if self.default_entry is not None: data += f'GRUB_DEFAULT={self.default_entry}\n' @@ -525,10 +563,15 @@ def main(tree, options): config.ignition = ignition config.greenboot = options.get("greenboot", False) config.kernel_opts = kernel_opts + config.disable_recovery = cfg.get("disable_recovery") + config.disable_submenu = cfg.get("disable_submenu") + config.distributor = cfg.get("distributor") config.serial = cfg.get("serial") + config.terminal = cfg.get("terminal") config.terminal_input = cfg.get("terminal_input") config.terminal_output = cfg.get("terminal_output") config.timeout = cfg.get("timeout", 0) + config.timeout_style = cfg.get("timeout_style") config.default_entry = cfg.get("default") # Create the configuration file that determines how grub.cfg is generated. diff --git a/stages/test/test_grub2.py b/stages/test/test_grub2.py index 5d664400..91a8d987 100644 --- a/stages/test/test_grub2.py +++ b/stages/test/test_grub2.py @@ -33,9 +33,9 @@ def test_grub2_copy_efi_data(tmp_path, stage_module): # Test that the /etc/default/grub file is created with the correct content -@pytest.mark.parametrize("test_data,expected_conf", [ +@pytest.mark.parametrize("test_data,kernel_opts,expected_conf", [ # default - ({}, """GRUB_CMDLINE_LINUX="" + ({}, "", """GRUB_CMDLINE_LINUX="" GRUB_TIMEOUT=0 GRUB_ENABLE_BLSCFG=true """), @@ -46,16 +46,41 @@ GRUB_ENABLE_BLSCFG=true "terminal_input": ["console"], "terminal_output": ["serial"], "serial": "serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1", - }, """GRUB_CMDLINE_LINUX="" + }, "", """GRUB_CMDLINE_LINUX="" GRUB_TIMEOUT=10 GRUB_ENABLE_BLSCFG=true GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1" GRUB_TERMINAL_INPUT="console" GRUB_TERMINAL_OUTPUT="serial" GRUB_DEFAULT=0 +"""), + # custom (Azure) + ({ + "default": "saved", + "disable_submenu": True, + "disable_recovery": True, + "distributor": "$(sed 's, release .*$,,g' /etc/system-release)", + "serial": "serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1", + "terminal": ["serial", "console"], + "terminal_output": ["console"], + "timeout": 10, + "timeout_style": "countdown", + }, + "loglevel=3 crashkernel=auto console=tty1 console=ttyS0 earlyprintk=ttyS0 rootdelay=300", + """GRUB_CMDLINE_LINUX="loglevel=3 crashkernel=auto console=tty1 console=ttyS0 earlyprintk=ttyS0 rootdelay=300" +GRUB_TIMEOUT=10 +GRUB_ENABLE_BLSCFG=true +GRUB_DISABLE_RECOVERY=true +GRUB_DISABLE_SUBMENU=true +GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)" +GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1" +GRUB_TERMINAL="serial console" +GRUB_TERMINAL_OUTPUT="console" +GRUB_TIMEOUT_STYLE=countdown +GRUB_DEFAULT=saved """), ]) -def test_grub2_default_conf(tmp_path, stage_module, test_data, expected_conf): +def test_grub2_default_conf(tmp_path, stage_module, test_data, kernel_opts, expected_conf): treedir = tmp_path / "tree" confpath = treedir / "etc/default/grub" confpath.parent.mkdir(parents=True, exist_ok=True) @@ -77,6 +102,7 @@ def test_grub2_default_conf(tmp_path, stage_module, test_data, expected_conf): } options["config"] = test_data + options["kernel_opts"] = kernel_opts stage_module.main(treedir, options) assert os.path.exists(confpath)