leapp-repository/0041-upgradeinitramfsgenerator-Check-the-free-space-prior.patch
Petr Stodulka ee57901913 CTC2 build candidate
- Fix the calculation of the required free space on each partitions/volume for the upgrade transactions
- Create source overlay images with dynamic sizes to optimize disk space consumption
- Update GRUB2 when /boot resides on multiple devices aggregated in RAID
- Use new leapp CLI API which provides better report summary output
- Introduce possibility to add (custom) kernel drivers to initramfs
- Detect and report use of deprecated Xorg drivers
- Fix the generation of the report about hybrid images
- Inhibit the upgrade when unsupported x86-64 microarchitecture is detected
- Minor improvements and fixes of various reports
- Requires leapp-framework 4.0
- Update leapp data files
- Resolves: rhbz#2140011, rhbz#2144304, rhbz#2174095, rhbz#2219544, rhbz#2215997
2023-07-18 09:39:37 +02:00

162 lines
7.5 KiB
Diff

From 591cdb865befff8035d53b861d9ff95b5704ed64 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Fri, 14 Jul 2023 17:32:46 +0200
Subject: [PATCH 41/42] upgradeinitramfsgenerator: Check the free space prior
the initeramfs generation
Under rare conditions it's possible the last piece free space
is consumed when the upgrade initramfs is generated. It's hard
to hit this problems right now without additional customisations
that consume more space than we expect. However, when it happens,
it not good situation. From this point, check the remaining free
space on the FS hosting the container. In case we have less than
500MB, do not even try. Possibly we will increase the value in future,
but consider it good enough for now.
---
.../libraries/upgradeinitramfsgenerator.py | 73 +++++++++++++++++++
.../unit_test_upgradeinitramfsgenerator.py | 14 ++++
2 files changed, 87 insertions(+)
diff --git a/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/libraries/upgradeinitramfsgenerator.py b/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/libraries/upgradeinitramfsgenerator.py
index f141d9e3..5a686a47 100644
--- a/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/libraries/upgradeinitramfsgenerator.py
+++ b/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/libraries/upgradeinitramfsgenerator.py
@@ -20,6 +20,7 @@ from leapp.utils.deprecation import suppress_deprecation
INITRAM_GEN_SCRIPT_NAME = 'generate-initram.sh'
DRACUT_DIR = '/dracut'
+DEDICATED_LEAPP_PART_URL = 'https://access.redhat.com/solutions/7011704'
def _get_target_kernel_version(context):
@@ -231,6 +232,77 @@ def prepare_userspace_for_initram(context):
_copy_files(context, files)
+def _get_fspace(path, convert_to_mibs=False, coefficient=1):
+ """
+ Return the free disk space on given path.
+
+ The default is in bytes, but if convert_to_mibs is True, return MiBs instead.
+
+ Raises OSError if nothing exists on the given `path`.
+
+ :param path: Path to an existing file or directory
+ :type path: str
+ :param convert_to_mibs: If True, convert the value to MiBs
+ :type convert_to_mibs: bool
+ :param coefficient: Coefficient to multiply the free space (e.g. 0.9 to have it 10% lower). Max: 1
+ :type coefficient: float
+ :rtype: int
+ """
+ # TODO(pstodulk): discuss the function params
+ # NOTE(pstodulk): This func is copied from the overlaygen.py lib
+ # probably it would make sense to make it public in the utils.py lib,
+ # but for now, let's keep it private
+ stat = os.statvfs(path)
+
+ coefficient = min(coefficient, 1)
+ fspace_bytes = int(stat.f_frsize * stat.f_bavail * coefficient)
+ if convert_to_mibs:
+ return int(fspace_bytes / 1024 / 1024) # noqa: W1619; pylint: disable=old-division
+ return fspace_bytes
+
+
+def _check_free_space(context):
+ """
+ Raise StopActorExecutionError if there is less than 500MB of free space available.
+
+ If there is not enough free space in the context, the initramfs will not be
+ generated successfully and it's hard to discover what was the issue. Also
+ the missing space is able to kill the leapp itself - trying to write to the
+ leapp.db when the FS hosting /var/lib/leapp is full, kills the framework
+ and the actor execution too - so there is no gentle way to handle such
+ exceptions when it happens. From this point, let's rather check the available
+ space in advance and stop the execution when it happens.
+
+ It is not expected to hit this issue, but I was successful and I know
+ it's still possible even with all other changes (just it's much harder
+ now to hit it). So adding this seatbelt, that is not 100% bulletproof,
+ but I call it good enough.
+
+ Currently protecting last 500MB. In case of problems, we can increase
+ the value.
+ """
+ message = 'There is not enough space on the file system hosting /var/lib/leapp.'
+ hint = (
+ 'Increase the free space on the filesystem hosting'
+ ' /var/lib/leapp by 500MB at minimum (suggested 1500MB).\n\n'
+ 'It is also a good practice to create dedicated partition'
+ ' for /var/lib/leapp when more space is needed, which can be'
+ ' dropped after the system upgrade is fully completed.'
+ ' For more info, see: {}'
+ .format(DEDICATED_LEAPP_PART_URL)
+ )
+ detail = (
+ 'Remaining free space is lower than 500MB which is not enough to'
+ ' be able to generate the upgrade initramfs. '
+ )
+
+ if _get_fspace(context.base_dir, convert_to_mibs=True) < 500:
+ raise StopActorExecutionError(
+ message=message,
+ details={'hint': hint, 'detail': detail}
+ )
+
+
def generate_initram_disk(context):
"""
Function to actually execute the init ramdisk creation.
@@ -238,6 +310,7 @@ def generate_initram_disk(context):
Includes handling of specified dracut and kernel modules from the host when
needed. The check for the 'conflicting' modules is in a separate actor.
"""
+ _check_free_space(context)
env = {}
if get_target_major_version() == '9':
env = {'SYSTEMD_SECCOMP': '0'}
diff --git a/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/tests/unit_test_upgradeinitramfsgenerator.py b/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/tests/unit_test_upgradeinitramfsgenerator.py
index a2f1c837..8068e177 100644
--- a/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/tests/unit_test_upgradeinitramfsgenerator.py
+++ b/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/tests/unit_test_upgradeinitramfsgenerator.py
@@ -10,6 +10,7 @@ from leapp.libraries.common.testutils import CurrentActorMocked, logger_mocked,
from leapp.utils.deprecation import suppress_deprecation
from leapp.models import ( # isort:skip
+ FIPSInfo,
RequiredUpgradeInitramPackages, # deprecated
UpgradeDracutModule, # deprecated
BootContent,
@@ -250,6 +251,16 @@ def test_prepare_userspace_for_initram(monkeypatch, adjust_cwd, input_msgs, pkgs
assert _sort_files(upgradeinitramfsgenerator._copy_files.args[1]) == _files
+class MockedGetFspace(object):
+ def __init__(self, space):
+ self.space = space
+
+ def __call__(self, dummy_path, convert_to_mibs=False):
+ if not convert_to_mibs:
+ return self.space
+ return int(self.space / 1024 / 1024) # noqa: W1619; pylint: disable=old-division
+
+
@pytest.mark.parametrize('input_msgs,dracut_modules,kernel_modules', [
# test dracut modules with UpgradeDracutModule(s) - orig functionality
(gen_UDM_list(MODULES[0]), MODULES[0], []),
@@ -275,8 +286,11 @@ def test_generate_initram_disk(monkeypatch, input_msgs, dracut_modules, kernel_m
monkeypatch.setattr(upgradeinitramfsgenerator, '_get_target_kernel_version', lambda _: '')
monkeypatch.setattr(upgradeinitramfsgenerator, 'copy_kernel_modules', MockedCopyArgs())
monkeypatch.setattr(upgradeinitramfsgenerator, 'copy_boot_files', lambda dummy: None)
+ monkeypatch.setattr(upgradeinitramfsgenerator, '_get_fspace', MockedGetFspace(2*2**30))
upgradeinitramfsgenerator.generate_initram_disk(context)
+ # TODO(pstodulk): add tests for the check of the free space (sep. from this func)
+
# test now just that all modules have been passed for copying - so we know
# all modules have been consumed
detected_dracut_modules = set()
--
2.41.0