Skip to content

Commit 22190cf

Browse files
committed
Add support for filtering out files from the ESP image for GRUB
Prior to this change, KIWI blindly synced the ESP directory into the embedded ESP image. Depending on the distribution and packages included for the created image, this can have undesirable side-effects. For image builds that need some more fine-grained control over the creation of the embedded ESP image (particularly for ISO images), this change introduces the ability to inject an exclusion list similar to what is used to filter out files for the root filesystem. Fixes: #2008 Fixes: #2777
1 parent 463a79c commit 22190cf

File tree

7 files changed

+104
-8
lines changed

7 files changed

+104
-8
lines changed

build-tests/x86/fedora/test-image-live-disk/appliance.kiwi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
<source path="obsrepositories:/"/>
6262
</repository>
6363
<packages type="image">
64+
<!-- Filter out unwanted EFI files from the embedded ESP -->
65+
<file name="iso-esp-excludes.yaml" target="image/exclude_files_efifatimage.yaml"/>
6466
<package name="grub2"/>
6567
<package name="grubby"/>
6668
<package name="kernel"/>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
exclude:
2+
- BOOT/fb*.efi
3+
- fedora

kiwi/bootloader/config/grub2.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from kiwi.system.identifier import SystemIdentifier
3636
from kiwi.utils.sync import DataSync
3737
from kiwi.utils.sysconfig import SysConfig
38+
from kiwi.utils.temporary import Temporary
3839

3940
from kiwi.exceptions import (
4041
KiwiTemplateError,
@@ -1032,6 +1033,12 @@ def _create_embedded_fat_efi_image(self, path):
10321033
self.xml_state.build_type
10331034
.get_efifatimagesize() or defaults.EFI_FAT_IMAGE_SIZE
10341035
)
1036+
efi_folder = Temporary(prefix='efi_folder').new_dir()
1037+
efi_data = DataSync(self.boot_dir + '/EFI/', efi_folder.name)
1038+
efi_data.sync_data(
1039+
options=Defaults.get_sync_options(),
1040+
exclude=Defaults.get_exclude_list_from_custom_exclude_files_for_efifatimage(self.root_dir)
1041+
)
10351042
Command.run(
10361043
['qemu-img', 'create', path, f'{fat_image_mbsize}M']
10371044
)
@@ -1041,7 +1048,7 @@ def _create_embedded_fat_efi_image(self, path):
10411048
Command.run(
10421049
[
10431050
'mcopy', '-Do', '-s', '-i', path,
1044-
self.boot_dir + '/EFI', '::'
1051+
efi_folder.name, '::EFI'
10451052
]
10461053
)
10471054

kiwi/defaults.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -443,19 +443,30 @@ def get_runtime_checker_metadata() -> Dict:
443443
return yaml.safe_load(meta)
444444

445445
@staticmethod
446-
def get_exclude_list_from_custom_exclude_files(root_dir: str) -> List:
446+
def _parse_exclude_file(root_dir: str, exclude_filename: str) -> List:
447447
"""
448-
Provides the list of folders that are excluded by the
449-
optional metadata file image/exclude_files.yaml
448+
Retrieves an exclusion list from the provided metadata file
450449
451-
:return: list of file and directory names
450+
The file should contain a YAML dictionary with a top-level key
451+
named 'exclude' and the list of exclusions as its value.
452+
453+
The list of exclusions may include:
454+
* file paths
455+
* folder paths
456+
* glob patterns
457+
458+
Paths and patterns should be relative to the filesystem or
459+
directory that they're being excluded from.
460+
461+
:return: list of paths and glob patterns
452462
453463
:param string root_dir: image root directory
464+
:param string exclude_filename: file exclusion YAML metadata file
454465
455466
:rtype: list
456467
"""
457468
exclude_file = os.sep.join(
458-
[root_dir, 'image', 'exclude_files.yaml']
469+
[root_dir, 'image', exclude_filename]
459470
)
460471
exclude_list = []
461472
if os.path.isfile(exclude_file):
@@ -473,6 +484,36 @@ def get_exclude_list_from_custom_exclude_files(root_dir: str) -> List:
473484
)
474485
return exclude_list
475486

487+
@staticmethod
488+
def get_exclude_list_from_custom_exclude_files(root_dir: str) -> List:
489+
"""
490+
Gets the list of excluded items for the root filesystem from
491+
the optional metadata file image/exclude_files.yaml
492+
493+
:return: list of paths and glob patterns
494+
495+
:param string root_dir: image root directory
496+
497+
:rtype: list
498+
"""
499+
return Defaults._parse_exclude_file(root_dir, 'exclude_files.yaml')
500+
501+
@staticmethod
502+
def get_exclude_list_from_custom_exclude_files_for_efifatimage(root_dir: str) -> List:
503+
"""
504+
Gets the list of excluded items for the ESP's EFI folder from
505+
the optional metadata file image/exclude_files_efifatimage.yaml
506+
507+
Excluded items must be relative to the ESP's /EFI directory.
508+
509+
:return: list of paths and glob patterns
510+
511+
:param string root_dir: EFI root directory
512+
513+
:rtype: list
514+
"""
515+
return Defaults._parse_exclude_file(root_dir, 'exclude_files_efifatimage.yaml')
516+
476517
@staticmethod
477518
def get_exclude_list_for_non_physical_devices():
478519
"""
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
exclude:
2+
- BOOT/fbia32.efi
3+
- BOOT/fbx64.efi

test/unit/bootloader/config/grub2_test.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,8 +326,13 @@ def test_write(
326326
'some-data'
327327
)
328328

329+
@patch('kiwi.bootloader.config.grub2.DataSync.sync_data')
330+
@patch('kiwi.bootloader.config.grub2.Temporary.new_dir')
329331
@patch('kiwi.bootloader.config.grub2.Command.run')
330-
def test_create_embedded_fat_efi_image(self, mock_command):
332+
def test_create_embedded_fat_efi_image(self, mock_command, mock_tmpdir, mock_syncdata):
333+
tmpdir = Mock()
334+
tmpdir.name = 'tmpdir'
335+
mock_tmpdir.return_value = tmpdir
331336
self.bootloader._create_embedded_fat_efi_image('tmp-esp-image')
332337
assert mock_command.call_args_list == [
333338
call(
@@ -343,7 +348,7 @@ def test_create_embedded_fat_efi_image(self, mock_command):
343348
call(
344349
[
345350
'mcopy', '-Do', '-s', '-i', 'tmp-esp-image',
346-
'root_dir/EFI', '::'
351+
'tmpdir', '::EFI'
347352
]
348353
)
349354
]

test/unit/defaults_test.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,23 @@ def test_get_vendor_grubenv(self, mock_path_exists):
107107
assert Defaults.get_vendor_grubenv('boot/efi') == \
108108
'boot/efi/EFI/fedora/grubenv'
109109

110+
def test_parse_exclude_file_is_valid(self):
111+
assert Defaults._parse_exclude_file(
112+
'../data/root-dir', 'exclude_files.yaml'
113+
) == [
114+
'usr/bin/qemu-binfmt',
115+
'usr/bin/qemu-x86_64-binfmt',
116+
'usr/bin/qemu-x86_64'
117+
]
118+
119+
@patch('yaml.safe_load')
120+
def test_parse_exclude_file_is_invalid(self, mock_yaml_safe_load):
121+
mock_yaml_safe_load.return_value = {'invalid': 'artificial'}
122+
with self._caplog.at_level(logging.WARNING):
123+
assert Defaults._parse_exclude_file(
124+
'../data/root-dir', 'exclude_files.yaml'
125+
) == []
126+
110127
def test_get_exclude_list_from_custom_exclude_files(self):
111128
assert Defaults.get_exclude_list_from_custom_exclude_files(
112129
'../data/root-dir'
@@ -126,6 +143,24 @@ def test_get_exclude_list_from_custom_exclude_files_is_invalid(
126143
'../data/root-dir'
127144
) == []
128145

146+
def test_get_exclude_list_from_custom_exclude_files_for_efifatimage(self):
147+
assert Defaults.get_exclude_list_from_custom_exclude_files_for_efifatimage(
148+
'../data/root-dir'
149+
) == [
150+
'BOOT/fbia32.efi',
151+
'BOOT/fbx64.efi',
152+
]
153+
154+
@patch('yaml.safe_load')
155+
def test_get_exclude_list_from_custom_exclude_files_for_efifatimage_is_invalid(
156+
self, mock_yaml_safe_load
157+
):
158+
mock_yaml_safe_load.return_value = {'invalid': 'artificial'}
159+
with self._caplog.at_level(logging.WARNING):
160+
assert Defaults.get_exclude_list_from_custom_exclude_files_for_efifatimage(
161+
'../data/root-dir'
162+
) == []
163+
129164
def test_get_exclude_list_for_root_data_sync(self):
130165
assert Defaults.get_exclude_list_for_root_data_sync() == [
131166
'image', '.kconfig',

0 commit comments

Comments
 (0)