From ffba7ef1a55fd4cbca6394662f611831df0723fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20Sch=C3=A4fer?= Date: Thu, 12 Sep 2024 17:29:29 +0200 Subject: [PATCH] Add support for erofs erofs is an alternative readonly filesystem that can be used as alternative to squashfs. This Fixes #2633 --- .../rawhide/test-image-erofs/appliance.kiwi | 40 +++++++++++++ .../test-image-live-disk/appliance.kiwi | 8 ++- .../tumbleweed/test-image-live/appliance.kiwi | 9 ++- .../x86/tumbleweed/test-image-live/config.sh | 39 +++++-------- kiwi/builder/filesystem.py | 2 +- kiwi/builder/live.py | 12 +++- kiwi/defaults.py | 2 +- kiwi/filesystem/__init__.py | 3 +- kiwi/filesystem/erofs.py | 57 +++++++++++++++++++ kiwi/schema/kiwi.rnc | 4 +- kiwi/schema/kiwi.rng | 2 + package/python-kiwi-spec-template | 7 +++ test/unit/filesystem/erofs_test.py | 36 ++++++++++++ 13 files changed, 185 insertions(+), 36 deletions(-) create mode 100644 build-tests/x86/rawhide/test-image-erofs/appliance.kiwi create mode 100644 kiwi/filesystem/erofs.py create mode 100644 test/unit/filesystem/erofs_test.py diff --git a/build-tests/x86/rawhide/test-image-erofs/appliance.kiwi b/build-tests/x86/rawhide/test-image-erofs/appliance.kiwi new file mode 100644 index 00000000000..28945ab0bb9 --- /dev/null +++ b/build-tests/x86/rawhide/test-image-erofs/appliance.kiwi @@ -0,0 +1,40 @@ + + + + + Marcus Schaefer + marcus.schaefer@suse.com + Fedora Appliance, Testing erofs filesystem image + + + 2.0.0 + dnf5 + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build-tests/x86/rawhide/test-image-live-disk/appliance.kiwi b/build-tests/x86/rawhide/test-image-live-disk/appliance.kiwi index e9039c726bb..d04c64b388a 100644 --- a/build-tests/x86/rawhide/test-image-live-disk/appliance.kiwi +++ b/build-tests/x86/rawhide/test-image-live-disk/appliance.kiwi @@ -11,6 +11,7 @@ + @@ -24,6 +25,11 @@ UTC false + + + + + @@ -71,7 +77,7 @@ - + diff --git a/build-tests/x86/tumbleweed/test-image-live/appliance.kiwi b/build-tests/x86/tumbleweed/test-image-live/appliance.kiwi index f713e7c57d4..c41a35f068d 100644 --- a/build-tests/x86/tumbleweed/test-image-live/appliance.kiwi +++ b/build-tests/x86/tumbleweed/test-image-live/appliance.kiwi @@ -14,6 +14,7 @@ + 1.42.3 @@ -31,6 +32,11 @@ + + + + + @@ -50,7 +56,7 @@ - + @@ -58,6 +64,7 @@ + diff --git a/build-tests/x86/tumbleweed/test-image-live/config.sh b/build-tests/x86/tumbleweed/test-image-live/config.sh index 1bd6f33a453..607183c193e 100644 --- a/build-tests/x86/tumbleweed/test-image-live/config.sh +++ b/build-tests/x86/tumbleweed/test-image-live/config.sh @@ -1,39 +1,26 @@ #!/bin/bash -#================ -# FILE : config.sh -#---------------- -# PROJECT : OpenSuSE KIWI Image System -# COPYRIGHT : (c) 2006 SUSE LINUX Products GmbH. All rights reserved -# : -# AUTHOR : Marcus Schaefer -# : -# BELONGS TO : Operating System images -# : -# DESCRIPTION : configuration script for SUSE based -# : operating systems -#---------------- -#====================================== -# Functions... -#-------------------------------------- -test -f /.kconfig && . /.kconfig -test -f /.profile && . /.profile + +set -ex + +declare kiwi_profiles=${kiwi_profiles} +declare kiwi_iname=${kiwi_iname} #====================================== # Greeting... #-------------------------------------- echo "Configure image: [$kiwi_iname]..." -#====================================== -# Setup baseproduct link -#-------------------------------------- -suseSetupProduct - #====================================== # Activate services #-------------------------------------- -suseInsertService sshd +systemctl enable sshd #====================================== -# Setup default target, multi-user +# Include erofs module #-------------------------------------- -baseSetRunlevel 3 +for profile in ${kiwi_profiles//,/ }; do + if [ "${profile}" = "EroFS" ]; then + # remove from blacklist + rm -f /usr/lib/modprobe.d/60-blacklist_fs-erofs.conf + fi +done diff --git a/kiwi/builder/filesystem.py b/kiwi/builder/filesystem.py index 1bc53a67479..34b6b42d0f4 100644 --- a/kiwi/builder/filesystem.py +++ b/kiwi/builder/filesystem.py @@ -89,7 +89,7 @@ def __init__( self.blocksize = xml_state.build_type.get_target_blocksize() self.filesystem_setup = FileSystemSetup(xml_state, root_dir) self.filesystems_no_device_node = [ - 'squashfs' + 'squashfs', 'erofs' ] self.luks = xml_state.get_luks_credentials() self.result = Result(xml_state) diff --git a/kiwi/builder/live.py b/kiwi/builder/live.py index 9be04d0a14d..f87a0d59bef 100644 --- a/kiwi/builder/live.py +++ b/kiwi/builder/live.py @@ -246,7 +246,7 @@ def create(self) -> Result: filesystem_setup = FileSystemSetup( self.xml_state, self.root_dir ) - if root_filesystem != 'squashfs': + if root_filesystem not in ['squashfs', 'erofs']: # Create a filesystem image of the specified type # and put it into a SquashFS container root_image = Temporary().new_file() @@ -302,13 +302,13 @@ def create(self) -> Result: else: # Put the root filesystem into SquashFS directly with FileSystem.new( - name='squashfs', + name=root_filesystem, device_provider=DeviceProvider(), root_dir=self.root_dir + os.sep, custom_args={ 'compression': self.xml_state.build_type.get_squashfscompression() - } + } if root_filesystem == 'squashfs' else {'compression': ''} ) as live_container_image: container_image = Temporary().new_file() live_container_image.create_on_file( @@ -316,6 +316,12 @@ def create(self) -> Result: ) Path.create(self.media_dir.name + '/LiveOS') os.chmod(container_image.name, 0o644) + # Note: we keep the filename of the read-only image as it is + # even if another read-only filesystem not matching this + # filename is used. This is because the following filename + # is also used in the initrd code for the kiwi-live and + # dmsquash dracut modules. The name can be overwritten + # with the rd.live.squashimg boot option though. shutil.copy( container_image.name, self.media_dir.name + '/LiveOS/squashfs.img' diff --git a/kiwi/defaults.py b/kiwi/defaults.py index 0deb1707c5f..7539f5c91a9 100644 --- a/kiwi/defaults.py +++ b/kiwi/defaults.py @@ -1523,7 +1523,7 @@ def get_filesystem_image_types(): """ return [ 'ext2', 'ext3', 'ext4', 'btrfs', 'squashfs', - 'xfs', 'fat16', 'fat32' + 'xfs', 'fat16', 'fat32', 'erofs' ] @staticmethod diff --git a/kiwi/filesystem/__init__.py b/kiwi/filesystem/__init__.py index 067048cc32f..3adfbc3d977 100644 --- a/kiwi/filesystem/__init__.py +++ b/kiwi/filesystem/__init__.py @@ -54,7 +54,8 @@ def new( 'fat16': 'Fat16', 'fat32': 'Fat32', 'squashfs': 'SquashFs', - 'swap': 'Swap' + 'swap': 'Swap', + 'erofs': 'EroFs' } try: filesystem = importlib.import_module( diff --git a/kiwi/filesystem/erofs.py b/kiwi/filesystem/erofs.py new file mode 100644 index 00000000000..c421680163a --- /dev/null +++ b/kiwi/filesystem/erofs.py @@ -0,0 +1,57 @@ +# Copyright (c) 2024 SUSE Software Solutions Germany GmbH. All rights reserved. +# +# 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 +# +from typing import List + +# project +from kiwi.filesystem.base import FileSystemBase +from kiwi.command import Command + + +class FileSystemEroFs(FileSystemBase): + """ + **Implements creation of erofs filesystem** + """ + def create_on_file( + self, filename, label: str = None, exclude: List[str] = None + ): + """ + Create erofs filesystem from data tree + + :param string filename: result file path name + :param string label: volume label + :param list exclude: list of exclude dirs/files + """ + self.filename = filename + exclude_options = [] + # compression = self.custom_args.get('compression') + + if exclude: + for item in exclude: + exclude_options.append(f'--exclude-regex={item}') + + if label: + self.custom_args['create_options'].append('-L') + self.custom_args['create_options'].append(label) + + Command.run( + [ + 'mkfs.erofs' + ] + self.custom_args['create_options'] + exclude_options + [ + self.filename, self.root_dir + ] + ) diff --git a/kiwi/schema/kiwi.rnc b/kiwi/schema/kiwi.rnc index cb39f22eaf8..37f7e274123 100644 --- a/kiwi/schema/kiwi.rnc +++ b/kiwi/schema/kiwi.rnc @@ -1671,7 +1671,7 @@ div { k.type.filesystem.attribute = ## Specifies the root filesystem type attribute filesystem { - "btrfs" | "ext2" | "ext3" | "ext4" | "squashfs" | "xfs" + "btrfs" | "ext2" | "ext3" | "ext4" | "squashfs" | "erofs" | "xfs" } >> sch:pattern [ id = "filesystem" is-a = "image_type" sch:param [ name = "attr" value = "filesystem" ] @@ -1958,7 +1958,7 @@ div { ## Specifies the image type attribute image { "btrfs" | "cpio" | "docker" | "ext2" | "ext3" | - "ext4" | "iso" | "oem" | "pxe" | "kis" | "squashfs" | "tbz" | + "ext4" | "iso" | "oem" | "pxe" | "kis" | "squashfs" | "erofs" | "tbz" | "xfs" | "oci" | "appx" | "enclave" } >> sch:pattern [ diff --git a/kiwi/schema/kiwi.rng b/kiwi/schema/kiwi.rng index 9988bac5f4c..439693e45a0 100644 --- a/kiwi/schema/kiwi.rng +++ b/kiwi/schema/kiwi.rng @@ -2435,6 +2435,7 @@ structure ext3 ext4 squashfs + erofs xfs @@ -2822,6 +2823,7 @@ initrd architecture. pxe kis squashfs + erofs tbz xfs oci diff --git a/package/python-kiwi-spec-template b/package/python-kiwi-spec-template index 40f0425c728..e4561ecd974 100644 --- a/package/python-kiwi-spec-template +++ b/package/python-kiwi-spec-template @@ -291,10 +291,17 @@ Provides: kiwi-filesystem:ext3 Provides: kiwi-filesystem:ext4 Provides: kiwi-filesystem:squashfs Provides: kiwi-filesystem:xfs +%if ! (0%{?suse_version} && 0%{?suse_version} < 1600) +Provides: kiwi-filesystem:erofs +Provides: kiwi-image:erofs +%endif %endif Requires: dosfstools Requires: e2fsprogs Requires: xfsprogs +%if ! (0%{?suse_version} && 0%{?suse_version} < 1600) +Requires: erofs-utils +%endif %if 0%{?suse_version} Requires: btrfsprogs %else diff --git a/test/unit/filesystem/erofs_test.py b/test/unit/filesystem/erofs_test.py new file mode 100644 index 00000000000..ea3db9a2efd --- /dev/null +++ b/test/unit/filesystem/erofs_test.py @@ -0,0 +1,36 @@ +from unittest.mock import patch + +import unittest.mock as mock + +from kiwi.defaults import Defaults +from kiwi.filesystem.erofs import FileSystemEroFs + + +class TestFileSystemEroFs: + @patch('os.path.exists') + def setup(self, mock_exists): + mock_exists.return_value = True + self.erofs = FileSystemEroFs(mock.Mock(), 'root_dir') + + @patch('os.path.exists') + def setup_method(self, cls, mock_exists): + self.setup() + + @patch('kiwi.filesystem.erofs.Command.run') + def test_create_on_file(self, mock_command): + Defaults.set_platform_name('x86_64') + self.erofs.create_on_file('myimage', 'label') + mock_command.assert_called_once_with( + ['mkfs.erofs', '-L', 'label', 'myimage', 'root_dir'] + ) + + @patch('kiwi.filesystem.erofs.Command.run') + def test_create_on_file_exclude_data(self, mock_command): + Defaults.set_platform_name('x86_64') + self.erofs.create_on_file('myimage', 'label', ['foo']) + mock_command.assert_called_once_with( + [ + 'mkfs.erofs', '-L', 'label', + '--exclude-regex=foo', 'myimage', 'root_dir' + ] + )