IPU 9.6-10.0: CTC 2 candidate 2
- Detect XFS file systems with problematic parameters - Raise an inhibitor if unsupported target version supplied instead of error - Prevent a possible crash with LiveMode when adding the upgrade boot entry on systems with LVM - Resolves: RHEL-57043, RHEL-52309, RHEL-60034
This commit is contained in:
parent
34e892dbf6
commit
74a92adf20
26
0054-linter-Fix-line-too-long-in-postgresqlcheck.patch
Normal file
26
0054-linter-Fix-line-too-long-in-postgresqlcheck.patch
Normal file
@ -0,0 +1,26 @@
|
||||
From 57fa7a5781f6cff6ab1632d83e971c4bc395fc20 Mon Sep 17 00:00:00 2001
|
||||
From: Matej Matuska <mmatuska@redhat.com>
|
||||
Date: Wed, 22 Jan 2025 14:50:06 +0100
|
||||
Subject: [PATCH 54/63] linter: Fix line too long in postgresqlcheck
|
||||
|
||||
---
|
||||
.../actors/postgresqlcheck/libraries/postgresqlcheck.py | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/repos/system_upgrade/el8toel9/actors/postgresqlcheck/libraries/postgresqlcheck.py b/repos/system_upgrade/el8toel9/actors/postgresqlcheck/libraries/postgresqlcheck.py
|
||||
index eefe583b..1cc5362d 100644
|
||||
--- a/repos/system_upgrade/el8toel9/actors/postgresqlcheck/libraries/postgresqlcheck.py
|
||||
+++ b/repos/system_upgrade/el8toel9/actors/postgresqlcheck/libraries/postgresqlcheck.py
|
||||
@@ -9,7 +9,8 @@ report_server_inst_summary = (
|
||||
' PostgreSQL server 13 by default, which is incompatible with 9.6, 10 and 12'
|
||||
' included in RHEL-8, in those cases, it is necessary to proceed with additional steps'
|
||||
' for the complete upgrade of the PostgreSQL data.'
|
||||
- 'If the database has already been upgraded, meaning the system is already using PostgreSQL 13, then no further actions are required.'
|
||||
+ 'If the database has already been upgraded, meaning the system is already using PostgreSQL 13,'
|
||||
+ ' then no further actions are required.'
|
||||
)
|
||||
|
||||
report_server_inst_hint = (
|
||||
--
|
||||
2.48.1
|
||||
|
39
0055-Fix-typos-in-comments-to-make-spellchecker-happy.patch
Normal file
39
0055-Fix-typos-in-comments-to-make-spellchecker-happy.patch
Normal file
@ -0,0 +1,39 @@
|
||||
From bfcf59e5f78aa7500a6524094bdebf28d359d9d5 Mon Sep 17 00:00:00 2001
|
||||
From: Petr Stodulka <pstodulk@redhat.com>
|
||||
Date: Thu, 23 Jan 2025 11:44:59 +0100
|
||||
Subject: [PATCH 55/63] Fix typos in comments to make spellchecker happy
|
||||
|
||||
---
|
||||
.../common/actors/filterrpmtransactionevents/actor.py | 2 +-
|
||||
.../selinuxcontentscanner/libraries/selinuxcontentscanner.py | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/repos/system_upgrade/common/actors/filterrpmtransactionevents/actor.py b/repos/system_upgrade/common/actors/filterrpmtransactionevents/actor.py
|
||||
index 5ccdb35b..582a5821 100644
|
||||
--- a/repos/system_upgrade/common/actors/filterrpmtransactionevents/actor.py
|
||||
+++ b/repos/system_upgrade/common/actors/filterrpmtransactionevents/actor.py
|
||||
@@ -14,7 +14,7 @@ class FilterRpmTransactionTasks(Actor):
|
||||
|
||||
In order to calculate a working DNF Upgrade transaction, Leapp can collect data from multiple
|
||||
sources and find workarounds for possible problems. This actor will filter all collected
|
||||
- workarounds and keep only those relevants to current system based on installed packages.
|
||||
+ workarounds and keep only those relevant to current system based on installed packages.
|
||||
"""
|
||||
|
||||
name = 'check_rpm_transaction_events'
|
||||
diff --git a/repos/system_upgrade/common/actors/selinux/selinuxcontentscanner/libraries/selinuxcontentscanner.py b/repos/system_upgrade/common/actors/selinux/selinuxcontentscanner/libraries/selinuxcontentscanner.py
|
||||
index 8f5e31ab..1ef69fe6 100644
|
||||
--- a/repos/system_upgrade/common/actors/selinux/selinuxcontentscanner/libraries/selinuxcontentscanner.py
|
||||
+++ b/repos/system_upgrade/common/actors/selinux/selinuxcontentscanner/libraries/selinuxcontentscanner.py
|
||||
@@ -126,7 +126,7 @@ def get_selinux_modules():
|
||||
|
||||
for (name, priority) in modules:
|
||||
# Udica templates should not be transferred, we only need a list of their
|
||||
- # names and priorities so that we can reinstall their latest verisions
|
||||
+ # names and priorities so that we can reinstall their latest versions
|
||||
if name in UDICA_TEMPLATES:
|
||||
template_list.append(
|
||||
SELinuxModule(
|
||||
--
|
||||
2.48.1
|
||||
|
@ -0,0 +1,43 @@
|
||||
From c8614161017104559d224c33a52648e2c317b8e0 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Michal=20He=C4=8Dko?= <michal.sk.com@gmail.com>
|
||||
Date: Tue, 28 Jan 2025 15:08:39 +0100
|
||||
Subject: [PATCH 56/63] fix(add_upgrade_boot_entry): convert arg list into a
|
||||
tuple (#1313)
|
||||
|
||||
Convert collected rd.lvm args into a tuple before trying to make
|
||||
a set with one of the elements being the args. As list is not hashable,
|
||||
this causes the actor to crash.
|
||||
---
|
||||
.../actors/addupgradebootentry/libraries/addupgradebootentry.py | 2 +-
|
||||
.../addupgradebootentry/tests/unit_test_addupgradebootentry.py | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/repos/system_upgrade/common/actors/addupgradebootentry/libraries/addupgradebootentry.py b/repos/system_upgrade/common/actors/addupgradebootentry/libraries/addupgradebootentry.py
|
||||
index b236e39b..981c9401 100644
|
||||
--- a/repos/system_upgrade/common/actors/addupgradebootentry/libraries/addupgradebootentry.py
|
||||
+++ b/repos/system_upgrade/common/actors/addupgradebootentry/libraries/addupgradebootentry.py
|
||||
@@ -303,7 +303,7 @@ def _get_rdlvm_arg_values():
|
||||
api.current_logger().debug('Collected the following rd.lvm.lv args that are undesired for the squashfs: %s',
|
||||
rd_lvm_values)
|
||||
|
||||
- return rd_lvm_values
|
||||
+ return tuple(rd_lvm_values)
|
||||
|
||||
|
||||
def construct_cmdline_args_for_livemode():
|
||||
diff --git a/repos/system_upgrade/common/actors/addupgradebootentry/tests/unit_test_addupgradebootentry.py b/repos/system_upgrade/common/actors/addupgradebootentry/tests/unit_test_addupgradebootentry.py
|
||||
index 2f58ba9e..dde18782 100644
|
||||
--- a/repos/system_upgrade/common/actors/addupgradebootentry/tests/unit_test_addupgradebootentry.py
|
||||
+++ b/repos/system_upgrade/common/actors/addupgradebootentry/tests/unit_test_addupgradebootentry.py
|
||||
@@ -273,7 +273,7 @@ def test_get_rdlvm_arg_values(monkeypatch):
|
||||
|
||||
args = addupgradebootentry._get_rdlvm_arg_values()
|
||||
|
||||
- assert args == ['A', 'B']
|
||||
+ assert args == ('A', 'B')
|
||||
|
||||
|
||||
def test_get_device_uuid(monkeypatch):
|
||||
--
|
||||
2.48.1
|
||||
|
251
0057-fix-arm-bootloader-efi-patch-grub.cfg-used-for-upgra.patch
Normal file
251
0057-fix-arm-bootloader-efi-patch-grub.cfg-used-for-upgra.patch
Normal file
@ -0,0 +1,251 @@
|
||||
From 1207dececb3911efacc4ba548b2d173c0f604a41 Mon Sep 17 00:00:00 2001
|
||||
From: Michal Hecko <mhecko@redhat.com>
|
||||
Date: Thu, 16 Jan 2025 18:54:34 +0100
|
||||
Subject: [PATCH 57/63] fix(arm,bootloader,efi): patch grub.cfg used for
|
||||
upgrading
|
||||
|
||||
Use the grub.cfg bundled within leapp if we detect that
|
||||
system's grub.cfg contains problematic configuration which
|
||||
will not load grubenv of the upgrade BLS entry. We need
|
||||
to ensure that this grubenv is loaded, as without it we
|
||||
cannot guarantee a successful boot into upgrade environment.
|
||||
---
|
||||
.../files/grub2_config_template | 26 +++++
|
||||
.../libraries/addupgradebootloader.py | 102 +++++++++++++++++-
|
||||
.../tests/test_addarmbootloaderworkaround.py | 29 +++++
|
||||
.../libraries/removeupgradeefientry.py | 4 +-
|
||||
4 files changed, 158 insertions(+), 3 deletions(-)
|
||||
create mode 100644 repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/files/grub2_config_template
|
||||
|
||||
diff --git a/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/files/grub2_config_template b/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/files/grub2_config_template
|
||||
new file mode 100644
|
||||
index 00000000..83de1417
|
||||
--- /dev/null
|
||||
+++ b/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/files/grub2_config_template
|
||||
@@ -0,0 +1,26 @@
|
||||
+set timeout=0
|
||||
+
|
||||
+# Make sure to load EFI/leapp/grubenv and not system's default path
|
||||
+if [ -f ${config_directory}/grubenv ]; then
|
||||
+ load_env -f ${config_directory}/grubenv
|
||||
+elif [ -s $prefix/grubenv ]; then
|
||||
+ load_env
|
||||
+fi
|
||||
+
|
||||
+# EFI/leapp/grubenv contains our upgrade BLS entry as saved_entry
|
||||
+if [ "${next_entry}" ] ; then
|
||||
+ set default="${next_entry}"
|
||||
+ set next_entry=
|
||||
+ save_env next_entry
|
||||
+ set boot_once=true
|
||||
+else
|
||||
+ set default="${saved_entry}"
|
||||
+fi
|
||||
+
|
||||
+search --no-floppy --set=root --fs-uuid LEAPP_BOOT_UUID
|
||||
+set boot=${root}
|
||||
+function load_video {
|
||||
+ insmod all_video
|
||||
+}
|
||||
+${serial}${terminal_input}${terminal_output}
|
||||
+blscfg
|
||||
diff --git a/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/libraries/addupgradebootloader.py b/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/libraries/addupgradebootloader.py
|
||||
index 5e9bf5c6..01db9bbf 100644
|
||||
--- a/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/libraries/addupgradebootloader.py
|
||||
+++ b/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/libraries/addupgradebootloader.py
|
||||
@@ -6,6 +6,7 @@ from leapp.libraries.common import mounting
|
||||
from leapp.libraries.common.grub import (
|
||||
canonical_path_to_efi_format,
|
||||
EFIBootInfo,
|
||||
+ get_boot_partition,
|
||||
get_device_number,
|
||||
get_efi_device,
|
||||
get_efi_partition,
|
||||
@@ -26,6 +27,15 @@ RHEL_EFIDIR_CANONICAL_PATH = os.path.join(EFI_MOUNTPOINT, 'EFI/redhat/')
|
||||
|
||||
CONTAINER_DOWNLOAD_DIR = '/tmp_pkg_download_dir'
|
||||
|
||||
+LEAPP_GRUB2_CFG_TEMPLATE = 'grub2_config_template'
|
||||
+"""
|
||||
+Our grub configuration file template that is used in case the system's grubcfg would not load our grubenv.
|
||||
+
|
||||
+The template contains placeholders named with LEAPP_*, that need to be replaced in order to
|
||||
+obtain a valid config.
|
||||
+
|
||||
+"""
|
||||
+
|
||||
|
||||
def _copy_file(src_path, dst_path):
|
||||
if os.path.exists(dst_path):
|
||||
@@ -49,11 +59,14 @@ def process():
|
||||
context.copytree_from(RHEL_EFIDIR_CANONICAL_PATH, LEAPP_EFIDIR_CANONICAL_PATH)
|
||||
|
||||
_copy_grub_files(['grubenv', 'grub.cfg'], ['user.cfg'])
|
||||
- _link_grubenv_to_upgrade_entry()
|
||||
|
||||
efibootinfo = EFIBootInfo()
|
||||
current_boot_entry = efibootinfo.entries[efibootinfo.current_bootnum]
|
||||
upgrade_boot_entry = _add_upgrade_boot_entry(efibootinfo)
|
||||
+
|
||||
+ leapp_efi_grubenv = os.path.join(EFI_MOUNTPOINT, LEAPP_EFIDIR_CANONICAL_PATH, 'grubenv')
|
||||
+ patch_efi_redhat_grubcfg_to_load_correct_grubenv()
|
||||
+
|
||||
_set_bootnext(upgrade_boot_entry.boot_number)
|
||||
|
||||
efibootentry_fields = ['boot_number', 'label', 'active', 'efi_bin_source']
|
||||
@@ -183,3 +196,90 @@ def _set_bootnext(boot_number):
|
||||
run(['/usr/sbin/efibootmgr', '--bootnext', boot_number])
|
||||
except CalledProcessError:
|
||||
raise StopActorExecutionError('Could not set boot entry {} as BootNext.'.format(boot_number))
|
||||
+
|
||||
+
|
||||
+def _notify_user_to_check_grub2_cfg():
|
||||
+ # Or maybe rather ask a question in a dialog? But this is rare, so maybe continuing is fine.
|
||||
+ pass
|
||||
+
|
||||
+
|
||||
+def _will_grubcfg_read_our_grubenv(grubcfg_path):
|
||||
+ with open(grubcfg_path) as grubcfg:
|
||||
+ config_lines = grubcfg.readlines()
|
||||
+
|
||||
+ will_read = False
|
||||
+ for line in config_lines:
|
||||
+ if line.strip() == 'load_env -f ${config_directory}/grubenv':
|
||||
+ will_read = True
|
||||
+ break
|
||||
+
|
||||
+ return will_read
|
||||
+
|
||||
+
|
||||
+def _get_boot_device_uuid():
|
||||
+ boot_device = get_boot_partition()
|
||||
+ try:
|
||||
+ raw_device_info_lines = run(['blkid', boot_device], split=True)['stdout']
|
||||
+ raw_device_info = raw_device_info_lines[0] # There is only 1 output line
|
||||
+
|
||||
+ uuid_needle_start_pos = raw_device_info.index('UUID')
|
||||
+ raw_device_info = raw_device_info[uuid_needle_start_pos:] # results in: "UUID="..." ....
|
||||
+
|
||||
+ uuid = raw_device_info.split(' ', 1)[0] # UUID cannot contain spaces
|
||||
+ uuid = uuid[len('UUID='):] # Remove UUID=
|
||||
+ uuid = uuid.strip('"')
|
||||
+ return uuid
|
||||
+
|
||||
+ except CalledProcessError as error:
|
||||
+ details = {'details': 'blkid failed with error: {}'.format(error)}
|
||||
+ raise StopActorExecutionError('Failed to obtain UUID of /boot partition', details=details)
|
||||
+
|
||||
+
|
||||
+def _prepare_config_contents():
|
||||
+ config_template_path = api.get_actor_file_path(LEAPP_GRUB2_CFG_TEMPLATE)
|
||||
+ with open(config_template_path) as config_template_handle:
|
||||
+ config_template = config_template_handle.read()
|
||||
+
|
||||
+ substitutions = {
|
||||
+ 'LEAPP_BOOT_UUID': _get_boot_device_uuid()
|
||||
+ }
|
||||
+
|
||||
+ api.current_logger().debug(
|
||||
+ 'Applying the following substitution map to grub config template: {}'.format(substitutions)
|
||||
+ )
|
||||
+
|
||||
+ for placeholder, placeholder_value in substitutions.items():
|
||||
+ config_template = config_template.replace(placeholder, placeholder_value)
|
||||
+
|
||||
+ return config_template
|
||||
+
|
||||
+
|
||||
+def _write_config(config_path, config_contents):
|
||||
+ with open(config_path, 'w') as grub_cfg_handle:
|
||||
+ grub_cfg_handle.write(config_contents)
|
||||
+
|
||||
+
|
||||
+def patch_efi_redhat_grubcfg_to_load_correct_grubenv():
|
||||
+ """
|
||||
+ Replaces /boot/efi/EFI/redhat/grub2.cfg with a patched grub2.cfg shipped in leapp.
|
||||
+
|
||||
+ The grub2.cfg shipped on some AWS images omits the section that loads grubenv different
|
||||
+ EFI entries. Thus, we need to replace it with our own that will load grubenv shipped
|
||||
+ of our UEFI boot entry.
|
||||
+ """
|
||||
+ leapp_grub_cfg_path = os.path.join(EFI_MOUNTPOINT, LEAPP_EFIDIR_CANONICAL_PATH, 'grub.cfg')
|
||||
+
|
||||
+ if not os.path.isfile(leapp_grub_cfg_path):
|
||||
+ msg = 'The file {} does not exists, cannot check whether bootloader is configured properly.'
|
||||
+ raise StopActorExecutionError(msg.format(leapp_grub_cfg_path))
|
||||
+
|
||||
+ if _will_grubcfg_read_our_grubenv(leapp_grub_cfg_path):
|
||||
+ api.current_logger().debug('The current grub.cfg will read our grubenv without any modifications.')
|
||||
+ return
|
||||
+
|
||||
+ api.current_logger().info('Current grub2.cfg is likely faulty (would not read our grubenv), patching.')
|
||||
+
|
||||
+ config_contents = _prepare_config_contents()
|
||||
+ _write_config(leapp_grub_cfg_path, config_contents)
|
||||
+
|
||||
+ api.current_logger().info('New upgrade grub.cfg has been written to {}'.format(leapp_grub_cfg_path))
|
||||
diff --git a/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/tests/test_addarmbootloaderworkaround.py b/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/tests/test_addarmbootloaderworkaround.py
|
||||
index d2015272..9ab3b7d0 100644
|
||||
--- a/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/tests/test_addarmbootloaderworkaround.py
|
||||
+++ b/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/tests/test_addarmbootloaderworkaround.py
|
||||
@@ -298,6 +298,9 @@ def test_process(monkeypatch):
|
||||
monkeypatch.setattr(addupgradebootloader, '_add_upgrade_boot_entry', mock_add_upgrade_boot_entry)
|
||||
monkeypatch.setattr(addupgradebootloader, '_set_bootnext', lambda _: None)
|
||||
|
||||
+ monkeypatch.setattr(addupgradebootloader, 'patch_efi_redhat_grubcfg_to_load_correct_grubenv',
|
||||
+ lambda: None)
|
||||
+
|
||||
addupgradebootloader.process()
|
||||
|
||||
assert api.produce.called == 1
|
||||
@@ -307,6 +310,32 @@ def test_process(monkeypatch):
|
||||
expected = ArmWorkaroundEFIBootloaderInfo(
|
||||
original_entry=EFIBootEntry(**{f: getattr(TEST_RHEL_EFI_ENTRY, f) for f in efibootentry_fields}),
|
||||
upgrade_entry=EFIBootEntry(**{f: getattr(TEST_UPGRADE_EFI_ENTRY, f) for f in efibootentry_fields}),
|
||||
+ upgrade_bls_dir='/boot/upgrade-loader/entries',
|
||||
+ upgrade_entry_efi_path='/boot/efi/EFI/leapp/',
|
||||
)
|
||||
actual = api.produce.model_instances[0]
|
||||
assert actual == expected
|
||||
+
|
||||
+
|
||||
+@pytest.mark.parametrize('is_config_ok', (True, False))
|
||||
+def test_patch_grubcfg(is_config_ok, monkeypatch):
|
||||
+
|
||||
+ expected_grubcfg_path = os.path.join(addupgradebootloader.EFI_MOUNTPOINT,
|
||||
+ addupgradebootloader.LEAPP_EFIDIR_CANONICAL_PATH,
|
||||
+ 'grub.cfg')
|
||||
+ def isfile_mocked(path):
|
||||
+ assert expected_grubcfg_path == path
|
||||
+ return True
|
||||
+
|
||||
+ def prepare_config_contents_mocked():
|
||||
+ return 'config contents'
|
||||
+
|
||||
+ def write_config(path, contents):
|
||||
+ assert not is_config_ok # We should write only when the config is not OK
|
||||
+ assert path == expected_grubcfg_path
|
||||
+ assert contents == 'config contents'
|
||||
+
|
||||
+ monkeypatch.setattr(os.path, 'isfile', isfile_mocked)
|
||||
+ monkeypatch.setattr(addupgradebootloader, '_will_grubcfg_read_our_grubenv', lambda cfg_path: is_config_ok)
|
||||
+ monkeypatch.setattr(addupgradebootloader, '_prepare_config_contents', prepare_config_contents_mocked)
|
||||
+ monkeypatch.setattr(addupgradebootloader, '_write_config', write_config)
|
||||
diff --git a/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/libraries/removeupgradeefientry.py b/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/libraries/removeupgradeefientry.py
|
||||
index 3ff3ead9..97ede80a 100644
|
||||
--- a/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/libraries/removeupgradeefientry.py
|
||||
+++ b/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/libraries/removeupgradeefientry.py
|
||||
@@ -35,8 +35,8 @@ def remove_upgrade_efi_entry():
|
||||
|
||||
bootloader_info = get_workaround_efi_info()
|
||||
|
||||
- _copy_grub_files(['grubenv', 'grub.cfg'], ['user.cfg'])
|
||||
- _link_grubenv_to_rhel_entry()
|
||||
+ # _copy_grub_files(['grubenv', 'grub.cfg'], ['user.cfg'])
|
||||
+ # _link_grubenv_to_rhel_entry()
|
||||
|
||||
upgrade_boot_number = bootloader_info.upgrade_entry.boot_number
|
||||
try:
|
||||
--
|
||||
2.48.1
|
||||
|
524
0058-feat-arm-bootloader-efi-use-separate-BLS-directory-f.patch
Normal file
524
0058-feat-arm-bootloader-efi-use-separate-BLS-directory-f.patch
Normal file
@ -0,0 +1,524 @@
|
||||
From b71b666594043ef6076c0c6220aeb54e7ee3a2a4 Mon Sep 17 00:00:00 2001
|
||||
From: Michal Hecko <mhecko@redhat.com>
|
||||
Date: Mon, 20 Jan 2025 14:59:37 +0100
|
||||
Subject: [PATCH 58/63] feat(arm,bootloader,efi): use separate BLS directory
|
||||
for upgrades
|
||||
|
||||
Use a separate BLS directory '/boot/upgrade-loader/entries'
|
||||
that mimics '/boot/loader/entries'. This allows very fine
|
||||
control of what boot entries are available when booting
|
||||
into upgrade environment via a separate EFI entry.
|
||||
---
|
||||
.../actors/addupgradebootentry/actor.py | 2 +
|
||||
.../libraries/addupgradebootentry.py | 97 +++++++++++++++++++
|
||||
.../tests/unit_test_addupgradebootentry.py | 53 ++++++++++
|
||||
.../actors/removeupgradebootentry/actor.py | 4 +-
|
||||
.../libraries/removeupgradebootentry.py | 10 +-
|
||||
.../tests/unit_test_removeupgradebootentry.py | 41 +++++---
|
||||
.../libraries/addupgradebootloader.py | 4 +-
|
||||
.../tests/test_addarmbootloaderworkaround.py | 3 +-
|
||||
.../libraries/removeupgradeefientry.py | 14 ++-
|
||||
.../tests/test_removeupgradeefientry.py | 11 ++-
|
||||
.../el8toel9/models/upgradeefientry.py | 16 +++
|
||||
11 files changed, 232 insertions(+), 23 deletions(-)
|
||||
|
||||
diff --git a/repos/system_upgrade/common/actors/addupgradebootentry/actor.py b/repos/system_upgrade/common/actors/addupgradebootentry/actor.py
|
||||
index e4ecf39e..9698f3c2 100644
|
||||
--- a/repos/system_upgrade/common/actors/addupgradebootentry/actor.py
|
||||
+++ b/repos/system_upgrade/common/actors/addupgradebootentry/actor.py
|
||||
@@ -4,6 +4,7 @@ from leapp.actors import Actor
|
||||
from leapp.exceptions import StopActorExecutionError
|
||||
from leapp.libraries.actor.addupgradebootentry import add_boot_entry, fix_grub_config_error
|
||||
from leapp.models import (
|
||||
+ ArmWorkaroundEFIBootloaderInfo,
|
||||
BootContent,
|
||||
FirmwareFacts,
|
||||
GrubConfigError,
|
||||
@@ -28,6 +29,7 @@ class AddUpgradeBootEntry(Actor):
|
||||
|
||||
name = 'add_upgrade_boot_entry'
|
||||
consumes = (
|
||||
+ ArmWorkaroundEFIBootloaderInfo,
|
||||
BootContent,
|
||||
GrubConfigError,
|
||||
FirmwareFacts,
|
||||
diff --git a/repos/system_upgrade/common/actors/addupgradebootentry/libraries/addupgradebootentry.py b/repos/system_upgrade/common/actors/addupgradebootentry/libraries/addupgradebootentry.py
|
||||
index 981c9401..53b57e95 100644
|
||||
--- a/repos/system_upgrade/common/actors/addupgradebootentry/libraries/addupgradebootentry.py
|
||||
+++ b/repos/system_upgrade/common/actors/addupgradebootentry/libraries/addupgradebootentry.py
|
||||
@@ -1,11 +1,13 @@
|
||||
import itertools
|
||||
import os
|
||||
import re
|
||||
+import shutil
|
||||
|
||||
from leapp.exceptions import StopActorExecutionError
|
||||
from leapp.libraries.common.config import architecture, get_env
|
||||
from leapp.libraries.stdlib import api, CalledProcessError, run
|
||||
from leapp.models import (
|
||||
+ ArmWorkaroundEFIBootloaderInfo,
|
||||
BootContent,
|
||||
KernelCmdline,
|
||||
KernelCmdlineArg,
|
||||
@@ -197,6 +199,8 @@ def add_boot_entry(configs=None):
|
||||
details={'details': '{}: {}'.format(str(e), e.stderr)}
|
||||
)
|
||||
|
||||
+ apply_arm_specific_modifications()
|
||||
+
|
||||
|
||||
def _remove_old_upgrade_boot_entry(kernel_dst_path, configs=None):
|
||||
"""
|
||||
@@ -357,3 +361,96 @@ def construct_cmdline_args_for_livemode():
|
||||
api.current_logger().info('The use of live mode image implies the following cmdline args: %s', args)
|
||||
|
||||
return args
|
||||
+
|
||||
+
|
||||
+def _list_grubenv_variables():
|
||||
+ try:
|
||||
+ output_lines = run(['grub2-editenv', 'list'], split=True)['stdout']
|
||||
+ except CalledProcessError:
|
||||
+ raise StopActorExecutionError('Failed to list grubenv variables used by the system')
|
||||
+
|
||||
+ vars_with_values = {}
|
||||
+ for line in output_lines:
|
||||
+ var_with_value = line.split('=', 1)
|
||||
+ if len(var_with_value) <= 1:
|
||||
+ api.current_logger().warning(
|
||||
+ 'Skipping \'{}\' in grub2-editenv output, the line does not have the form <var>=<value>'
|
||||
+ )
|
||||
+ continue
|
||||
+ vars_with_values[var_with_value[0]] = var_with_value[1]
|
||||
+
|
||||
+ return vars_with_values
|
||||
+
|
||||
+
|
||||
+def apply_arm_specific_modifications():
|
||||
+ arm_efi_info = next(api.consume(ArmWorkaroundEFIBootloaderInfo), None)
|
||||
+ if not arm_efi_info:
|
||||
+ return
|
||||
+
|
||||
+ modify_our_grubenv_to_have_separate_blsdir(arm_efi_info)
|
||||
+
|
||||
+
|
||||
+def modify_our_grubenv_to_have_separate_blsdir(efi_info):
|
||||
+ """ Create a new blsdir for the upgrade entry if using a separate EFI entry. """
|
||||
+ leapp_efi_grubenv_path = os.path.join(efi_info.upgrade_entry_efi_path, 'grubenv')
|
||||
+
|
||||
+ api.current_logger().debug(
|
||||
+ 'Setting up separate blsdir for the upgrade using grubenv: {}'.format(leapp_efi_grubenv_path)
|
||||
+ )
|
||||
+
|
||||
+ grubenv_vars = _list_grubenv_variables()
|
||||
+ system_bls_dir = grubenv_vars.get('blsdir', '/loader/entries').lstrip('/')
|
||||
+
|
||||
+ # BLS dir is relative to /boot, prepend it so we can list its contents
|
||||
+ system_bls_dir = os.path.join('/boot', system_bls_dir)
|
||||
+
|
||||
+ # Find our loader entry
|
||||
+ try:
|
||||
+ bls_entries = os.listdir(system_bls_dir)
|
||||
+ except IOError: # Technically, we want FileNotFoundError, but that is only Python3.3+, so this is fine
|
||||
+ details = {
|
||||
+ 'details': 'Failed to list {}.'.format(system_bls_dir)
|
||||
+ }
|
||||
+ raise StopActorExecutionError('Failed to set up bootloader for the upgrade.', details=details)
|
||||
+
|
||||
+ leapp_bls_entry = None
|
||||
+ for bls_entry in bls_entries:
|
||||
+ if bls_entry.endswith('upgrade.aarch64.conf'):
|
||||
+ leapp_bls_entry = bls_entry
|
||||
+ break
|
||||
+
|
||||
+ if not leapp_bls_entry:
|
||||
+ details = {
|
||||
+ 'details': 'Failed to identify BLS entry that belongs to leapp in {}'.format(system_bls_dir)
|
||||
+ }
|
||||
+ raise StopActorExecutionError('Failed to set up bootloader for the upgrade.')
|
||||
+
|
||||
+ # The 'blsdir' grubenv variable specifies location of bls directory relative to /boot
|
||||
+ if os.path.exists(efi_info.upgrade_bls_dir):
|
||||
+ msg = 'The {} directory exists, probably a left-over from previous executions. Removing.'
|
||||
+ api.current_logger().debug(msg.format(efi_info.upgrade_bls_dir))
|
||||
+ shutil.rmtree(efi_info.upgrade_bls_dir)
|
||||
+
|
||||
+ os.makedirs(efi_info.upgrade_bls_dir)
|
||||
+ api.current_logger().debug('Successfully created upgrade BLS directory: {}'.format(efi_info.upgrade_bls_dir))
|
||||
+
|
||||
+ leapp_bls_entry_fullpath = os.path.join(system_bls_dir, leapp_bls_entry)
|
||||
+ bls_entry_dst = os.path.join(efi_info.upgrade_bls_dir, leapp_bls_entry)
|
||||
+ api.current_logger().debug(
|
||||
+ 'Moving leapp\'s BLS entry ({}) into a separate BLS dir located at {}'.format(
|
||||
+ leapp_bls_entry, efi_info.upgrade_bls_dir
|
||||
+ )
|
||||
+ )
|
||||
+
|
||||
+ shutil.move(leapp_bls_entry_fullpath, bls_entry_dst)
|
||||
+
|
||||
+ upgrade_bls_dir_rel_to_boot = efi_info.upgrade_bls_dir[len('/boot'):]
|
||||
+
|
||||
+ # Modify leapp's grubenv to define our own BLSDIR
|
||||
+ try:
|
||||
+ run(['grub2-editenv', leapp_efi_grubenv_path, 'set', 'blsdir={}'.format(upgrade_bls_dir_rel_to_boot)])
|
||||
+ except CalledProcessError as error:
|
||||
+ details = {
|
||||
+ 'details': 'Failed to modify upgrade grubenv to contain a custom blsdir definition. Error {}'.format(error)
|
||||
+ }
|
||||
+ raise StopActorExecutionError('Failed to set up bootloader for the upgrade.', details=details)
|
||||
diff --git a/repos/system_upgrade/common/actors/addupgradebootentry/tests/unit_test_addupgradebootentry.py b/repos/system_upgrade/common/actors/addupgradebootentry/tests/unit_test_addupgradebootentry.py
|
||||
index dde18782..2a0b3f0f 100644
|
||||
--- a/repos/system_upgrade/common/actors/addupgradebootentry/tests/unit_test_addupgradebootentry.py
|
||||
+++ b/repos/system_upgrade/common/actors/addupgradebootentry/tests/unit_test_addupgradebootentry.py
|
||||
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
+import shutil
|
||||
from collections import namedtuple
|
||||
|
||||
import pytest
|
||||
@@ -9,7 +10,9 @@ from leapp.libraries.common.config.architecture import ARCH_S390X, ARCH_X86_64
|
||||
from leapp.libraries.common.testutils import CurrentActorMocked, produce_mocked
|
||||
from leapp.libraries.stdlib import api
|
||||
from leapp.models import (
|
||||
+ ArmWorkaroundEFIBootloaderInfo,
|
||||
BootContent,
|
||||
+ EFIBootEntry,
|
||||
KernelCmdline,
|
||||
KernelCmdlineArg,
|
||||
LateTargetKernelCmdlineArgTasks,
|
||||
@@ -326,3 +329,53 @@ def test_get_device_uuid(monkeypatch):
|
||||
uuid = addupgradebootentry._get_device_uuid(path)
|
||||
|
||||
assert uuid == 'MY_UUID1'
|
||||
+
|
||||
+
|
||||
+def test_modify_grubenv_to_have_separate_blsdir(monkeypatch):
|
||||
+ efi_info = ArmWorkaroundEFIBootloaderInfo(
|
||||
+ original_entry=EFIBootEntry(
|
||||
+ boot_number='0001',
|
||||
+ label='Redhat',
|
||||
+ active=True,
|
||||
+ efi_bin_source="HD(.*)/File(\\EFI\\redhat\\shimx64.efi)",
|
||||
+ ),
|
||||
+ upgrade_entry=EFIBootEntry(
|
||||
+ boot_number='0002',
|
||||
+ label='Leapp',
|
||||
+ active=True,
|
||||
+ efi_bin_source="HD(.*)/File(\\EFI\\leapp\\shimx64.efi)",
|
||||
+ ),
|
||||
+ upgrade_bls_dir='/boot/upgrade-loader/entries',
|
||||
+ upgrade_entry_efi_path='/boot/efi/EFI/leapp'
|
||||
+ )
|
||||
+
|
||||
+ def list_grubenv_variables_mock():
|
||||
+ return {
|
||||
+ 'blsdir': '/blsdir'
|
||||
+ }
|
||||
+
|
||||
+ def listdir_mock(dir_path):
|
||||
+ assert dir_path == '/boot/blsdir'
|
||||
+ return [
|
||||
+ '4a9c76478b98444fb5e0fbf533950edf-6.12.5-200.fc41.x86_64.conf',
|
||||
+ '4a9c76478b98444fb5e0fbf533950edf-upgrade.aarch64.conf',
|
||||
+ ]
|
||||
+
|
||||
+ def assert_path_correct(path):
|
||||
+ assert path == efi_info.upgrade_bls_dir
|
||||
+
|
||||
+ def move_mocked(src, dst):
|
||||
+ assert src == '/boot/blsdir/4a9c76478b98444fb5e0fbf533950edf-upgrade.aarch64.conf'
|
||||
+ assert dst == '/boot/upgrade-loader/entries/4a9c76478b98444fb5e0fbf533950edf-upgrade.aarch64.conf'
|
||||
+
|
||||
+ def run_mocked(cmd, *arg, **kwargs):
|
||||
+ assert cmd == ['grub2-editenv', '/boot/efi/EFI/leapp/grubenv', 'set', 'blsdir=/upgrade-loader/entries']
|
||||
+
|
||||
+ monkeypatch.setattr(addupgradebootentry, '_list_grubenv_variables', list_grubenv_variables_mock)
|
||||
+ monkeypatch.setattr(os, 'listdir', listdir_mock)
|
||||
+ monkeypatch.setattr(os.path, 'exists', assert_path_correct)
|
||||
+ monkeypatch.setattr(os, 'makedirs', assert_path_correct)
|
||||
+ monkeypatch.setattr(shutil, 'move', move_mocked)
|
||||
+ monkeypatch.setattr(addupgradebootentry, 'run', run_mocked)
|
||||
+
|
||||
+ addupgradebootentry.modify_our_grubenv_to_have_separate_blsdir(efi_info)
|
||||
diff --git a/repos/system_upgrade/common/actors/removeupgradebootentry/actor.py b/repos/system_upgrade/common/actors/removeupgradebootentry/actor.py
|
||||
index 32759e77..6a0a1081 100644
|
||||
--- a/repos/system_upgrade/common/actors/removeupgradebootentry/actor.py
|
||||
+++ b/repos/system_upgrade/common/actors/removeupgradebootentry/actor.py
|
||||
@@ -1,6 +1,6 @@
|
||||
from leapp.actors import Actor
|
||||
from leapp.libraries.actor.removeupgradebootentry import remove_boot_entry
|
||||
-from leapp.models import BootContent, FirmwareFacts
|
||||
+from leapp.models import ArmWorkaroundEFIBootloaderInfo, BootContent, FirmwareFacts
|
||||
from leapp.tags import InitRamStartPhaseTag, IPUWorkflowTag
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ class RemoveUpgradeBootEntry(Actor):
|
||||
"""
|
||||
|
||||
name = 'remove_upgrade_boot_entry'
|
||||
- consumes = (BootContent, FirmwareFacts)
|
||||
+ consumes = (ArmWorkaroundEFIBootloaderInfo, BootContent, FirmwareFacts)
|
||||
produces = ()
|
||||
tags = (IPUWorkflowTag, InitRamStartPhaseTag)
|
||||
|
||||
diff --git a/repos/system_upgrade/common/actors/removeupgradebootentry/libraries/removeupgradebootentry.py b/repos/system_upgrade/common/actors/removeupgradebootentry/libraries/removeupgradebootentry.py
|
||||
index ee8e1ecd..7434e48c 100644
|
||||
--- a/repos/system_upgrade/common/actors/removeupgradebootentry/libraries/removeupgradebootentry.py
|
||||
+++ b/repos/system_upgrade/common/actors/removeupgradebootentry/libraries/removeupgradebootentry.py
|
||||
@@ -1,7 +1,7 @@
|
||||
from leapp.exceptions import StopActorExecutionError
|
||||
from leapp.libraries.common.config import architecture
|
||||
from leapp.libraries.stdlib import api, CalledProcessError, run
|
||||
-from leapp.models import BootContent, FirmwareFacts
|
||||
+from leapp.models import ArmWorkaroundEFIBootloaderInfo, BootContent, FirmwareFacts
|
||||
|
||||
|
||||
def remove_boot_entry():
|
||||
@@ -25,6 +25,14 @@ def remove_boot_entry():
|
||||
# partitions have been most likely already mounted
|
||||
pass
|
||||
kernel_filepath = get_upgrade_kernel_filepath()
|
||||
+
|
||||
+ arm_bootloader_workaround_info = next(api.consume(ArmWorkaroundEFIBootloaderInfo), None)
|
||||
+ if arm_bootloader_workaround_info and arm_bootloader_workaround_info.upgrade_bls_dir:
|
||||
+ # Leapp has a separate BLS dir and grubby will not know about it. We don't need to call
|
||||
+ # grubby here - we are removing the entire BLS dir in another actor.
|
||||
+ api.current_logger().debug('Skipping removal of upgrade kernel entry since we are using a separate BLS dir.')
|
||||
+ return
|
||||
+
|
||||
run([
|
||||
'/usr/sbin/grubby',
|
||||
'--remove-kernel={0}'.format(kernel_filepath)
|
||||
diff --git a/repos/system_upgrade/common/actors/removeupgradebootentry/tests/unit_test_removeupgradebootentry.py b/repos/system_upgrade/common/actors/removeupgradebootentry/tests/unit_test_removeupgradebootentry.py
|
||||
index 54eec552..c84d3085 100644
|
||||
--- a/repos/system_upgrade/common/actors/removeupgradebootentry/tests/unit_test_removeupgradebootentry.py
|
||||
+++ b/repos/system_upgrade/common/actors/removeupgradebootentry/tests/unit_test_removeupgradebootentry.py
|
||||
@@ -5,11 +5,12 @@ from leapp.libraries.actor import removeupgradebootentry
|
||||
from leapp.libraries.common.config import architecture
|
||||
from leapp.libraries.common.testutils import CurrentActorMocked, logger_mocked
|
||||
from leapp.libraries.stdlib import api
|
||||
-from leapp.models import BootContent, FirmwareFacts
|
||||
+from leapp.models import ArmWorkaroundEFIBootloaderInfo, BootContent, EFIBootEntry, FirmwareFacts
|
||||
|
||||
|
||||
class run_mocked(object):
|
||||
- args = []
|
||||
+ def __init__(self):
|
||||
+ self.args = []
|
||||
|
||||
def __call__(self, args, split=True):
|
||||
self.args.append(args)
|
||||
@@ -17,17 +18,25 @@ class run_mocked(object):
|
||||
|
||||
@pytest.mark.parametrize('firmware', ['bios', 'efi'])
|
||||
@pytest.mark.parametrize('arch', [architecture.ARCH_X86_64, architecture.ARCH_S390X])
|
||||
-def test_remove_boot_entry(firmware, arch, monkeypatch):
|
||||
+@pytest.mark.parametrize('has_separate_bls_dir', [True, False])
|
||||
+def test_remove_boot_entry(firmware, arch, has_separate_bls_dir, monkeypatch):
|
||||
def get_upgrade_kernel_filepath_mocked():
|
||||
return '/abc'
|
||||
|
||||
- def consume_systemfacts_mocked(*models):
|
||||
- yield FirmwareFacts(firmware=firmware)
|
||||
-
|
||||
- monkeypatch.setattr(removeupgradebootentry, 'get_upgrade_kernel_filepath', get_upgrade_kernel_filepath_mocked, )
|
||||
- monkeypatch.setattr(api, 'consume', consume_systemfacts_mocked)
|
||||
+ messages = [FirmwareFacts(firmware=firmware)]
|
||||
+ if has_separate_bls_dir:
|
||||
+ some_efi_entry = EFIBootEntry(boot_number='0001', label='entry', active=True, efi_bin_source='')
|
||||
+ workaround_info = ArmWorkaroundEFIBootloaderInfo(
|
||||
+ original_entry=some_efi_entry,
|
||||
+ upgrade_entry=some_efi_entry,
|
||||
+ upgrade_bls_dir='/boot/upgrade-loader/entries',
|
||||
+ upgrade_entry_efi_path='/boot/efi/EFI/leapp/'
|
||||
+ )
|
||||
+ messages.append(workaround_info)
|
||||
+
|
||||
+ monkeypatch.setattr(removeupgradebootentry, 'get_upgrade_kernel_filepath', get_upgrade_kernel_filepath_mocked)
|
||||
monkeypatch.setattr(removeupgradebootentry, 'run', run_mocked())
|
||||
- monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(arch))
|
||||
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(arch, msgs=messages))
|
||||
monkeypatch.setattr(api, 'current_logger', logger_mocked())
|
||||
|
||||
removeupgradebootentry.remove_boot_entry()
|
||||
@@ -36,16 +45,16 @@ def test_remove_boot_entry(firmware, arch, monkeypatch):
|
||||
if firmware == 'efi':
|
||||
boot_mounts.append(['/bin/mount', '/boot/efi'])
|
||||
|
||||
- calls = boot_mounts + [['/usr/sbin/grubby', '--remove-kernel=/abc']]
|
||||
- if arch == architecture.ARCH_S390X:
|
||||
- calls.append(['/usr/sbin/zipl'])
|
||||
- calls.append(['/bin/mount', '-a'])
|
||||
+ calls = boot_mounts
|
||||
+ if not has_separate_bls_dir:
|
||||
+ # If we are using a separate BLS dir (ARM specific), then do not call anything
|
||||
+ calls += [['/usr/sbin/grubby', '--remove-kernel=/abc']]
|
||||
+ if arch == architecture.ARCH_S390X:
|
||||
+ calls.append(['/usr/sbin/zipl'])
|
||||
+ calls.append(['/bin/mount', '-a'])
|
||||
|
||||
assert removeupgradebootentry.run.args == calls
|
||||
|
||||
- # clear args for next run
|
||||
- del removeupgradebootentry.run.args[:]
|
||||
-
|
||||
|
||||
def test_get_upgrade_kernel_filepath(monkeypatch):
|
||||
# BootContent message available
|
||||
diff --git a/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/libraries/addupgradebootloader.py b/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/libraries/addupgradebootloader.py
|
||||
index 01db9bbf..27621185 100644
|
||||
--- a/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/libraries/addupgradebootloader.py
|
||||
+++ b/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/libraries/addupgradebootloader.py
|
||||
@@ -24,6 +24,7 @@ ARM_GRUB_PACKAGE_NAME = 'grub2-efi-aa64'
|
||||
EFI_MOUNTPOINT = '/boot/efi/'
|
||||
LEAPP_EFIDIR_CANONICAL_PATH = os.path.join(EFI_MOUNTPOINT, 'EFI/leapp/')
|
||||
RHEL_EFIDIR_CANONICAL_PATH = os.path.join(EFI_MOUNTPOINT, 'EFI/redhat/')
|
||||
+UPGRADE_BLS_DIR = '/boot/upgrade-loader'
|
||||
|
||||
CONTAINER_DOWNLOAD_DIR = '/tmp_pkg_download_dir'
|
||||
|
||||
@@ -64,7 +65,6 @@ def process():
|
||||
current_boot_entry = efibootinfo.entries[efibootinfo.current_bootnum]
|
||||
upgrade_boot_entry = _add_upgrade_boot_entry(efibootinfo)
|
||||
|
||||
- leapp_efi_grubenv = os.path.join(EFI_MOUNTPOINT, LEAPP_EFIDIR_CANONICAL_PATH, 'grubenv')
|
||||
patch_efi_redhat_grubcfg_to_load_correct_grubenv()
|
||||
|
||||
_set_bootnext(upgrade_boot_entry.boot_number)
|
||||
@@ -74,6 +74,8 @@ def process():
|
||||
ArmWorkaroundEFIBootloaderInfo(
|
||||
original_entry=EFIBootEntry(**{f: getattr(current_boot_entry, f) for f in efibootentry_fields}),
|
||||
upgrade_entry=EFIBootEntry(**{f: getattr(upgrade_boot_entry, f) for f in efibootentry_fields}),
|
||||
+ upgrade_bls_dir=UPGRADE_BLS_DIR,
|
||||
+ upgrade_entry_efi_path=os.path.join(EFI_MOUNTPOINT, LEAPP_EFIDIR_CANONICAL_PATH),
|
||||
)
|
||||
)
|
||||
|
||||
diff --git a/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/tests/test_addarmbootloaderworkaround.py b/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/tests/test_addarmbootloaderworkaround.py
|
||||
index 9ab3b7d0..7017e645 100644
|
||||
--- a/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/tests/test_addarmbootloaderworkaround.py
|
||||
+++ b/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/tests/test_addarmbootloaderworkaround.py
|
||||
@@ -310,7 +310,7 @@ def test_process(monkeypatch):
|
||||
expected = ArmWorkaroundEFIBootloaderInfo(
|
||||
original_entry=EFIBootEntry(**{f: getattr(TEST_RHEL_EFI_ENTRY, f) for f in efibootentry_fields}),
|
||||
upgrade_entry=EFIBootEntry(**{f: getattr(TEST_UPGRADE_EFI_ENTRY, f) for f in efibootentry_fields}),
|
||||
- upgrade_bls_dir='/boot/upgrade-loader/entries',
|
||||
+ upgrade_bls_dir=addupgradebootloader.UPGRADE_BLS_DIR,
|
||||
upgrade_entry_efi_path='/boot/efi/EFI/leapp/',
|
||||
)
|
||||
actual = api.produce.model_instances[0]
|
||||
@@ -323,6 +323,7 @@ def test_patch_grubcfg(is_config_ok, monkeypatch):
|
||||
expected_grubcfg_path = os.path.join(addupgradebootloader.EFI_MOUNTPOINT,
|
||||
addupgradebootloader.LEAPP_EFIDIR_CANONICAL_PATH,
|
||||
'grub.cfg')
|
||||
+
|
||||
def isfile_mocked(path):
|
||||
assert expected_grubcfg_path == path
|
||||
return True
|
||||
diff --git a/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/libraries/removeupgradeefientry.py b/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/libraries/removeupgradeefientry.py
|
||||
index 97ede80a..3a32ddcc 100644
|
||||
--- a/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/libraries/removeupgradeefientry.py
|
||||
+++ b/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/libraries/removeupgradeefientry.py
|
||||
@@ -54,6 +54,8 @@ def remove_upgrade_efi_entry():
|
||||
except CalledProcessError:
|
||||
api.current_logger().warning('Unable to remove Leapp upgrade efi files.')
|
||||
|
||||
+ _remove_upgrade_blsdir(bootloader_info)
|
||||
+
|
||||
original_boot_number = bootloader_info.original_entry.boot_number
|
||||
run(['/usr/sbin/efibootmgr', '--bootnext', original_boot_number])
|
||||
|
||||
@@ -82,7 +84,7 @@ def _copy_file(src_path, dst_path):
|
||||
|
||||
def _copy_grub_files(required, optional):
|
||||
"""
|
||||
- Copy grub files from redhat/ dir to the /boot/efi/EFI/leapp/ dir.
|
||||
+ Copy grub files from /boot/efi/EFI/leapp/ dir to the /boot/efi/EFI/redhat/ dir.
|
||||
"""
|
||||
|
||||
all_files = required + optional
|
||||
@@ -98,3 +100,13 @@ def _copy_grub_files(required, optional):
|
||||
continue
|
||||
|
||||
_copy_file(src_path, dst_path)
|
||||
+
|
||||
+
|
||||
+def _remove_upgrade_blsdir(bootloader_info):
|
||||
+ api.current_logger().debug('Removing upgrade BLS directory: {}'.format(bootloader_info.upgrade_bls_dir))
|
||||
+ try:
|
||||
+ shutil.rmtree(bootloader_info.upgrade_bls_dir)
|
||||
+ except OSError as error:
|
||||
+ # I tried, no can do at this point
|
||||
+ msg = 'Failed to remove upgrade BLS directory: {} with error {}'
|
||||
+ api.current_logger().debug(msg.format(bootloader_info.upgrade_bls_dir, error))
|
||||
diff --git a/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/tests/test_removeupgradeefientry.py b/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/tests/test_removeupgradeefientry.py
|
||||
index 1af3cd1e..30fde2da 100644
|
||||
--- a/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/tests/test_removeupgradeefientry.py
|
||||
+++ b/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/tests/test_removeupgradeefientry.py
|
||||
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
+import shutil
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -20,7 +21,9 @@ TEST_EFI_INFO = ArmWorkaroundEFIBootloaderInfo(
|
||||
label='Leapp',
|
||||
active=True,
|
||||
efi_bin_source="HD(.*)/File(\\EFI\\leapp\\shimx64.efi)",
|
||||
- )
|
||||
+ ),
|
||||
+ upgrade_bls_dir='/boot/upgrade-loaders/entries',
|
||||
+ upgrade_entry_efi_path='/boot/efi/EFI/leapp'
|
||||
)
|
||||
|
||||
|
||||
@@ -89,9 +92,14 @@ def test_remove_upgrade_efi_entry(monkeypatch):
|
||||
def mock_copy_grub_files(required, optional):
|
||||
copy_grub_files_calls.append((required, optional))
|
||||
|
||||
+ def rmtree_mocked(tree, *args):
|
||||
+ run_calls.append('shutil.rmtree')
|
||||
+ assert tree == TEST_EFI_INFO.upgrade_bls_dir
|
||||
+
|
||||
monkeypatch.setattr(removeupgradeefientry, '_copy_grub_files', mock_copy_grub_files)
|
||||
monkeypatch.setattr(removeupgradeefientry, '_link_grubenv_to_rhel_entry', lambda: None)
|
||||
monkeypatch.setattr(removeupgradeefientry, 'run', mock_run)
|
||||
+ monkeypatch.setattr(shutil, 'rmtree', rmtree_mocked)
|
||||
|
||||
removeupgradeefientry.remove_upgrade_efi_entry()
|
||||
|
||||
@@ -100,6 +108,7 @@ def test_remove_upgrade_efi_entry(monkeypatch):
|
||||
['/bin/mount', '/boot/efi'],
|
||||
['/usr/sbin/efibootmgr', '--delete-bootnum', '--bootnum', '0002'],
|
||||
['rm', '-rf', removeupgradeefientry.LEAPP_EFIDIR_CANONICAL_PATH],
|
||||
+ 'shutil.rmtree',
|
||||
['/usr/sbin/efibootmgr', '--bootnext', '0001'],
|
||||
['/bin/mount', '-a'],
|
||||
]
|
||||
diff --git a/repos/system_upgrade/el8toel9/models/upgradeefientry.py b/repos/system_upgrade/el8toel9/models/upgradeefientry.py
|
||||
index 877cdc8f..f29fc88f 100644
|
||||
--- a/repos/system_upgrade/el8toel9/models/upgradeefientry.py
|
||||
+++ b/repos/system_upgrade/el8toel9/models/upgradeefientry.py
|
||||
@@ -12,3 +12,19 @@ class ArmWorkaroundEFIBootloaderInfo(Model):
|
||||
original_entry = fields.Model(EFIBootEntry)
|
||||
|
||||
upgrade_entry = fields.Model(EFIBootEntry)
|
||||
+
|
||||
+ upgrade_bls_dir = fields.String()
|
||||
+ """
|
||||
+ Path to custom BLS dir used by the upgrade EFI bootloader
|
||||
+
|
||||
+ The path is absolute w.r.t. '/'. The actual value of the 'blsdir' variable
|
||||
+ that is set in the upgrade grubenv will be relative to '/boot/'.
|
||||
+ """
|
||||
+
|
||||
+ upgrade_entry_efi_path = fields.String()
|
||||
+ """
|
||||
+ Full path to the folder containing EFI binaries for the upgrade entry.
|
||||
+
|
||||
+ Example:
|
||||
+ /boot/efi/EFI/leapp
|
||||
+ """
|
||||
--
|
||||
2.48.1
|
||||
|
@ -0,0 +1,21 @@
|
||||
From 8fe49982ee048d6b74aec4f4537ea9f1b4a7e021 Mon Sep 17 00:00:00 2001
|
||||
From: Michal Hecko <mhecko@redhat.com>
|
||||
Date: Mon, 27 Jan 2025 10:58:48 +0100
|
||||
Subject: [PATCH 59/63] fix(models): move arm bootloader workaround model into
|
||||
common
|
||||
|
||||
Move model used to implement arm bootloader workarounds to common
|
||||
as this model will be also used when adding/removing kernel entries
|
||||
to use custom blsdir.
|
||||
---
|
||||
.../system_upgrade/{el8toel9 => common}/models/upgradeefientry.py | 0
|
||||
1 file changed, 0 insertions(+), 0 deletions(-)
|
||||
rename repos/system_upgrade/{el8toel9 => common}/models/upgradeefientry.py (100%)
|
||||
|
||||
diff --git a/repos/system_upgrade/el8toel9/models/upgradeefientry.py b/repos/system_upgrade/common/models/upgradeefientry.py
|
||||
similarity index 100%
|
||||
rename from repos/system_upgrade/el8toel9/models/upgradeefientry.py
|
||||
rename to repos/system_upgrade/common/models/upgradeefientry.py
|
||||
--
|
||||
2.48.1
|
||||
|
184
0060-cleanup-8to9-efi-do-not-use-symlinks-or-copy-grub-fi.patch
Normal file
184
0060-cleanup-8to9-efi-do-not-use-symlinks-or-copy-grub-fi.patch
Normal file
@ -0,0 +1,184 @@
|
||||
From 31af8f485f6bb78b4aed665857daa956aa79adf1 Mon Sep 17 00:00:00 2001
|
||||
From: Michal Hecko <mhecko@redhat.com>
|
||||
Date: Tue, 28 Jan 2025 15:09:12 +0100
|
||||
Subject: [PATCH 60/63] cleanup(8to9,efi): do not use symlinks or copy grub
|
||||
files
|
||||
|
||||
---
|
||||
.../libraries/addupgradebootloader.py | 10 +----
|
||||
.../tests/test_addarmbootloaderworkaround.py | 1 -
|
||||
.../libraries/removeupgradeefientry.py | 41 -------------------
|
||||
.../tests/test_removeupgradeefientry.py | 35 ----------------
|
||||
4 files changed, 1 insertion(+), 86 deletions(-)
|
||||
|
||||
diff --git a/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/libraries/addupgradebootloader.py b/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/libraries/addupgradebootloader.py
|
||||
index 27621185..c076fe6b 100644
|
||||
--- a/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/libraries/addupgradebootloader.py
|
||||
+++ b/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/libraries/addupgradebootloader.py
|
||||
@@ -9,9 +9,7 @@ from leapp.libraries.common.grub import (
|
||||
get_boot_partition,
|
||||
get_device_number,
|
||||
get_efi_device,
|
||||
- get_efi_partition,
|
||||
- GRUB2_BIOS_ENTRYPOINT,
|
||||
- GRUB2_BIOS_ENV_FILE
|
||||
+ get_efi_partition
|
||||
)
|
||||
from leapp.libraries.stdlib import api, CalledProcessError, run
|
||||
from leapp.models import ArmWorkaroundEFIBootloaderInfo, EFIBootEntry, TargetUserSpaceInfo
|
||||
@@ -118,12 +116,6 @@ def _copy_grub_files(required, optional):
|
||||
_copy_file(src_path, dst_path)
|
||||
|
||||
|
||||
-def _link_grubenv_to_upgrade_entry():
|
||||
- upgrade_env_file = os.path.join(LEAPP_EFIDIR_CANONICAL_PATH, 'grubenv')
|
||||
- upgrade_env_file_relpath = os.path.relpath(upgrade_env_file, GRUB2_BIOS_ENTRYPOINT)
|
||||
- run(['ln', '--symbolic', '--force', upgrade_env_file_relpath, GRUB2_BIOS_ENV_FILE])
|
||||
-
|
||||
-
|
||||
def _add_upgrade_boot_entry(efibootinfo):
|
||||
"""
|
||||
Create a new UEFI bootloader entry with a upgrade label and bin file.
|
||||
diff --git a/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/tests/test_addarmbootloaderworkaround.py b/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/tests/test_addarmbootloaderworkaround.py
|
||||
index 7017e645..4f990e00 100644
|
||||
--- a/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/tests/test_addarmbootloaderworkaround.py
|
||||
+++ b/repos/system_upgrade/el8toel9/actors/addarmbootloaderworkaround/tests/test_addarmbootloaderworkaround.py
|
||||
@@ -287,7 +287,6 @@ def test_process(monkeypatch):
|
||||
monkeypatch.setattr(addupgradebootloader.mounting, 'NspawnActions', lambda *args, **kwargs: context_mock)
|
||||
|
||||
monkeypatch.setattr(addupgradebootloader, '_copy_grub_files', lambda optional, required: None)
|
||||
- monkeypatch.setattr(addupgradebootloader, '_link_grubenv_to_upgrade_entry', lambda: None)
|
||||
|
||||
efibootinfo_mock = MockEFIBootInfo([TEST_RHEL_EFI_ENTRY])
|
||||
monkeypatch.setattr(addupgradebootloader, 'EFIBootInfo', lambda: efibootinfo_mock)
|
||||
diff --git a/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/libraries/removeupgradeefientry.py b/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/libraries/removeupgradeefientry.py
|
||||
index 3a32ddcc..daa7b2ca 100644
|
||||
--- a/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/libraries/removeupgradeefientry.py
|
||||
+++ b/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/libraries/removeupgradeefientry.py
|
||||
@@ -2,7 +2,6 @@ import os
|
||||
import shutil
|
||||
|
||||
from leapp.exceptions import StopActorExecutionError
|
||||
-from leapp.libraries.common.grub import GRUB2_BIOS_ENTRYPOINT, GRUB2_BIOS_ENV_FILE
|
||||
from leapp.libraries.stdlib import api, CalledProcessError, run
|
||||
from leapp.models import ArmWorkaroundEFIBootloaderInfo
|
||||
|
||||
@@ -35,9 +34,6 @@ def remove_upgrade_efi_entry():
|
||||
|
||||
bootloader_info = get_workaround_efi_info()
|
||||
|
||||
- # _copy_grub_files(['grubenv', 'grub.cfg'], ['user.cfg'])
|
||||
- # _link_grubenv_to_rhel_entry()
|
||||
-
|
||||
upgrade_boot_number = bootloader_info.upgrade_entry.boot_number
|
||||
try:
|
||||
run([
|
||||
@@ -65,43 +61,6 @@ def remove_upgrade_efi_entry():
|
||||
run(['/bin/mount', '-a'])
|
||||
|
||||
|
||||
-def _link_grubenv_to_rhel_entry():
|
||||
- rhel_env_file = os.path.join(RHEL_EFIDIR_CANONICAL_PATH, 'grubenv')
|
||||
- rhel_env_file_relpath = os.path.relpath(rhel_env_file, GRUB2_BIOS_ENTRYPOINT)
|
||||
- run(['ln', '--symbolic', '--force', rhel_env_file_relpath, GRUB2_BIOS_ENV_FILE])
|
||||
-
|
||||
-
|
||||
-def _copy_file(src_path, dst_path):
|
||||
- if os.path.exists(dst_path):
|
||||
- api.current_logger().debug("The {} file already exists and its content will be overwritten.".format(dst_path))
|
||||
-
|
||||
- api.current_logger().info("Copying {} to {}".format(src_path, dst_path))
|
||||
- try:
|
||||
- shutil.copy2(src_path, dst_path)
|
||||
- except (OSError, IOError) as err:
|
||||
- raise StopActorExecutionError('I/O error({}): {}'.format(err.errno, err.strerror))
|
||||
-
|
||||
-
|
||||
-def _copy_grub_files(required, optional):
|
||||
- """
|
||||
- Copy grub files from /boot/efi/EFI/leapp/ dir to the /boot/efi/EFI/redhat/ dir.
|
||||
- """
|
||||
-
|
||||
- all_files = required + optional
|
||||
- for filename in all_files:
|
||||
- src_path = os.path.join(LEAPP_EFIDIR_CANONICAL_PATH, filename)
|
||||
- dst_path = os.path.join(RHEL_EFIDIR_CANONICAL_PATH, filename)
|
||||
-
|
||||
- if not os.path.exists(src_path):
|
||||
- if filename in required:
|
||||
- msg = 'Required file {} does not exists. Aborting.'.format(filename)
|
||||
- raise StopActorExecutionError(msg)
|
||||
-
|
||||
- continue
|
||||
-
|
||||
- _copy_file(src_path, dst_path)
|
||||
-
|
||||
-
|
||||
def _remove_upgrade_blsdir(bootloader_info):
|
||||
api.current_logger().debug('Removing upgrade BLS directory: {}'.format(bootloader_info.upgrade_bls_dir))
|
||||
try:
|
||||
diff --git a/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/tests/test_removeupgradeefientry.py b/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/tests/test_removeupgradeefientry.py
|
||||
index 30fde2da..11cd3126 100644
|
||||
--- a/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/tests/test_removeupgradeefientry.py
|
||||
+++ b/repos/system_upgrade/el8toel9/actors/removeupgradeefientry/tests/test_removeupgradeefientry.py
|
||||
@@ -1,4 +1,3 @@
|
||||
-import os
|
||||
import shutil
|
||||
|
||||
import pytest
|
||||
@@ -52,52 +51,18 @@ def test_get_workaround_efi_info_no_entry(monkeypatch):
|
||||
removeupgradeefientry.get_workaround_efi_info()
|
||||
|
||||
|
||||
-def test_copy_grub_files(monkeypatch):
|
||||
- copy_file_calls = []
|
||||
-
|
||||
- def mock_copy_file(src, dst):
|
||||
- copy_file_calls.append((src, dst))
|
||||
-
|
||||
- monkeypatch.setattr(removeupgradeefientry, '_copy_file', mock_copy_file)
|
||||
- monkeypatch.setattr(os.path, 'exists', lambda path: True)
|
||||
-
|
||||
- removeupgradeefientry._copy_grub_files(['required'], ['optional'])
|
||||
-
|
||||
- assert (
|
||||
- os.path.join(removeupgradeefientry.LEAPP_EFIDIR_CANONICAL_PATH, 'required'),
|
||||
- os.path.join(removeupgradeefientry.RHEL_EFIDIR_CANONICAL_PATH, 'required'),
|
||||
- ) in copy_file_calls
|
||||
- assert (
|
||||
- os.path.join(removeupgradeefientry.LEAPP_EFIDIR_CANONICAL_PATH, 'optional'),
|
||||
- os.path.join(removeupgradeefientry.RHEL_EFIDIR_CANONICAL_PATH, 'optional'),
|
||||
- ) in copy_file_calls
|
||||
-
|
||||
-
|
||||
-def test_copy_grub_files_missing_required(monkeypatch):
|
||||
- monkeypatch.setattr(os.path, 'exists', lambda path: False)
|
||||
-
|
||||
- with pytest.raises(StopActorExecutionError, match='Required file required does not exists'):
|
||||
- removeupgradeefientry._copy_grub_files(['required'], [])
|
||||
-
|
||||
-
|
||||
def test_remove_upgrade_efi_entry(monkeypatch):
|
||||
run_calls = []
|
||||
- copy_grub_files_calls = []
|
||||
monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=[TEST_EFI_INFO]))
|
||||
|
||||
def mock_run(command, checked=False):
|
||||
run_calls.append(command)
|
||||
return {'exit_code': 0}
|
||||
|
||||
- def mock_copy_grub_files(required, optional):
|
||||
- copy_grub_files_calls.append((required, optional))
|
||||
-
|
||||
def rmtree_mocked(tree, *args):
|
||||
run_calls.append('shutil.rmtree')
|
||||
assert tree == TEST_EFI_INFO.upgrade_bls_dir
|
||||
|
||||
- monkeypatch.setattr(removeupgradeefientry, '_copy_grub_files', mock_copy_grub_files)
|
||||
- monkeypatch.setattr(removeupgradeefientry, '_link_grubenv_to_rhel_entry', lambda: None)
|
||||
monkeypatch.setattr(removeupgradeefientry, 'run', mock_run)
|
||||
monkeypatch.setattr(shutil, 'rmtree', rmtree_mocked)
|
||||
|
||||
--
|
||||
2.48.1
|
||||
|
303
0061-Introduce-deprecated-IPUPaths-msg-temporary-solution.patch
Normal file
303
0061-Introduce-deprecated-IPUPaths-msg-temporary-solution.patch
Normal file
@ -0,0 +1,303 @@
|
||||
From a6438828415c094c600de80e2e05409a4ccd5822 Mon Sep 17 00:00:00 2001
|
||||
From: Petr Stodulka <pstodulk@redhat.com>
|
||||
Date: Wed, 29 Jan 2025 04:43:33 +0100
|
||||
Subject: [PATCH 61/63] Introduce deprecated IPUPaths msg (temporary solution)
|
||||
|
||||
This is hackish precursor to move checking of the specified
|
||||
target system versions into actors to be able to create report
|
||||
when unsupported target version is specified.
|
||||
|
||||
The problem is that currently there is no information about the
|
||||
supported upgrade paths in messages. Also, the information about
|
||||
supported source and target versions are stored in two different
|
||||
places (in system upgrade common repo):
|
||||
* shared configs.version library
|
||||
* files/upgrade_paths.json
|
||||
|
||||
As a temporary solution let's introduce IPUPaths message which
|
||||
will contain filtered data from the json file based on:
|
||||
* the upgrade flavour (default, saphana)
|
||||
* and source major version
|
||||
|
||||
There is no value to print information to users about different
|
||||
upgrade paths for other flavours and OS major versions. The model
|
||||
is marked as deprecated so we can remove it in the next release when
|
||||
we redesign this solution to unify how actors get this data
|
||||
(and define them just in one place).
|
||||
|
||||
jira: RHEL-51072
|
||||
---
|
||||
.../actors/scandefinedipupaths/actor.py | 31 ++++++
|
||||
.../libraries/scandefinedipupaths.py | 43 ++++++++
|
||||
.../tests/files/upgrade_paths.json | 15 +++
|
||||
.../tests/test_scandefinedipupaths.py | 97 +++++++++++++++++++
|
||||
.../system_upgrade/common/models/ipupaths.py | 43 ++++++++
|
||||
5 files changed, 229 insertions(+)
|
||||
create mode 100644 repos/system_upgrade/common/actors/scandefinedipupaths/actor.py
|
||||
create mode 100644 repos/system_upgrade/common/actors/scandefinedipupaths/libraries/scandefinedipupaths.py
|
||||
create mode 100644 repos/system_upgrade/common/actors/scandefinedipupaths/tests/files/upgrade_paths.json
|
||||
create mode 100644 repos/system_upgrade/common/actors/scandefinedipupaths/tests/test_scandefinedipupaths.py
|
||||
create mode 100644 repos/system_upgrade/common/models/ipupaths.py
|
||||
|
||||
diff --git a/repos/system_upgrade/common/actors/scandefinedipupaths/actor.py b/repos/system_upgrade/common/actors/scandefinedipupaths/actor.py
|
||||
new file mode 100644
|
||||
index 00000000..a84c85f2
|
||||
--- /dev/null
|
||||
+++ b/repos/system_upgrade/common/actors/scandefinedipupaths/actor.py
|
||||
@@ -0,0 +1,31 @@
|
||||
+from leapp.actors import Actor
|
||||
+from leapp.libraries.actor import scandefinedipupaths
|
||||
+from leapp.models import IPUPaths
|
||||
+from leapp.tags import FactsPhaseTag, IPUWorkflowTag
|
||||
+
|
||||
+
|
||||
+class ScanDefinedIPUPaths(Actor):
|
||||
+ """
|
||||
+ Load defined IPU paths for the current major source system version
|
||||
+ and defined upgrade flavour.
|
||||
+
|
||||
+ The upgrade paths are defined inside `files/upgrade_paths.json`.
|
||||
+ Based on the defined upgrade flavour (default, saphana, ..) loads particular
|
||||
+ definitions and filter out all upgrade paths from other system major versions.
|
||||
+ I.e. for RHEL 8.10 system with the default upgrade flavour, load all upgrade
|
||||
+ paths from any RHEL 8 system defined under the 'default' flavour.
|
||||
+
|
||||
+ The code is mostly taken from the CLI command_utils. The duplicate solution
|
||||
+ is not so problematic now as it will be unified next time.
|
||||
+
|
||||
+ Note the deprecation suppression is expected here as this is considered as
|
||||
+ temporary solution now.
|
||||
+ """
|
||||
+
|
||||
+ name = 'scan_defined_ipu_paths'
|
||||
+ consumes = ()
|
||||
+ produces = (IPUPaths,)
|
||||
+ tags = (IPUWorkflowTag, FactsPhaseTag)
|
||||
+
|
||||
+ def process(self):
|
||||
+ scandefinedipupaths.process()
|
||||
diff --git a/repos/system_upgrade/common/actors/scandefinedipupaths/libraries/scandefinedipupaths.py b/repos/system_upgrade/common/actors/scandefinedipupaths/libraries/scandefinedipupaths.py
|
||||
new file mode 100644
|
||||
index 00000000..1e39f2c8
|
||||
--- /dev/null
|
||||
+++ b/repos/system_upgrade/common/actors/scandefinedipupaths/libraries/scandefinedipupaths.py
|
||||
@@ -0,0 +1,43 @@
|
||||
+import json
|
||||
+
|
||||
+from leapp.libraries.common.config.version import get_source_major_version
|
||||
+from leapp.libraries.stdlib import api
|
||||
+from leapp.models import IPUPath, IPUPaths
|
||||
+from leapp.utils.deprecation import suppress_deprecation
|
||||
+
|
||||
+
|
||||
+def load_ipu_paths_for_flavour(flavour, _filename='upgrade_paths.json'):
|
||||
+ """
|
||||
+ Load defined IPU paths from the upgrade_paths.json file for the specified
|
||||
+ flavour.
|
||||
+
|
||||
+ Note the file is required to be always present, so skipping any test
|
||||
+ for the missing file. Crash hard and terribly if the file is missing
|
||||
+ or the content is invalid.
|
||||
+
|
||||
+ We expect the flavour to be always good as it is under our control
|
||||
+ (already sanitized in IPUConfig), but return empty dict and log it if missing.
|
||||
+ """
|
||||
+ with open(api.get_common_file_path(_filename)) as fp:
|
||||
+ data = json.loads(fp.read())
|
||||
+ if flavour not in data:
|
||||
+ api.current_logger().warning(
|
||||
+ 'Cannot discover any upgrade paths for flavour: {}'
|
||||
+ .format(flavour)
|
||||
+ )
|
||||
+ return data.get(flavour, {})
|
||||
+
|
||||
+
|
||||
+def get_filtered_ipu_paths(ipu_paths, src_major_version):
|
||||
+ result = []
|
||||
+ for src_version, tgt_versions in ipu_paths.items():
|
||||
+ if src_version.split('.')[0] == src_major_version:
|
||||
+ result.append(IPUPath(source_version=src_version, target_versions=tgt_versions))
|
||||
+ return result
|
||||
+
|
||||
+
|
||||
+@suppress_deprecation(IPUPaths)
|
||||
+def process():
|
||||
+ flavour = api.current_actor().configuration.flavour
|
||||
+ ipu_paths = load_ipu_paths_for_flavour(flavour)
|
||||
+ api.produce(IPUPaths(data=get_filtered_ipu_paths(ipu_paths, get_source_major_version())))
|
||||
diff --git a/repos/system_upgrade/common/actors/scandefinedipupaths/tests/files/upgrade_paths.json b/repos/system_upgrade/common/actors/scandefinedipupaths/tests/files/upgrade_paths.json
|
||||
new file mode 100644
|
||||
index 00000000..edd32224
|
||||
--- /dev/null
|
||||
+++ b/repos/system_upgrade/common/actors/scandefinedipupaths/tests/files/upgrade_paths.json
|
||||
@@ -0,0 +1,15 @@
|
||||
+{
|
||||
+ "default": {
|
||||
+ "8.10": ["9.4", "9.5", "9.6"],
|
||||
+ "8.4": ["9.2"],
|
||||
+ "9.6": ["10.0"],
|
||||
+ "8": ["9.4", "9.5", "9.6"],
|
||||
+ "9": ["10.0"]
|
||||
+ },
|
||||
+ "saphana": {
|
||||
+ "8.10": ["9.6", "9.4"],
|
||||
+ "8": ["9.6", "9.4"],
|
||||
+ "9.6": ["10.0"],
|
||||
+ "9": ["10.0"]
|
||||
+ }
|
||||
+}
|
||||
diff --git a/repos/system_upgrade/common/actors/scandefinedipupaths/tests/test_scandefinedipupaths.py b/repos/system_upgrade/common/actors/scandefinedipupaths/tests/test_scandefinedipupaths.py
|
||||
new file mode 100644
|
||||
index 00000000..9ffc9829
|
||||
--- /dev/null
|
||||
+++ b/repos/system_upgrade/common/actors/scandefinedipupaths/tests/test_scandefinedipupaths.py
|
||||
@@ -0,0 +1,97 @@
|
||||
+import json
|
||||
+import os
|
||||
+
|
||||
+import pytest
|
||||
+
|
||||
+from leapp.libraries.actor import scandefinedipupaths
|
||||
+from leapp.libraries.common.testutils import CurrentActorMocked, produce_mocked
|
||||
+from leapp.models import IPUPath, IPUPaths
|
||||
+from leapp.utils.deprecation import suppress_deprecation
|
||||
+
|
||||
+CUR_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
+
|
||||
+
|
||||
+class CurrentActorMockedModified(CurrentActorMocked):
|
||||
+ def get_common_file_path(self, fname):
|
||||
+ fpath = os.path.join(CUR_DIR, 'files', fname)
|
||||
+ assert os.path.exists(fpath)
|
||||
+ if os.path.exists(fpath):
|
||||
+ return fpath
|
||||
+ return None
|
||||
+
|
||||
+
|
||||
+@pytest.mark.parametrize(('flavour', 'expected_result'), (
|
||||
+ ('nonsense', {}),
|
||||
+ (
|
||||
+ 'default',
|
||||
+ {
|
||||
+ '8.10': ['9.4', '9.5', '9.6'],
|
||||
+ '8.4': ['9.2'],
|
||||
+ '9.6': ['10.0'],
|
||||
+ '8': ['9.4', '9.5', '9.6'],
|
||||
+ '9': ['10.0']
|
||||
+ }
|
||||
+ ),
|
||||
+ (
|
||||
+ 'saphana',
|
||||
+ {
|
||||
+ '8.10': ['9.6', '9.4'],
|
||||
+ '8': ['9.6', '9.4'],
|
||||
+ '9.6': ['10.0'],
|
||||
+ '9': ['10.0']
|
||||
+ }
|
||||
+ ),
|
||||
+))
|
||||
+def test_load_ipu_paths_for_flavour(monkeypatch, flavour, expected_result):
|
||||
+ monkeypatch.setattr(scandefinedipupaths.api, 'current_actor', CurrentActorMockedModified())
|
||||
+
|
||||
+ result = scandefinedipupaths.load_ipu_paths_for_flavour(flavour=flavour)
|
||||
+ assert result == expected_result
|
||||
+
|
||||
+
|
||||
+_DATA_IPU_PATHS = {
|
||||
+ '8.10': ['9.4', '9.5', '9.6'],
|
||||
+ '8.4': ['9.2'],
|
||||
+ '9.6': ['10.0'],
|
||||
+ '8': ['9.4', '9.5', '9.6'],
|
||||
+ '80.0': ['81.0']
|
||||
+}
|
||||
+
|
||||
+
|
||||
+@suppress_deprecation(IPUPaths)
|
||||
+@pytest.mark.parametrize(('maj_version', 'expected_result'), (
|
||||
+ ('7', []),
|
||||
+ (
|
||||
+ '8',
|
||||
+ [
|
||||
+ IPUPath(source_version='8.10', target_versions=['9.4', '9.5', '9.6']),
|
||||
+ IPUPath(source_version='8.4', target_versions=['9.2']),
|
||||
+ IPUPath(source_version='8', target_versions=['9.4', '9.5', '9.6']),
|
||||
+ ]
|
||||
+ ),
|
||||
+ (
|
||||
+ '80',
|
||||
+ [
|
||||
+ IPUPath(source_version='80.0', target_versions=['81.0']),
|
||||
+ ]
|
||||
+ ),
|
||||
+
|
||||
+
|
||||
+))
|
||||
+def test_get_filtered_ipu_paths(monkeypatch, maj_version, expected_result):
|
||||
+ result = scandefinedipupaths.get_filtered_ipu_paths(_DATA_IPU_PATHS, maj_version)
|
||||
+ result = sorted(result, key=lambda x: x.source_version)
|
||||
+ assert result == sorted(expected_result, key=lambda x: x.source_version)
|
||||
+
|
||||
+
|
||||
+def test_scan_defined_ipu_paths(monkeypatch):
|
||||
+ # let's try one 'full' happy run
|
||||
+ monkeypatch.setattr(scandefinedipupaths.api, 'current_actor', CurrentActorMockedModified(src_ver='9.6'))
|
||||
+ monkeypatch.setattr(scandefinedipupaths.api, 'produce', produce_mocked())
|
||||
+ scandefinedipupaths.process()
|
||||
+
|
||||
+ assert scandefinedipupaths.api.produce.called == 1
|
||||
+ msg = scandefinedipupaths.api.produce.model_instances[0]
|
||||
+ assert isinstance(msg, IPUPaths)
|
||||
+ assert len(msg.data) == 2
|
||||
+ assert {i.source_version for i in msg.data} == {'9', '9.6'}
|
||||
diff --git a/repos/system_upgrade/common/models/ipupaths.py b/repos/system_upgrade/common/models/ipupaths.py
|
||||
new file mode 100644
|
||||
index 00000000..5469f25e
|
||||
--- /dev/null
|
||||
+++ b/repos/system_upgrade/common/models/ipupaths.py
|
||||
@@ -0,0 +1,43 @@
|
||||
+from leapp.models import fields, Model
|
||||
+from leapp.topics import SystemInfoTopic
|
||||
+from leapp.utils.deprecation import deprecated
|
||||
+
|
||||
+
|
||||
+class IPUPath(Model):
|
||||
+ """
|
||||
+ Represent upgrade paths from a source system version.
|
||||
+
|
||||
+ This model is not supposed to be produced nor consumed directly by any actor.
|
||||
+ See `IPUPaths` instead.
|
||||
+ """
|
||||
+ topic = SystemInfoTopic
|
||||
+
|
||||
+ source_version = fields.String()
|
||||
+ """Version of a particular source system."""
|
||||
+
|
||||
+ target_versions = fields.List(fields.String())
|
||||
+ """List of defined target system versions for the `source_version` system."""
|
||||
+
|
||||
+
|
||||
+@deprecated(
|
||||
+ since="2025-02-01",
|
||||
+ message="This model is temporary and not assumed to be used in any actors."
|
||||
+)
|
||||
+class IPUPaths(Model):
|
||||
+ """
|
||||
+ Defined Upgrade paths from the source system major version and used upgrade flavour.
|
||||
+
|
||||
+ In example for the RHEL 8.10 system with the 'default' upgrade flavour it will
|
||||
+ contain information about all defined upgrade paths from any RHEL 8 system
|
||||
+ for the 'default' flavour (other flavour can be e.g. 'saphana' for systems
|
||||
+ with SAP HANA installed.
|
||||
+
|
||||
+ Note this model is marked as deprecated now as it is considered as a temporary
|
||||
+ solution. It can be removed in any future release!
|
||||
+ """
|
||||
+ topic = SystemInfoTopic
|
||||
+
|
||||
+ data = fields.List(fields.Model(IPUPath))
|
||||
+ """
|
||||
+ List of defined (filtered) upgrade paths.
|
||||
+ """
|
||||
--
|
||||
2.48.1
|
||||
|
385
0062-Verify-supported-target-OS-version-in-actors.patch
Normal file
385
0062-Verify-supported-target-OS-version-in-actors.patch
Normal file
@ -0,0 +1,385 @@
|
||||
From 0a5f66e7d04e41f25a87781cc2e8fb1601cfe70e Mon Sep 17 00:00:00 2001
|
||||
From: tomasfratrik <tomasfratrik8@gmail.com>
|
||||
Date: Tue, 14 Jan 2025 14:59:04 +0100
|
||||
Subject: [PATCH 62/63] Verify supported target OS version in actors
|
||||
|
||||
Originally when user specified the target system release using
|
||||
`--target` CLI option the verification has been performed immediately
|
||||
as only supported releases have been listed as possible choices for
|
||||
this option. The benefit of this solution was that users did not have
|
||||
to wait for all other checks to realize they execute leapp probably
|
||||
incorrectly. Unfortunately,
|
||||
* number of users do not understand why only some versions are supported
|
||||
* users upgrading with via various webUIs presenting only leapp reports
|
||||
could not see the error message available in terminal
|
||||
|
||||
To resolve this problem the checks are moved into actors so in case
|
||||
of specified unsupported target version the information is present
|
||||
in generated leapp reports.
|
||||
|
||||
Current behaviour is like this:
|
||||
* in case of invalid input (incorrect format of input data) the hard
|
||||
error is raised as before immediately. Malformed input data will
|
||||
not be processed anyhow by any actors
|
||||
* report error when the specified target major version is not direct
|
||||
successor of the current system version. I.e. specify 10.0 when
|
||||
upgrading from RHEL 8 (only RHEL 9 is acceptable).
|
||||
* this prevents number of cryptic errors as actors are not prepared
|
||||
for this situation
|
||||
* report standard inhibitor if the target release is not in the defined
|
||||
upgrade path, unless LEAPP_UNSUPPORTED=1
|
||||
* running leapp in unsupported (devel) mode skips the inhibitor and
|
||||
entire report
|
||||
|
||||
Additional changes:
|
||||
* Update error message when format of target version is incorrect to
|
||||
clarify the expected version format
|
||||
|
||||
jira: RHEL-51072
|
||||
|
||||
Co-authored-by: Petr Stodulk <pstodulk@redhat.com>
|
||||
---
|
||||
commands/command_utils.py | 13 +--
|
||||
commands/preupgrade/__init__.py | 3 +-
|
||||
commands/upgrade/__init__.py | 3 +-
|
||||
.../common/actors/checktargetversion/actor.py | 22 +++++
|
||||
.../libraries/checktargetversion.py | 86 ++++++++++++++++++
|
||||
.../tests/test_checktargetversion.py | 90 +++++++++++++++++++
|
||||
.../libraries/ipuworkflowconfig.py | 26 +++++-
|
||||
7 files changed, 229 insertions(+), 14 deletions(-)
|
||||
create mode 100644 repos/system_upgrade/common/actors/checktargetversion/actor.py
|
||||
create mode 100644 repos/system_upgrade/common/actors/checktargetversion/libraries/checktargetversion.py
|
||||
create mode 100644 repos/system_upgrade/common/actors/checktargetversion/tests/test_checktargetversion.py
|
||||
|
||||
diff --git a/commands/command_utils.py b/commands/command_utils.py
|
||||
index 190f5f03..84b9de1b 100644
|
||||
--- a/commands/command_utils.py
|
||||
+++ b/commands/command_utils.py
|
||||
@@ -28,7 +28,10 @@ def check_version(version):
|
||||
:return: release tuple
|
||||
"""
|
||||
if not re.match(VERSION_REGEX, version):
|
||||
- raise CommandError('Unexpected format of target version: {}'.format(version))
|
||||
+ raise CommandError(
|
||||
+ "Unexpected format of target version: {}. "
|
||||
+ "The required format is 'X.Y' (major and minor version).".format(version)
|
||||
+ )
|
||||
return version.split('.')
|
||||
|
||||
|
||||
@@ -126,7 +129,6 @@ def vet_upgrade_path(args):
|
||||
Make sure the user requested upgrade_path is a supported one.
|
||||
If LEAPP_DEVEL_TARGET_RELEASE is set then it's value is not vetted against upgrade_paths_map but used as is.
|
||||
|
||||
- :raises: `CommandError` if the specified upgrade_path is not supported
|
||||
:return: `tuple` (target_release, flavor)
|
||||
"""
|
||||
flavor = get_upgrade_flavour()
|
||||
@@ -135,13 +137,6 @@ def vet_upgrade_path(args):
|
||||
check_version(env_version_override)
|
||||
return (env_version_override, flavor)
|
||||
target_release = args.target or get_target_version(flavor)
|
||||
- supported_target_versions = get_supported_target_versions(flavor)
|
||||
- if target_release not in supported_target_versions:
|
||||
- raise CommandError(
|
||||
- "Upgrade to {to} for {flavor} upgrade path is not supported, possible choices are {choices}".format(
|
||||
- to=target_release,
|
||||
- flavor=flavor,
|
||||
- choices=','.join(supported_target_versions)))
|
||||
return (target_release, flavor)
|
||||
|
||||
|
||||
diff --git a/commands/preupgrade/__init__.py b/commands/preupgrade/__init__.py
|
||||
index 631eca6b..c1fabbbd 100644
|
||||
--- a/commands/preupgrade/__init__.py
|
||||
+++ b/commands/preupgrade/__init__.py
|
||||
@@ -28,8 +28,7 @@ from leapp.utils.output import beautify_actor_exception, report_errors, report_i
|
||||
choices=['ga', 'e4s', 'eus', 'aus'],
|
||||
value_type=str.lower) # This allows the choices to be case insensitive
|
||||
@command_opt('iso', help='Use provided target RHEL installation image to perform the in-place upgrade.')
|
||||
-@command_opt('target', choices=command_utils.get_supported_target_versions(),
|
||||
- help='Specify RHEL version to upgrade to for {} detected upgrade flavour'.format(
|
||||
+@command_opt('target', help='Specify RHEL version to upgrade to for {} detected upgrade flavour'.format(
|
||||
command_utils.get_upgrade_flavour()))
|
||||
@command_opt('report-schema', help='Specify report schema version for leapp-report.json',
|
||||
choices=['1.0.0', '1.1.0', '1.2.0'], default=get_config().get('report', 'schema'))
|
||||
diff --git a/commands/upgrade/__init__.py b/commands/upgrade/__init__.py
|
||||
index 3dedd438..608099ac 100644
|
||||
--- a/commands/upgrade/__init__.py
|
||||
+++ b/commands/upgrade/__init__.py
|
||||
@@ -34,8 +34,7 @@ from leapp.utils.output import beautify_actor_exception, report_errors, report_i
|
||||
choices=['ga', 'e4s', 'eus', 'aus'],
|
||||
value_type=str.lower) # This allows the choices to be case insensitive
|
||||
@command_opt('iso', help='Use provided target RHEL installation image to perform the in-place upgrade.')
|
||||
-@command_opt('target', choices=command_utils.get_supported_target_versions(),
|
||||
- help='Specify RHEL version to upgrade to for {} detected upgrade flavour'.format(
|
||||
+@command_opt('target', help='Specify RHEL version to upgrade to for {} detected upgrade flavour'.format(
|
||||
command_utils.get_upgrade_flavour()))
|
||||
@command_opt('report-schema', help='Specify report schema version for leapp-report.json',
|
||||
choices=['1.0.0', '1.1.0', '1.2.0'], default=get_config().get('report', 'schema'))
|
||||
diff --git a/repos/system_upgrade/common/actors/checktargetversion/actor.py b/repos/system_upgrade/common/actors/checktargetversion/actor.py
|
||||
new file mode 100644
|
||||
index 00000000..291ce3da
|
||||
--- /dev/null
|
||||
+++ b/repos/system_upgrade/common/actors/checktargetversion/actor.py
|
||||
@@ -0,0 +1,22 @@
|
||||
+from leapp.actors import Actor
|
||||
+from leapp.libraries.actor import checktargetversion
|
||||
+from leapp.models import IPUPaths
|
||||
+from leapp.reporting import Report
|
||||
+from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
|
||||
+
|
||||
+
|
||||
+class CheckTargetVersion(Actor):
|
||||
+ """
|
||||
+ Check that the target system version is supported by the upgrade process.
|
||||
+
|
||||
+ Invoke inhibitor if the target system is not supported.
|
||||
+ Allow unsupported target if `LEAPP_UNSUPPORTED=1` is set.
|
||||
+ """
|
||||
+
|
||||
+ name = 'check_target_version'
|
||||
+ consumes = (IPUPaths,)
|
||||
+ produces = (Report,)
|
||||
+ tags = (ChecksPhaseTag, IPUWorkflowTag)
|
||||
+
|
||||
+ def process(self):
|
||||
+ checktargetversion.process()
|
||||
diff --git a/repos/system_upgrade/common/actors/checktargetversion/libraries/checktargetversion.py b/repos/system_upgrade/common/actors/checktargetversion/libraries/checktargetversion.py
|
||||
new file mode 100644
|
||||
index 00000000..0df1ece2
|
||||
--- /dev/null
|
||||
+++ b/repos/system_upgrade/common/actors/checktargetversion/libraries/checktargetversion.py
|
||||
@@ -0,0 +1,86 @@
|
||||
+from leapp import reporting
|
||||
+from leapp.exceptions import StopActorExecutionError
|
||||
+from leapp.libraries.common.config import get_env, version
|
||||
+from leapp.libraries.stdlib import api
|
||||
+from leapp.models import IPUPaths
|
||||
+from leapp.utils.deprecation import suppress_deprecation
|
||||
+
|
||||
+FMT_LIST_SEPARATOR = '\n - '
|
||||
+
|
||||
+
|
||||
+@suppress_deprecation(IPUPaths)
|
||||
+def get_supported_target_versions():
|
||||
+ ipu_paths = next(api.consume(IPUPaths), None)
|
||||
+ src_version = version.get_source_version()
|
||||
+ if not ipu_paths:
|
||||
+ # NOTE: missing unit-tests. Unexpected situation and the solution
|
||||
+ # is possibly temporary
|
||||
+ raise StopActorExecutionError('Missing the IPUPaths message. Cannot determine defined upgrade paths.')
|
||||
+ for ipu_path in ipu_paths.data:
|
||||
+ if ipu_path.source_version == src_version:
|
||||
+ return ipu_path.target_versions
|
||||
+
|
||||
+ # Nothing discovered. Current src_version is not already supported or not yet.
|
||||
+ # Problem of supported source versions is handled now separately in other
|
||||
+ # actors. Fallbak from X.Y versioning to major version only.
|
||||
+ api.current_logger().warning(
|
||||
+ 'Cannot discover support upgrade path for this system release: {}'
|
||||
+ .format(src_version)
|
||||
+ )
|
||||
+ maj_version = version.get_source_major_version()
|
||||
+ for ipu_path in ipu_paths.data:
|
||||
+ if ipu_path.source_version == maj_version:
|
||||
+ return ipu_path.target_versions
|
||||
+
|
||||
+ # Completely unknown
|
||||
+ api.current_logger().warning(
|
||||
+ 'Cannot discover supported upgrade path for this system major version: {}'
|
||||
+ .format(maj_version)
|
||||
+ )
|
||||
+ return []
|
||||
+
|
||||
+
|
||||
+def process():
|
||||
+ target_version = version.get_target_version()
|
||||
+ supported_target_versions = get_supported_target_versions()
|
||||
+
|
||||
+ if target_version in supported_target_versions:
|
||||
+ api.current_logger().info('Target version is supported. Continue.')
|
||||
+ return
|
||||
+
|
||||
+ if get_env('LEAPP_UNSUPPORTED', '0') == '1':
|
||||
+ api.current_logger().warning(
|
||||
+ 'Upgrading to an unsupported version of the target system but LEAPP_UNSUPPORTED=1. Continue.'
|
||||
+ )
|
||||
+ return
|
||||
+
|
||||
+ # inhibit the upgrade - unsupported target and leapp running in production mode
|
||||
+ hint = (
|
||||
+ 'Choose a supported version of the target OS for the upgrade.'
|
||||
+ ' Alternatively, if you require to upgrade using an unsupported upgrade path,'
|
||||
+ ' set the `LEAPP_UNSUPPORTED=1` environment variable to confirm you'
|
||||
+ ' want to upgrade on your own risk.'
|
||||
+ )
|
||||
+
|
||||
+ reporting.create_report([
|
||||
+ reporting.Title('Specified version of the target system is not supported'),
|
||||
+ reporting.Summary(
|
||||
+ 'The in-place upgrade to the specified version ({tgt_ver}) of the target system'
|
||||
+ ' is not supported from the current system version. Follow the official'
|
||||
+ ' documentation for up to date information about supported upgrade'
|
||||
+ ' paths and future plans (see the attached link).'
|
||||
+ ' The in-place upgrade is enabled to the following versions of the target system:{sep}{ver_list}'
|
||||
+ .format(
|
||||
+ sep=FMT_LIST_SEPARATOR,
|
||||
+ ver_list=FMT_LIST_SEPARATOR.join(supported_target_versions),
|
||||
+ tgt_ver=target_version
|
||||
+ )
|
||||
+ ),
|
||||
+ reporting.Groups([reporting.Groups.INHIBITOR]),
|
||||
+ reporting.Severity(reporting.Severity.HIGH),
|
||||
+ reporting.Remediation(hint=hint),
|
||||
+ reporting.ExternalLink(
|
||||
+ url='https://access.redhat.com/articles/4263361',
|
||||
+ title='Supported in-place upgrade paths for Red Hat Enterprise Linux'
|
||||
+ )
|
||||
+ ])
|
||||
diff --git a/repos/system_upgrade/common/actors/checktargetversion/tests/test_checktargetversion.py b/repos/system_upgrade/common/actors/checktargetversion/tests/test_checktargetversion.py
|
||||
new file mode 100644
|
||||
index 00000000..07391e7a
|
||||
--- /dev/null
|
||||
+++ b/repos/system_upgrade/common/actors/checktargetversion/tests/test_checktargetversion.py
|
||||
@@ -0,0 +1,90 @@
|
||||
+import os
|
||||
+
|
||||
+import pytest
|
||||
+
|
||||
+from leapp import reporting
|
||||
+from leapp.libraries.actor import checktargetversion
|
||||
+from leapp.libraries.common.testutils import create_report_mocked, CurrentActorMocked, logger_mocked
|
||||
+from leapp.libraries.stdlib import api
|
||||
+from leapp.models import IPUPath, IPUPaths
|
||||
+from leapp.utils.deprecation import suppress_deprecation
|
||||
+from leapp.utils.report import is_inhibitor
|
||||
+
|
||||
+
|
||||
+# It must be in a function so we can suppress the deprecation warning in tests.
|
||||
+@suppress_deprecation(IPUPaths)
|
||||
+def _get_upgrade_paths_data():
|
||||
+ return IPUPaths(data=[
|
||||
+ IPUPath(source_version='7.9', target_versions=['8.10']),
|
||||
+ IPUPath(source_version='8.10', target_versions=['9.4', '9.5', '9.6']),
|
||||
+ IPUPath(source_version='9.6', target_versions=['10.0']),
|
||||
+ IPUPath(source_version='7', target_versions=['8.10']),
|
||||
+ IPUPath(source_version='8', target_versions=['9.4', '9.5', '9.6']),
|
||||
+ IPUPath(source_version='9', target_versions=['10.0'])
|
||||
+ ])
|
||||
+
|
||||
+
|
||||
+@pytest.fixture
|
||||
+def setup_monkeypatch(monkeypatch):
|
||||
+ """Fixture to set up common monkeypatches."""
|
||||
+
|
||||
+ def _setup(source_version, target_version, leapp_unsupported='0'):
|
||||
+ curr_actor_mocked = CurrentActorMocked(
|
||||
+ src_ver=source_version,
|
||||
+ dst_ver=target_version,
|
||||
+ envars={'LEAPP_UNSUPPORTED': leapp_unsupported},
|
||||
+ msgs=[_get_upgrade_paths_data()]
|
||||
+ )
|
||||
+ monkeypatch.setattr(api, 'current_actor', curr_actor_mocked)
|
||||
+ monkeypatch.setattr(api, 'current_logger', logger_mocked())
|
||||
+ monkeypatch.setattr(reporting, 'create_report', create_report_mocked())
|
||||
+ return _setup
|
||||
+
|
||||
+
|
||||
+@pytest.mark.parametrize(('source_version', 'target_version', 'leapp_unsupported'), [
|
||||
+ # LEAPP_UNSUPPORTED=0
|
||||
+ ('7.9', '9.0', '0'),
|
||||
+ ('8.10', '9.0', '0'),
|
||||
+ ('9.6', '10.1', '0'),
|
||||
+ ('7', '9.0', '0'),
|
||||
+ ('8', '9.0', '0'),
|
||||
+ ('9', '10.1', '0'),
|
||||
+ # LEAPP_UNSUPPORTED=1
|
||||
+ ('7.9', '9.0', '1'),
|
||||
+ ('8.10', '9.0', '1'),
|
||||
+ ('9.6', '10.1', '1'),
|
||||
+ ('7', '9.0', '1'),
|
||||
+ ('8', '9.0', '1'),
|
||||
+ ('9', '10.1', '1'),
|
||||
+])
|
||||
+def test_unsuppoted_paths(setup_monkeypatch, source_version, target_version, leapp_unsupported):
|
||||
+ setup_monkeypatch(source_version, target_version, leapp_unsupported)
|
||||
+
|
||||
+ if leapp_unsupported == '1':
|
||||
+ checktargetversion.process()
|
||||
+ assert reporting.create_report.called == 0
|
||||
+ assert api.current_logger.warnmsg
|
||||
+ else:
|
||||
+ checktargetversion.process()
|
||||
+ assert reporting.create_report.called == 1
|
||||
+ assert is_inhibitor(reporting.create_report.report_fields)
|
||||
+
|
||||
+
|
||||
+@pytest.mark.parametrize(('source_version', 'target_version'), [
|
||||
+ ('7.9', '8.10'),
|
||||
+ ('8.10', '9.4'),
|
||||
+ ('8.10', '9.5'),
|
||||
+ ('8.10', '9.6'),
|
||||
+ ('9.6', '10.0'),
|
||||
+ ('7', '8.10'),
|
||||
+ ('8', '9.4'),
|
||||
+ ('8', '9.5'),
|
||||
+ ('8', '9.6'),
|
||||
+ ('9', '10.0'),
|
||||
+])
|
||||
+def test_supported_paths(setup_monkeypatch, source_version, target_version):
|
||||
+ setup_monkeypatch(source_version, target_version, leapp_unsupported='0')
|
||||
+
|
||||
+ checktargetversion.process()
|
||||
+ assert reporting.create_report.called == 0
|
||||
+ assert api.current_logger.infomsg
|
||||
diff --git a/repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py b/repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py
|
||||
index 9e213f64..749b3347 100644
|
||||
--- a/repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py
|
||||
+++ b/repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py
|
||||
@@ -64,17 +64,41 @@ def get_os_release(path):
|
||||
details={'details': str(e)})
|
||||
|
||||
|
||||
+def check_target_major_version(curr_version, target_version):
|
||||
+ required_major_version = int(curr_version.split('.')[0]) + 1
|
||||
+ specified_major_version = int(target_version.split('.')[0])
|
||||
+ if specified_major_version != required_major_version:
|
||||
+ raise StopActorExecutionError(
|
||||
+ message='Specified invalid major version of the target system',
|
||||
+ details={
|
||||
+ 'Specified target major version': str(specified_major_version),
|
||||
+ 'Required target major version': str(required_major_version),
|
||||
+ 'hint': (
|
||||
+ 'The in-place upgrade is possible only to the next system'
|
||||
+ ' major version: {ver}. Specify a valid version of the'
|
||||
+ ' target system when running leapp.'
|
||||
+ ' For more information about supported in-place upgrade paths'
|
||||
+ ' follow: https://access.redhat.com/articles/4263361'
|
||||
+ .format(ver=required_major_version)
|
||||
+ )
|
||||
+ }
|
||||
+ )
|
||||
+
|
||||
+
|
||||
def produce_ipu_config(actor):
|
||||
flavour = os.environ.get('LEAPP_UPGRADE_PATH_FLAVOUR')
|
||||
target_version = os.environ.get('LEAPP_UPGRADE_PATH_TARGET_RELEASE')
|
||||
os_release = get_os_release('/etc/os-release')
|
||||
+ source_version = os_release.version_id
|
||||
+
|
||||
+ check_target_major_version(source_version, target_version)
|
||||
|
||||
actor.produce(IPUConfig(
|
||||
leapp_env_vars=get_env_vars(),
|
||||
os_release=os_release,
|
||||
architecture=platform.machine(),
|
||||
version=Version(
|
||||
- source=os_release.version_id,
|
||||
+ source=source_version,
|
||||
target=target_version
|
||||
),
|
||||
kernel=get_booted_kernel(),
|
||||
--
|
||||
2.48.1
|
||||
|
1402
0063-Add-inhibitor-for-unsupported-XFS.patch
Normal file
1402
0063-Add-inhibitor-for-unsupported-XFS.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -52,7 +52,7 @@ py2_byte_compile "%1" "%2"}
|
||||
|
||||
Name: leapp-repository
|
||||
Version: 0.21.0
|
||||
Release: 5%{?dist}
|
||||
Release: 6%{?dist}
|
||||
Summary: Repositories for leapp
|
||||
|
||||
License: ASL 2.0
|
||||
@ -118,6 +118,16 @@ Patch0050: 0050-redhatsignedrpmcheck-Add-remediation-hint-and-URL.patch
|
||||
Patch0051: 0051-Update-postgresqlcheck.py.patch
|
||||
Patch0052: 0052-Update-repos-system_upgrade-el8toel9-actors-postgres.patch
|
||||
Patch0053: 0053-Fix-remediation-message-in-the-networkdeprecations-a.patch
|
||||
Patch0054: 0054-linter-Fix-line-too-long-in-postgresqlcheck.patch
|
||||
Patch0055: 0055-Fix-typos-in-comments-to-make-spellchecker-happy.patch
|
||||
Patch0056: 0056-fix-add_upgrade_boot_entry-convert-arg-list-into-a-t.patch
|
||||
Patch0057: 0057-fix-arm-bootloader-efi-patch-grub.cfg-used-for-upgra.patch
|
||||
Patch0058: 0058-feat-arm-bootloader-efi-use-separate-BLS-directory-f.patch
|
||||
Patch0059: 0059-fix-models-move-arm-bootloader-workaround-model-into.patch
|
||||
Patch0060: 0060-cleanup-8to9-efi-do-not-use-symlinks-or-copy-grub-fi.patch
|
||||
Patch0061: 0061-Introduce-deprecated-IPUPaths-msg-temporary-solution.patch
|
||||
Patch0062: 0062-Verify-supported-target-OS-version-in-actors.patch
|
||||
Patch0063: 0063-Add-inhibitor-for-unsupported-XFS.patch
|
||||
|
||||
|
||||
%description
|
||||
@ -339,6 +349,16 @@ Requires: libdb-utils
|
||||
%patch -P 0051 -p1
|
||||
%patch -P 0052 -p1
|
||||
%patch -P 0053 -p1
|
||||
%patch -P 0054 -p1
|
||||
%patch -P 0055 -p1
|
||||
%patch -P 0056 -p1
|
||||
%patch -P 0057 -p1
|
||||
%patch -P 0058 -p1
|
||||
%patch -P 0059 -p1
|
||||
%patch -P 0060 -p1
|
||||
%patch -P 0061 -p1
|
||||
%patch -P 0062 -p1
|
||||
%patch -P 0063 -p1
|
||||
|
||||
|
||||
%build
|
||||
@ -420,6 +440,12 @@ done;
|
||||
# no files here
|
||||
|
||||
%changelog
|
||||
* Wed Jan 29 2025 Petr Stodulka <pstodulk@redhat.com> - 0.21.0-6
|
||||
- Detect XFS file systems with problematic parameters
|
||||
- Raise an inhibitor if unsupported target version supplied instead of error
|
||||
- Prevent a possible crash with LiveMode when adding the upgrade boot entry on systems with LVM
|
||||
- Resolves: RHEL-57043, RHEL-52309, RHEL-60034
|
||||
|
||||
* Fri Jan 17 2025 Petr Stodulka <pstodulk@redhat.com> - 0.21.0-5
|
||||
- Obsolete RHEL9 GPG key signed with SHA1
|
||||
- Activate LVM VGs with `--sysinit` option to correct the use in the upgrade initramfs
|
||||
|
Loading…
Reference in New Issue
Block a user