Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Evaluate the @root volume name also for btrfs #2324

Merged
merged 12 commits into from
Jul 31, 2023
7 changes: 6 additions & 1 deletion build-tests/x86/fedora/test-image-live-disk/appliance.kiwi
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@
</type>
</preferences>
<preferences profiles="Virtual">
<type image="oem" filesystem="ext4" kernelcmdline="console=ttyS0" firmware="uefi" format="qcow2">
<type image="oem" filesystem="btrfs" kernelcmdline="console=ttyS0 rootflags=subvol=root" firmware="uefi" format="qcow2" btrfs_root_is_subvolume="true" btrfs_set_default_volume="false" rootfs_label="fedora" bootpartition="true" bootfilesystem="ext4">
schaefi marked this conversation as resolved.
Show resolved Hide resolved
<systemdisk name="fedora">
<volume name="@root=root"/>
<volume name="home" parent="/"/>
</systemdisk>
<oemconfig>
<oem-resize>false</oem-resize>
</oemconfig>
Expand Down Expand Up @@ -67,6 +71,7 @@
<package name="vim"/>
<package name="tzdata"/>
<package name="NetworkManager"/>
<package name="btrfs-progs"/>
</packages>
<packages type="image" profiles="Live,Disk">
<package name="syslinux"/>
Expand Down
22 changes: 22 additions & 0 deletions doc/source/image_description/elements.rst
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,28 @@ btrfs_quota_groups="true|false":
Boolean parameter to activate filesystem quotas if
the filesystem is `btrfs`. By default quotas are inactive.

btrfs_set_default_volume="true|false":
Tell kiwi to explicitly make a volume the default volume
This can be either `/` or the root subvolume or the root
snapshot depending on the specified btrfs configuration
attributes. By default btrfs_set_default_volume is set to: true
If no default volume should be set, this attribute can be
used to turn it off

btrfs_root_is_subvolume="true|false":
Tell kiwi to create a root volume to host (/) inside.
The name of this subvolume is by default set to: `@`.
The name of the subvolume can be changed via a volume entry
of the form:

.. code:: xml

<systemdisk>
<volume name="@root=TOPLEVEL_NAME"/>
</systemdisk>

By default the creation of a toplevel volume is set to: `true`

btrfs_root_is_snapshot="true|false":
Boolean parameter that tells {kiwi} to install
the system into a btrfs snapshot. The snapshot layout is compatible with
Expand Down
8 changes: 6 additions & 2 deletions kiwi/bootloader/config/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,8 @@ def get_gfxmode(self, target):
return gfxmode

def _mount_system(
self, root_device, boot_device, efi_device=None, volumes=None
self, root_device, boot_device, efi_device=None,
volumes=None, root_volume_name=None
):
self.root_mount = MountManager(
device=root_device
Expand All @@ -522,7 +523,10 @@ def _mount_system(
mountpoint=self.root_mount.mountpoint + '/boot/efi'
)

self.root_mount.mount()
custom_root_mount_args = []
if root_volume_name and root_volume_name != '/':
custom_root_mount_args += [f'subvol={root_volume_name}']
self.root_mount.mount(options=custom_root_mount_args)

if not self.root_mount.device == self.boot_mount.device:
self.boot_mount.mount()
Expand Down
64 changes: 40 additions & 24 deletions kiwi/bootloader/config/grub2.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,14 +233,18 @@ def setup_disk_image_config(
'root_device': string,
'boot_device': string,
'efi_device': string,
'system_volumes': volume_manager_instance.get_volumes()
'system_volumes':
volume_manager_instance.get_volumes(),
'system_root_volume':
volume_manager_instance.get_root_volume_name()
}
"""
self._mount_system(
boot_options.get('root_device'),
boot_options.get('boot_device'),
boot_options.get('efi_device'),
boot_options.get('system_volumes')
boot_options.get('system_volumes'),
boot_options.get('system_root_volume')
)
config_file = os.sep.join(
[
Expand Down Expand Up @@ -809,35 +813,47 @@ def _setup_secure_boot_efi_image(
# a grub image that got signed by the shim. The shim image
# is the one that gets loaded by the firmware which itself
# loads the second stage grub image
log.info(
f'--> Using shim image: {shim_image.filename}'
)
log.info(
f'--> Using grub image: {grub_image.filename}'
)
Command.run(
['cp', shim_image.filename, self._get_efi_image_name()]
)
Command.run(
[
'cp', grub_image.filename,
os.sep.join([self.efi_boot_path, grub_image.binaryname])
]
target_efi_image_name = self._get_efi_image_name()
target_grub_image_name = os.sep.join(
[self.efi_boot_path, grub_image.binaryname]
)
if not os.path.isfile(target_efi_image_name):
log.info(
f'--> Using shim image: {shim_image.filename}'
)
Command.run(
['cp', shim_image.filename, target_efi_image_name]
)
if not os.path.isfile(target_grub_image_name):
log.info(
f'--> Using grub image: {grub_image.filename}'
)
Command.run(
['cp', grub_image.filename, target_grub_image_name]
)
mok_manager = Defaults.get_mok_manager(lookup_path)
if mok_manager:
Command.run(
['cp', mok_manager, self.efi_boot_path]
target_mok_manager = os.sep.join(
[self.efi_boot_path, os.path.basename(mok_manager)]
)
if not os.path.isfile(target_mok_manager):
log.info(
f'--> Using mok image: {mok_manager}'
)
Command.run(
['cp', mok_manager, self.efi_boot_path]
)
else:
# Without shim a self signed grub image is used that
# gets loaded by the firmware
log.info(
f'--> No shim image, using grub image: {grub_image.filename}'
)
Command.run(
['cp', grub_image.filename, self._get_efi_image_name()]
)
target_efi_image_name = self._get_efi_image_name()
if not os.path.isfile(target_efi_image_name):
log.info(
f'--> No shim image, using grub image: {grub_image.filename}'
)
Command.run(
['cp', grub_image.filename, target_efi_image_name]
)
self._create_efi_config_search(uuid, mbrid)

def _setup_efi_image(
Expand Down
9 changes: 8 additions & 1 deletion kiwi/bootloader/install/grub2.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def post_init(self, custom_args):
{
'target_removable': bool,
'system_volumes': list_of_volumes,
'system_root_volume': root volume name if required
'firmware': FirmWare_instance,
'efi_device': string,
'boot_device': string,
Expand All @@ -71,12 +72,15 @@ def post_init(self, custom_args):
self.proc_mount = None
self.sysfs_mount = None
self.volumes = None
self.root_volume_name = None
self.volumes_mount = []
self.target_removable = None
if custom_args and 'target_removable' in custom_args:
self.target_removable = custom_args['target_removable']
if custom_args and 'system_volumes' in custom_args:
self.volumes = custom_args['system_volumes']
if custom_args and 'system_root_volume' in custom_args:
self.root_volume_name = custom_args['system_root_volume']
if custom_args and 'firmware' in custom_args:
self.firmware = custom_args['firmware']
if custom_args and 'install_options' in custom_args:
Expand Down Expand Up @@ -302,7 +306,10 @@ def _mount_device_and_volumes(self):
self.root_mount = MountManager(
device=self.custom_args['root_device']
)
self.root_mount.mount()
custom_root_mount_args = []
if self.root_volume_name and self.root_volume_name != '/':
custom_root_mount_args += [f'subvol={self.root_volume_name}']
self.root_mount.mount(options=custom_root_mount_args)

if self.boot_mount is None:
if 's390' in self.arch:
Expand Down
20 changes: 19 additions & 1 deletion kiwi/builder/disk.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,12 @@ def create_disk(self) -> Result:
'root_is_readonly_snapshot':
self.xml_state.build_type.
get_btrfs_root_is_readonly_snapshot(),
'root_is_subvolume':
self.xml_state.build_type.
get_btrfs_root_is_subvolume(),
'set_default_volume':
self.xml_state.build_type.
get_btrfs_set_default_volume(),
'quota_groups':
self.xml_state.build_type.get_btrfs_quota_groups(),
'resize_on_boot':
Expand Down Expand Up @@ -1116,6 +1122,13 @@ def _write_generic_fstab(
custom_root_mount_args += ['ro']
fs_check_interval = '0 0'

if self.volume_manager_name and self.volume_manager_name == 'btrfs':
root_volume_name = system.get_root_volume_name()
if root_volume_name != '/':
custom_root_mount_args += [
f'defaults,subvol={root_volume_name}'
]

self._add_fstab_entry(
device_map['root'].get_device(), '/',
custom_root_mount_args, fs_check_interval
Expand Down Expand Up @@ -1524,7 +1537,12 @@ def _install_bootloader(
if self.volume_manager_name:
system.umount_volumes()
custom_install_arguments.update(
{'system_volumes': system.get_volumes()}
{
'system_volumes': system.get_volumes(),
'system_root_volume':
system.get_root_volume_name()
if self.volume_manager_name == 'btrfs' else None
}
)

if self.bootloader != 'custom':
Expand Down
17 changes: 15 additions & 2 deletions kiwi/mount_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
import time
import logging
from textwrap import dedent
from typing import List
from typing import (
List, Dict
)

# project
from kiwi.path import Path
Expand All @@ -41,9 +43,14 @@ class MountManager:

* :param string device: device node name
* :param string mountpoint: mountpoint directory name
* :param dict attributes: optional attributes to store
"""
def __init__(self, device: str, mountpoint: str = ''):
def __init__(
self, device: str, mountpoint: str = '',
attributes: Dict[str, str] = {}
):
self.device = device
self.attributes = attributes
if not mountpoint:
self.mountpoint_tempdir = Temporary(
prefix='kiwi_mount_manager.'
Expand All @@ -53,6 +60,12 @@ def __init__(self, device: str, mountpoint: str = ''):
Path.create(mountpoint)
self.mountpoint = mountpoint

def get_attributes(self) -> Dict[str, str]:
"""
Return attributes dict for this mount manager
"""
return self.attributes

def bind_mount(self) -> None:
"""
Bind mount the device to the mountpoint
Expand Down
33 changes: 33 additions & 0 deletions kiwi/schema/kiwi.rnc
Original file line number Diff line number Diff line change
Expand Up @@ -1433,6 +1433,29 @@ div {
sch:param [ name = "attr" value = "btrfs_quota_groups" ]
sch:param [ name = "types" value = "oem" ]
]
k.type.btrfs_set_default_volume.attribute =
## Tell kiwi to explicitly make a volume the default volume
## This can be either (/) or the root subvolume or the root
## snapshot depending on the specified btrfs configuration
## attributes. By default btrfs_set_default_volume is set to: true
## If no default volume should be set, this attribute can be
## used to turn it off
attribute btrfs_set_default_volume { xsd:boolean }
>> sch:pattern [ id = "btrfs_set_default_volume" is-a = "image_type"
sch:param [ name = "attr" value = "btrfs_set_default_volume" ]
sch:param [ name = "types" value = "oem" ]
]
k.type.btrfs_root_is_subvolume.attribute =
## Tell kiwi to create a root volume to host (/) inside.
## The name of this subvolume is by default set to: '@'
## The name of the subvolume can be changed via
## a volume entry of the form '<volume name="@root=NAME"/>'
## By default the creation of a root subvolume is set to: true
attribute btrfs_root_is_subvolume { xsd:boolean }
>> sch:pattern [ id = "btrfs_root_is_subvolume" is-a = "image_type"
sch:param [ name = "attr" value = "btrfs_root_is_subvolume" ]
sch:param [ name = "types" value = "oem" ]
]
k.type.btrfs_root_is_snapshot.attribute =
## Tell kiwi to install the system into a btrfs snapshot
## The snapshot layout is compatible with the snapper management
Expand Down Expand Up @@ -2218,6 +2241,8 @@ div {
k.type.bootprofile.attribute? &
k.type.btrfs_quota_groups.attribute? &
k.type.btrfs_root_is_snapshot.attribute? &
k.type.btrfs_root_is_subvolume.attribute? &
k.type.btrfs_set_default_volume.attribute? &
k.type.btrfs_root_is_readonly_snapshot.attribute? &
k.type.compressed.attribute? &
k.type.devicepersistency.attribute? &
Expand Down Expand Up @@ -2552,6 +2577,13 @@ div {
## not specified the name specifies a path which has to
## exist inside the root directory.
attribute name { text }
k.volume.parent.attribute =
## The name/path of the parent volume.
## Evaluated only for the btrfs volume manager to allow
## specifying the parent subvolume to nest this volume in.
## If not specified the parent is always the volume set
## as the default volume
attribute parent { text }
k.volume.mountpoint.attribute =
## volume path. The mountpoint specifies a path which has to
## exist inside the root directory.
Expand Down Expand Up @@ -2584,6 +2616,7 @@ div {
k.volume.mountpoint.attribute? &
k.volume.label.attribute? &
k.volume.name.attribute &
k.volume.parent.attribute? &
k.volume.size.attribute?
k.volume =
## Specify which parts of the filesystem should be
Expand Down