kiwi-el8/kiwi/bootloader/config/bootloader_spec_base.py
Marcus Schäfer ae497f2504
Lookup distro provided BLS entries for zipl
Check if there is already an entry file name produced by the
distribution logic/policy. If we can find an already present
entry name, prefer this name over the kiwi naming policy
2024-03-12 15:37:16 +01:00

263 lines
8.2 KiB
Python

# Copyright (c) 2022 Marcus Schäfer
#
# This file is part of kiwi.
#
# kiwi is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# kiwi is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty 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 kiwi. If not, see <http://www.gnu.org/licenses/>
#
import os
import glob
from typing import (
Dict, NamedTuple
)
# project
from kiwi.firmware import FirmWare
from kiwi.bootloader.config.base import BootLoaderConfigBase
from kiwi.system.identifier import SystemIdentifier
from kiwi.defaults import Defaults
from kiwi.utils.os_release import OsRelease
from kiwi.exceptions import KiwiKernelLookupError
target_type = NamedTuple(
'target_type', [
('disk', str),
('install', str),
('live', str)
]
)
class BootLoaderSpecBase(BootLoaderConfigBase):
"""
**Base class for Boot Loader Specification**
This base class follows the bootloader specifications as
described in:
* https://uapi-group.org/specifications/specs/boot_loader_specification
All supported bootloaders which follows this specification
are derived from this base class
:param object xml_state: instance of :class:`XMLState`
:param str root_dir: root directory path name
:param str boot_dir: boot directory path name
:param dict custom_args:
custom bootloader configuration parameters
"""
def post_init(self, custom_args: Dict = {}) -> None:
"""
Post init for all bootloader spec loaders
Store custom arguments in an instance dict and initialize
target identifiers
"""
self.entries_dir = Defaults.get_bls_loader_entries_dir()
self.target = target_type(
disk='disk', install='install(iso)', live='live(iso)'
)
self.custom_args = custom_args
self.timeout = self.get_boot_timeout_seconds()
self.disk_type = self.xml_state.get_build_type_bootloader_targettype()
self.disk_blocksize = self.xml_state.build_type.get_target_blocksize()
self.firmware = FirmWare(self.xml_state)
self.cmdline = ''
def write(self) -> None:
"""
For bootloaders following the bootloader spec
no collective write will happen
"""
pass
def setup_sysconfig_bootloader(self) -> None:
"""
For bootloaders following the bootloader spec
no setting to sysconfig/bootloader will be made
"""
pass
def setup_disk_image_config(
self, boot_uuid: str = '', root_uuid: str = '', hypervisor: str = '',
kernel: str = '', initrd: str = '', boot_options: Dict = {}
) -> None:
"""
Create boot config file to boot from disk
:param str boot_uuid: boot device UUID
:param str root_uuid: root device UUID
:param str hypervisor: unused
:param str kernel: kernel name
:param str initrd: initrd name
:param dict boot_options:
custom options dictionary required to setup the bootloader.
Targeted to bootloader spec interface
"""
self.custom_args['boot_uuid'] = boot_uuid
self.custom_args['root_uuid'] = root_uuid
self.custom_args['kernel'] = kernel
self.custom_args['initrd'] = initrd
self.custom_args['boot_options'] = boot_options
self.cmdline = ' '.join(
[
self.get_boot_cmdline(
boot_options.get('root_device'),
boot_options.get('write_device')
)
]
)
self.setup_loader(self.target.disk)
def setup_install_image_config(
self, mbrid: SystemIdentifier, hypervisor: str = '',
kernel: str = '', initrd: str = ''
) -> None:
"""
Create boot config file to boot install ISO image
:param str mbrid: mbrid file name on boot device
:param str hypervisor: unused
:param str kernel: kernel name
:param str initrd: initrd name
Targeted to bootloader spec interface
"""
pass
def setup_live_image_config(
self, mbrid: SystemIdentifier, hypervisor: str = '',
kernel: str = '', initrd: str = ''
) -> None:
"""
Create boot config file to boot live ISO image
:param str mbrid: mbrid file name on boot device
:param str hypervisor: unused
:param str kernel: kernel name
:param str initrd: initrd name
Targeted to bootloader spec interface
"""
pass
def setup_disk_boot_images(
self, boot_uuid: str, lookup_path: str = ''
) -> None:
"""
Create bootloader image(s) for disk boot
:param string mbrid: unused
:param str lookup_path: unused
Targeted to bootloader spec interface
"""
self.create_loader_image(self.target.disk)
def setup_install_boot_images(
self, mbrid: SystemIdentifier, lookup_path: str = ''
) -> None:
"""
Create bootloader image(s) for install ISO boot
:param string mbrid: unused
:param str lookup_path: unused
Targeted to bootloader spec interface
"""
self.create_loader_image(self.target.install)
def setup_live_boot_images(
self, mbrid: SystemIdentifier, lookup_path: str = ''
) -> None:
"""
Create bootloader image(s) for live ISO boot
:param string mbrid: unused
:param str lookup_path: unused
Targeted to bootloader spec interface
"""
self.create_loader_image(self.target.live)
def create_loader_image(self, target: str) -> None:
"""
Create on demand bootloader image(s)
For bootloaders following the bootloader spec we expect
that the creation of a custom boot image is not needed.
However, if needed this entry point exists
:param str target:
target identifier, one of disk, live(iso) or install(iso)
Implementation in specialized loader class
"""
raise NotImplementedError
def setup_loader(self, target: str) -> None:
"""
Setup main bootloader configuration boot/loader.conf
:param str target:
target identifier, one of disk, live(iso) or install(iso)
Implementation in specialized loader class
"""
raise NotImplementedError
def set_loader_entry(self, root_dir: str, target: str) -> None:
"""
Setup bootloader menu entry boot/loader/entries/X.conf
:param str root_dir:
path to root directory tree
:param str target:
target identifier, one of disk, live(iso) or install(iso)
Implementation in specialized loader class
"""
raise NotImplementedError
def get_entry_name(self) -> str:
"""
Construct entry filename of the form
[OS_release_ID]-[kernel-version].conf or use the
naming policy of an existing entries file
:return: file basename
:rtype: str
"""
os_release = OsRelease(self.root_dir)
try:
kernel_name = os.path.basename(
list(glob.iglob(f'{self.root_dir}/lib/modules/*'))[0]
)
except Exception as issue:
raise KiwiKernelLookupError(
'Kernel lookup in {0}/lib/modules failed with: {1}'.format(
self.root_dir, issue
)
)
entry_filename = f'{os_release.get("ID")}-{kernel_name}.conf'
# Check if there is already an entry file name produced by the
# distribution logic/policy. If we can find an already present
# entry name, prefer this name over the kiwi naming policy
for dist_entry in glob.iglob(f'{self.root_dir}/{self.entries_dir}/*'):
entry_filename = os.path.basename(dist_entry)
break
return entry_filename