From 17fd46ec387fc6d4bb8a2ab21d2b2ae3327a7b98 Mon Sep 17 00:00:00 2001 From: Jeremy Linton Date: Fri, 14 Oct 2022 12:15:42 -0500 Subject: [PATCH 1/9] bootloader/base.py drop stage2 requirement systemd-boot places all the files need for boot on the ESP, removing the need for a dedicated stage2 boot partition to hold the initrd/etc. So, lets add an option to skip the stage2 validation. Signed-off-by: Jeremy Linton --- pyanaconda/modules/storage/bootloader/base.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyanaconda/modules/storage/bootloader/base.py b/pyanaconda/modules/storage/bootloader/base.py index 3bb0722493d..35b92c4388a 100644 --- a/pyanaconda/modules/storage/bootloader/base.py +++ b/pyanaconda/modules/storage/bootloader/base.py @@ -176,6 +176,7 @@ class BootLoader(object): image_label_attr = "label" encryption_support = False stage2_is_valid_stage1 = False + stage2_required = True # requirements for stage2 devices stage2_device = None @@ -645,6 +646,10 @@ def is_valid_stage2_device(self, device, linux=True, non_linux=False): log.debug("Is %s a valid stage2 target device?", device.name) + if not self.stage2_required: + log.debug("stage2 not required") + return True + if device.protected: valid = False From c4b31b67f3feba561d226032f8001199c3ae898b Mon Sep 17 00:00:00 2001 From: Jeremy Linton Date: Fri, 23 Sep 2022 19:33:02 -0500 Subject: [PATCH 2/9] storage: Add a systemd class for systemd-boot Systemd-boot is a lightweight boot selector that only runs in EFI enviroments. Compared to shim+grub its incredibly simple as it utilizes efi boot services. Lets add a subclass that anaconda can use to install it rather than grub. Signed-off-by: Jeremy Linton --- .../modules/storage/bootloader/systemd.py | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 pyanaconda/modules/storage/bootloader/systemd.py diff --git a/pyanaconda/modules/storage/bootloader/systemd.py b/pyanaconda/modules/storage/bootloader/systemd.py new file mode 100644 index 00000000000..f8bf588d4d3 --- /dev/null +++ b/pyanaconda/modules/storage/bootloader/systemd.py @@ -0,0 +1,147 @@ +# +# Copyright (C) 2022 Arm +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions of +# the GNU General Public License v.2, or (at your option) any later version. +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY expressed or implied, including the implied warranties 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, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the +# source code or documentation are not subject to the GNU General Public +# License and may only be used or replicated with the express permission of +# Red Hat, Inc. +# + +from pyanaconda.modules.storage.bootloader.base import BootLoader, BootLoaderError +from pyanaconda.core import util +from pyanaconda.core.configuration.anaconda import conf +from pyanaconda.core.i18n import _ +from pyanaconda.core.path import join_paths +from pyanaconda.product import productName + +from pyanaconda.anaconda_loggers import get_module_logger +log = get_module_logger(__name__) + +__all__ = ["SystemdBoot"] + +class SystemdBoot(BootLoader): + """Systemd-boot. + + Systemd-boot is dead simple, it basically provides a second boot menu + and injects the kernel parms into an efi stubbed kernel, which in turn + (optionally) loads it's initrd. As such there aren't any filesystem or + drivers to worry about as everything needed is provided by UEFI. Even the + console remains on the UEFI framebuffer, or serial as selected by UEFI. + Basically rather than trying to be another mini-os (like grub) and duplicate + much of what UEFI provides, it simply utilizes the existing services. + + Further, while we could keep stage1 (ESP) and stage2 (/boot) seperate it + simplifies things just to merge them and place the kernel/initrd on the + ESP. This requires a larger than normal ESP, but for now we assume that + this linux installer is creating the partitions, so where the space + is allocated doesn't matter. + + """ + name = "SDBOOT" + # oddly systemd-boot files are part of the systemd-udev package + # and in /usr/lib/systemd/boot/efi/systemd-boot[aa64].efi + # and the systemd stubs are in /usr/lib/systemd/linuxaa64.efi.stub + _config_file = "loader.conf" + _config_dir = "/loader" + + # systemd-boot doesn't require a stage2 as + # everything is stored on the ESP + stage2_max_end = None + stage2_is_valid_stage1 = True + stage2_required = False + + # + # configuration + # + + @property + def config_dir(self): + """ Full path to configuration directory. """ + esp = util.execWithCapture("bootctl", [ "--print-esp-path" ], + root=conf.target.system_root) + return esp.strip() + self._config_dir + + @property + def config_file(self): + """ Full path to configuration file. """ + return "%s/%s" % (self.config_dir, self._config_file) + + # copy console update from grub2.py + def write_config_console(self, config): + log.info("systemd.py: write_config_console") + if not self.console: + return + + console_arg = "console=%s" % self.console + if self.console_options: + console_arg += ",%s" % self.console_options + self.boot_args.add(console_arg) + + def write_config(self): + log.info("systemd.py: write_config systemd start") + self.write_config_console(None) + + # Rewrite the loader.conf + # For now we are just updating the timeout to actually + # implement the bootloader --timeout option + config_path = join_paths(conf.target.system_root, self.config_file) + log.info("systemd.py: write_config systemd loader conf : %s ", config_path) + + with open(config_path, "w") as config: + config.write("timeout "+ str(self.timeout) + "\n") + config.write("#console-mode keep\n") + + # update /etc/kernel/cmdline + # should look something like "root=UUID=45b931b7-592a-46dc-9c33-d38d5901ec29 ro resume=/dev/sda3" + config_path = join_paths(conf.target.system_root, "/etc/kernel/cmdline") + log.info("systemd.py: write_config systemd commandline : %s ", config_path) + with open(config_path, "w") as config: + args = str(self.boot_args) + log.info("systemd.py: systemd used boot args: %s ", args) + + # pick up the UUID of the mounted rootfs, + root_uuid = util.execWithCapture("findmnt", [ "-sfn", "-oUUID", "/" ], + root=conf.target.system_root) + args += " root=UUID=" + root_uuid + config.write(args) + + # rather than creating a mess in python lets just + # write the options above, and run a script which will merge the + # boot cmdline (after stripping inst. and BOOT_) with the anaconda + # settings and the kernel-install recovery/etc options. + rc = util.execWithRedirect( + "/usr/sbin/updateloaderentries", + [" "], + root=conf.target.system_root + ) + if rc: + raise BootLoaderError(_("Failed to write boot loader configuration. " + "More information may be found in the log files stored in /tmp")) + + # + # installation + # + def install(self, args=None): + log.info("systemd.py: install systemd boot install (root=%s)", conf.target.system_root) + + # the --esp-path= isn't strictly required, but we want to be explicit about it. + rc = util.execWithRedirect("bootctl", [ "install", "--esp-path=/boot/efi", + "--efi-boot-option-description=" + productName.split("-")[0] ], + root=conf.target.system_root, + env_prune=['MALLOC_PERTURB_']) + if rc: + raise BootLoaderError(_("bootctl failed to install UEFI boot loader. " + "More information may be found in the log files stored in /tmp")) + + + def write_config_images(self, config): + return True From e069f2a5e46c97bddf6899ed21f0fed83cdfdf53 Mon Sep 17 00:00:00 2001 From: Jeremy Linton Date: Thu, 1 Dec 2022 16:02:26 -0600 Subject: [PATCH 3/9] Hoist firmware bit size check EFIGRUB is checking fw_platform_size to choose which grub, 32 or 64-bit, needs to be installed. Lets hoist that check because systemd-boot will use it to verify that the platform firmware is 64-bits. Signed-off-by: Jeremy Linton --- pyanaconda/modules/storage/bootloader/efi.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/pyanaconda/modules/storage/bootloader/efi.py b/pyanaconda/modules/storage/bootloader/efi.py index 932f5b02a19..dd1908acd43 100644 --- a/pyanaconda/modules/storage/bootloader/efi.py +++ b/pyanaconda/modules/storage/bootloader/efi.py @@ -42,6 +42,16 @@ def efi_config_dir(self): def _efi_config_dir(self): return "efi/EFI/{}".format(conf.bootloader.efi_dir) + def get_fw_platform_size(self): + try: + with open("/sys/firmware/efi/fw_platform_size", "r") as f: + value = f.readline().strip() + except OSError: + log.info("Reading /sys/firmware/efi/fw_platform_size failed, " + "defaulting to 64-bit install.") + value = '64' + return value + def efibootmgr(self, *args, **kwargs): if not conf.target.is_hardware: log.info("Skipping efibootmgr for image/directory install.") @@ -144,14 +154,7 @@ def __init__(self): super().__init__() self._packages64 = [ "grub2-efi-x64", "shim-x64" ] - try: - f = open("/sys/firmware/efi/fw_platform_size", "r") - value = f.readline().strip() - except OSError: - log.info("Reading /sys/firmware/efi/fw_platform_size failed, " - "defaulting to 64-bit install.") - value = '64' - if value == '32': + if self.get_fw_platform_size() == '32': self._is_32bit_firmware = True @property From d8f03846f00b7b4fdd6c5185734b5978988bc7e8 Mon Sep 17 00:00:00 2001 From: Jeremy Linton Date: Tue, 26 Jul 2022 16:17:35 -0500 Subject: [PATCH 4/9] Add EFISYSTEMD class and enable aarch64 Now that we have a systemd bootloader class lets add an efi class that can call it to install the bootloader. Then create Aarch64EFISystemBoot class that can utilize it. Signed-off-by: Jeremy Linton --- pyanaconda/modules/storage/bootloader/efi.py | 56 +++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/pyanaconda/modules/storage/bootloader/efi.py b/pyanaconda/modules/storage/bootloader/efi.py index dd1908acd43..45cc897adea 100644 --- a/pyanaconda/modules/storage/bootloader/efi.py +++ b/pyanaconda/modules/storage/bootloader/efi.py @@ -20,15 +20,18 @@ from pyanaconda.modules.storage.bootloader.base import BootLoaderError from pyanaconda.modules.storage.bootloader.grub2 import GRUB2 +from pyanaconda.modules.storage.bootloader.systemd import SystemdBoot from pyanaconda.core import util -from pyanaconda.core.kernel import kernel_arguments +from pyanaconda.core.i18n import _ from pyanaconda.core.configuration.anaconda import conf +from pyanaconda.core.kernel import kernel_arguments +from pyanaconda.core.path import join_paths from pyanaconda.product import productName from pyanaconda.anaconda_loggers import get_module_logger log = get_module_logger(__name__) -__all__ = ["EFIBase", "EFIGRUB", "Aarch64EFIGRUB", "ArmEFIGRUB", "MacEFIGRUB"] +__all__ = ["EFIBase", "EFIGRUB", "Aarch64EFIGRUB", "ArmEFIGRUB", "MacEFIGRUB", "Aarch64EFISystemdBoot"] class EFIBase(object): @@ -200,6 +203,46 @@ def write_config(self): super().write_config() +class EFISystemdBoot(EFIBase, SystemdBoot): + """EFI Systemd-boot""" + _packages_common = ["efibootmgr", "systemd-udev", "systemd-boot", "sdubby"] + _packages64 = [] + + def __init__(self): + super().__init__() + + if self.get_fw_platform_size() == '32': + # not supported try a different bootloader + log.error("efi.py: systemd-boot is not supported on 32-bit platforms") + raise BootLoaderError(_("Systemd-boot is not supported on this platform")) + + @property + def packages(self): + return self._packages64 + self._packages_common + + @property + def efi_config_file(self): + """ Full path to EFI configuration file. """ + return join_paths(self.efi_config_dir, self._config_file) + + def write_config(self): + """ Write the config settings to config file (ex: grub.cfg) not needed for systemd. """ + config_path = join_paths(conf.target.system_root, self.efi_config_file) + + log.info("efi.py: (systemd) write_config systemd : %s ", config_path) + + super().write_config() + + def install(self, args=None): + log.info("efi.py: (systemd) install") + # force the resolution order, we don't want to: + # efibootmgr remove old "fedora" + # or use efiboot mgr to install a new one + # lets just use `bootctl install` directly. + # which will fix the efi boot variables too. + SystemdBoot.install(self) + + class Aarch64EFIGRUB(EFIGRUB): _serial_consoles = ["ttyAMA", "ttyS"] _efi_binary = "\\shimaa64.efi" @@ -209,6 +252,15 @@ def __init__(self): self._packages64 = ["grub2-efi-aa64", "shim-aa64"] +class Aarch64EFISystemdBoot(EFISystemdBoot): + _serial_consoles = ["ttyAMA", "ttyS"] + _efi_binary = "\\systemd-bootaa64.efi" + + def __init__(self): + super().__init__() + self._packages64 = [] + + class ArmEFIGRUB(EFIGRUB): _serial_consoles = ["ttyAMA", "ttyS"] _efi_binary = "\\grubarm.efi" From 1891b0f306cc252e32335ac185a609df1828edb7 Mon Sep 17 00:00:00 2001 From: Jeremy Linton Date: Tue, 27 Sep 2022 20:01:34 -0500 Subject: [PATCH 5/9] Add the grub packages removed from comps to grub installs Signed-off-by: Jeremy Linton --- pyanaconda/modules/storage/bootloader/efi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyanaconda/modules/storage/bootloader/efi.py b/pyanaconda/modules/storage/bootloader/efi.py index 45cc897adea..e7f8c1cfb6f 100644 --- a/pyanaconda/modules/storage/bootloader/efi.py +++ b/pyanaconda/modules/storage/bootloader/efi.py @@ -147,7 +147,7 @@ def install(self, args=None): class EFIGRUB(EFIBase, GRUB2): """EFI GRUBv2""" _packages32 = [ "grub2-efi-ia32", "shim-ia32" ] - _packages_common = [ "efibootmgr", "grub2-tools" ] + _packages_common = ["efibootmgr", "grub2-tools", "grub2-tools-extra", "grubby" ] stage2_is_valid_stage1 = False stage2_bootable = False @@ -249,7 +249,7 @@ class Aarch64EFIGRUB(EFIGRUB): def __init__(self): super().__init__() - self._packages64 = ["grub2-efi-aa64", "shim-aa64"] + self._packages64 = ["grub2-efi-aa64", "shim-aa64", "grub2-efi-aa64-cdboot"] class Aarch64EFISystemdBoot(EFISystemdBoot): From 30eb96cef42c46af68cb5dd9b5f93e4e9b542c28 Mon Sep 17 00:00:00 2001 From: Jeremy Linton Date: Tue, 27 Sep 2022 20:03:13 -0500 Subject: [PATCH 6/9] add x86 systemd-boot option Signed-off-by: Jeremy Linton --- pyanaconda/modules/storage/bootloader/efi.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pyanaconda/modules/storage/bootloader/efi.py b/pyanaconda/modules/storage/bootloader/efi.py index e7f8c1cfb6f..d4c0fb60e8a 100644 --- a/pyanaconda/modules/storage/bootloader/efi.py +++ b/pyanaconda/modules/storage/bootloader/efi.py @@ -31,7 +31,7 @@ from pyanaconda.anaconda_loggers import get_module_logger log = get_module_logger(__name__) -__all__ = ["EFIBase", "EFIGRUB", "Aarch64EFIGRUB", "ArmEFIGRUB", "MacEFIGRUB", "Aarch64EFISystemdBoot"] +__all__ = ["EFIBase", "EFIGRUB", "Aarch64EFIGRUB", "ArmEFIGRUB", "MacEFIGRUB", "Aarch64EFISystemdBoot", "X64EFISystemdBoot"] class EFIBase(object): @@ -260,6 +260,14 @@ def __init__(self): super().__init__() self._packages64 = [] +class X64EFISystemdBoot(EFISystemdBoot): + _efi_binary = "\\systemd-bootx64.efi" + + def __init__(self): + super().__init__() + self._packages64 = [] + + class ArmEFIGRUB(EFIGRUB): _serial_consoles = ["ttyAMA", "ttyS"] From 73486e91ac89523a2bd65d9d7e077b00c3182df9 Mon Sep 17 00:00:00 2001 From: Jeremy Linton Date: Tue, 27 Sep 2022 20:03:32 -0500 Subject: [PATCH 7/9] Add kickstart/command line control to enable systemd-boot Now, that we have all the infrastructure in place, lets add and document a 'inst.systemd' option that can be used on the boot commadline or placed in kickstart files. Signed-off-by: Jeremy Linton --- anaconda.spec.in | 2 +- data/anaconda.conf | 1 + data/anaconda_options.txt | 5 +++++ docs/boot-options.rst | 9 +++++++++ dracut/parse-kickstart | 2 +- pyanaconda/argument_parsing.py | 2 ++ pyanaconda/core/configuration/anaconda.py | 2 ++ pyanaconda/core/configuration/bootloader.py | 4 +++- pyanaconda/core/kickstart/commands.py | 2 +- pyanaconda/modules/storage/bootloader/bootloader.py | 7 +++++++ pyanaconda/modules/storage/bootloader/factory.py | 10 ++++++++++ pyanaconda/modules/storage/bootloader/installation.py | 8 ++++++-- .../modules/storage/test_module_bootloader.py | 5 +++++ 13 files changed, 53 insertions(+), 6 deletions(-) diff --git a/anaconda.spec.in b/anaconda.spec.in index 79b70df0247..28716f1823c 100644 --- a/anaconda.spec.in +++ b/anaconda.spec.in @@ -39,7 +39,7 @@ Source0: https://github.com/rhinstaller/%{name}/releases/download/%{name}-%{vers %define libxklavierver 5.4 %define mehver 0.23-1 %define nmver 1.0 -%define pykickstartver 3.44-1 +%define pykickstartver 3.45-1 %define pypartedver 2.5-2 %define pythonblivetver 1:3.6.0-1 %define rpmver 4.15.0 diff --git a/data/anaconda.conf b/data/anaconda.conf index da8e67fd109..148df258281 100644 --- a/data/anaconda.conf +++ b/data/anaconda.conf @@ -138,6 +138,7 @@ selinux = -1 # # DEFAULT Choose the type by platform. # EXTLINUX Use extlinux as the bootloader. +# SDBOOT Use systemd-boot as the bootloader. # type = DEFAULT diff --git a/data/anaconda_options.txt b/data/anaconda_options.txt index fee285dbc32..ac09c44743e 100644 --- a/data/anaconda_options.txt +++ b/data/anaconda_options.txt @@ -225,6 +225,11 @@ Use extlinux as the bootloader. Note that there's no attempt to validate that this will work for your platform or anything; it assumes that if you ask for it, you want to try. +sdboot +Use systemd-boot as the bootloader. Note that there's no attempt to validate +that this will work for your platform or anything; it assumes that if you +ask for it, you want to try. + nombr If nombr is specified the grub2 bootloader will be installed but the diff --git a/docs/boot-options.rst b/docs/boot-options.rst index ae02d73a7b5..6f110171ef0 100644 --- a/docs/boot-options.rst +++ b/docs/boot-options.rst @@ -669,6 +669,15 @@ Use extlinux as the bootloader. Note that there's no attempt to validate that this will work for your platform or anything; it assumes that if you ask for it, you want to try. +.. inst.sdboot: + +inst.sdboot +^^^^^^^^^^^^^ + +Use systemd-boot as the bootloader. Note that there's no attempt to validate that +this will work for your platform or anything; it assumes that if you ask for it, +you want to try. + .. inst.leavebootorder: inst.leavebootorder diff --git a/dracut/parse-kickstart b/dracut/parse-kickstart index 5c6a8511273..c81ddb0813c 100755 --- a/dracut/parse-kickstart +++ b/dracut/parse-kickstart @@ -54,7 +54,7 @@ from pykickstart.commands.mediacheck import FC4_MediaCheck as MediaCheck from pykickstart.commands.driverdisk import F14_DriverDisk as DriverDisk from pykickstart.commands.network import F38_Network as Network from pykickstart.commands.displaymode import F26_DisplayMode as DisplayMode -from pykickstart.commands.bootloader import F34_Bootloader as Bootloader +from pykickstart.commands.bootloader import F39_Bootloader as Bootloader # Default logging: none log = logging.getLogger('parse-kickstart').addHandler(logging.NullHandler()) diff --git a/pyanaconda/argument_parsing.py b/pyanaconda/argument_parsing.py index 95d3b080cbd..0b57e46f709 100644 --- a/pyanaconda/argument_parsing.py +++ b/pyanaconda/argument_parsing.py @@ -591,6 +591,8 @@ def __call__(self, parser, namespace, values, option_string=None): help=help_parser.help_text("noeject")) ap.add_argument("--extlinux", action="store_true", default=False, help=help_parser.help_text("extlinux")) + ap.add_argument("--sdboot", action="store_true", default=False, + help=help_parser.help_text("sdboot")) ap.add_argument("--nombr", action="store_true", default=False, help=help_parser.help_text("nombr")) ap.add_argument("--mpathfriendlynames", dest="multipath_friendly_names", action="store_true", diff --git a/pyanaconda/core/configuration/anaconda.py b/pyanaconda/core/configuration/anaconda.py index 94fe384e2ee..551dc9f4514 100644 --- a/pyanaconda/core/configuration/anaconda.py +++ b/pyanaconda/core/configuration/anaconda.py @@ -375,6 +375,8 @@ def set_from_opts(self, opts): # Set the bootloader type. if opts.extlinux: self.bootloader._set_option("type", BootloaderType.EXTLINUX.value) + if opts.sdboot: + self.bootloader._set_option("type", BootloaderType.SDBOOT.value) # Set the boot loader flags. self.bootloader._set_option("nonibft_iscsi_boot", opts.nonibftiscsiboot) diff --git a/pyanaconda/core/configuration/bootloader.py b/pyanaconda/core/configuration/bootloader.py index 6746e4503ee..18b956bbe47 100644 --- a/pyanaconda/core/configuration/bootloader.py +++ b/pyanaconda/core/configuration/bootloader.py @@ -23,8 +23,9 @@ class BootloaderType(Enum): """Type of the bootloader.""" - DEFAULT = "DEFAULT" + DEFAULT = "DEFAULT" EXTLINUX = "EXTLINUX" + SDBOOT = "SDBOOT" class BootloaderSection(Section): @@ -38,6 +39,7 @@ def type(self): DEFAULT Choose the type by platform. EXTLINUX Use extlinux as the bootloader. + SDBOOT Use systemd-boot as the bootloader. :return: an instance of BootloaderType """ diff --git a/pyanaconda/core/kickstart/commands.py b/pyanaconda/core/kickstart/commands.py index 224e356ecec..83e17f25ea9 100644 --- a/pyanaconda/core/kickstart/commands.py +++ b/pyanaconda/core/kickstart/commands.py @@ -25,7 +25,7 @@ from pykickstart.commands.authselect import F28_Authselect as Authselect from pykickstart.commands.autopart import F38_AutoPart as AutoPart from pykickstart.commands.autostep import F34_AutoStep as AutoStep -from pykickstart.commands.bootloader import F34_Bootloader as Bootloader +from pykickstart.commands.bootloader import F39_Bootloader as Bootloader from pykickstart.commands.btrfs import F23_BTRFS as BTRFS from pykickstart.commands.cdrom import FC3_Cdrom as Cdrom from pykickstart.commands.clearpart import F28_ClearPart as ClearPart diff --git a/pyanaconda/modules/storage/bootloader/bootloader.py b/pyanaconda/modules/storage/bootloader/bootloader.py index c805c0d7853..ef89fa818e3 100644 --- a/pyanaconda/modules/storage/bootloader/bootloader.py +++ b/pyanaconda/modules/storage/bootloader/bootloader.py @@ -129,6 +129,9 @@ def _set_module_from_kickstart(self, data): if data.bootloader.extlinux: self.set_default_type(BootloaderType.EXTLINUX) + if data.bootloader.sdboot: + self.set_default_type(BootloaderType.SDBOOT) + if data.bootloader.bootDrive: self.set_drive(data.bootloader.bootDrive) @@ -184,6 +187,9 @@ def setup_kickstart(self, data): if self.get_default_type() == BootloaderType.EXTLINUX: data.bootloader.extlinux = True + if self.get_default_type() == BootloaderType.SDBOOT: + data.bootloader.sdboot = True + if self.bootloader_mode == BootloaderMode.DISABLED: data.bootloader.disabled = True data.bootloader.location = "none" @@ -503,6 +509,7 @@ def generate_initramfs_with_tasks(self, payload_type, kernel_versions): """ return [ RecreateInitrdsTask( + storage=self.storage, payload_type=payload_type, kernel_versions=kernel_versions, sysroot=conf.target.system_root diff --git a/pyanaconda/modules/storage/bootloader/factory.py b/pyanaconda/modules/storage/bootloader/factory.py index 8aa3afb53fe..07a0c7c321c 100644 --- a/pyanaconda/modules/storage/bootloader/factory.py +++ b/pyanaconda/modules/storage/bootloader/factory.py @@ -82,6 +82,7 @@ def get_class_by_name(cls, name): Supported values: EXTLINUX + SDBOOT :param name: a boot loader name or None :return: a boot loader class or None @@ -90,6 +91,15 @@ def get_class_by_name(cls, name): from pyanaconda.modules.storage.bootloader.extlinux import EXTLINUX return EXTLINUX + if name == "SDBOOT": + platform_class = platform.platform.__class__ + if platform_class is platform.Aarch64EFI: + from pyanaconda.modules.storage.bootloader.efi import Aarch64EFISystemdBoot + return Aarch64EFISystemdBoot + if platform_class is platform.EFI: + from pyanaconda.modules.storage.bootloader.efi import X64EFISystemdBoot + return X64EFISystemdBoot + return None @classmethod diff --git a/pyanaconda/modules/storage/bootloader/installation.py b/pyanaconda/modules/storage/bootloader/installation.py index 47f445abb3c..1dfb917491f 100644 --- a/pyanaconda/modules/storage/bootloader/installation.py +++ b/pyanaconda/modules/storage/bootloader/installation.py @@ -21,7 +21,7 @@ from blivet.devices import BTRFSDevice from pyanaconda.core.constants import PAYLOAD_TYPE_RPM_OSTREE, PAYLOAD_LIVE_TYPES from pyanaconda.modules.storage.bootloader import BootLoaderError - +from pyanaconda.modules.storage.bootloader.systemd import SystemdBoot from pyanaconda.core.util import execWithRedirect from pyanaconda.modules.common.errors.installation import BootloaderInstallationError from pyanaconda.modules.storage.constants import BootloaderMode @@ -173,9 +173,10 @@ def run(self): class RecreateInitrdsTask(Task): """Installation task that recreates the initrds.""" - def __init__(self, payload_type, kernel_versions, sysroot): + def __init__(self, storage, payload_type, kernel_versions, sysroot): """Create a new task.""" super().__init__() + self._storage = storage self._payload_type = payload_type self._versions = kernel_versions self._sysroot = sysroot @@ -192,6 +193,9 @@ def run(self): if self._payload_type == PAYLOAD_TYPE_RPM_OSTREE: log.debug("Don't regenerate initramfs on rpm-ostree systems.") return + if isinstance(self._storage.bootloader, SystemdBoot): + log.debug("Don't regenerate initramfs on systemd-boot systems.") + return recreate_initrds( sysroot=self._sysroot, diff --git a/tests/unit_tests/pyanaconda_tests/modules/storage/test_module_bootloader.py b/tests/unit_tests/pyanaconda_tests/modules/storage/test_module_bootloader.py index ea52270870e..da9bbf5b88a 100644 --- a/tests/unit_tests/pyanaconda_tests/modules/storage/test_module_bootloader.py +++ b/tests/unit_tests/pyanaconda_tests/modules/storage/test_module_bootloader.py @@ -483,10 +483,12 @@ def test_create_bls_entries(self, exec_mock): @patch('pyanaconda.modules.storage.bootloader.utils.conf') def test_recreate_initrds(self, conf_mock, exec_mock): """Test the installation task that recreates initrds.""" + storage = Mock(bootloader=EFIGRUB()) version = "4.17.7-200.fc28.x86_64" with tempfile.TemporaryDirectory() as root: task = RecreateInitrdsTask( + storage=storage, sysroot=root, payload_type=PAYLOAD_TYPE_RPM_OSTREE, kernel_versions=[version] @@ -499,6 +501,7 @@ def test_recreate_initrds(self, conf_mock, exec_mock): with tempfile.TemporaryDirectory() as root: task = RecreateInitrdsTask( + storage=storage, sysroot=root, payload_type=PAYLOAD_TYPE_LIVE_IMAGE, kernel_versions=[version] @@ -526,6 +529,7 @@ def test_recreate_initrds(self, conf_mock, exec_mock): open(root + "/usr/sbin/new-kernel-pkg", 'wb').close() task = RecreateInitrdsTask( + storage=storage, sysroot=root, payload_type=PAYLOAD_TYPE_LIVE_IMAGE, kernel_versions=[version] @@ -546,6 +550,7 @@ def test_recreate_initrds(self, conf_mock, exec_mock): with tempfile.TemporaryDirectory() as root: task = RecreateInitrdsTask( + storage=storage, sysroot=root, payload_type=PAYLOAD_TYPE_LIVE_IMAGE, kernel_versions=[version] From d05eb784bd3162deb7da17ae2ab66375523436b0 Mon Sep 17 00:00:00 2001 From: Jeremy Linton Date: Mon, 17 Oct 2022 15:01:15 -0500 Subject: [PATCH 8/9] release-notes: Document that its possible to install with systemd-boot Place a release note for the next verison of anaconda which notes that it is now possible given the right set of packages/etc to install a system utilizing systemd-boot. Signed-off-by: Jeremy Linton --- docs/release-notes/systemd-boot.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 docs/release-notes/systemd-boot.rst diff --git a/docs/release-notes/systemd-boot.rst b/docs/release-notes/systemd-boot.rst new file mode 100644 index 00000000000..111b717be2f --- /dev/null +++ b/docs/release-notes/systemd-boot.rst @@ -0,0 +1,20 @@ +:Type: Kickstart Installation +:Summary: Install an image using systemd-boot rather than grub (#2135531) + +:Description: + With this release, systemd-boot can be selected as an alternative boot + loader for testing and development purposes. + + This can be done with 'inst.sdboot' from the grub/kernel command + line or with '--sdboot' in a kickstart file as part of the + bootloader command. The resulting machine should be free of grub, + shim, and grubby packages, with all the boot files on the EFI + System Partition (ESP). This may mean that it is wise to dedicate + the space previously allocated for /boot to the ESP in order to + assure that future kernel upgrades will have sufficient space. + + For more information, refer to the anaconda and systemd-boot documentation. + +:Links: + - https://bugzilla.redhat.com/show_bug.cgi?id=2135531 + - https://github.com/rhinstaller/anaconda/pull/4368 From a9e05598e2f3c44c14f32f79b2506a5ec7171ea7 Mon Sep 17 00:00:00 2001 From: Jeremy Linton Date: Tue, 8 Nov 2022 14:25:41 -0600 Subject: [PATCH 9/9] CONTRIBUTING: Add note about systemd-boot The systemd-boot install feature is for the moment largly expermental, but adding the ability to create a clean install without grub drippings is important for testing. Signed-off-by: Jeremy Linton --- CONTRIBUTING.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 711d1b60d7c..7ddba7513e0 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -256,3 +256,13 @@ Below is a list of pure community features, their community maintainers, and mai * Description: ``Enable boot of the installed system from a BTRFS subvolume.`` + +systemd-boot as a bootloader +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Origin: https://github.com/rhinstaller/anaconda/pull/4368 +* Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2135531 +* Maintainer: Jeremy Linton +* Description: + +``Enable boot using systemd-boot rather than grub2.``