Compare commits

...

No commits in common. "c8" and "a8-elevate-0220" have entirely different histories.

138 changed files with 126490 additions and 23880 deletions

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
SOURCES/deps-pkgs-13.tar.gz
SOURCES/leapp-repository-0.23.0.tar.gz
SOURCES/leapp-repository-0.22.0.tar.gz

View File

@ -1,2 +1,2 @@
3590b33b4a79ebe62f5cfa0eeca7efb41d526498 SOURCES/deps-pkgs-13.tar.gz
b5b541cc0c0372ee476f0ab6073a62e67290d031 SOURCES/leapp-repository-0.23.0.tar.gz
e23b32573b375337b079dd7a0dc07e9232851b1c SOURCES/leapp-repository-0.22.0.tar.gz

View File

@ -1,333 +0,0 @@
From dcf53c28ea9c3fdd03277abcdeb1d124660f7f8e Mon Sep 17 00:00:00 2001
From: karolinku <kkula@redhat.com>
Date: Tue, 19 Aug 2025 09:48:11 +0200
Subject: [PATCH 01/55] Add upgrade inhibitor for custom DNF pluginpath
configuration
Implements detection and inhibition of the upgrade when DNF
pluginpath is configured in /etc/dnf/dnf.conf:
- Add DnfPluginPathDetected model to communicate detection results
- Add ScanDnfPluginPath actor (FactsPhase) to scan DNF configuration
- Add CheckDnfPluginPath actor (ChecksPhase) to create inhibitor report
- Add related unit tests
Localisation of dnf plugins is not constant between system releases
which can cause issues with the upgrade, so the user should remove
this option or comment it out.
Jira: RHEL-69601
---
.../common/actors/checkdnfpluginpath/actor.py | 22 ++++++++
.../libraries/checkdnfpluginpath.py | 35 ++++++++++++
.../tests/test_checkdnfpluginpath.py | 34 ++++++++++++
.../common/actors/scandnfpluginpath/actor.py | 21 ++++++++
.../libraries/scandnfpluginpath.py | 30 +++++++++++
.../files/dnf_config_incorrect_pluginpath | 7 +++
.../tests/files/dnf_config_no_pluginpath | 6 +++
.../tests/files/dnf_config_with_pluginpath | 7 +++
.../tests/test_scandnfpluginpath.py | 53 +++++++++++++++++++
.../common/models/dnfpluginpathdetected.py | 14 +++++
10 files changed, 229 insertions(+)
create mode 100644 repos/system_upgrade/common/actors/checkdnfpluginpath/actor.py
create mode 100644 repos/system_upgrade/common/actors/checkdnfpluginpath/libraries/checkdnfpluginpath.py
create mode 100644 repos/system_upgrade/common/actors/checkdnfpluginpath/tests/test_checkdnfpluginpath.py
create mode 100644 repos/system_upgrade/common/actors/scandnfpluginpath/actor.py
create mode 100644 repos/system_upgrade/common/actors/scandnfpluginpath/libraries/scandnfpluginpath.py
create mode 100644 repos/system_upgrade/common/actors/scandnfpluginpath/tests/files/dnf_config_incorrect_pluginpath
create mode 100644 repos/system_upgrade/common/actors/scandnfpluginpath/tests/files/dnf_config_no_pluginpath
create mode 100644 repos/system_upgrade/common/actors/scandnfpluginpath/tests/files/dnf_config_with_pluginpath
create mode 100644 repos/system_upgrade/common/actors/scandnfpluginpath/tests/test_scandnfpluginpath.py
create mode 100644 repos/system_upgrade/common/models/dnfpluginpathdetected.py
diff --git a/repos/system_upgrade/common/actors/checkdnfpluginpath/actor.py b/repos/system_upgrade/common/actors/checkdnfpluginpath/actor.py
new file mode 100644
index 00000000..34055886
--- /dev/null
+++ b/repos/system_upgrade/common/actors/checkdnfpluginpath/actor.py
@@ -0,0 +1,22 @@
+from leapp.actors import Actor
+from leapp.libraries.actor.checkdnfpluginpath import perform_check
+from leapp.models import DnfPluginPathDetected
+from leapp.reporting import Report
+from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
+
+
+class CheckDnfPluginPath(Actor):
+ """
+ Inhibits the upgrade if a custom DNF plugin path is configured.
+
+ This actor checks whether the pluginpath option is configured in /etc/dnf/dnf.conf and produces a report if it is.
+ If the option is detected with any value, the upgrade is inhibited.
+ """
+
+ name = 'check_dnf_pluginpath'
+ consumes = (DnfPluginPathDetected,)
+ produces = (Report,)
+ tags = (ChecksPhaseTag, IPUWorkflowTag)
+
+ def process(self):
+ perform_check()
diff --git a/repos/system_upgrade/common/actors/checkdnfpluginpath/libraries/checkdnfpluginpath.py b/repos/system_upgrade/common/actors/checkdnfpluginpath/libraries/checkdnfpluginpath.py
new file mode 100644
index 00000000..ce705361
--- /dev/null
+++ b/repos/system_upgrade/common/actors/checkdnfpluginpath/libraries/checkdnfpluginpath.py
@@ -0,0 +1,35 @@
+from leapp import reporting
+from leapp.libraries.stdlib import api
+from leapp.models import DnfPluginPathDetected
+
+DNF_CONFIG_PATH = '/etc/dnf/dnf.conf'
+
+
+def check_dnf_pluginpath(dnf_pluginpath_detected):
+ """Create an inhibitor when pluginpath is detected in DNF configuration."""
+ if not dnf_pluginpath_detected.is_pluginpath_detected:
+ return
+ reporting.create_report([
+ reporting.Title('Detected specified pluginpath in DNF configuration.'),
+ reporting.Summary(
+ 'The "pluginpath" option is set in the {} file. The path to DNF plugins differs between '
+ 'system major releases due to different versions of Python. '
+ 'This breaks the in-place upgrades if defined explicitly as DNF plugins '
+ 'are stored on a different path on the new system.'
+ .format(DNF_CONFIG_PATH)
+ ),
+ reporting.Remediation(
+ hint='Remove or comment out the pluginpath option in the DNF '
+ 'configuration file to be able to upgrade the system',
+ commands=[['sed', '-i', '\'s/^pluginpath[[:space:]]*=/#pluginpath=/\'', DNF_CONFIG_PATH]],
+ ),
+ reporting.Severity(reporting.Severity.HIGH),
+ reporting.Groups([reporting.Groups.INHIBITOR]),
+ reporting.RelatedResource('file', DNF_CONFIG_PATH),
+ ])
+
+
+def perform_check():
+ dnf_pluginpath_detected = next(api.consume(DnfPluginPathDetected), None)
+ if dnf_pluginpath_detected:
+ check_dnf_pluginpath(dnf_pluginpath_detected)
diff --git a/repos/system_upgrade/common/actors/checkdnfpluginpath/tests/test_checkdnfpluginpath.py b/repos/system_upgrade/common/actors/checkdnfpluginpath/tests/test_checkdnfpluginpath.py
new file mode 100644
index 00000000..7dd8bbf2
--- /dev/null
+++ b/repos/system_upgrade/common/actors/checkdnfpluginpath/tests/test_checkdnfpluginpath.py
@@ -0,0 +1,34 @@
+import pytest
+
+from leapp import reporting
+from leapp.libraries.actor.checkdnfpluginpath import check_dnf_pluginpath, perform_check
+from leapp.libraries.common.testutils import create_report_mocked, CurrentActorMocked
+from leapp.libraries.stdlib import api
+from leapp.models import DnfPluginPathDetected
+from leapp.utils.report import is_inhibitor
+
+
+@pytest.mark.parametrize('is_detected', [False, True])
+def test_check_dnf_pluginpath(monkeypatch, is_detected):
+ actor_reports = create_report_mocked()
+ msg = DnfPluginPathDetected(is_pluginpath_detected=is_detected)
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=[msg]))
+ monkeypatch.setattr(reporting, 'create_report', actor_reports)
+
+ perform_check()
+
+ assert bool(actor_reports.called) == is_detected
+
+ if is_detected:
+ assert is_inhibitor(actor_reports.report_fields)
+
+
+def test_perform_check_no_message_available(monkeypatch):
+ """Test perform_check when no DnfPluginPathDetected message is available."""
+ actor_reports = create_report_mocked()
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked())
+ monkeypatch.setattr(reporting, 'create_report', actor_reports)
+
+ perform_check()
+
+ assert not actor_reports.called
diff --git a/repos/system_upgrade/common/actors/scandnfpluginpath/actor.py b/repos/system_upgrade/common/actors/scandnfpluginpath/actor.py
new file mode 100644
index 00000000..e43a691e
--- /dev/null
+++ b/repos/system_upgrade/common/actors/scandnfpluginpath/actor.py
@@ -0,0 +1,21 @@
+from leapp.actors import Actor
+from leapp.libraries.actor.scandnfpluginpath import scan_dnf_pluginpath
+from leapp.models import DnfPluginPathDetected
+from leapp.tags import FactsPhaseTag, IPUWorkflowTag
+
+
+class ScanDnfPluginPath(Actor):
+ """
+ Scans DNF configuration for custom pluginpath option.
+
+ This actor collects information about whether the pluginpath option is configured in DNF configuration
+ and produces a DnfPluginPathDetected message, containing the information.
+ """
+
+ name = 'scan_dnf_pluginpath'
+ consumes = ()
+ produces = (DnfPluginPathDetected,)
+ tags = (FactsPhaseTag, IPUWorkflowTag)
+
+ def process(self):
+ scan_dnf_pluginpath()
diff --git a/repos/system_upgrade/common/actors/scandnfpluginpath/libraries/scandnfpluginpath.py b/repos/system_upgrade/common/actors/scandnfpluginpath/libraries/scandnfpluginpath.py
new file mode 100644
index 00000000..818f7700
--- /dev/null
+++ b/repos/system_upgrade/common/actors/scandnfpluginpath/libraries/scandnfpluginpath.py
@@ -0,0 +1,30 @@
+import os
+
+from six.moves import configparser
+
+from leapp.libraries.stdlib import api
+from leapp.models import DnfPluginPathDetected
+
+DNF_CONFIG_PATH = '/etc/dnf/dnf.conf'
+
+
+def _is_pluginpath_set(config_path):
+ """Check if pluginpath option is set in DNF configuration file."""
+ if not os.path.isfile(config_path):
+ api.current_logger().warning('The %s file is missing.', config_path)
+ return False
+
+ parser = configparser.ConfigParser()
+
+ try:
+ parser.read(config_path)
+ return parser.has_option('main', 'pluginpath')
+ except (configparser.Error, IOError) as e:
+ api.current_logger().warning('The DNF config file %s couldn\'t be parsed: %s', config_path, e)
+ return False
+
+
+def scan_dnf_pluginpath():
+ """Scan DNF configuration and produce DnfPluginPathDetected message."""
+ is_detected = _is_pluginpath_set(DNF_CONFIG_PATH)
+ api.produce(DnfPluginPathDetected(is_pluginpath_detected=is_detected))
diff --git a/repos/system_upgrade/common/actors/scandnfpluginpath/tests/files/dnf_config_incorrect_pluginpath b/repos/system_upgrade/common/actors/scandnfpluginpath/tests/files/dnf_config_incorrect_pluginpath
new file mode 100644
index 00000000..aa29db09
--- /dev/null
+++ b/repos/system_upgrade/common/actors/scandnfpluginpath/tests/files/dnf_config_incorrect_pluginpath
@@ -0,0 +1,7 @@
+[main]
+gpgcheck=1
+installonly_limit=3
+clean_requirements_on_remove=True
+best=True
+skip_if_unavailable=False
+pluginpathincorrect=/usr/lib/python3.6/site-packages/dnf-plugins
diff --git a/repos/system_upgrade/common/actors/scandnfpluginpath/tests/files/dnf_config_no_pluginpath b/repos/system_upgrade/common/actors/scandnfpluginpath/tests/files/dnf_config_no_pluginpath
new file mode 100644
index 00000000..3d08d075
--- /dev/null
+++ b/repos/system_upgrade/common/actors/scandnfpluginpath/tests/files/dnf_config_no_pluginpath
@@ -0,0 +1,6 @@
+[main]
+gpgcheck=1
+installonly_limit=3
+clean_requirements_on_remove=True
+best=True
+skip_if_unavailable=False
diff --git a/repos/system_upgrade/common/actors/scandnfpluginpath/tests/files/dnf_config_with_pluginpath b/repos/system_upgrade/common/actors/scandnfpluginpath/tests/files/dnf_config_with_pluginpath
new file mode 100644
index 00000000..09a81e64
--- /dev/null
+++ b/repos/system_upgrade/common/actors/scandnfpluginpath/tests/files/dnf_config_with_pluginpath
@@ -0,0 +1,7 @@
+[main]
+gpgcheck=1
+installonly_limit=3
+clean_requirements_on_remove=True
+best=True
+skip_if_unavailable=False
+pluginpath=/usr/lib/python3.6/site-packages/dnf-plugins
diff --git a/repos/system_upgrade/common/actors/scandnfpluginpath/tests/test_scandnfpluginpath.py b/repos/system_upgrade/common/actors/scandnfpluginpath/tests/test_scandnfpluginpath.py
new file mode 100644
index 00000000..fefb9d3f
--- /dev/null
+++ b/repos/system_upgrade/common/actors/scandnfpluginpath/tests/test_scandnfpluginpath.py
@@ -0,0 +1,53 @@
+import os
+
+import pytest
+
+from leapp.libraries.actor import scandnfpluginpath
+from leapp.libraries.common.testutils import CurrentActorMocked, logger_mocked, produce_mocked
+from leapp.libraries.stdlib import api
+from leapp.models import DnfPluginPathDetected
+
+
+@pytest.mark.parametrize('is_detected', [False, True])
+def test_scan_detects_pluginpath(monkeypatch, is_detected):
+ mocked_producer = produce_mocked()
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked())
+ monkeypatch.setattr(api, 'produce', mocked_producer)
+
+ monkeypatch.setattr(scandnfpluginpath, '_is_pluginpath_set',
+ lambda path: is_detected)
+
+ scandnfpluginpath.scan_dnf_pluginpath()
+
+ assert mocked_producer.called == 1
+ assert mocked_producer.model_instances[0].is_pluginpath_detected is is_detected
+
+
+@pytest.mark.parametrize(('config_file', 'result'), [
+ ('files/dnf_config_no_pluginpath', False),
+ ('files/dnf_config_with_pluginpath', True),
+ ('files/dnf_config_incorrect_pluginpath', False),
+ ('files/not_existing_file.conf', False)
+])
+def test_is_pluginpath_set(config_file, result):
+ CUR_DIR = os.path.dirname(os.path.abspath(__file__))
+
+ assert scandnfpluginpath._is_pluginpath_set(os.path.join(CUR_DIR, config_file)) == result
+
+
+def test_scan_no_config_file(monkeypatch):
+ mocked_producer = produce_mocked()
+ logger = logger_mocked()
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked())
+ monkeypatch.setattr(api, 'produce', mocked_producer)
+ monkeypatch.setattr(api, 'current_logger', lambda: logger)
+
+ filename = 'files/not_existing_file.conf'
+ monkeypatch.setattr(scandnfpluginpath, 'DNF_CONFIG_PATH', filename)
+ scandnfpluginpath.scan_dnf_pluginpath()
+
+ assert mocked_producer.called == 1
+ assert mocked_producer.model_instances[0].is_pluginpath_detected is False
+
+ assert 'The %s file is missing.' in logger.warnmsg
+ assert filename in logger.warnmsg
diff --git a/repos/system_upgrade/common/models/dnfpluginpathdetected.py b/repos/system_upgrade/common/models/dnfpluginpathdetected.py
new file mode 100644
index 00000000..c5474857
--- /dev/null
+++ b/repos/system_upgrade/common/models/dnfpluginpathdetected.py
@@ -0,0 +1,14 @@
+from leapp.models import fields, Model
+from leapp.topics import SystemInfoTopic
+
+
+class DnfPluginPathDetected(Model):
+ """
+ This model contains information about whether DNF pluginpath option is configured in /etc/dnf/dnf.conf.
+ """
+ topic = SystemInfoTopic
+
+ is_pluginpath_detected = fields.Boolean()
+ """
+ True if pluginpath option is found in /etc/dnf/dnf.conf, False otherwise.
+ """
--
2.51.1

View File

@ -0,0 +1,49 @@
From 092ea5e7c5b8a453bcd30be5fefb0e2ecab752c4 Mon Sep 17 00:00:00 2001
From: Yuriy Kohut <yura.kohut@gmail.com>
Date: Mon, 3 Mar 2025 15:36:43 +0200
Subject: [PATCH 01/37] Use leapp.libraries.common.rpms.get_leapp_packages
(which is backward compatible) to get the list of leapp and leapp-repository
rpms, that should be preserved during the 9to10 upgrade
Do not import get_source_major_version as it isn't used anywhere
---
.../common/libraries/dnfconfig.py | 22 +------------------
1 file changed, 1 insertion(+), 21 deletions(-)
diff --git a/repos/system_upgrade/common/libraries/dnfconfig.py b/repos/system_upgrade/common/libraries/dnfconfig.py
index 5b8180f0..4b5afeb5 100644
--- a/repos/system_upgrade/common/libraries/dnfconfig.py
+++ b/repos/system_upgrade/common/libraries/dnfconfig.py
@@ -1,28 +1,8 @@
from leapp.exceptions import StopActorExecutionError
-from leapp.libraries.common.config.version import get_source_major_version
+from leapp.libraries.common.rpms import get_leapp_packages
from leapp.libraries.stdlib import api, CalledProcessError
-def get_leapp_packages():
- """
- Return the list of leapp and leapp-repository rpms that should be preserved
- during the upgrade.
-
- It's list of packages that should be preserved, not what is really
- installed.
-
- The snactor RPM doesn't have to be installed, but if so, we have to take
- care about that too as well to prevent broken dnf transaction.
- """
- # TODO: should we set the seatbelt and exclude leapp RPMs from the target
- # system too?
- generic = ['leapp', 'snactor']
- if get_source_major_version() == '7':
- return generic + ['python2-leapp', 'leapp-upgrade-el7toel8']
-
- return generic + ['python3-leapp', 'leapp-upgrade-el8toel9']
-
-
def _strip_split(data, sep, maxsplit=-1):
"""
Just like str.split(), but remove ambient whitespaces from all items
--
2.49.0

View File

@ -1,245 +0,0 @@
From 004cec5bd33025412df84f07590b6c5452d70ab6 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Wed, 17 Apr 2024 09:58:00 +0200
Subject: [PATCH 02/55] Upgrade dracut module: Update /usr mounting solution
Originally we had implemented our own mount_usr.sh script, which
took care about mounting the /usr when it is present on separate
partition / mountpoint. It took care also about LVM activation.
However, it has been problematic in various cases (e.g. when device
needed more time for initialisation - e.g. when connected using FC).
Let's use instead existing system solutions, starting
the upgrade.target after initrd-fs.target (instead of just
basic.target). IOW, let's get as close to the standard booting
procedure when speaking about the storage, as possible.
Note that the booting is still broken in this commit and needs
additional changes made in followup commits. But due to complexity
of the solution, keeping this separated.
jira: RHEL-3344, RHEL-35446
---
.../85sys-upgrade-redhat/module-setup.sh | 1 -
.../dracut/85sys-upgrade-redhat/mount_usr.sh | 148 ------------------
.../initrd-cleanup-override.conf | 3 +
.../dracut/90sys-upgrade/module-setup.sh | 11 ++
.../files/dracut/90sys-upgrade/upgrade.target | 4 +-
5 files changed, 16 insertions(+), 151 deletions(-)
delete mode 100755 repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/85sys-upgrade-redhat/mount_usr.sh
create mode 100644 repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/90sys-upgrade/initrd-cleanup-override.conf
diff --git a/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/85sys-upgrade-redhat/module-setup.sh b/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/85sys-upgrade-redhat/module-setup.sh
index d73060cb..45f98148 100755
--- a/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/85sys-upgrade-redhat/module-setup.sh
+++ b/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/85sys-upgrade-redhat/module-setup.sh
@@ -102,7 +102,6 @@ install() {
inst_binary grep
# script to actually run the upgrader binary
- inst_hook upgrade 49 "$_moddir/mount_usr.sh"
inst_hook upgrade 50 "$_moddir/do-upgrade.sh"
#NOTE: some clean up?.. ideally, everything should be inside the leapp*
diff --git a/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/85sys-upgrade-redhat/mount_usr.sh b/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/85sys-upgrade-redhat/mount_usr.sh
deleted file mode 100755
index 9366ac13..00000000
--- a/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/85sys-upgrade-redhat/mount_usr.sh
+++ /dev/null
@@ -1,148 +0,0 @@
-#!/bin/sh
-# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
-# ex: ts=8 sw=4 sts=4 et filetype=sh
-
-type info >/dev/null 2>&1 || . /lib/dracut-lib.sh
-
-export NEWROOT=${NEWROOT:-"/sysroot"}
-
-filtersubvol() {
- _oldifs="$IFS"
- IFS=","
- set "$@"
- IFS="$_oldifs"
- while [ $# -gt 0 ]; do
- case $1 in
- subvol=*) :;;
- *) printf '%s' "${1}," ;;
- esac
- shift
- done
-}
-
-mount_usr()
-{
- #
- # mount_usr [true | false]
- # Expected a "true" value for the last attempt to mount /usr. On the last
- # attempt, in case of failure drop to shell.
- #
- # Return 0 when everything is all right
- # In case of failure and /usr has been detected:
- # return 2 when $1 is "true" (drop to shell invoked)
- # (note: possibly it's nonsense, but to be sure..)
- # return 1 otherwise
- #
- _last_attempt="$1"
- # check, if we have to mount the /usr filesystem
- while read -r _dev _mp _fs _opts _freq _passno; do
- [ "${_dev%%#*}" != "$_dev" ] && continue
- if [ "$_mp" = "/usr" ]; then
- case "$_dev" in
- LABEL=*)
- _dev="$(echo "$_dev" | sed 's,/,\\x2f,g')"
- _dev="/dev/disk/by-label/${_dev#LABEL=}"
- ;;
- UUID=*)
- _dev="${_dev#block:}"
- _dev="/dev/disk/by-uuid/${_dev#UUID=}"
- ;;
- esac
-
- # shellcheck disable=SC2154 # Variable root is assigned by dracut
- _root_dev=${root#block:}
-
- if strstr "$_opts" "subvol=" && \
- [ "$(stat -c '%D:%i' "$_root_dev")" = "$(stat -c '%D:%i' "$_dev")" ] && \
- [ -n "$rflags" ]; then
- # for btrfs subvolumes we have to mount /usr with the same rflags
- rflags=$(filtersubvol "$rflags")
- rflags=${rflags%%,}
- _opts="${_opts:+${_opts},}${rflags}"
- elif getargbool 0 ro; then
- # if "ro" is specified, we want /usr to be mounted read-only
- _opts="${_opts:+${_opts},}ro"
- elif getargbool 0 rw; then
- # if "rw" is specified, we want /usr to be mounted read-write
- _opts="${_opts:+${_opts},}rw"
- fi
- echo "$_dev ${NEWROOT}${_mp} $_fs ${_opts} $_freq $_passno"
- _usr_found="1"
- break
- fi
- done < "${NEWROOT}/etc/fstab" >> /etc/fstab
-
- if [ "$_usr_found" = "" ]; then
- # nothing to do
- return 0
- fi
-
- info "Mounting /usr with -o $_opts"
- mount "${NEWROOT}/usr" 2>&1 | vinfo
- mount -o remount,rw "${NEWROOT}/usr"
-
- if ismounted "${NEWROOT}/usr"; then
- # success!!
- return 0
- fi
-
- if [ "$_last_attempt" = "true" ]; then
- warn "Mounting /usr to ${NEWROOT}/usr failed"
- warn "*** Dropping you to a shell; the system will continue"
- warn "*** when you leave the shell."
- action_on_fail
- return 2
- fi
-
- return 1
-}
-
-
-try_to_mount_usr() {
- _last_attempt="$1"
- if [ ! -f "${NEWROOT}/etc/fstab" ]; then
- warn "File ${NEWROOT}/etc/fstab doesn't exist."
- return 1
- fi
-
- # In case we have the LVM command available try make it activate all partitions
- if command -v lvm 2>/dev/null 1>/dev/null; then
- lvm vgchange --sysinit -a y || {
- warn "Detected problem when tried to activate LVM VG."
- if [ "$_last_attempt" != "true" ]; then
- # this is not last execution, retry
- return 1
- fi
- # NOTE(pstodulk):
- # last execution, so call mount_usr anyway
- # I am not 100% about lvm vgchange exit codes and I am aware of
- # possible warnings, in this last run, let's keep it on mount_usr
- # anyway..
- }
- fi
-
- mount_usr "$1"
-}
-
-_sleep_timeout=15
-_last_attempt="false"
-for i in 0 1 2 3 4 5 6 7 8 9 10 11; do
- info "Storage initialisation: Attempt $i of 11. Wait $_sleep_timeout seconds."
- sleep $_sleep_timeout
- if [ $i -eq 11 ]; then
- _last_attempt="true"
- fi
- try_to_mount_usr "$_last_attempt" && break
-
- # something is wrong. In some cases, storage needs more time for the
- # initialisation - especially in case of SAN.
-
- if [ "$_last_attempt" = "true" ]; then
- warn "The last attempt to initialize storage has not been successful."
- warn "Unknown state of the storage. It is possible that upgrade will be stopped."
- break
- fi
-
- warn "Failed attempt to initialize the storage. Retry..."
-done
-
diff --git a/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/90sys-upgrade/initrd-cleanup-override.conf b/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/90sys-upgrade/initrd-cleanup-override.conf
new file mode 100644
index 00000000..d24e0ef0
--- /dev/null
+++ b/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/90sys-upgrade/initrd-cleanup-override.conf
@@ -0,0 +1,3 @@
+[Service]
+ExecStart=
+ExecStart=-/usr/bin/true
diff --git a/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/90sys-upgrade/module-setup.sh b/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/90sys-upgrade/module-setup.sh
index 06479fb5..30ae57b3 100755
--- a/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/90sys-upgrade/module-setup.sh
+++ b/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/90sys-upgrade/module-setup.sh
@@ -54,6 +54,17 @@ install() {
ln -sf "../${s}.service" "$upgrade_wantsdir"
done
+ # Setup modified initrd-cleanup.service in the upgrade initramfs to enable
+ # storage initialisation using systemd-fstab-generator. We want to run the
+ # initrd-parse-etc.service but this one triggers also the initrd-cleanup.service
+ # which triggers the switch-root and isolated actions that basically kills
+ # the original upgrade service when used.
+ # The initrd-parse-etc.service has different content across RHEL systems,
+ # so we override rather initrd-cleanup.service instead as we do not need
+ # that one for the upgrade process.
+ mkdir -p "${unitdir}/initrd-cleanup.service.d"
+ inst_simple "${_moddir}/initrd-cleanup-override.conf" "${unitdir}/initrd-cleanup.service.d/initrd-cleanup-override.conf"
+
# just try : set another services into the wantsdir
# sysroot.mount \
# dracut-mount \
diff --git a/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/90sys-upgrade/upgrade.target b/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/90sys-upgrade/upgrade.target
index 366b5cab..d2bf7313 100644
--- a/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/90sys-upgrade/upgrade.target
+++ b/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/90sys-upgrade/upgrade.target
@@ -2,7 +2,7 @@
Description=System Upgrade
Documentation=man:upgrade.target(7)
# ##sysinit.target sockets.target initrd-root-fs.target initrd-root-device.target initrd-fs.target
-Wants=initrd-root-fs.target initrd-root-device.target initrd-fs.target initrd-usr-fs.target
+Wants=initrd-root-fs.target initrd-root-device.target initrd-fs.target initrd-usr-fs.target initrd-parse-etc.service
Requires=basic.target sysroot.mount
-After=basic.target sysroot.mount
+After=basic.target sysroot.mount initrd-fs.target
AllowIsolate=yes
--
2.51.1

View File

@ -0,0 +1,38 @@
From 1be52a6430b878bd4984bcf2577f3c7c847d2e48 Mon Sep 17 00:00:00 2001
From: Joe Ashcraft <joeashcraft@gmail.com>
Date: Tue, 4 Mar 2025 16:31:14 -0600
Subject: [PATCH 02/37] fix - spell AllowZoneDrifting correctly
resolves #1354
---
.../actors/firewalldcheckallowzonedrifting/actor.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/repos/system_upgrade/el8toel9/actors/firewalldcheckallowzonedrifting/actor.py b/repos/system_upgrade/el8toel9/actors/firewalldcheckallowzonedrifting/actor.py
index 0002f6aa..6f1c8f43 100644
--- a/repos/system_upgrade/el8toel9/actors/firewalldcheckallowzonedrifting/actor.py
+++ b/repos/system_upgrade/el8toel9/actors/firewalldcheckallowzonedrifting/actor.py
@@ -7,9 +7,9 @@ from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
class FirewalldCheckAllowZoneDrifting(Actor):
"""
- This actor will check if AllowZoneDrifiting=yes in firewalld.conf. This
+ This actor will check if AllowZoneDrifting=yes in firewalld.conf. This
option has been removed in RHEL-9 and behavior is as if
- AllowZoneDrifiting=no.
+ AllowZoneDrifting=no.
"""
name = 'firewalld_check_allow_zone_drifting'
@@ -37,7 +37,7 @@ class FirewalldCheckAllowZoneDrifting(Actor):
reporting.Summary('Firewalld has enabled configuration option '
'"{conf_key}" which has been removed in RHEL-9. '
'New behavior is as if "{conf_key}" was set to "no".'.format(
- conf_key='AllowZoneDrifiting')),
+ conf_key='AllowZoneDrifting')),
reporting.Severity(reporting.Severity.HIGH),
reporting.Groups([reporting.Groups.SANITY, reporting.Groups.FIREWALL]),
reporting.Groups([reporting.Groups.INHIBITOR]),
--
2.49.0

View File

@ -0,0 +1,134 @@
From 9ea195e84dbc70e4539efe86b6d8f8ca597e2661 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Thu, 27 Feb 2025 09:36:45 +0100
Subject: [PATCH 03/37] cli(upgrade): allow users to enable entire experimental
features
Introduce a new CLI option --enable-experimental-feature that allows
users to enable entire features that might be facilitated by a large
number of experimental actors. Previously, the used had to
remember/figure out the names of all of these actors and list them
manually using `--whitelist-experimental`. Using
`--enable-experimental-feature` therefore lifts this burden from the
user, and the user simply needs to know what experimental feature to
enable. The help for the new options includes a list of all supported
experimental feature - at the moment, the list contains only 'livemode'.
Jira-ref: RHELMISC-10648
---
commands/preupgrade/__init__.py | 4 ++++
commands/rerun/__init__.py | 1 +
commands/upgrade/__init__.py | 4 ++++
commands/upgrade/util.py | 35 ++++++++++++++++++++++++++++++++-
4 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/commands/preupgrade/__init__.py b/commands/preupgrade/__init__.py
index c1fabbbd..e52b6561 100644
--- a/commands/preupgrade/__init__.py
+++ b/commands/preupgrade/__init__.py
@@ -14,6 +14,10 @@ from leapp.utils.output import beautify_actor_exception, report_errors, report_i
@command('preupgrade', help='Generate preupgrade report')
@command_opt('whitelist-experimental', action='append', metavar='ActorName', help='Enables experimental actors')
+@command_opt('enable-experimental-feature', action='append', metavar='Feature',
+ help=('Enable experimental feature. '
+ 'Available experimental features: {}').format(util.get_help_str_with_avail_experimental_features()),
+ choices=list(util.EXPERIMENTAL_FEATURES), default=[])
@command_opt('debug', is_flag=True, help='Enable debug mode', inherit=False)
@command_opt('verbose', is_flag=True, help='Enable verbose logging', inherit=False)
@command_opt('no-rhsm', is_flag=True, help='Use only custom repositories and skip actions'
diff --git a/commands/rerun/__init__.py b/commands/rerun/__init__.py
index a06dd266..842178af 100644
--- a/commands/rerun/__init__.py
+++ b/commands/rerun/__init__.py
@@ -71,6 +71,7 @@ def rerun(args):
nogpgcheck=False,
channel=None,
report_schema='1.1.0',
+ enable_experimental_feature=[],
whitelist_experimental=[],
enablerepo=[]))
diff --git a/commands/upgrade/__init__.py b/commands/upgrade/__init__.py
index 608099ac..6f7504bf 100644
--- a/commands/upgrade/__init__.py
+++ b/commands/upgrade/__init__.py
@@ -20,6 +20,10 @@ from leapp.utils.output import beautify_actor_exception, report_errors, report_i
@command_opt('resume', is_flag=True, help='Continue the last execution after it was stopped (e.g. after reboot)')
@command_opt('reboot', is_flag=True, help='Automatically performs reboot when requested.')
@command_opt('whitelist-experimental', action='append', metavar='ActorName', help='Enable experimental actors')
+@command_opt('enable-experimental-feature', action='append', metavar='Feature',
+ help=('Enable experimental feature. '
+ 'Available experimental features: {}').format(util.get_help_str_with_avail_experimental_features()),
+ choices=list(util.EXPERIMENTAL_FEATURES), default=[])
@command_opt('debug', is_flag=True, help='Enable debug mode', inherit=False)
@command_opt('verbose', is_flag=True, help='Enable verbose logging', inherit=False)
@command_opt('no-rhsm', is_flag=True, help='Use only custom repositories and skip actions'
diff --git a/commands/upgrade/util.py b/commands/upgrade/util.py
index b20c316d..bfdbc4fa 100644
--- a/commands/upgrade/util.py
+++ b/commands/upgrade/util.py
@@ -17,6 +17,25 @@ from leapp.utils.output import report_unsupported
from leapp.utils.report import fetch_upgrade_report_messages, generate_report_file
+EXPERIMENTAL_FEATURES = {
+ 'livemode': [
+ 'live_image_generator',
+ 'live_mode_config_scanner',
+ 'live_mode_reporter',
+ 'prepare_live_image',
+ 'emit_livemode_requirements',
+ 'remove_live_image',
+ ]
+}
+""" Maps experimental features to a set of experimental actors that need to be enabled. """
+
+
+def get_help_str_with_avail_experimental_features():
+ if EXPERIMENTAL_FEATURES:
+ return ', '.join(EXPERIMENTAL_FEATURES)
+ return 'There are no experimental features available'
+
+
def disable_database_sync():
def disable_db_sync_decorator(f):
@functools.wraps(f)
@@ -184,11 +203,25 @@ def handle_output_level(args):
# the latest supported release because of target_version discovery attempt.
def prepare_configuration(args):
"""Returns a configuration dict object while setting a few env vars as a side-effect"""
+
if args.whitelist_experimental:
args.whitelist_experimental = list(itertools.chain(*[i.split(',') for i in args.whitelist_experimental]))
os.environ['LEAPP_EXPERIMENTAL'] = '1'
else:
os.environ['LEAPP_EXPERIMENTAL'] = '0'
+ args.whitelist_experimental = []
+
+ for experimental_feature in set(args.enable_experimental_feature):
+ # It might happen that there are no experimental features, which would allow user
+ # to pass us any string as an experimental feature.
+ if experimental_feature not in EXPERIMENTAL_FEATURES:
+ continue
+
+ actors_needed_for_feature = EXPERIMENTAL_FEATURES[experimental_feature]
+ args.whitelist_experimental.extend(actors_needed_for_feature)
+ if args.enable_experimental_feature:
+ os.environ['LEAPP_EXPERIMENTAL'] = '1'
+
os.environ['LEAPP_UNSUPPORTED'] = '0' if os.getenv('LEAPP_UNSUPPORTED', '0') == '0' else '1'
if args.no_rhsm:
os.environ['LEAPP_NO_RHSM'] = '1'
@@ -235,7 +268,7 @@ def prepare_configuration(args):
configuration = {
'debug': os.getenv('LEAPP_DEBUG', '0'),
'verbose': os.getenv('LEAPP_VERBOSE', '0'),
- 'whitelist_experimental': args.whitelist_experimental or (),
+ 'whitelist_experimental': args.whitelist_experimental or (), # Modified to also contain exp. features
'environment': {env: os.getenv(env) for env in os.environ if env.startswith('LEAPP_')},
'cmd': sys.argv,
}
--
2.49.0

View File

@ -1,132 +0,0 @@
From 04a2ec2574da233a41d32f70eab780b6c305ff31 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Thu, 19 Dec 2024 10:33:24 +0100
Subject: [PATCH 03/55] feat(lvm_autoactivation): add lvm autoactivation
Add LVM autoactivation mechanism to the upgrade initramfs. The core
of the mechanism is based on a special udev rule that is triggered
when a new device is detected. The rule then calls two lvm binaries
(which are also included into the upgrade initrams) to activate
the volume groups and logical volumes.
---
.../enable_lvm_autoactivation/actor.py | 21 ++++++++
.../libraries/enable_lvm_autoactivation.py | 21 ++++++++
.../test_lvm_autoactivation_enablement.py | 50 +++++++++++++++++++
3 files changed, 92 insertions(+)
create mode 100644 repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/actor.py
create mode 100644 repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/libraries/enable_lvm_autoactivation.py
create mode 100644 repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/tests/test_lvm_autoactivation_enablement.py
diff --git a/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/actor.py b/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/actor.py
new file mode 100644
index 00000000..aba60645
--- /dev/null
+++ b/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/actor.py
@@ -0,0 +1,21 @@
+from leapp.actors import Actor
+from leapp.libraries.actor import enable_lvm_autoactivation as enable_lvm_autoactivation_lib
+from leapp.models import DistributionSignedRPM, UpgradeInitramfsTasks
+from leapp.tags import FactsPhaseTag, IPUWorkflowTag
+
+
+class EnableLVMAutoactivation(Actor):
+ """
+ Enable LVM autoactivation in upgrade initramfs.
+
+ Produce instructions for upgrade initramfs generation that will result in LVM
+ autoactivation in the initramfs.
+ """
+
+ name = 'enable_lvm_autoactivation'
+ consumes = (DistributionSignedRPM,)
+ produces = (UpgradeInitramfsTasks, )
+ tags = (FactsPhaseTag, IPUWorkflowTag)
+
+ def process(self):
+ enable_lvm_autoactivation_lib.emit_lvm_autoactivation_instructions()
diff --git a/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/libraries/enable_lvm_autoactivation.py b/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/libraries/enable_lvm_autoactivation.py
new file mode 100644
index 00000000..e312277b
--- /dev/null
+++ b/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/libraries/enable_lvm_autoactivation.py
@@ -0,0 +1,21 @@
+from leapp.libraries.common.rpms import has_package
+from leapp.libraries.stdlib import api
+from leapp.models import DistributionSignedRPM, UpgradeInitramfsTasks
+
+
+def emit_lvm_autoactivation_instructions():
+ if not has_package(DistributionSignedRPM, 'lvm2'):
+ api.current_logger().debug(
+ 'Upgrade initramfs will not autoenable LVM devices - `lvm2` RPM is not installed.'
+ )
+ return
+
+ # the 69-dm-lvm.rules trigger pvscan and vgchange when LVM device is detected
+ files_to_include = [
+ '/usr/sbin/pvscan',
+ '/usr/sbin/vgchange',
+ '/usr/lib/udev/rules.d/69-dm-lvm.rules'
+ ]
+ lvm_autoactivation_instructions = UpgradeInitramfsTasks(include_files=files_to_include)
+
+ api.produce(lvm_autoactivation_instructions)
diff --git a/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/tests/test_lvm_autoactivation_enablement.py b/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/tests/test_lvm_autoactivation_enablement.py
new file mode 100644
index 00000000..c5150aea
--- /dev/null
+++ b/repos/system_upgrade/common/actors/initramfs/enable_lvm_autoactivation/tests/test_lvm_autoactivation_enablement.py
@@ -0,0 +1,50 @@
+from leapp.libraries.actor import enable_lvm_autoactivation
+from leapp.libraries.common.testutils import CurrentActorMocked, produce_mocked
+from leapp.libraries.stdlib import api
+from leapp.models import DistributionSignedRPM, RPM, UpgradeInitramfsTasks
+
+
+def test_emit_lvm_autoactivation_instructions_produces_correct_message(monkeypatch):
+ """Test that emit_lvm_autoactivation_instructions produces UpgradeInitramfsTasks with correct files."""
+ lvm_package = RPM(
+ name='lvm2',
+ version='2',
+ release='1',
+ epoch='1',
+ packager='',
+ arch='x86_64',
+ pgpsig='RSA/SHA256, Mon 01 Jan 1970 00:00:00 AM -03, Key ID 199e2f91fd431d51'
+ )
+
+ msgs = [
+ DistributionSignedRPM(items=[lvm_package])
+ ]
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=msgs))
+ monkeypatch.setattr(api, 'produce', produce_mocked())
+
+ enable_lvm_autoactivation.emit_lvm_autoactivation_instructions()
+
+ assert api.produce.called == 1
+
+ produced_msg = api.produce.model_instances[0]
+
+ assert isinstance(produced_msg, UpgradeInitramfsTasks)
+
+ expected_files = [
+ '/usr/sbin/pvscan',
+ '/usr/sbin/vgchange',
+ '/usr/lib/udev/rules.d/69-dm-lvm.rules'
+ ]
+ assert produced_msg.include_files == expected_files
+
+
+def test_no_action_if_lvm_rpm_missing(monkeypatch):
+ msgs = [
+ DistributionSignedRPM(items=[])
+ ]
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=msgs))
+ monkeypatch.setattr(api, 'produce', produce_mocked())
+
+ enable_lvm_autoactivation.emit_lvm_autoactivation_instructions()
+
+ assert api.produce.called == 0
--
2.51.1

View File

@ -0,0 +1,91 @@
From 11b9733cfe1c7cc10db675fba24d94c0c30f6b6e Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Thu, 27 Feb 2025 10:18:17 +0100
Subject: [PATCH 04/37] feat(livemode): exclude DNF cache from the created
squashfs image
Exclude /var/cache/dnf from the generated squashfs image. The DNF
cache is not needed for the live system that we boot into, since leapp
will always use DNF cache stored within target userspace container
(/sysroot/var/lib/leapp/...). Therefore, this optimization saves
a lot of disk space for the user (2GB->700mb).
---
.../libraries/liveimagegenerator.py | 22 ++++++++++++++-----
.../tests/test_image_generation.py | 6 +++--
2 files changed, 21 insertions(+), 7 deletions(-)
diff --git a/repos/system_upgrade/common/actors/livemode/liveimagegenerator/libraries/liveimagegenerator.py b/repos/system_upgrade/common/actors/livemode/liveimagegenerator/libraries/liveimagegenerator.py
index af8981d8..46118630 100644
--- a/repos/system_upgrade/common/actors/livemode/liveimagegenerator/libraries/liveimagegenerator.py
+++ b/repos/system_upgrade/common/actors/livemode/liveimagegenerator/libraries/liveimagegenerator.py
@@ -24,7 +24,7 @@ def lighten_target_userpace(context):
tree_to_prune, error)
-def build_squashfs(livemode_config, userspace_info):
+def build_squashfs(livemode_config, userspace_info, paths_to_exclude=None):
"""
Generate the live rootfs image based on the target userspace
@@ -34,8 +34,11 @@ def build_squashfs(livemode_config, userspace_info):
target_userspace_fullpath = userspace_info.path
squashfs_fullpath = livemode_config.squashfs_fullpath
- api.current_logger().info('Building the squashfs image %s from target userspace located at %s',
- squashfs_fullpath, target_userspace_fullpath)
+ if not paths_to_exclude:
+ paths_to_exclude = []
+
+ api.current_logger().info('Building the squashfs image %s from target userspace located at %s with excludes: %s',
+ squashfs_fullpath, target_userspace_fullpath, ', '.join(paths_to_exclude))
try:
if os.path.exists(squashfs_fullpath):
@@ -44,8 +47,13 @@ def build_squashfs(livemode_config, userspace_info):
api.current_logger().warning('Failed to remove already existing %s. Full error: %s',
squashfs_fullpath, error)
+ mksquashfs_command = ['mksquashfs', target_userspace_fullpath, squashfs_fullpath]
+ if paths_to_exclude:
+ mksquashfs_command.append('-e')
+ mksquashfs_command.extend(paths_to_exclude)
+
try:
- run(['mksquashfs', target_userspace_fullpath, squashfs_fullpath])
+ run(mksquashfs_command)
except CalledProcessError as error:
raise StopActorExecutionError(
'Cannot pack the target userspace into a squash image. ',
@@ -68,5 +76,9 @@ def generate_live_image_if_enabled():
with mounting.NspawnActions(base_dir=userspace_info.path) as context:
lighten_target_userpace(context)
- squashfs_path = build_squashfs(livemode_config, userspace_info)
+
+ # Exclude the DNF cache - we do not need it, leapp mounts /sysroot and uses userspace's dnf cache from there
+ paths_to_exclude = [os.path.join(userspace_info.path, 'var/cache/dnf')]
+
+ squashfs_path = build_squashfs(livemode_config, userspace_info, paths_to_exclude=paths_to_exclude)
api.produce(LiveModeArtifacts(squashfs_path=squashfs_path))
diff --git a/repos/system_upgrade/common/actors/livemode/liveimagegenerator/tests/test_image_generation.py b/repos/system_upgrade/common/actors/livemode/liveimagegenerator/tests/test_image_generation.py
index 5c434a6b..16ae0a09 100644
--- a/repos/system_upgrade/common/actors/livemode/liveimagegenerator/tests/test_image_generation.py
+++ b/repos/system_upgrade/common/actors/livemode/liveimagegenerator/tests/test_image_generation.py
@@ -78,10 +78,12 @@ def test_generate_live_image_if_enabled(monkeypatch, livemode_config, should_pro
def __exit__(self, *args, **kwargs):
pass
+ def build_squashfs_image_mock(livemode_config, userspace_info, *args, **kwargs):
+ return '/squashfs'
+
monkeypatch.setattr(mounting, 'NspawnActions', NspawnMock)
monkeypatch.setattr(live_image_generator_lib, 'lighten_target_userpace', lambda context: None)
- monkeypatch.setattr(live_image_generator_lib, 'build_squashfs',
- lambda livemode_config, userspace_info: '/squashfs')
+ monkeypatch.setattr(live_image_generator_lib, 'build_squashfs', build_squashfs_image_mock)
monkeypatch.setattr(api, 'produce', produce_mocked())
live_image_generator_lib.generate_live_image_if_enabled()
--
2.49.0

View File

@ -1,658 +0,0 @@
From 47fce173e75408d9a7a26225d389161caf72e244 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Sun, 31 Aug 2025 23:49:57 +0200
Subject: [PATCH 04/55] feat(mount_unit_gen): generate mount units for the
upgrade initramfs
Run systemd-fstab-generator to produce mount units that correspond to
the content of source system's fstab. The generated mount units are then
modified to mount /target into /sysroot/target, to reflect that the root
of the source system is mounted as /sysroot. These mount units are made
dependencies of local-fs.target, and, therefore, will be triggered by
systemd before the upgrade.
Assisted-by: Cursor (Claude Sonnet 4)
Jira-ref: RHEL-35446
@pstodulk:
Updated the code to cover also other systemd targets that can be
covered by systemd-fstab-generator. Also cover the situation when
a directory with systemd target (requires, wants) already exists.
Tests have been updated.
Note that there are still possible issues hidden in the generate
mount unit files as we update at this moment just the `Where` clause
however we are not touching anything else. (Before, After,
RequiresMountsFor, ...). But keeping that for future development and
testing. The call for `mount -a` is still present, we expect followup
PRs at this point.
Co-authored-by: Petr Stodulka <pstodulk@redhat.com>
---
.../initramfs/mount_units_generator/actor.py | 22 ++
.../libraries/mount_unit_generator.py | 307 ++++++++++++++++++
.../tests/test_mount_unit_generation.py | 269 +++++++++++++++
3 files changed, 598 insertions(+)
create mode 100644 repos/system_upgrade/common/actors/initramfs/mount_units_generator/actor.py
create mode 100644 repos/system_upgrade/common/actors/initramfs/mount_units_generator/libraries/mount_unit_generator.py
create mode 100644 repos/system_upgrade/common/actors/initramfs/mount_units_generator/tests/test_mount_unit_generation.py
diff --git a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/actor.py b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/actor.py
new file mode 100644
index 00000000..5fe25515
--- /dev/null
+++ b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/actor.py
@@ -0,0 +1,22 @@
+from leapp.actors import Actor
+from leapp.libraries.actor import mount_unit_generator as mount_unit_generator_lib
+from leapp.models import TargetUserSpaceInfo, UpgradeInitramfsTasks
+from leapp.tags import InterimPreparationPhaseTag, IPUWorkflowTag
+
+
+class MountUnitGenerator(Actor):
+ """
+ Sets up storage initialization using systemd's mount units in the upgrade container.
+ """
+
+ name = 'mount_unit_generator'
+ consumes = (
+ TargetUserSpaceInfo,
+ )
+ produces = (
+ UpgradeInitramfsTasks,
+ )
+ tags = (IPUWorkflowTag, InterimPreparationPhaseTag)
+
+ def process(self):
+ mount_unit_generator_lib.setup_storage_initialization()
diff --git a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/libraries/mount_unit_generator.py b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/libraries/mount_unit_generator.py
new file mode 100644
index 00000000..e1060559
--- /dev/null
+++ b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/libraries/mount_unit_generator.py
@@ -0,0 +1,307 @@
+import os
+import shutil
+import tempfile
+
+from leapp.exceptions import StopActorExecutionError
+from leapp.libraries.common import mounting
+from leapp.libraries.stdlib import api, CalledProcessError, run
+from leapp.models import TargetUserSpaceInfo, UpgradeInitramfsTasks
+
+
+def run_systemd_fstab_generator(output_directory):
+ api.current_logger().debug(
+ 'Generating mount units for the source system into {}'.format(output_directory)
+ )
+
+ try:
+ generator_cmd = [
+ '/usr/lib/systemd/system-generators/systemd-fstab-generator',
+ output_directory,
+ output_directory,
+ output_directory
+ ]
+ run(generator_cmd)
+ except CalledProcessError as error:
+ api.current_logger().error(
+ 'Failed to generate mount units using systemd-fstab-generator. Error: {}'.format(error)
+ )
+ details = {'details': str(error)}
+ raise StopActorExecutionError(
+ 'Failed to generate mount units using systemd-fstab-generator',
+ details
+ )
+
+ api.current_logger().debug(
+ 'Mount units successfully generated into {}'.format(output_directory)
+ )
+
+
+def _read_unit_file_lines(unit_file_path): # Encapsulate IO for tests
+ with open(unit_file_path) as unit_file:
+ return unit_file.readlines()
+
+
+def _write_unit_file_lines(unit_file_path, lines): # Encapsulate IO for tests
+ with open(unit_file_path, 'w') as unit_file:
+ unit_file.write('\n'.join(lines) + '\n')
+
+
+def _delete_file(file_path):
+ os.unlink(file_path)
+
+
+def _prefix_mount_unit_with_sysroot(mount_unit_path, new_unit_destination):
+ """
+ Prefix the mount target with /sysroot as expected in the upgrade initramfs.
+
+ A new mount unit file is written to new_unit_destination.
+ """
+ # NOTE(pstodulk): Note that right now we update just the 'Where' key, however
+ # what about RequiresMountsFor, .. there could be some hidden dragons.
+ # In case of issues, investigate these values in generated unit files.
+ api.current_logger().debug(
+ 'Prefixing {}\'s mount target with /sysroot. Output will be written to {}'.format(
+ mount_unit_path,
+ new_unit_destination
+ )
+ )
+ unit_lines = _read_unit_file_lines(mount_unit_path)
+
+ output_lines = []
+ for line in unit_lines:
+ line = line.strip()
+ if not line.startswith('Where='):
+ output_lines.append(line)
+ continue
+
+ _, destination = line.split('=', 1)
+ new_destination = os.path.join('/sysroot', destination.lstrip('/'))
+
+ output_lines.append('Where={}'.format(new_destination))
+
+ _write_unit_file_lines(new_unit_destination, output_lines)
+
+ api.current_logger().debug(
+ 'Done. Modified mount unit successfully written to {}'.format(new_unit_destination)
+ )
+
+
+def prefix_all_mount_units_with_sysroot(dir_containing_units):
+ for unit_file_path in os.listdir(dir_containing_units):
+ # systemd requires mount path to be in the unit name
+ modified_unit_destination = 'sysroot-{}'.format(unit_file_path)
+ modified_unit_destination = os.path.join(dir_containing_units, modified_unit_destination)
+
+ unit_file_path = os.path.join(dir_containing_units, unit_file_path)
+
+ if not unit_file_path.endswith('.mount'):
+ api.current_logger().debug(
+ 'Skipping {} when prefixing mount units with /sysroot - not a mount unit.'.format(
+ unit_file_path
+ )
+ )
+ continue
+
+ _prefix_mount_unit_with_sysroot(unit_file_path, modified_unit_destination)
+
+ _delete_file(unit_file_path)
+ api.current_logger().debug('Original mount unit {} removed.'.format(unit_file_path))
+
+
+def _fix_symlinks_in_dir(dir_containing_mount_units, target_dir):
+ """
+ Fix broken symlinks in given target_dir due to us modifying (renaming) the mount units.
+
+ The target_dir contains symlinks to the (mount) units that are required
+ in order for the local-fs.target to be reached. However, we renamed these units to reflect
+ that we have changed their mount destinations by prefixing the mount destination with /sysroot.
+ Hence, we regenerate the symlinks.
+ """
+
+ target_dir_path = os.path.join(dir_containing_mount_units, target_dir)
+ if not os.path.exists(target_dir_path):
+ api.current_logger().debug(
+ 'The {} directory does not exist. Skipping'
+ .format(target_dir)
+ )
+ return
+
+ api.current_logger().debug(
+ 'Removing the old {} directory from {}.'
+ .format(target_dir, dir_containing_mount_units)
+ )
+
+ shutil.rmtree(target_dir_path)
+ os.mkdir(target_dir_path)
+
+ api.current_logger().debug('Populating {} with new symlinks.'.format(target_dir))
+
+ for unit_file in os.listdir(dir_containing_mount_units):
+ if not unit_file.endswith('.mount'):
+ continue
+
+ place_fastlink_at = os.path.join(target_dir_path, unit_file)
+ fastlink_points_to = os.path.join('../', unit_file)
+ try:
+ run(['ln', '-s', fastlink_points_to, place_fastlink_at])
+
+ api.current_logger().debug(
+ 'Dependency on {} created.'.format(unit_file)
+ )
+ except CalledProcessError as err:
+ err_descr = (
+ 'Failed to create required unit dependencies under {} for the upgrade initramfs.'
+ .format(target_dir)
+ )
+ details = {'details': str(err)}
+ raise StopActorExecutionError(err_descr, details=details)
+
+
+def fix_symlinks_in_targets(dir_containing_mount_units):
+ """
+ Fix broken symlinks in *.target.* directories caused by earlier modified mount units.
+
+ Generated mount unit files are part of one of systemd targets (list below),
+ which means that a symlink from a systemd target to exists for each of
+ them. Based on this, systemd knows when (local or remote file systems?)
+ they must (".requires" suffix") or could (".wants" suffix) be mounted.
+ See the man 5 systemd.mount for more details how mount units are split into
+ these targets.
+
+ The list of possible target directories where these mount units could end:
+ * local-fs.target.requires
+ * local-fs.target.wants
+ * local-fs-pre.target.requires
+ * local-fs-pre.target.wants
+ * remote-fs.target.requires
+ * remote-fs.target.wants
+ * remote-fs-pre.target.requires
+ * remote-fs-pre.target.wants
+ Most likely, unit files are not generated for "*pre*" targets, but to be
+ sure really. Longer list does not cause any issues in this code.
+
+ In most cases, "local-fs.target.requires" is the only important directory
+ for us during the upgrade. But in some (sometimes common) cases we will
+ need some of the others as well.
+
+ These directories do not have to necessarily exists if there are no mount
+ unit files that could be put there. But most likely "local-fs.target.requires"
+ will always exists.
+ """
+ dir_list = [
+ 'local-fs.target.requires',
+ 'local-fs.target.wants',
+ 'local-fs-pre.target.requires',
+ 'local-fs-pre.target.wants',
+ 'remote-fs.target.requires',
+ 'remote-fs.target.wants',
+ 'remote-fs-pre.target.requires',
+ 'remote-fs-pre.target.wants',
+ ]
+ for tdir in dir_list:
+ _fix_symlinks_in_dir(dir_containing_mount_units, tdir)
+
+
+def copy_units_into_system_location(upgrade_container_ctx, dir_with_our_mount_units):
+ """
+ Copy units and their .wants/.requires directories into the target userspace container.
+
+ :return: A list of files in the target userspace that were created by copying.
+ :rtype: list[str]
+ """
+ dest_inside_container = '/usr/lib/systemd/system'
+
+ api.current_logger().debug(
+ 'Copying generated mount units for upgrade from {} to {}'.format(
+ dir_with_our_mount_units,
+ upgrade_container_ctx.full_path(dest_inside_container)
+ )
+ )
+
+ copied_files = []
+ prefix_len_to_drop = len(upgrade_container_ctx.base_dir)
+
+ # We cannot rely on mounting library when copying into container
+ # as we want to control what happens to symlinks and
+ # shutil.copytree in Python3.6 fails if dst directory exists already
+ # - which happens in some cases when copying these files.
+ for root, dummy_dirs, files in os.walk(dir_with_our_mount_units):
+ rel_path = os.path.relpath(root, dir_with_our_mount_units)
+ if rel_path == '.':
+ rel_path = ''
+ dst_dir = os.path.join(upgrade_container_ctx.full_path(dest_inside_container), rel_path)
+ os.makedirs(dst_dir, mode=0o755, exist_ok=True)
+
+ for file in files:
+ src_file = os.path.join(root, file)
+ dst_file = os.path.join(dst_dir, file)
+ api.current_logger().debug(
+ 'Copying mount unit file {} to {}'.format(src_file, dst_file)
+ )
+ if os.path.islink(dst_file):
+ # If the target file already exists and it is a symlink, it will
+ # fail and we want to overwrite this.
+ # NOTE(pstodulk): You could think that it cannot happen, but
+ # in future possibly it could happen, so let's rather be careful
+ # and handle it. If the dst file exists, we want to overwrite it
+ # for sure
+ _delete_file(dst_file)
+ shutil.copy2(src_file, dst_file, follow_symlinks=False)
+ copied_files.append(dst_file[prefix_len_to_drop:])
+
+ return copied_files
+
+
+def remove_units_for_targets_that_are_already_mounted_by_dracut(dir_with_our_mount_units):
+ """
+ Remove mount units for mount targets that are already mounted by dracut.
+
+ Namely, remove mount units:
+ '-.mount' (mounts /)
+ 'usr.mount' (mounts /usr)
+ """
+
+ # NOTE: remount-fs.service creates dependency cycles that are nondeterministically broken
+ # by systemd, causing unpredictable failures. The service is supposed to remount root
+ # and /usr, reapplying mount options from /etc/fstab. However, the fstab file present in
+ # the initramfs is not the fstab from the source system, and, therefore, it is pointless
+ # to require the service. It would make sense after we switched root during normal boot
+ # process.
+ already_mounted_units = [
+ '-.mount',
+ 'usr.mount',
+ 'local-fs.target.wants/systemd-remount-fs.service'
+ ]
+
+ for unit in already_mounted_units:
+ unit_location = os.path.join(dir_with_our_mount_units, unit)
+
+ if not os.path.exists(unit_location):
+ api.current_logger().debug('The {} unit does not exists, no need to remove it.'.format(unit))
+ continue
+
+ _delete_file(unit_location)
+
+
+def request_units_inclusion_in_initramfs(files_to_include):
+ api.current_logger().debug('Including the following files into initramfs: {}'.format(files_to_include))
+
+ additional_files = [
+ '/usr/sbin/swapon' # If the system has swap, we have also generated a swap unit to activate it
+ ]
+
+ tasks = UpgradeInitramfsTasks(include_files=files_to_include + additional_files)
+ api.produce(tasks)
+
+
+def setup_storage_initialization():
+ userspace_info = next(api.consume(TargetUserSpaceInfo), None)
+
+ with mounting.NspawnActions(base_dir=userspace_info.path) as upgrade_container_ctx:
+ with tempfile.TemporaryDirectory(dir='/var/lib/leapp/', prefix='tmp_systemd_fstab_') as workspace_path:
+ run_systemd_fstab_generator(workspace_path)
+ remove_units_for_targets_that_are_already_mounted_by_dracut(workspace_path)
+ prefix_all_mount_units_with_sysroot(workspace_path)
+ fix_symlinks_in_targets(workspace_path)
+ mount_unit_files = copy_units_into_system_location(upgrade_container_ctx, workspace_path)
+ request_units_inclusion_in_initramfs(mount_unit_files)
diff --git a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/tests/test_mount_unit_generation.py b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/tests/test_mount_unit_generation.py
new file mode 100644
index 00000000..b814f6ce
--- /dev/null
+++ b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/tests/test_mount_unit_generation.py
@@ -0,0 +1,269 @@
+import os
+import shutil
+
+import pytest
+
+from leapp.exceptions import StopActorExecutionError
+from leapp.libraries.actor import mount_unit_generator
+from leapp.libraries.common.testutils import logger_mocked
+from leapp.libraries.stdlib import api, CalledProcessError
+from leapp.models import TargetUserSpaceInfo, UpgradeInitramfsTasks
+
+
+def test_run_systemd_fstab_generator_successful_generation(monkeypatch):
+ """Test successful mount unit generation."""
+
+ output_dir = '/tmp/test_output'
+ expected_cmd = [
+ '/usr/lib/systemd/system-generators/systemd-fstab-generator',
+ output_dir,
+ output_dir,
+ output_dir
+ ]
+
+ def mock_run(command):
+ assert command == expected_cmd
+
+ return {
+ "stdout": "",
+ "stderr": "",
+ "exit_code": 0,
+ }
+
+ monkeypatch.setattr(mount_unit_generator, 'run', mock_run)
+ mount_unit_generator.run_systemd_fstab_generator(output_dir)
+
+
+def test_run_systemd_fstab_generator_failure(monkeypatch):
+ """Test handling of systemd-fstab-generator failure."""
+ output_dir = '/tmp/test_output'
+ expected_cmd = [
+ '/usr/lib/systemd/system-generators/systemd-fstab-generator',
+ output_dir,
+ output_dir,
+ output_dir
+ ]
+
+ def mock_run(command):
+ assert command == expected_cmd
+ raise CalledProcessError(message='Generator failed', command=['test'], result={'exit_code': 1})
+
+ monkeypatch.setattr(mount_unit_generator, 'run', mock_run)
+ monkeypatch.setattr(api, 'current_logger', logger_mocked())
+
+ with pytest.raises(StopActorExecutionError):
+ mount_unit_generator.run_systemd_fstab_generator(output_dir)
+
+
+def test_prefix_mount_unit_with_sysroot(monkeypatch):
+ """Test prefixing a single mount unit with /sysroot."""
+ monkeypatch.setattr(api, 'current_logger', logger_mocked())
+
+ input_content = [
+ "[Unit]\n",
+ "Description=Test Mount\n",
+ "[Mount]\n",
+ "Where=/home\n",
+ "What=/dev/sda1\n"
+ ]
+
+ expected_output_lines = [
+ "[Unit]",
+ "Description=Test Mount",
+ "[Mount]",
+ "Where=/sysroot/home",
+ "What=/dev/sda1"
+ ]
+
+ def mock_read_unit_file_lines(unit_file_path):
+ return input_content
+
+ def mock_write_unit_file_lines(unit_file_path, lines):
+ assert unit_file_path == '/test/output.mount'
+ assert lines == expected_output_lines
+
+ monkeypatch.setattr(mount_unit_generator, '_read_unit_file_lines', mock_read_unit_file_lines)
+ monkeypatch.setattr(mount_unit_generator, '_write_unit_file_lines', mock_write_unit_file_lines)
+
+ mount_unit_generator._prefix_mount_unit_with_sysroot(
+ '/test/input.mount',
+ '/test/output.mount'
+ )
+
+
+def test_prefix_all_mount_units_with_sysroot(monkeypatch):
+ """Test prefixing all mount units in a directory."""
+
+ expected_changes = {
+ '/test/dir/home.mount': {
+ 'new_unit_destination': '/test/dir/sysroot-home.mount',
+ 'should_be_deleted': True,
+ 'deleted': False,
+ },
+ '/test/dir/var.mount': {
+ 'new_unit_destination': '/test/dir/sysroot-var.mount',
+ 'should_be_deleted': True,
+ 'deleted': False,
+ },
+ '/test/dir/not-a-mount.service': {
+ 'new_unit_destination': None,
+ 'should_be_deleted': False,
+ 'deleted': False,
+ }
+ }
+
+ def mock_listdir(dir_path):
+ return ['home.mount', 'var.mount', 'not-a-mount.service']
+
+ def mock_delete_file(file_path):
+ assert file_path in expected_changes
+ expected_changes[file_path]['deleted'] = True
+
+ def mock_prefix(unit_file_path, new_unit_destination):
+ assert expected_changes[unit_file_path]['new_unit_destination'] == new_unit_destination
+
+ monkeypatch.setattr('os.listdir', mock_listdir)
+ monkeypatch.setattr(mount_unit_generator, '_delete_file', mock_delete_file)
+ monkeypatch.setattr(mount_unit_generator, '_prefix_mount_unit_with_sysroot', mock_prefix)
+
+ mount_unit_generator.prefix_all_mount_units_with_sysroot('/test/dir')
+
+ for original_mount_unit_location in expected_changes:
+ should_be_deleted = expected_changes[original_mount_unit_location]['should_be_deleted']
+ was_deleted = expected_changes[original_mount_unit_location]['deleted']
+ assert should_be_deleted == was_deleted
+
+
+@pytest.mark.parametrize('dirname', (
+ 'local-fs.target.requires',
+ 'local-fs.target.wants',
+ 'local-fs-pre.target.requires',
+ 'local-fs-pre.target.wants',
+ 'remote-fs.target.requires',
+ 'remote-fs.target.wants',
+ 'remote-fs-pre.target.requires',
+ 'remote-fs-pre.target.wants',
+))
+def test_fix_symlinks_in_dir(monkeypatch, dirname):
+ """Test fixing local-fs.target.requires symlinks."""
+
+ DIR_PATH = os.path.join('/test/dir/', dirname)
+
+ def mock_rmtree(dir_path):
+ assert dir_path == DIR_PATH
+
+ def mock_mkdir(dir_path):
+ assert dir_path == DIR_PATH
+
+ def mock_listdir(dir_path):
+ return ['sysroot-home.mount', 'sysroot-var.mount', 'not-a-mount.service']
+
+ def mock_os_path_exist(dir_path):
+ assert dir_path == DIR_PATH
+ return dir_path == DIR_PATH
+
+ expected_calls = [
+ ['ln', '-s', '../sysroot-home.mount', os.path.join(DIR_PATH, 'sysroot-home.mount')],
+ ['ln', '-s', '../sysroot-var.mount', os.path.join(DIR_PATH, 'sysroot-var.mount')]
+ ]
+ call_count = 0
+
+ def mock_run(command):
+ nonlocal call_count
+ assert command in expected_calls
+ call_count += 1
+ return {
+ "stdout": "",
+ "stderr": "",
+ "exit_code": 0,
+ }
+
+ monkeypatch.setattr('shutil.rmtree', mock_rmtree)
+ monkeypatch.setattr('os.mkdir', mock_mkdir)
+ monkeypatch.setattr('os.listdir', mock_listdir)
+ monkeypatch.setattr('os.path.exists', mock_os_path_exist)
+ monkeypatch.setattr(mount_unit_generator, 'run', mock_run)
+
+ mount_unit_generator._fix_symlinks_in_dir('/test/dir', dirname)
+
+
+# Test the copy_units_into_system_location function
+def test_copy_units_mixed_content(monkeypatch):
+ """Test copying units with mixed files and directories."""
+
+ def mock_walk(dir_path):
+ tuples_to_yield = [
+ ('/source/dir', ['local-fs.target.requires'], ['unit1.mount', 'unit2.mount']),
+ ('/source/dir/local-fs.target.requires', [], ['unit1.mount', 'unit2.mount']),
+ ]
+ for i in tuples_to_yield:
+ yield i
+
+ def mock_isdir(path):
+ return 'local-fs.target.requires' in path
+
+ def _make_couple(sub_path):
+ return (
+ os.path.join('/source/dir/', sub_path),
+ os.path.join('/container/usr/lib/systemd/system/', sub_path)
+ )
+
+ def mock_copy2(src, dst, follow_symlinks=True):
+ valid_combinations = [
+ _make_couple('unit1.mount'),
+ _make_couple('unit2.mount'),
+ _make_couple('local-fs.target.requires/unit1.mount'),
+ _make_couple('local-fs.target.requires/unit2.mount'),
+ ]
+ assert not follow_symlinks
+ assert (src, dst) in valid_combinations
+
+ def mock_islink(file_path):
+ return file_path == '/container/usr/lib/systemd/system/local-fs.target.requires/unit2.mount'
+
+ class MockedDeleteFile:
+ def __init__(self):
+ self.removal_called = False
+
+ def __call__(self, file_path):
+ assert file_path == '/container/usr/lib/systemd/system/local-fs.target.requires/unit2.mount'
+ self.removal_called = True
+
+ def mock_makedirs(dst_dir, mode=0o777, exist_ok=False):
+ assert exist_ok
+ assert mode == 0o755
+
+ allowed_paths = [
+ '/container/usr/lib/systemd/system',
+ '/container/usr/lib/systemd/system/local-fs.target.requires'
+ ]
+ assert dst_dir.rstrip('/') in allowed_paths
+
+ monkeypatch.setattr(os, 'walk', mock_walk)
+ monkeypatch.setattr(os, 'makedirs', mock_makedirs)
+ monkeypatch.setattr(os.path, 'isdir', mock_isdir)
+ monkeypatch.setattr(os.path, 'islink', mock_islink)
+ monkeypatch.setattr(mount_unit_generator, '_delete_file', MockedDeleteFile())
+ monkeypatch.setattr(shutil, 'copy2', mock_copy2)
+
+ class MockedContainerContext:
+ def __init__(self):
+ self.base_dir = '/container'
+
+ def full_path(self, path):
+ return os.path.join('/container', path.lstrip('/'))
+
+ mock_container = MockedContainerContext()
+
+ files = mount_unit_generator.copy_units_into_system_location(
+ mock_container, '/source/dir'
+ )
+
+ expected_files = [
+ '/usr/lib/systemd/system/unit1.mount',
+ '/usr/lib/systemd/system/unit2.mount',
+ '/usr/lib/systemd/system/local-fs.target.requires/unit1.mount',
+ '/usr/lib/systemd/system/local-fs.target.requires/unit2.mount',
+ ]
+ assert sorted(files) == sorted(expected_files)
+ assert mount_unit_generator._delete_file.removal_called
--
2.51.1

View File

@ -1,101 +0,0 @@
From e26359877b1d90d1f95a424216a00e711c72c923 Mon Sep 17 00:00:00 2001
From: karolinku <kkula@redhat.com>
Date: Tue, 9 Sep 2025 13:56:37 +0200
Subject: [PATCH 05/55] Prevent sssdupdate actor from rising errors
Potential error rise (StopActorExecutionError) is replaced with
warning logs in the SSSD update file processing function. This
prevents the upgrade from failing when accessing non-critical files.
Also fix minor formatting nit picks.
Jira: RHEL-108992
---
.../sssd/sssdchecks/libraries/sssdchecks.py | 4 ++--
.../sssd/sssdfacts/libraries/sssdfacts.py | 5 ++++-
.../sssd/sssdupdate/libraries/sssdupdate.py | 18 +++++++-----------
3 files changed, 13 insertions(+), 14 deletions(-)
diff --git a/repos/system_upgrade/el9toel10/actors/sssd/sssdchecks/libraries/sssdchecks.py b/repos/system_upgrade/el9toel10/actors/sssd/sssdchecks/libraries/sssdchecks.py
index 0a86fa7b..cb95026c 100644
--- a/repos/system_upgrade/el9toel10/actors/sssd/sssdchecks/libraries/sssdchecks.py
+++ b/repos/system_upgrade/el9toel10/actors/sssd/sssdchecks/libraries/sssdchecks.py
@@ -15,8 +15,8 @@ def check_config(model):
'SSSD\'s sss_ssh_knownhostsproxy tool is replaced by the more '
'reliable sss_ssh_knownhosts tool. SSH\'s configuration will be updated '
'to reflect this by updating every mention of sss_ssh_knownhostsproxy by '
- 'the corresponding mention of sss_ssh_knownhosts, even those commented out.\n'
- 'SSSD\'s ssh service will be enabled if not already done.\n'
+ 'the corresponding mention of sss_ssh_knownhosts, even those commented out. '
+ 'SSSD\'s ssh service will be enabled if not already done.\n\n'
'The following files will be updated:{}{}'.format(
FMT_LIST_SEPARATOR,
FMT_LIST_SEPARATOR.join(model.sssd_config_files + model.ssh_config_files)
diff --git a/repos/system_upgrade/el9toel10/actors/sssd/sssdfacts/libraries/sssdfacts.py b/repos/system_upgrade/el9toel10/actors/sssd/sssdfacts/libraries/sssdfacts.py
index 0ae9d93f..7d343229 100644
--- a/repos/system_upgrade/el9toel10/actors/sssd/sssdfacts/libraries/sssdfacts.py
+++ b/repos/system_upgrade/el9toel10/actors/sssd/sssdfacts/libraries/sssdfacts.py
@@ -19,7 +19,10 @@ def _does_file_contain_expression(file_path, expression):
)
return False
except OSError as e:
- raise StopActorExecutionError('Could not open file ' + file_path, details={'details': str(e)})
+ raise StopActorExecutionError(
+ 'Could not open configuration file',
+ details={'details': 'Coudn\'t open {} file with error: {}.'.format(file_path, str(e))}
+ )
def _look_for_files(expression: str, path_list: list[str]) -> list[str]:
diff --git a/repos/system_upgrade/el9toel10/actors/sssd/sssdupdate/libraries/sssdupdate.py b/repos/system_upgrade/el9toel10/actors/sssd/sssdupdate/libraries/sssdupdate.py
index 6d745ead..5b96bcc6 100644
--- a/repos/system_upgrade/el9toel10/actors/sssd/sssdupdate/libraries/sssdupdate.py
+++ b/repos/system_upgrade/el9toel10/actors/sssd/sssdupdate/libraries/sssdupdate.py
@@ -1,7 +1,7 @@
import os
import re
-from leapp.exceptions import StopActorExecutionError
+from leapp.libraries.stdlib import api
def _process_knownhosts(line: str) -> str:
@@ -29,30 +29,26 @@ def _process_enable_svc(line: str) -> str:
def _update_file(filename, process_function):
- newname = filename + '.new'
- oldname = filename + '.old'
+ newname = '{}.leappnew'.format(filename)
+ oldname = '{}.leappsave'.format(filename)
try:
- with open(filename, 'r') as input_file, open(newname, 'x') as output_file:
+ with open(filename, 'r') as input_file, open(newname, 'w') as output_file:
istat = os.fstat(input_file.fileno())
os.fchmod(output_file.fileno(), istat.st_mode)
for line in input_file:
try:
output_file.write(process_function(line))
except OSError as e:
- raise StopActorExecutionError('Failed to write to {}'.format(newname),
- details={'details': str(e)})
+ api.current_logger().warning('Failed to write to {}'.format(newname), details={'details': str(e)})
- except FileExistsError as e:
- raise StopActorExecutionError('Temporary file already exists: {}'.format(newname),
- details={'details': str(e)})
except OSError as e:
try:
os.unlink(newname)
except FileNotFoundError:
pass
- raise StopActorExecutionError('Failed to access the required files', details={'details': str(e)})
+ api.current_logger().error('Failed to access the required files', details={'details': str(e)})
- # Let's make sure the old configuration is preserverd if something goes wrong
+ # Let's make sure the old configuration is preserved if something goes wrong
os.replace(filename, oldname)
os.replace(newname, filename)
os.unlink(oldname)
--
2.51.1

View File

@ -0,0 +1,156 @@
From 36d245e59bab8f392c163c01a77f0ea9b210d0a2 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Fri, 28 Feb 2025 11:02:32 +0100
Subject: [PATCH 05/37] livemode(cfg): add declaration of livemode config
fields
Add definitions of all config classes that describe configuration of the
livemode feature using the configurability provided by the leapp
framework. The list of configuration options remains unchanged (except
for the `is_enabled` field that is removed) when compared to the
current implementation that relies on an ad-hoc INI file. The next step
is to drop the INI-based implementation in favour of using
framework-based configs relying on the field definitions from this PR.
Jira-ref: RHELMISC-10648
---
.../configs/livemode.py | 127 ++++++++++++++++++
1 file changed, 127 insertions(+)
create mode 100644 repos/system_upgrade/common/actors/livemode/livemode_config_scanner/configs/livemode.py
diff --git a/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/configs/livemode.py b/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/configs/livemode.py
new file mode 100644
index 00000000..eeef03f8
--- /dev/null
+++ b/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/configs/livemode.py
@@ -0,0 +1,127 @@
+"""
+Configuration keys for the 'livemode' feature.
+"""
+
+from leapp.actors.config import Config
+from leapp.models import fields
+
+LIVEMODE_CONFIG_SECTION = 'livemode'
+
+
+class SquashfsImagePath(Config):
+ section = LIVEMODE_CONFIG_SECTION
+ name = "squashfs_image_path"
+ type_ = fields.String()
+ default = '/var/lib/leapp/live-upgrade.img'
+ description = """
+ Location where the squashfs image of the minimal target system will be placed.
+ """
+
+
+class AdditionalPackages(Config):
+ section = LIVEMODE_CONFIG_SECTION
+ name = "additional_packages"
+ type_ = fields.List(fields.String())
+ default = []
+ description = """
+ Additional packages to be installed into the squashfs image.
+
+ Can be used to install various debugging utilities when connecting to the upgrade environment.
+ """
+
+
+class AutostartUpgradeAfterReboot(Config):
+ section = LIVEMODE_CONFIG_SECTION
+ name = "autostart_upgrade_after_reboot"
+ type_ = fields.Boolean()
+ default = True
+ description = """
+ If set to True, the upgrade will start automatically after the reboot. Otherwise a manual trigger is required.
+ """
+
+
+class SetupNetworkManager(Config):
+ section = LIVEMODE_CONFIG_SECTION
+ name = "setup_network_manager"
+ type_ = fields.Boolean()
+ default = False
+ description = """
+ Try enabling Network Manager in the squashfs image.
+
+ If set to True, leapp will copy source system's Network Manager profiles into the squashfs image and
+ enable the Network Manager service.
+ """
+
+
+class DracutNetwork(Config):
+ section = LIVEMODE_CONFIG_SECTION
+ name = "dracut_network"
+ type_ = fields.String()
+ default = ''
+ description = """
+ Dracut network arguments, required if the `url_to_load_squashfs_from` option is set.
+
+ Example:
+ ip=192.168.122.146::192.168.122.1:255.255.255.0:foo::none
+ """
+
+
+class URLToLoadSquashfsImageFrom(Config):
+ section = LIVEMODE_CONFIG_SECTION
+ name = "url_to_load_squashfs_image_from"
+ type_ = fields.String()
+ default = ''
+ description = """
+ Url pointing to the squashfs image that should be used for the upgrade environment.
+
+ Example:
+ http://192.168.122.1/live-upgrade.img
+ """
+
+
+class SetupPasswordlessRoot(Config):
+ section = LIVEMODE_CONFIG_SECTION
+ name = "setup_passwordless_root"
+ type_ = fields.Boolean()
+ default = False
+ description = """
+ If set to True, the root account of the squashfs image will have empty password. Use with caution.
+ """
+
+
+class SetupOpenSSHDUsingAuthKeys(Config):
+ section = LIVEMODE_CONFIG_SECTION
+ name = "setup_opensshd_using_auth_keys"
+ type_ = fields.String()
+ default = ''
+ description = """
+ If set to a non-empty string, openssh daemon will be setup within the squashfs image using the provided
+ authorized keys.
+
+ Example:
+ /root/.ssh/authorized_keys
+ """
+
+
+class CaptureSTraceInfoInto(Config):
+ section = LIVEMODE_CONFIG_SECTION
+ name = "capture_strace_info_into"
+ type_ = fields.String()
+ default = ''
+ description = """
+ If set to a non-empty string, leapp will be executed under strace and results will be stored within
+ the provided file path.
+ """
+
+
+livemode_cfg_fields = (
+ AdditionalPackages,
+ AutostartUpgradeAfterReboot,
+ CaptureSTraceInfoInto,
+ DracutNetwork,
+ SetupNetworkManager,
+ SetupOpenSSHDUsingAuthKeys,
+ SetupPasswordlessRoot,
+ SquashfsImagePath,
+ URLToLoadSquashfsImageFrom,
+)
--
2.49.0

View File

@ -1,132 +0,0 @@
From 23d8f69509e692ceaa3dacc0de927349ec056189 Mon Sep 17 00:00:00 2001
From: Tomas Fratrik <tfratrik@redhat.com>
Date: Tue, 19 Aug 2025 09:19:18 +0200
Subject: [PATCH 06/55] Update our test container to Fedora 42
The distro.linux_distribution in createresumeservice test is replaced
distro.id(). The distro.linux_distribution has been deprecated and on
Fedora 42 containerized tests with python3.13 it doesn't work correctly
and the createresumeservice tests don't get skipped.
Jira: RHELMISC-13271
---
Makefile | 19 +++++++++----------
.../tests/test_createresumeservice.py | 2 +-
.../{Containerfile.f34 => Containerfile.f42} | 4 ++--
3 files changed, 12 insertions(+), 13 deletions(-)
rename utils/container-tests/{Containerfile.f34 => Containerfile.f42} (84%)
diff --git a/Makefile b/Makefile
index 81b16376..e0fc7e00 100644
--- a/Makefile
+++ b/Makefile
@@ -165,7 +165,7 @@ help:
@echo " MR=6 COPR_CONFIG='path/to/the/config/copr/file' make <target>"
@echo " ACTOR=<actor> TEST_LIBS=y make test"
@echo " BUILD_CONTAINER=rhel8 make build_container"
- @echo " TEST_CONTAINER=f34 make test_container"
+ @echo " TEST_CONTAINER=f42 make test_container"
@echo " CONTAINER_TOOL=docker TEST_CONTAINER=rhel8 make test_container_no_lint"
@echo ""
@@ -379,7 +379,6 @@ test_no_lint:
done; \
$(_PYTHON_VENV) -m pytest $(REPORT_ARG) $(TEST_PATHS) $(LIBRARY_PATH) $(PYTEST_ARGS)
-
test: lint test_no_lint
# container images act like a cache so that dependencies can only be downloaded once
@@ -416,7 +415,7 @@ lint_container:
@_TEST_CONT_TARGET="lint" $(MAKE) test_container
lint_container_all:
- @for container in "f34" "rhel8" "rhel9"; do \
+ @for container in "f42" "rhel8" "rhel9"; do \
TEST_CONTAINER=$$container $(MAKE) lint_container || exit 1; \
done
@@ -426,9 +425,9 @@ lint_container_all:
# because e.g RHEL8 to RHEL9 IPU must work on python3.6 and python3.9.
test_container:
@case $(_TEST_CONTAINER) in \
- f34) \
- export CONT_FILE="utils/container-tests/Containerfile.f34"; \
- export _VENV="python3.9"; \
+ f42) \
+ export CONT_FILE="utils/container-tests/Containerfile.f42"; \
+ export _VENV="python3.13"; \
;; \
rhel8) \
export CONT_FILE="utils/container-tests/Containerfile.rhel8"; \
@@ -439,7 +438,7 @@ test_container:
export _VENV="python3.9"; \
;; \
*) \
- echo "Error: Available containers are: f34, rhel8, rhel9"; exit 1; \
+ echo "Error: Available containers are: f42, rhel8, rhel9"; exit 1; \
;; \
esac; \
export TEST_IMAGE="leapp-repo-tests-$(_TEST_CONTAINER)"; \
@@ -471,7 +470,7 @@ test_container:
exit $$res
test_container_all:
- @for container in "f34" "rhel8" "rhel9"; do \
+ @for container in "f42" "rhel8" "rhel9"; do \
TEST_CONTAINER=$$container $(MAKE) test_container || exit 1; \
done
@@ -479,13 +478,13 @@ test_container_no_lint:
@_TEST_CONT_TARGET="test_no_lint" $(MAKE) test_container
test_container_all_no_lint:
- @for container in "f34" "rhel8" "rhel9"; do \
+ @for container in "f42" "rhel8" "rhel9"; do \
TEST_CONTAINER=$$container $(MAKE) test_container_no_lint || exit 1; \
done
# clean all testing and building containers and their images
clean_containers:
- @for i in "leapp-repo-tests-f34" "leapp-repo-tests-rhel8" \
+ @for i in "leapp-repo-tests-f42" "leapp-repo-tests-rhel8" \
"leapp-repo-tests-rhel9" "leapp-repo-build-el8"; do \
$(_CONTAINER_TOOL) kill "$$i-cont" || :; \
$(_CONTAINER_TOOL) rm "$$i-cont" || :; \
diff --git a/repos/system_upgrade/common/actors/createresumeservice/tests/test_createresumeservice.py b/repos/system_upgrade/common/actors/createresumeservice/tests/test_createresumeservice.py
index 5302cdd2..c1cefc37 100644
--- a/repos/system_upgrade/common/actors/createresumeservice/tests/test_createresumeservice.py
+++ b/repos/system_upgrade/common/actors/createresumeservice/tests/test_createresumeservice.py
@@ -6,7 +6,7 @@ import pytest
@pytest.mark.skipif(os.getuid() != 0, reason='User is not a root')
@pytest.mark.skipif(
- distro.linux_distribution()[0] == 'Fedora',
+ distro.id() == 'fedora',
reason='default.target.wants does not exists on Fedora distro',
)
def test_create_resume_service(current_actor_context):
diff --git a/utils/container-tests/Containerfile.f34 b/utils/container-tests/Containerfile.f42
similarity index 84%
rename from utils/container-tests/Containerfile.f34
rename to utils/container-tests/Containerfile.f42
index a9346635..46f0f63a 100644
--- a/utils/container-tests/Containerfile.f34
+++ b/utils/container-tests/Containerfile.f42
@@ -1,11 +1,11 @@
-FROM fedora:34
+FROM fedora:42
VOLUME /repo
RUN dnf update -y && \
dnf install -y findutils make rsync python3-gobject-base NetworkManager-libnm
-ENV PYTHON_VENV python3.9
+ENV PYTHON_VENV python3.13
COPY . /repocopy
--
2.51.1

View File

@ -0,0 +1,250 @@
From 849a8f2fcd04ee6d419b3856562fbff5b85577f5 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Thu, 6 Mar 2025 11:33:05 +0100
Subject: [PATCH 06/37] livemode(cfg): use framework's configurability instead
of ad-hoc INI
Drop the ad-hoc INI-based config for livemode in favour and replace it
with configuration facilitated by the leapp framework. The list of
configuration options remains (and their semantics) remains almost
unchanged, save for some field names that are renamed in a way that
better reveals their effect to the user.
Jira-ref: RHELMISC-10648
---
commands/upgrade/util.py | 1 -
etc/leapp/files/devel-livemode.ini | 9 --
.../livemode/livemode_config_scanner/actor.py | 2 +
.../libraries/scan_livemode_config.py | 101 +++++-------------
.../tests/test_config_scanner.py | 40 +++----
5 files changed, 44 insertions(+), 109 deletions(-)
delete mode 100644 etc/leapp/files/devel-livemode.ini
diff --git a/commands/upgrade/util.py b/commands/upgrade/util.py
index bfdbc4fa..6cdfa6d8 100644
--- a/commands/upgrade/util.py
+++ b/commands/upgrade/util.py
@@ -16,7 +16,6 @@ from leapp.utils.audit import get_checkpoints, get_connection, get_messages
from leapp.utils.output import report_unsupported
from leapp.utils.report import fetch_upgrade_report_messages, generate_report_file
-
EXPERIMENTAL_FEATURES = {
'livemode': [
'live_image_generator',
diff --git a/etc/leapp/files/devel-livemode.ini b/etc/leapp/files/devel-livemode.ini
deleted file mode 100644
index b79ed4df..00000000
--- a/etc/leapp/files/devel-livemode.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-# Configuration for the *experimental* livemode feature
-# It is likely that this entire configuration file will be replaced by some
-# other mechanism/file in the future. For the full list of configuration options,
-# see models/livemode.py
-[livemode]
-squashfs_fullpath=/var/lib/leapp/live-upgrade.img
-setup_network_manager=no
-autostart_upgrade_after_reboot=yes
-setup_passwordless_root=no
diff --git a/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/actor.py b/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/actor.py
index dc79ecff..bd909736 100644
--- a/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/actor.py
+++ b/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/actor.py
@@ -1,4 +1,5 @@
from leapp.actors import Actor
+from leapp.configs.actor import livemode as livemode_config_lib
from leapp.libraries.actor import scan_livemode_config as scan_livemode_config_lib
from leapp.models import InstalledRPM, LiveModeConfig
from leapp.tags import ExperimentalTag, FactsPhaseTag, IPUWorkflowTag
@@ -10,6 +11,7 @@ class LiveModeConfigScanner(Actor):
"""
name = 'live_mode_config_scanner'
+ config_schemas = livemode_config_lib.livemode_cfg_fields
consumes = (InstalledRPM,)
produces = (LiveModeConfig,)
tags = (ExperimentalTag, FactsPhaseTag, IPUWorkflowTag,)
diff --git a/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/libraries/scan_livemode_config.py b/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/libraries/scan_livemode_config.py
index b2f0af7f..57408c23 100644
--- a/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/libraries/scan_livemode_config.py
+++ b/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/libraries/scan_livemode_config.py
@@ -1,14 +1,9 @@
-try:
- import configparser
-except ImportError:
- import ConfigParser as configparser
-
+from leapp.configs.actor import livemode as livemode_config_lib
from leapp.exceptions import StopActorExecutionError
from leapp.libraries.common.config import architecture, get_env
from leapp.libraries.common.rpms import has_package
from leapp.libraries.stdlib import api
from leapp.models import InstalledRPM, LiveModeConfig
-from leapp.models.fields import ModelViolationError
LIVEMODE_CONFIG_LOCATION = '/etc/leapp/files/devel-livemode.ini'
DEFAULT_SQUASHFS_PATH = '/var/lib/leapp/live-upgrade.img'
@@ -50,76 +45,32 @@ def scan_config_and_emit_message():
return
api.current_logger().info('Loading livemode config from %s', LIVEMODE_CONFIG_LOCATION)
- parser = configparser.ConfigParser()
- try:
- parser.read((LIVEMODE_CONFIG_LOCATION, ))
- except configparser.ParsingError as error:
- api.current_logger().error('Failed to parse live mode configuration due to the following error: %s', error)
+ config = api.current_actor().config[livemode_config_lib.LIVEMODE_CONFIG_SECTION]
+
+ # Mapping from model field names to configuration fields - because we might have
+ # changed some configuration field names for configuration to be more
+ # comprehensible for our users.
+ model_fields_to_config_options_map = {
+ 'url_to_load_squashfs_from': livemode_config_lib.URLToLoadSquashfsImageFrom,
+ 'squashfs_fullpath': livemode_config_lib.SquashfsImagePath,
+ 'dracut_network': livemode_config_lib.DracutNetwork,
+ 'setup_network_manager': livemode_config_lib.SetupNetworkManager,
+ 'additional_packages': livemode_config_lib.AdditionalPackages,
+ 'autostart_upgrade_after_reboot': livemode_config_lib.AutostartUpgradeAfterReboot,
+ 'setup_opensshd_with_auth_keys': livemode_config_lib.SetupOpenSSHDUsingAuthKeys,
+ 'setup_passwordless_root': livemode_config_lib.SetupPasswordlessRoot,
+ 'capture_upgrade_strace_into': livemode_config_lib.CaptureSTraceInfoInto
+ }
- details = 'Failed to read livemode configuration due to the following error: {0}.'
- raise StopActorExecutionError(
- 'Failed to read livemode configuration',
- details={'Problem': details.format(error)}
- )
+ # Read values of model fields from user-supplied configuration according to the above mapping
+ config_msg_init_kwargs = {}
+ for model_field_name, config_field in model_fields_to_config_options_map.items():
+ config_msg_init_kwargs[model_field_name] = config[config_field.name]
- livemode_section = 'livemode'
- if not parser.has_section(livemode_section):
- details = 'The configuration is missing the \'[{0}]\' section'.format(livemode_section)
- raise StopActorExecutionError(
- 'Live mode configuration does not have the required structure',
- details={'Problem': details}
- )
-
- config_kwargs = {
- 'is_enabled': True,
- 'url_to_load_squashfs_from': None,
- 'squashfs_fullpath': DEFAULT_SQUASHFS_PATH,
- 'dracut_network': None,
- 'setup_network_manager': False,
- 'additional_packages': [],
- 'autostart_upgrade_after_reboot': True,
- 'setup_opensshd_with_auth_keys': None,
- 'setup_passwordless_root': False,
- 'capture_upgrade_strace_into': None
- }
+ # Some fields of the LiveModeConfig are historical and can no longer be changed by the user
+ # in the config. Therefore, we just hard-code them here.
+ config_msg_init_kwargs['is_enabled'] = True
- config_str_options = (
- 'url_to_load_squashfs_from',
- 'squashfs_fullpath',
- 'dracut_network',
- 'setup_opensshd_with_auth_keys',
- 'capture_upgrade_strace_into'
- )
-
- config_list_options = (
- 'additional_packages',
- )
-
- config_bool_options = (
- 'setup_network_manager',
- 'setup_passwordless_root',
- 'autostart_upgrade_after_reboot',
- )
-
- for config_option in config_str_options:
- if parser.has_option(livemode_section, config_option):
- config_kwargs[config_option] = parser.get(livemode_section, config_option)
-
- for config_option in config_bool_options:
- if parser.has_option(livemode_section, config_option):
- config_kwargs[config_option] = parser.getboolean(livemode_section, config_option)
-
- for config_option in config_list_options:
- if parser.has_option(livemode_section, config_option):
- option_val = parser.get(livemode_section, config_option)
- option_list = (opt_val.strip() for opt_val in option_val.split(','))
- option_list = [opt for opt in option_list if opt]
- config_kwargs[config_option] = option_list
-
- try:
- config = LiveModeConfig(**config_kwargs)
- except ModelViolationError as error:
- raise StopActorExecutionError('Failed to parse livemode configuration.', details={'Problem': str(error)})
-
- api.produce(config)
+ config_msg = LiveModeConfig(**config_msg_init_kwargs)
+ api.produce(config_msg)
diff --git a/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/tests/test_config_scanner.py b/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/tests/test_config_scanner.py
index 016f6c04..8ddde22e 100644
--- a/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/tests/test_config_scanner.py
+++ b/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/tests/test_config_scanner.py
@@ -86,29 +86,21 @@ def test_enablement_conditions(monkeypatch, case_descr):
def test_config_scanning(monkeypatch):
""" Test whether scanning a valid config is properly transcribed into a config message. """
- config_lines = [
- '[livemode]',
- 'squashfs_fullpath=IMG',
- 'setup_network_manager=yes',
- 'autostart_upgrade_after_reboot=no',
- 'setup_opensshd_with_auth_keys=/root/.ssh/authorized_keys',
- 'setup_passwordless_root=no',
- 'additional_packages=pkgA,pkgB'
- ]
- config_content = '\n'.join(config_lines) + '\n'
-
- if sys.version[0] == '2':
- config_content = config_content.decode('utf-8') # python2 compat
-
- class ConfigParserMock(configparser.ConfigParser): # pylint: disable=too-many-ancestors
- def read(self, file_paths, *args, **kwargs):
- self.read_string(config_content)
- return file_paths
-
- monkeypatch.setattr(configparser, 'ConfigParser', ConfigParserMock)
-
+ config = {
+ 'livemode': {
+ 'squashfs_image_path': '/var/lib/leapp/live-upgrade2.img',
+ 'additional_packages': ['petri-nets'],
+ 'autostart_upgrade_after_reboot': True,
+ 'setup_network_manager': True,
+ 'setup_passwordless_root': True,
+ 'dracut_network': '',
+ 'url_to_load_squashfs_image_from': '',
+ 'setup_opensshd_using_auth_keys': '/root/.ssh/authorized_keys',
+ 'capture_strace_info_into': ''
+ }
+ }
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(config=config))
monkeypatch.setattr(scan_livemode_config_lib, 'should_scan_config', lambda: True)
-
monkeypatch.setattr(api, 'produce', produce_mocked())
scan_livemode_config_lib.scan_config_and_emit_message()
@@ -119,7 +111,7 @@ def test_config_scanning(monkeypatch):
produced_message = api.produce.model_instances[0]
assert isinstance(produced_message, LiveModeConfig)
- assert produced_message.additional_packages == ['pkgA', 'pkgB']
- assert produced_message.squashfs_fullpath == 'IMG'
+ assert produced_message.additional_packages == ['petri-nets']
+ assert produced_message.squashfs_fullpath == '/var/lib/leapp/live-upgrade2.img'
assert produced_message.setup_opensshd_with_auth_keys == '/root/.ssh/authorized_keys'
assert produced_message.setup_network_manager
--
2.49.0

View File

@ -0,0 +1,61 @@
From 96c911454e4e68a749503b644c31df3a853e8a0b Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Thu, 20 Mar 2025 22:29:36 +0100
Subject: [PATCH 07/37] fix(livemode): do not stop if dbus already appears to
be enabled
Some of the systemd units might be already enabled in the target
userspace container, causing an unhandled FileAlreadyExists error
when we attempt to enable them. This commit ignores such errors, working
on under the assumption that the services we wanted to enable are
already enabled. Hence, we ignore the possibility that the file which
unexpectedly resides at the destination of the symlink which enables the
service might contain some unexpected/incorrect content.
---
.../libraries/prepareliveimage.py | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/repos/system_upgrade/common/actors/livemode/modify_userspace_for_livemode/libraries/prepareliveimage.py b/repos/system_upgrade/common/actors/livemode/modify_userspace_for_livemode/libraries/prepareliveimage.py
index c573c84a..686c4cd6 100644
--- a/repos/system_upgrade/common/actors/livemode/modify_userspace_for_livemode/libraries/prepareliveimage.py
+++ b/repos/system_upgrade/common/actors/livemode/modify_userspace_for_livemode/libraries/prepareliveimage.py
@@ -1,3 +1,4 @@
+import errno
import grp
import os
import os.path
@@ -253,16 +254,30 @@ def enable_dbus(context):
Enable dbus-daemon into the target userspace
Looks like it's not enabled by default when installing into a container.
"""
- api.current_logger().info('Configuring the dbus services')
+ dbus_daemon_service = '/usr/lib/systemd/system/dbus-daemon.service'
links = ['/etc/systemd/system/multi-user.target.wants/dbus-daemon.service',
'/etc/systemd/system/dbus.service',
'/etc/systemd/system/messagebus.service']
+ api.current_logger().info(('Enabling dbus services. Leapp will attempt to create the following '
+ 'symlinks: {0}, all pointing to {1}').format(', '.join(links),
+ dbus_daemon_service))
+
for link in links:
+ api.current_logger().debug('Creating symlink at {0} that points to {1}'.format(link, dbus_daemon_service))
try:
os.symlink('/usr/lib/systemd/system/dbus-daemon.service', context.full_path(link))
except OSError as err:
+ if err.errno == errno.EEXIST:
+ # @Note: We are not catching FileExistsError because of python2 (there is no such error class)
+ # We are performing installations within container, so the systemd symlinks that are created
+ # during installation should have correct destination
+ api.current_logger().debug(
+ 'A file already exists at {0}, assuming it is a symlink with a correct content.'
+ )
+ continue
+
details = {'Problem': 'An error occurred while creating the systemd symlink', 'source_error': str(err)}
raise StopActorExecutionError('Cannot enable the dbus services', details=details)
--
2.49.0

View File

@ -1,46 +0,0 @@
From db8d1f3fcc155b94b07d89d90eb82cd2a52d5cf9 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Wed, 20 Aug 2025 15:41:34 +0200
Subject: [PATCH 07/55] networkmanagerconnectionscanner: Skip test on Python !=
3.6
The test_nm_conn tests fails on at least Python >= 3.9 (not sure which
version exactly).
Let's skip the test on Python != 3.6 as they never run on a different
version - the actor is in the el8toel9 repo and is in FactsPhase.
---
.../unit_test_networkmanagerconnectionscanner.py | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/repos/system_upgrade/el8toel9/actors/networkmanagerconnectionscanner/tests/unit_test_networkmanagerconnectionscanner.py b/repos/system_upgrade/el8toel9/actors/networkmanagerconnectionscanner/tests/unit_test_networkmanagerconnectionscanner.py
index 46af07c1..7558b307 100644
--- a/repos/system_upgrade/el8toel9/actors/networkmanagerconnectionscanner/tests/unit_test_networkmanagerconnectionscanner.py
+++ b/repos/system_upgrade/el8toel9/actors/networkmanagerconnectionscanner/tests/unit_test_networkmanagerconnectionscanner.py
@@ -1,4 +1,5 @@
import errno
+import sys
import textwrap
import pytest
@@ -57,7 +58,16 @@ def test_no_conf(monkeypatch):
assert not api.produce.called
-@pytest.mark.skipif(not nmconnscanner.libnm_available, reason="NetworkManager g-ir not installed")
+@pytest.mark.skipif(
+ sys.version_info.major != 3 or sys.version_info.minor != 6,
+ # On Python > 3.6 the GLib and NM libraries apparently behave differently and
+ # the test fails. Let's skip it since the actor it's only ever run with
+ # Python3.6 (el8toel9 repo and FactsPhase)
+ reason="Only runs on Python 3.6",
+)
+@pytest.mark.skipif(
+ not nmconnscanner.libnm_available, reason="NetworkManager g-ir not installed"
+)
def test_nm_conn(monkeypatch):
"""
Check a basic keyfile
--
2.51.1

View File

@ -1,132 +0,0 @@
From c4c36a2abd0c83b021a20a450e66b8b1fe7be2da Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Wed, 27 Aug 2025 20:02:46 +0200
Subject: [PATCH 08/55] Remove unused (rh)el7 Containerfiles
---
utils/container-builds/Containerfile.centos7 | 15 -----------
utils/container-tests/Containerfile.rhel7 | 24 ------------------
utils/container-tests/Containerfile.ubi7 | 25 -------------------
utils/container-tests/Containerfile.ubi7-lint | 25 -------------------
4 files changed, 89 deletions(-)
delete mode 100644 utils/container-builds/Containerfile.centos7
delete mode 100644 utils/container-tests/Containerfile.rhel7
delete mode 100644 utils/container-tests/Containerfile.ubi7
delete mode 100644 utils/container-tests/Containerfile.ubi7-lint
diff --git a/utils/container-builds/Containerfile.centos7 b/utils/container-builds/Containerfile.centos7
deleted file mode 100644
index af00eddb..00000000
--- a/utils/container-builds/Containerfile.centos7
+++ /dev/null
@@ -1,15 +0,0 @@
-FROM centos:7
-
-VOLUME /repo
-
-# mirror.centos.org is dead, comment out mirrorlist and set baseurl to vault.centos.org
-RUN sed -i s/mirror.centos.org/vault.centos.org/ /etc/yum.repos.d/CentOS-*.repo
-RUN sed -i s/^#\s*baseurl=http/baseurl=http/ /etc/yum.repos.d/CentOS-*.repo
-RUN sed -i s/^mirrorlist=http/#mirrorlist=http/ /etc/yum.repos.d/CentOS-*.repo
-
-RUN yum update -y && \
- yum install -y rpm-build python-devel make git
-
-WORKDIR /repo
-ENV DIST_VERSION 7
-ENTRYPOINT make _build_local
diff --git a/utils/container-tests/Containerfile.rhel7 b/utils/container-tests/Containerfile.rhel7
deleted file mode 100644
index 0a0c384a..00000000
--- a/utils/container-tests/Containerfile.rhel7
+++ /dev/null
@@ -1,24 +0,0 @@
-FROM registry.access.redhat.com/ubi7/ubi:7.9
-
-VOLUME /repo
-
-RUN yum update -y && \
- yum install -y python-virtualenv python-setuptools make git rsync
-
-# see ./Containerfile.ubi7 for explanation
-RUN yum -y install python27-python-pip && \
- scl enable python27 -- pip install -U --target /usr/lib/python2.7/site-packages/ pip==20.3.0 && \
- python -m pip install --ignore-installed pip==20.3.4 ipaddress virtualenv
-
-ENV PYTHON_VENV python2.7
-
-COPY . /repocopy
-
-WORKDIR /repocopy
-
-RUN rm -rf tut*
-
-RUN make clean && make install-deps
-
-WORKDIR /
-
diff --git a/utils/container-tests/Containerfile.ubi7 b/utils/container-tests/Containerfile.ubi7
deleted file mode 100644
index 44625a76..00000000
--- a/utils/container-tests/Containerfile.ubi7
+++ /dev/null
@@ -1,25 +0,0 @@
-FROM registry.access.redhat.com/ubi7/ubi:7.9
-
-VOLUME /payload
-
-RUN yum update -y && \
- yum install python-virtualenv python-setuptools make git -y
-
-# NOTE(ivasilev,pstodulk) We need at least pip v10.0.1, however centos:7
-# provides just v8.1.2 (via EPEL). So do this: install epel repos -> install
-# python2-pip -> use pip to update to specific pip version we require. period
-# NOTE(pstodulk) I see we take care about pip for py3 inside the Makefile,
-# however I am afraid of additional possible troubles in future because of the
-# archaic pip3 version (v9.0.1). As we want to run tests for Py2 and Py3 in ci
-# always anyway, let's put py3 installation here as well..
-# Dropped Python3 as it is now added in its own container on RHEL8
-
-# This is some trickery: We install python27-python-pip from the scl, use the scl to bootstrap the python
-# module of pip version 20.3.0 and then make it update to 20.3.4 resulting the 'pip' command to be available.
-# The --target approach doesn't add it, but at least we now have pip 20.3.4 installed ;-)
-RUN yum -y install python27-python-pip && \
- scl enable python27 -- pip install -U --target /usr/lib/python2.7/site-packages/ pip==20.3.0 && \
- python -m pip install --ignore-installed pip==20.3.4 ipaddress virtualenv
-
-WORKDIR /payload
-ENTRYPOINT make install-deps && make test_no_lint
diff --git a/utils/container-tests/Containerfile.ubi7-lint b/utils/container-tests/Containerfile.ubi7-lint
deleted file mode 100644
index ed548985..00000000
--- a/utils/container-tests/Containerfile.ubi7-lint
+++ /dev/null
@@ -1,25 +0,0 @@
-FROM registry.access.redhat.com/ubi7/ubi:7.9
-
-VOLUME /payload
-
-RUN yum update -y && \
- yum install python-virtualenv python-setuptools make git -y
-
-# NOTE(ivasilev,pstodulk) We need at least pip v10.0.1, however centos:7
-# provides just v8.1.2 (via EPEL). So do this: install epel repos -> install
-# python2-pip -> use pip to update to specific pip version we require. period
-# NOTE(pstodulk) I see we take care about pip for py3 inside the Makefile,
-# however I am afraid of additional possible troubles in future because of the
-# archaic pip3 version (v9.0.1). As we want to run tests for Py2 and Py3 in ci
-# always anyway, let's put py3 installation here as well..
-# Dropped Python3 as it is now added in its own container on RHEL8
-
-# This is some trickery: We install python27-python-pip from the scl, use the scl to bootstrap the python
-# module of pip version 20.3.0 and then make it update to 20.3.4 resulting the 'pip' command to be available.
-# The --target approach doesn't add it, but at least we now have pip 20.3.4 installed ;-)
-RUN yum -y install python27-python-pip && \
- scl enable python27 -- pip install -U --target /usr/lib/python2.7/site-packages/ pip==20.3.0 && \
- python -m pip install --ignore-installed pip==20.3.4 ipaddress virtualenv
-
-WORKDIR /payload
-ENTRYPOINT make install-deps && make lint
--
2.51.1

View File

@ -0,0 +1,94 @@
From 6b3f6565e70290da1e02e3945851b430efb02109 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Fri, 11 Apr 2025 15:07:49 +0200
Subject: [PATCH 08/37] feat(livemode): remove the use of
LEAPP_DEVEL_ENABLE_LIVEMODE
The environmental variable has been introduced to prevent accidental
execution of livemode. However, in order for users to use the feature,
this environmental variable introduced unnecessary friction. Therefore,
this patch removes the use of the variable. Instead, whitelisting
experimental actors that facilitate livemode should be the only
mechanism that is used to enabled/disable the feature.
Jira-ref: RHELMISC-10648
---
docs/source/configuring-ipu.md | 3 ---
.../libraries/scan_livemode_config.py | 5 -----
.../tests/test_config_scanner.py | 12 ++++--------
3 files changed, 4 insertions(+), 16 deletions(-)
diff --git a/docs/source/configuring-ipu.md b/docs/source/configuring-ipu.md
index 6b838b8f..059b72c2 100644
--- a/docs/source/configuring-ipu.md
+++ b/docs/source/configuring-ipu.md
@@ -52,9 +52,6 @@ The alternative to the --channel leapp option. As a parameter accepts a channel
To use development variables, the LEAPP_UNSUPPORTED variable has to be set.
```
-#### LEAPP_DEVEL_ENABLE_LIVE_MODE
-If set to `1`, enable the use of the experimental live mode
-
#### LEAPP_DEVEL_DM_DISABLE_UDEV
Setting the environment variable provides a more convenient way of disabling udev support in libdevmapper, dmsetup and LVM2 tools globally without a need to modify any existing configuration settings. This is mostly useful if the system environment does not use udev.
diff --git a/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/libraries/scan_livemode_config.py b/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/libraries/scan_livemode_config.py
index 57408c23..26fd9d09 100644
--- a/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/libraries/scan_livemode_config.py
+++ b/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/libraries/scan_livemode_config.py
@@ -11,16 +11,11 @@ DEFAULT_SQUASHFS_PATH = '/var/lib/leapp/live-upgrade.img'
def should_scan_config():
is_unsupported = get_env('LEAPP_UNSUPPORTED', '0') == '1'
- is_livemode_enabled = get_env('LEAPP_DEVEL_ENABLE_LIVE_MODE', '0') == '1'
if not is_unsupported:
api.current_logger().debug('Will not scan livemode config - the upgrade is not unsupported.')
return False
- if not is_livemode_enabled:
- api.current_logger().debug('Will not scan livemode config - the live mode is not enabled.')
- return False
-
if not architecture.matches_architecture(architecture.ARCH_X86_64):
api.current_logger().debug('Will not scan livemode config - livemode is currently limited to x86_64.')
details = 'Live upgrades are currently limited to x86_64 only.'
diff --git a/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/tests/test_config_scanner.py b/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/tests/test_config_scanner.py
index 8ddde22e..e24aa366 100644
--- a/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/tests/test_config_scanner.py
+++ b/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/tests/test_config_scanner.py
@@ -29,19 +29,16 @@ EnablementTestCase = namedtuple('EnablementTestCase', ('env_vars', 'arch', 'pkgs
@pytest.mark.parametrize(
'case_descr',
(
- EnablementTestCase(env_vars={'LEAPP_UNSUPPORTED': '1', 'LEAPP_DEVEL_ENABLE_LIVE_MODE': '1'},
+ EnablementTestCase(env_vars={'LEAPP_UNSUPPORTED': '1'},
arch=architecture.ARCH_X86_64, pkgs=('squashfs-tools', ),
result=EnablementResult.SCAN_CONFIG),
- EnablementTestCase(env_vars={'LEAPP_UNSUPPORTED': '0', 'LEAPP_DEVEL_ENABLE_LIVE_MODE': '1'},
+ EnablementTestCase(env_vars={'LEAPP_UNSUPPORTED': '0'},
arch=architecture.ARCH_X86_64, pkgs=('squashfs-tools', ),
result=EnablementResult.DO_NOTHING),
- EnablementTestCase(env_vars={'LEAPP_UNSUPPORTED': '1', 'LEAPP_DEVEL_ENABLE_LIVE_MODE': '0'},
- arch=architecture.ARCH_X86_64, pkgs=('squashfs-tools', ),
- result=EnablementResult.DO_NOTHING),
- EnablementTestCase(env_vars={'LEAPP_UNSUPPORTED': '1', 'LEAPP_DEVEL_ENABLE_LIVE_MODE': '1'},
+ EnablementTestCase(env_vars={'LEAPP_UNSUPPORTED': '1'},
arch=architecture.ARCH_ARM64, pkgs=('squashfs-tools', ),
result=EnablementResult.RAISE),
- EnablementTestCase(env_vars={'LEAPP_UNSUPPORTED': '1', 'LEAPP_DEVEL_ENABLE_LIVE_MODE': '1'},
+ EnablementTestCase(env_vars={'LEAPP_UNSUPPORTED': '1'},
arch=architecture.ARCH_ARM64, pkgs=tuple(),
result=EnablementResult.RAISE),
)
@@ -52,7 +49,6 @@ def test_enablement_conditions(monkeypatch, case_descr):
Enablement conditions:
- LEAPP_UNSUPPORTED=1
- - LEAPP_DEVEL_ENABLE_LIVE_MODE=1
Not meeting enablement conditions should prevent config message from being produced.
--
2.49.0

View File

@ -1,239 +0,0 @@
From 29c7619f0368384dd2e266610098a1f8d7a13813 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Wed, 27 Aug 2025 20:04:28 +0200
Subject: [PATCH 09/55] Rename Containerfiles to consistent names
The container files (both those used in CI and locally by the Makefile)
and both build and test, use various base containers - Centos, UBIs.
This patch unifies the naming scheme to Containerfile.elX to avoid
making the user remember which one is used by which command an at
which version.
The containerfiles used by Github Actions are moved to separate
folder to avoid name clashes.
Also, in the GitHub actions test workflow the
--security-opt=seccomp=unconfined is removed. Not sure why it was set in
the first place, but seems it's not needed anymore.
---
.github/workflows/unit-tests.yml | 24 ++++++++------
Makefile | 31 +++++++++----------
.../{Containerfile.ubi8 => Containerfile.el8} | 0
.../{Containerfile.ubi9 => Containerfile.el9} | 0
...{Containerfile.rhel8 => Containerfile.el8} | 0
...{Containerfile.rhel9 => Containerfile.el9} | 0
.../Containerfile.el8} | 0
.../Containerfile.el8-lint} | 0
.../Containerfile.el9} | 0
.../Containerfile.el9-lint} | 0
10 files changed, 30 insertions(+), 25 deletions(-)
rename utils/container-builds/{Containerfile.ubi8 => Containerfile.el8} (100%)
rename utils/container-builds/{Containerfile.ubi9 => Containerfile.el9} (100%)
rename utils/container-tests/{Containerfile.rhel8 => Containerfile.el8} (100%)
rename utils/container-tests/{Containerfile.rhel9 => Containerfile.el9} (100%)
rename utils/container-tests/{Containerfile.ubi8 => ci/Containerfile.el8} (100%)
rename utils/container-tests/{Containerfile.ubi8-lint => ci/Containerfile.el8-lint} (100%)
rename utils/container-tests/{Containerfile.ubi9 => ci/Containerfile.el9} (100%)
rename utils/container-tests/{Containerfile.ubi9-lint => ci/Containerfile.el9-lint} (100%)
diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml
index ed82e0e5..cfcec437 100644
--- a/.github/workflows/unit-tests.yml
+++ b/.github/workflows/unit-tests.yml
@@ -19,36 +19,36 @@ jobs:
- name: 'Unit tests (python:3.12; repos:el9toel10,common)'
python: python3.12
repos: 'el9toel10,common'
- container: ubi9
+ container: el9
- name: 'Linters (python:3.12; repos:el9toel10,common)'
python: python3.12
repos: 'el9toel10,common'
- container: ubi9-lint
+ container: el9-lint
- name: 'Unit tests (python:3.9; repos:el9toel10,common)'
python: python3.9
repos: 'el9toel10,common'
- container: ubi9
+ container: el9
- name: 'Linters (python:3.9; repos:el9toel10,common)'
python: python3.9
repos: 'el9toel10,common'
- container: ubi9-lint
+ container: el9-lint
# 8to9
- name: 'Unit tests (python:3.9; repos:el8toel9,common)'
python: python3.9
repos: 'el8toel9,common'
- container: ubi9
+ container: el9
- name: 'Linters (python:3.9; repos:el8toel9,common)'
python: python3.9
repos: 'el8toel9,common'
- container: ubi9-lint
+ container: el9-lint
- name: 'Unit tests (python:3.6; repos:el8toel9,common)'
python: python3.6
repos: 'el8toel9,common'
- container: ubi8
+ container: el8
- name: 'Linters (python:3.6; repos:el8toel9,common)'
python: python3.6
repos: 'el8toel9,common'
- container: ubi8-lint
+ container: el8-lint
steps:
- name: Checkout code
@@ -63,4 +63,10 @@ jobs:
run: |
git branch -f main origin/main
- name: ${{matrix.scenarios.name}}
- run: script -e -c /bin/bash -c 'TERM=xterm podman build --security-opt=seccomp=unconfined -t leapp-tests -f utils/container-tests/Containerfile.${{matrix.scenarios.container}} utils/container-tests && PYTHON_VENV=${{matrix.scenarios.python}} REPOSITORIES=${{matrix.scenarios.repos}} podman run --security-opt=seccomp=unconfined --rm -ti -v ${PWD}:/payload --env=PYTHON_VENV --env=REPOSITORIES leapp-tests'
+ run: |
+ script -e -c /bin/bash -c \
+ 'TERM=xterm \
+ podman build -t leapp-tests -f utils/container-tests/ci/Containerfile.${{matrix.scenarios.container}} . && \
+ PYTHON_VENV=${{matrix.scenarios.python}} \
+ REPOSITORIES=${{matrix.scenarios.repos}} \
+ podman run --rm -ti -v ${PWD}:/payload --env=PYTHON_VENV --env=REPOSITORIES leapp-tests'
diff --git a/Makefile b/Makefile
index e0fc7e00..754c2c63 100644
--- a/Makefile
+++ b/Makefile
@@ -51,7 +51,7 @@ _COPR_CONFIG=$${COPR_CONFIG:-~/.config/copr_rh_oamg.conf}
_CONTAINER_TOOL=$${CONTAINER_TOOL:-podman}
# container to run tests in
-_TEST_CONTAINER=$${TEST_CONTAINER:-rhel8}
+_TEST_CONTAINER=$${TEST_CONTAINER:-el8}
# In case just specific CHROOTs should be used for the COPR build, you can
# set the multiple CHROOTs separated by comma in the COPR_CHROOT envar, e.g.
@@ -129,7 +129,7 @@ help:
@echo " test lint source code and run tests"
@echo " test_no_lint run tests without linting the source code"
@echo " test_container run lint and tests in container"
- @echo " - default container is 'rhel8'"
+ @echo " - default container is 'el8'"
@echo " - can be changed by setting TEST_CONTAINER env"
@echo " test_container_all run lint and tests in all available containers"
@echo " test_container_no_lint run tests without linting in container, see test_container"
@@ -164,9 +164,9 @@ help:
@echo " PR=7 SUFFIX='my_additional_suffix' make <target>"
@echo " MR=6 COPR_CONFIG='path/to/the/config/copr/file' make <target>"
@echo " ACTOR=<actor> TEST_LIBS=y make test"
- @echo " BUILD_CONTAINER=rhel8 make build_container"
+ @echo " BUILD_CONTAINER=el8 make build_container"
@echo " TEST_CONTAINER=f42 make test_container"
- @echo " CONTAINER_TOOL=docker TEST_CONTAINER=rhel8 make test_container_no_lint"
+ @echo " CONTAINER_TOOL=docker TEST_CONTAINER=el8 make test_container_no_lint"
@echo ""
clean:
@@ -252,10 +252,10 @@ build_container:
echo "--- Build RPM ${PKGNAME}-${VERSION}-${RELEASE}.el$(DIST_VERSION).rpm in container ---";
case "$(BUILD_CONTAINER)" in \
el8) \
- CONT_FILE="utils/container-builds/Containerfile.ubi8"; \
+ CONT_FILE="utils/container-builds/Containerfile.el8"; \
;; \
el9) \
- CONT_FILE="utils/container-builds/Containerfile.ubi9"; \
+ CONT_FILE="utils/container-builds/Containerfile.el9"; \
;; \
"") \
echo "BUILD_CONTAINER must be set"; \
@@ -415,7 +415,7 @@ lint_container:
@_TEST_CONT_TARGET="lint" $(MAKE) test_container
lint_container_all:
- @for container in "f42" "rhel8" "rhel9"; do \
+ @for container in f42 el{8,9}; do \
TEST_CONTAINER=$$container $(MAKE) lint_container || exit 1; \
done
@@ -429,16 +429,16 @@ test_container:
export CONT_FILE="utils/container-tests/Containerfile.f42"; \
export _VENV="python3.13"; \
;; \
- rhel8) \
- export CONT_FILE="utils/container-tests/Containerfile.rhel8"; \
+ el8) \
+ export CONT_FILE="utils/container-tests/Containerfile.el8"; \
export _VENV="python3.6"; \
;; \
- rhel9) \
- export CONT_FILE="utils/container-tests/Containerfile.rhel9"; \
+ el9) \
+ export CONT_FILE="utils/container-tests/Containerfile.el9"; \
export _VENV="python3.9"; \
;; \
*) \
- echo "Error: Available containers are: f42, rhel8, rhel9"; exit 1; \
+ echo "Error: Available containers are: f42, el8, el9"; exit 1; \
;; \
esac; \
export TEST_IMAGE="leapp-repo-tests-$(_TEST_CONTAINER)"; \
@@ -470,7 +470,7 @@ test_container:
exit $$res
test_container_all:
- @for container in "f42" "rhel8" "rhel9"; do \
+ @for container in "f42" "el8" "el9"; do \
TEST_CONTAINER=$$container $(MAKE) test_container || exit 1; \
done
@@ -478,14 +478,13 @@ test_container_no_lint:
@_TEST_CONT_TARGET="test_no_lint" $(MAKE) test_container
test_container_all_no_lint:
- @for container in "f42" "rhel8" "rhel9"; do \
+ @for container in f42 el{8,9}; do \
TEST_CONTAINER=$$container $(MAKE) test_container_no_lint || exit 1; \
done
# clean all testing and building containers and their images
clean_containers:
- @for i in "leapp-repo-tests-f42" "leapp-repo-tests-rhel8" \
- "leapp-repo-tests-rhel9" "leapp-repo-build-el8"; do \
+ @for i in leapp-repo-tests-f42 leapp-repo-tests-el{8,9} leapp-repo-build-el{8,9}; do \
$(_CONTAINER_TOOL) kill "$$i-cont" || :; \
$(_CONTAINER_TOOL) rm "$$i-cont" || :; \
$(_CONTAINER_TOOL) rmi "$$i" || :; \
diff --git a/utils/container-builds/Containerfile.ubi8 b/utils/container-builds/Containerfile.el8
similarity index 100%
rename from utils/container-builds/Containerfile.ubi8
rename to utils/container-builds/Containerfile.el8
diff --git a/utils/container-builds/Containerfile.ubi9 b/utils/container-builds/Containerfile.el9
similarity index 100%
rename from utils/container-builds/Containerfile.ubi9
rename to utils/container-builds/Containerfile.el9
diff --git a/utils/container-tests/Containerfile.rhel8 b/utils/container-tests/Containerfile.el8
similarity index 100%
rename from utils/container-tests/Containerfile.rhel8
rename to utils/container-tests/Containerfile.el8
diff --git a/utils/container-tests/Containerfile.rhel9 b/utils/container-tests/Containerfile.el9
similarity index 100%
rename from utils/container-tests/Containerfile.rhel9
rename to utils/container-tests/Containerfile.el9
diff --git a/utils/container-tests/Containerfile.ubi8 b/utils/container-tests/ci/Containerfile.el8
similarity index 100%
rename from utils/container-tests/Containerfile.ubi8
rename to utils/container-tests/ci/Containerfile.el8
diff --git a/utils/container-tests/Containerfile.ubi8-lint b/utils/container-tests/ci/Containerfile.el8-lint
similarity index 100%
rename from utils/container-tests/Containerfile.ubi8-lint
rename to utils/container-tests/ci/Containerfile.el8-lint
diff --git a/utils/container-tests/Containerfile.ubi9 b/utils/container-tests/ci/Containerfile.el9
similarity index 100%
rename from utils/container-tests/Containerfile.ubi9
rename to utils/container-tests/ci/Containerfile.el9
diff --git a/utils/container-tests/Containerfile.ubi9-lint b/utils/container-tests/ci/Containerfile.el9-lint
similarity index 100%
rename from utils/container-tests/Containerfile.ubi9-lint
rename to utils/container-tests/ci/Containerfile.el9-lint
--
2.51.1

View File

@ -0,0 +1,29 @@
From 021f083509b074905c18b79afba4a22f8ca483f6 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Fri, 11 Apr 2025 15:12:18 +0200
Subject: [PATCH 09/37] spec: require leapp-framework 6.1 for default CLI vals
Bump framework version as we want to use default=[] for the newly
introduced `--enable-experimental-features` switch.
Jira-ref: RHELMISC-10648
---
packaging/leapp-repository.spec | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packaging/leapp-repository.spec b/packaging/leapp-repository.spec
index f45fda68..34768de1 100644
--- a/packaging/leapp-repository.spec
+++ b/packaging/leapp-repository.spec
@@ -120,7 +120,7 @@ Requires: leapp-repository-dependencies = %{leapp_repo_deps}
# IMPORTANT: this is capability provided by the leapp framework rpm.
# Check that 'version' instead of the real framework rpm version.
-Requires: leapp-framework >= 6.0, leapp-framework < 7
+Requires: leapp-framework >= 6.1, leapp-framework < 7
# Since we provide sub-commands for the leapp utility, we expect the leapp
# tool to be installed as well.
--
2.49.0

View File

@ -1,80 +0,0 @@
From 17767238d038d36341181e1702b73681ae432439 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Wed, 20 Aug 2025 14:12:13 +0200
Subject: [PATCH 10/55] Replace ubi:8 containers with centos:8
The networkmanagerconnectionscanner depends on NetworkManager-nmlib and
python3-gobject. These are not available in the UBI 8 repos and the
tests are skipped.
This patch changes the base container from UBI 8 to Centos 8 which has
the packages available and the tests are not skipped.
---
commands/tests/test_upgrade_paths.py | 5 +++++
utils/container-tests/Containerfile.el8 | 10 ++++++++--
utils/container-tests/ci/Containerfile.el8 | 10 ++++++++--
3 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/commands/tests/test_upgrade_paths.py b/commands/tests/test_upgrade_paths.py
index 89b5eb71..9bdf5792 100644
--- a/commands/tests/test_upgrade_paths.py
+++ b/commands/tests/test_upgrade_paths.py
@@ -42,6 +42,11 @@ def test_get_target_version(mock_open, monkeypatch):
},
)
def test_get_target_release(mock_open, monkeypatch): # do not remove mock_open
+ # Make it look like it's RHEL even on centos, because that's what the test
+ # assumes.
+ # Otherwise the test, when ran on Centos, fails because it works
+ # with MAJOR.MINOR version format while Centos uses MAJOR format.
+ monkeypatch.setattr(command_utils, 'get_distro_id', lambda: 'rhel')
monkeypatch.setattr(command_utils, 'get_os_release_version_id', lambda x: '8.6')
# make sure env var LEAPP_DEVEL_TARGET_RELEASE takes precedence
diff --git a/utils/container-tests/Containerfile.el8 b/utils/container-tests/Containerfile.el8
index 6f21839b..b92e8742 100644
--- a/utils/container-tests/Containerfile.el8
+++ b/utils/container-tests/Containerfile.el8
@@ -1,9 +1,15 @@
-FROM registry.access.redhat.com/ubi8/ubi:latest
+FROM centos:8
+
+RUN sed -i s/mirror.centos.org/vault.centos.org/ /etc/yum.repos.d/CentOS-*.repo
+RUN sed -i s/^#\s*baseurl=http/baseurl=http/ /etc/yum.repos.d/CentOS-*.repo
+RUN sed -i s/^mirrorlist=http/#mirrorlist=http/ /etc/yum.repos.d/CentOS-*.repo
VOLUME /repo
RUN dnf update -y && \
- dnf install -y python3-virtualenv python3-setuptools python3-pip make git rsync
+ dnf install -y git make rsync \
+ python3-virtualenv python3-setuptools python3-pip \
+ python3-gobject NetworkManager-libnm
ENV PYTHON_VENV python3.6
diff --git a/utils/container-tests/ci/Containerfile.el8 b/utils/container-tests/ci/Containerfile.el8
index 4da60c18..4a19092e 100644
--- a/utils/container-tests/ci/Containerfile.el8
+++ b/utils/container-tests/ci/Containerfile.el8
@@ -1,9 +1,15 @@
-FROM registry.access.redhat.com/ubi8/ubi:latest
+FROM centos:8
+
+RUN sed -i s/mirror.centos.org/vault.centos.org/ /etc/yum.repos.d/CentOS-*.repo
+RUN sed -i s/^#\s*baseurl=http/baseurl=http/ /etc/yum.repos.d/CentOS-*.repo
+RUN sed -i s/^mirrorlist=http/#mirrorlist=http/ /etc/yum.repos.d/CentOS-*.repo
VOLUME /payload
RUN dnf update -y && \
- dnf install python3-virtualenv python3-setuptools python3-pip make git -y
+ dnf install -y make git \
+ python3-virtualenv python3-setuptools python3-pip \
+ python3-gobject NetworkManager-libnm
WORKDIR /payload
ENTRYPOINT make install-deps && make test_no_lint
--
2.51.1

View File

@ -0,0 +1,98 @@
From 51b26776405a926882509c3f62d0bedbb4eab188 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Mon, 14 Apr 2025 10:07:53 +0200
Subject: [PATCH 10/37] docs(configuring-ipu): add experimental features
section
With the upcoming introduction of documentation of the LiveMode feature,
a question arises where to put the documentation. This patch introduces
a new subsection 'Experimental features' under the 'Configuring IPU'
section, so we have one place to where to put such features.
---
.../{ => configuring-ipu}/configuring-ipu.md | 0
.../experimental-features/index.rst | 23 +++++++++++++++++++
docs/source/configuring-ipu/index.rst | 23 +++++++++++++++++++
docs/source/index.rst | 2 +-
4 files changed, 47 insertions(+), 1 deletion(-)
rename docs/source/{ => configuring-ipu}/configuring-ipu.md (100%)
create mode 100644 docs/source/configuring-ipu/experimental-features/index.rst
create mode 100644 docs/source/configuring-ipu/index.rst
diff --git a/docs/source/configuring-ipu.md b/docs/source/configuring-ipu/configuring-ipu.md
similarity index 100%
rename from docs/source/configuring-ipu.md
rename to docs/source/configuring-ipu/configuring-ipu.md
diff --git a/docs/source/configuring-ipu/experimental-features/index.rst b/docs/source/configuring-ipu/experimental-features/index.rst
new file mode 100644
index 00000000..7a26116e
--- /dev/null
+++ b/docs/source/configuring-ipu/experimental-features/index.rst
@@ -0,0 +1,23 @@
+Experimental features
+========================================================
+
+This section provides descriptions of all available experimental
+features. Low-level details and design decisions of these features
+are provided.
+
+.. warning::
+ Actor configuration is currently a preview of the feature, it might change in future releases.
+
+.. toctree::
+ :maxdepth: 4
+ :caption: Contents:
+ :glob:
+
+
+
+.. Indices and tables
+.. ==================
+..
+.. * :ref:`genindex`
+.. * :ref:`modindex`
+.. * :ref:`search`
diff --git a/docs/source/configuring-ipu/index.rst b/docs/source/configuring-ipu/index.rst
new file mode 100644
index 00000000..1be3ebcf
--- /dev/null
+++ b/docs/source/configuring-ipu/index.rst
@@ -0,0 +1,23 @@
+Configuring the in-place upgrade
+========================================================
+
+This section covers possible ways of modifying the in-place upgrade
+without making any code changes. Leapp offers multiple mechanism
+to affect the upgrade ranging from simple environmental variables
+to more robust configuration files. This section also covers available
+experimental features.
+
+.. toctree::
+ :maxdepth: 4
+ :caption: Contents:
+ :glob:
+
+ configuring-ipu
+ experimental-features/index
+
+.. Indices and tables
+.. ==================
+..
+.. * :ref:`genindex`
+.. * :ref:`modindex`
+.. * :ref:`search`
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 33a920ec..27537ca4 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -19,7 +19,7 @@ providing Red Hat Enterprise Linux in-place upgrade functionality.
tutorials/index
project-structure/index
upgrade-architecture-and-workflow/index
- configuring-ipu
+ configuring-ipu/index
libraries-and-api/index
contrib-and-devel-guidelines
faq
--
2.49.0

View File

@ -1,53 +0,0 @@
From c4f3ace1ebb909dc53796e16959a2459a15d9d74 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 9 Oct 2025 13:30:16 +0000
Subject: [PATCH 11/55] chore(deps): update actions/checkout action to v5
---
.github/workflows/codespell.yml | 2 +-
.github/workflows/differential-shellcheck.yml | 2 +-
.github/workflows/unit-tests.yml | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml
index 3e595e32..4b07e4b3 100644
--- a/.github/workflows/codespell.yml
+++ b/.github/workflows/codespell.yml
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- uses: codespell-project/actions-codespell@v2
with:
ignore_words_list: ro,fo,couldn,repositor,zeor,bootup
diff --git a/.github/workflows/differential-shellcheck.yml b/.github/workflows/differential-shellcheck.yml
index e1bafb93..6c81713c 100644
--- a/.github/workflows/differential-shellcheck.yml
+++ b/.github/workflows/differential-shellcheck.yml
@@ -19,7 +19,7 @@ jobs:
steps:
- name: Repository checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
fetch-depth: 0
diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml
index cfcec437..d1b8fb2a 100644
--- a/.github/workflows/unit-tests.yml
+++ b/.github/workflows/unit-tests.yml
@@ -52,7 +52,7 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
with:
# NOTE(ivasilev) fetch-depth 0 is critical here as leapp deps discovery depends on specific substring in
# commit message and default 1 option will get us just merge commit which has an unrelevant message.
--
2.51.1

View File

@ -0,0 +1,142 @@
From af35d1fd718258d37ed34be59084e7c77072096c Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Mon, 14 Apr 2025 10:14:12 +0200
Subject: [PATCH 11/37] docs(livemode): add LiveMode documentation
This commit introduces a high-level documentation of the livemode
feature. The following is documented:
- how the upgrade process differs from the standard one when using
livemode
- why is the feature useful, i.e., why would anyone use it
- how to enable and use the feature
- what configuration options are available, including an example of
configuration
Jira-ref: RHELMISC-9703
---
.github/workflows/codespell.yml | 2 +-
.../experimental-features/index.rst | 1 +
.../experimental-features/livemode.md | 86 +++++++++++++++++++
3 files changed, 88 insertions(+), 1 deletion(-)
create mode 100644 docs/source/configuring-ipu/experimental-features/livemode.md
diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml
index b8da5ebb..3e595e32 100644
--- a/.github/workflows/codespell.yml
+++ b/.github/workflows/codespell.yml
@@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v4
- uses: codespell-project/actions-codespell@v2
with:
- ignore_words_list: ro,fo,couldn,repositor,zeor
+ ignore_words_list: ro,fo,couldn,repositor,zeor,bootup
skip: "./repos/system_upgrade/common/actors/storagescanner/tests/files/mounts,\
./repos/system_upgrade/common/actors/networkmanagerreadconfig/tests/files/nm_cfg_file_error,\
./repos/system_upgrade/el8toel9/actors/xorgdrvfact/tests/files/journalctl-xorg-intel,\
diff --git a/docs/source/configuring-ipu/experimental-features/index.rst b/docs/source/configuring-ipu/experimental-features/index.rst
index 7a26116e..37de2fed 100644
--- a/docs/source/configuring-ipu/experimental-features/index.rst
+++ b/docs/source/configuring-ipu/experimental-features/index.rst
@@ -13,6 +13,7 @@ are provided.
:caption: Contents:
:glob:
+ livemode
.. Indices and tables
diff --git a/docs/source/configuring-ipu/experimental-features/livemode.md b/docs/source/configuring-ipu/experimental-features/livemode.md
new file mode 100644
index 00000000..44200e80
--- /dev/null
+++ b/docs/source/configuring-ipu/experimental-features/livemode.md
@@ -0,0 +1,86 @@
+# LiveMode
+
+_LiveMode_ is an experimental feature that partially replaces
+leapp's custom upgrade environment with a bootable squashfs image of the target
+system. Intuitively, this squashfs-based mechanism is similar to using a live
+CD (hence the name LiveMode) from which the DNF transaction and other
+post-reboot steps will be applied. Such an upgrade environment closely
+resembles an ordinary Linux installation, making developing desired
+functionality (e.g. supporting network-based storage) much easier.
+
+## Technical details
+During an upgrade, prior to rebooting, leapp constructs a minimal target system
+container in order to obtain a version of the DNF stack expected by the new
+packages installed during the upgrade. After the container is created, the new
+DNF stack is used to download packages that will be installed during the
+upgrade. Having all necessary packages, leapp checks the RPM transaction to be
+performed during the upgrade. Finally, the upgrade environment is created - an
+initramfs containing custom dracut modules that ultimately execute leapp very
+early in the boot process. Such an upgrade environment guarantees isolation
+from other system services as there is essentially only the upgrade process
+running. However, the downside of using such an approach is that the bootup
+process of the upgrade environment is non-standard, meaning that almost none of
+the classical system initialisation services (e.g., LVM autoactivation) are
+running. Developing advanced features such as support for network-based
+storage, is, therefore demanding as only a little of the usual initialisation
+is present and executed during bootup.
+
+The LiveMode feature obtains a similar isolation level of the upgrade process
+in a different way. Instead of using an initramfs image that executes leapp
+early, the system boots into a read-only squashfs system built from the target
+system container build previously to check the upgrade RPM transaction. Since
+leapp controls the creation of the target system container, it is also in
+control of what will be running alongside the upgrade process, limiting the
+possibility of arbitrary user-defined services interfering with the upgrade.
+The upgrade environment boots into the `multi-user.target` target and leapp is
+started as an ordinary systemd service. However, the squashfs image needs to be
+stored on the disk, and, hence, the using feature **requires about 700mb of
+additional disk space**.
+
+## Using the feature
+It is possible to use the LiveMode feature by having set `LEAPP_UNSUPPORTED=1`
+and running leapp as `leapp upgrade --enable-experimental-feature livemode`.
+```
+LEAPP_UNSUPPORTED=1 leapp upgrade --enable-experimental-feature livemode
+```
+### Configuration
+The feature offers an extensive list of configuration options that can be set
+by creating a YAML file in `/etc/leapp/actor_conf.d/` with the extension
+`.yaml`. The content of the configuration file must be a mapping defining the
+`livemode` key with a value that is a mapping with (some) of the following
+keys:
+
+| Configuration field | Value type | Default | Semantics |
+|---------------------|------------|---------|-----------|
+| `squashfs_image_path` | `str` | `/var/lib/leapp/live-upgrade.img` | Location where the squashfs image of the minimal target system will be placed. |
+| `additional_packages` | `List[str]` | `[]` | Additional packages to be installed into the squashfs image. |
+| `autostart_upgrade_after_reboot` | `bool` | `True` | If set to True, the upgrade will start automatically after the reboot. Otherwise a manual trigger is required. |
+| `setup_network_manager` | `bool` | `False` | Try enabling Network Manager in the squashfs image. |
+| `dracut_network` | `str` | `''` | Dracut network arguments, required if the `url_to_load_squashfs_from` option is set. |
+| `url_to_load_squashfs_image_from` | `str` | `''` | URL pointing to the squashfs image that should be used for the upgrade environment. |
+| `setup_passwordless_root` | `bool` | `False` | If set to True, the root account of the squashfs image will have empty password. Use with caution. |
+| `setup_opensshd_using_auth_keys` | `str` | `''` | If set to a non-empty string, openssh daemon will be setup within the squashfs image using the provided authorized keys file. |
+| `capture_strace_info_into` | `str` | `''` | If set to a non-empty string, leapp will be executed under strace and results will be stored within the provided file path. |
+
+#### Configuration example
+Consider the file `/etc/leapp/actor_conf.d/livemode.yaml` with the following contents.
+```
+livemode:
+ additional_packages : [ vim ]
+ autostart_upgrade_after_reboot : false
+ setup_network_manager : true
+ setup_opensshd_using_auth_keys : /root/.ssh/authorized_keys
+```
+
+The configuration results in the following actions:
+- Leapp will install the `vim` package into the upgrade environment.
+- The upgrade will not be started automatically after reboot. Instead, user
+ needs to resume the upgrade manually. Therefore, it is possible to manually
+ inspect the system and verify that everything is in order, e.g., all of the
+ necessary storage is mounted.
+- Leapp will attempt to enable `NetworkManager` inside the upgrade environment
+ using source system's network profiles. This attempt is best-effort, meaning
+ that there is no guarantee that the network will be functional.
+- Leapp will enable the `opensshd` service. If a network access is established
+ successfully, it will be possible to login using ssh into the upgrade
+ environment using the `root` account and interact with the system.
--
2.49.0

View File

@ -0,0 +1,54 @@
From c3ec002d6ebc825c1c918e3abe9e2c849ef9ddc4 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Wed, 16 Apr 2025 13:39:28 +0200
Subject: [PATCH 12/37] DOC: rename configuring-ipu.md to envars.md
The file has bas been created before we introduced the section of
"Configuring in-place upgrade" and it contained mixture of various
stuff. We have the section now, so let's rename this file to envars
and keep here documented environments variables only.
Dropping information from this file about actors' configurations.
This needs to be anyway documented separately now and original
information has not been so helpful.
---
.../configuring-ipu/{configuring-ipu.md => envars.md} | 8 --------
docs/source/configuring-ipu/index.rst | 2 +-
2 files changed, 1 insertion(+), 9 deletions(-)
rename docs/source/configuring-ipu/{configuring-ipu.md => envars.md} (95%)
diff --git a/docs/source/configuring-ipu/configuring-ipu.md b/docs/source/configuring-ipu/envars.md
similarity index 95%
rename from docs/source/configuring-ipu/configuring-ipu.md
rename to docs/source/configuring-ipu/envars.md
index 059b72c2..61a50b82 100644
--- a/docs/source/configuring-ipu/configuring-ipu.md
+++ b/docs/source/configuring-ipu/envars.md
@@ -78,11 +78,3 @@ Change the default target RHEL version. Format: `MAJOR.MINOR`.
#### LEAPP_DEVEL_USE_PERSISTENT_PACKAGE_CACHE
Caches downloaded packages when set to `1`. This will reduce the time needed by leapp when executed multiple times, because it will not have to download already downloaded packages. However, this can lead to a random issues in case the data is not up-to-date or when setting or repositories change. The environment variable is meant to be used only for the part of the upgrade before the reboot and has no effect or use otherwise.
-
-## Actor configuration
-```{warning}
-Actor configuration is currently a preview of the feature, it might change in future releases.
-```
-The actor configuration is to be placed in the `/etc/leapp/actor_conf.d/` directory. An actor configuration is a file in YAML format.
-
-To define configuration options on your own actor refer to this tutorial TODO link.
diff --git a/docs/source/configuring-ipu/index.rst b/docs/source/configuring-ipu/index.rst
index 1be3ebcf..6490d6fd 100644
--- a/docs/source/configuring-ipu/index.rst
+++ b/docs/source/configuring-ipu/index.rst
@@ -12,7 +12,7 @@ experimental features.
:caption: Contents:
:glob:
- configuring-ipu
+ envars
experimental-features/index
.. Indices and tables
--
2.49.0

View File

@ -1,46 +0,0 @@
From 601c26f795a7b2f6cb553c656112235d17137b8f Mon Sep 17 00:00:00 2001
From: karolinku <kkula@redhat.com>
Date: Tue, 16 Sep 2025 15:58:29 +0200
Subject: [PATCH 12/55] LiveMode: Add /etc/crypttab file to the target
userspace container
When upgrading with LiveMode, the auto-unlock of encrypted devices
fails because the /etc/crypttab configuration file is not present inside
the squashfs, causing the boot process to fail.
This change copy /etc/crypttab file to the target userspace container
during the upgrade process, allowing encrypted devices to be properly
unlocked.
Jira: RHEL-90098
---
.../common/actors/checkluks/libraries/checkluks.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/repos/system_upgrade/common/actors/checkluks/libraries/checkluks.py b/repos/system_upgrade/common/actors/checkluks/libraries/checkluks.py
index 57a94e9d..aac171a7 100644
--- a/repos/system_upgrade/common/actors/checkluks/libraries/checkluks.py
+++ b/repos/system_upgrade/common/actors/checkluks/libraries/checkluks.py
@@ -3,6 +3,7 @@ from leapp.libraries.common.config.version import get_source_major_version
from leapp.libraries.stdlib import api
from leapp.models import (
CephInfo,
+ CopyFile,
DracutModule,
LuksDumps,
StorageInfo,
@@ -156,7 +157,10 @@ def check_invalid_luks_devices():
'tpm2-tools',
'tpm2-abrmd'
]
- api.produce(TargetUserSpaceUpgradeTasks(install_rpms=required_crypt_rpms))
+ api.produce(TargetUserSpaceUpgradeTasks(
+ copy_files=[CopyFile(src="/etc/crypttab")],
+ install_rpms=required_crypt_rpms)
+ )
api.produce(UpgradeInitramfsTasks(include_dracut_modules=[
DracutModule(name='clevis'),
DracutModule(name='clevis-pin-tpm2')
--
2.51.1

View File

@ -0,0 +1,68 @@
From 53f125b42f3e17354cc2d3e93b80fe089cf4c3b2 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Tue, 4 Mar 2025 14:42:44 +0100
Subject: [PATCH 13/37] fix(userspacegen): add exeception handling to swapping
of RHUI clients
Leapp swaps to RHUI target clients (uninstall source client+install
target client) in the scratch container to gain repository access.
To perform this step atomically, without loosing repository access
in between, `dnf shell` is invoked. The instruction as to which RPMs
should be uninstalled and which should be installed are given on
stdin of the `dnf shell` command. Currently, if we fail to swap clients
we crash with an unhandled exception `CalledProcessError` that contains
no information about what went wrong since the actual performed
transaction is hidden within the stdin of the process. This patch
adds error handling, so that we can tell that we have failed to swap
RHUI clients. Leapp's logs also contain the full DNF transaction as well
as possible explanations on why we failed.
jira-ref: RHEL-77945
---
.../libraries/userspacegen.py | 30 ++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
index 12736ab7..9fc96a52 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
@@ -1239,7 +1239,35 @@ def setup_target_rhui_access_if_needed(context, indata):
'shell'
]
- context.call(cmd, callback_raw=utils.logging_handler, stdin='\n'.join(dnf_transaction_steps))
+ try:
+ dnf_shell_instructions = '\n'.join(dnf_transaction_steps)
+ api.current_logger().debug(
+ 'Supplying the following instructions to the `dnf shell`: {}'.format(dnf_shell_instructions)
+ )
+ context.call(cmd, callback_raw=utils.logging_handler, stdin=dnf_shell_instructions)
+ except CalledProcessError as error:
+ api.current_logger().debug(
+ 'Failed to swap RHUI clients. This is likely because there are no repositories '
+ ' containing RHUI clients enabled, or we cannot access them.'
+ )
+ api.current_logger().debug(error)
+
+ swapping_clients_info_msg = 'Failed to swap `{0}` (source client{1}) with {2} (target client{3}).'
+ swapping_clients_info_msg = swapping_clients_info_msg.format(
+ ' '.join(indata.rhui_info.src_client_pkg_names),
+ '' if len(indata.rhui_info.src_client_pkg_names) == 1 else 's',
+ ' '.join(indata.rhui_info.target_client_pkg_names),
+ '' if len(indata.rhui_info.target_client_pkg_names) == 1 else 's',
+ )
+
+ details = {
+ 'details': swapping_clients_info_msg,
+ 'error': str(error)
+ }
+ raise StopActorExecutionError(
+ 'Failed to swap RHUI clients to establish content access',
+ details=details
+ )
_apply_rhui_access_postinstall_tasks(context, setup_info)
--
2.49.0

View File

@ -1,50 +0,0 @@
From ae048a890ddd2169f3f46d9fbd1545fd65670e16 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Mon, 6 Oct 2025 15:56:16 +0200
Subject: [PATCH 13/55] livemode: Include /etc/crypttab in upgrade initramfs
The /etc/crypttab file is sometimes not picked up automatically by
dracut, this change includes it unconditionally. This is required for
auto-unlocking encrypted devices in upgrade environment.
The upgradeinitramfsgenerator is modified to process
UpgradeInitramfsTasksinclude's include_files when upgrading in livemode.
Jira: RHEL-90098
---
.../common/actors/checkluks/libraries/checkluks.py | 4 +++-
.../libraries/upgradeinitramfsgenerator.py | 3 +++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/repos/system_upgrade/common/actors/checkluks/libraries/checkluks.py b/repos/system_upgrade/common/actors/checkluks/libraries/checkluks.py
index aac171a7..d52b9e73 100644
--- a/repos/system_upgrade/common/actors/checkluks/libraries/checkluks.py
+++ b/repos/system_upgrade/common/actors/checkluks/libraries/checkluks.py
@@ -161,7 +161,9 @@ def check_invalid_luks_devices():
copy_files=[CopyFile(src="/etc/crypttab")],
install_rpms=required_crypt_rpms)
)
- api.produce(UpgradeInitramfsTasks(include_dracut_modules=[
+ api.produce(UpgradeInitramfsTasks(
+ include_files=['/etc/crypttab'],
+ include_dracut_modules=[
DracutModule(name='clevis'),
DracutModule(name='clevis-pin-tpm2')
])
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 02c3fd9d..3ad92167 100644
--- a/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/libraries/upgradeinitramfsgenerator.py
+++ b/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/libraries/upgradeinitramfsgenerator.py
@@ -436,6 +436,9 @@ def _generate_livemode_initramfs(context, userspace_initramfs_dest, target_kerne
'--lvmconf', '--mdadmconf',
'--kver', target_kernel_ver, '-f', userspace_initramfs_dest]
+ # Add included files
+ cmd.extend(itertools.chain(*(('--install', file) for file in initramfs_includes.files)))
+
# Add dracut modules
cmd.extend(itertools.chain(*(('--add', module) for module in dracut_modules)))
--
2.51.1

View File

@ -1,25 +0,0 @@
From 8248f6afd54bedcfe9d9d639fda3760669360dbe Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Mon, 13 Oct 2025 13:39:14 +0200
Subject: [PATCH 14/55] overlaygen: Fix not enough arguments for format string
---
repos/system_upgrade/common/libraries/overlaygen.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/repos/system_upgrade/common/libraries/overlaygen.py b/repos/system_upgrade/common/libraries/overlaygen.py
index 867e3559..a048af2b 100644
--- a/repos/system_upgrade/common/libraries/overlaygen.py
+++ b/repos/system_upgrade/common/libraries/overlaygen.py
@@ -710,7 +710,7 @@ def _create_mount_disk_image_old(disk_images_directory, path):
try:
utils.call_with_oserror_handled(cmd=['/sbin/mkfs.ext4', '-F', diskimage_path])
except CalledProcessError as e:
- api.current_logger().error('Failed to create ext4 filesystem in %s', exc_info=True)
+ api.current_logger().error('Failed to create ext4 filesystem in %s', diskimage_path, exc_info=True)
raise StopActorExecutionError(
message=str(e)
)
--
2.51.1

View File

@ -0,0 +1,40 @@
From 474b26cbcadc804ff50935a87ca78379999960d4 Mon Sep 17 00:00:00 2001
From: Vit Mojzis <vmojzis@redhat.com>
Date: Tue, 4 Mar 2025 11:49:05 +0100
Subject: [PATCH 14/37] selinux: do not run "semodule" when no modules are
selected
Fixes:
2025-03-04 11:21:31.550 DEBUG PID: 679 leapp.workflow.Applications.selinuxapplycustom: External command has finished: ['semodule', '-lfull']
2025-03-04 11:21:31.551 INFO PID: 679 leapp.workflow.Applications.selinuxapplycustom: Processing custom SELinux policy modules. Count: 1.
2025-03-04 11:21:31.551 INFO PID: 679 leapp.workflow.Applications.selinuxapplycustom: Skipping module permissive_rhcd_t on priority 400 because it is already installed.
2025-03-04 11:21:31.551 DEBUG PID: 679 leapp.workflow.Applications.selinuxapplycustom: External command has started: ['semodule']
2025-03-04 11:21:31.555 DEBUG PID: 679 leapp.workflow.Applications.selinuxapplycustom: At least one mode must be specified.
2025-03-04 11:21:31.555 DEBUG PID: 679 leapp.workflow.Applications.selinuxapplycustom: usage: semodule [option]... MODE...
2025-03-04 11:21:31.555 DEBUG PID: 679 leapp.workflow.Applications.selinuxapplycustom: Manage SELinux policy modules.
2025-03-04 11:21:31.556 DEBUG PID: 679 leapp.workflow.Applications.selinuxapplycustom: MODES:
2025-03-04 11:21:31.556 DEBUG PID: 679 leapp.workflow.Applications.selinuxapplycustom: -R, --reload reload policy
...
2025-03-04 11:21:31.564 WARNING PID: 679 leapp.workflow.Applications.selinuxapplycustom: Error installing modules in a single transaction:At least one mode must be specified.
---
.../common/actors/selinux/selinuxapplycustom/actor.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/repos/system_upgrade/common/actors/selinux/selinuxapplycustom/actor.py b/repos/system_upgrade/common/actors/selinux/selinuxapplycustom/actor.py
index 55c64c3e..4856f36a 100644
--- a/repos/system_upgrade/common/actors/selinux/selinuxapplycustom/actor.py
+++ b/repos/system_upgrade/common/actors/selinux/selinuxapplycustom/actor.py
@@ -92,6 +92,10 @@ class SELinuxApplyCustom(Actor):
command.extend(['-X', str(module.priority), '-i', cil_filename])
+ if command == ['semodule']:
+ # no modules selected for installation
+ continue
+
try:
run(command)
except CalledProcessError as e:
--
2.49.0

View File

@ -1,444 +0,0 @@
From 546d18f64deabe8440ac6d4ee707d7a5b69415db Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Mon, 15 Sep 2025 11:09:59 +0200
Subject: [PATCH 15/55] Generalize TargetRepositories
The RHELTargetRepository model is deprecated and replaced by the
DistroTargetRepository. The target TargetRepositories model is updated
accordingly.
TargetRepositories.rhel_repos are only filled on RHEL.
---
.../libraries/checktargetrepos.py | 4 ++-
.../tests/test_checktargetrepos.py | 32 +++++++++++++------
.../cloud/checkrhui/libraries/checkrhui.py | 5 ++-
.../tests/component_test_checkrhui.py | 1 +
.../libraries/setuptargetrepos.py | 29 +++++++++++------
.../libraries/setuptargetrepos_repomap.py | 4 +--
.../tests/test_setuptargetrepos.py | 22 ++++++++++---
.../libraries/userspacegen.py | 2 ++
.../tests/unit_test_targetuserspacecreator.py | 7 ++++
.../common/models/targetrepositories.py | 32 +++++++++++++++++--
10 files changed, 107 insertions(+), 31 deletions(-)
diff --git a/repos/system_upgrade/common/actors/checktargetrepos/libraries/checktargetrepos.py b/repos/system_upgrade/common/actors/checktargetrepos/libraries/checktargetrepos.py
index c286ed4f..141cf8e4 100644
--- a/repos/system_upgrade/common/actors/checktargetrepos/libraries/checktargetrepos.py
+++ b/repos/system_upgrade/common/actors/checktargetrepos/libraries/checktargetrepos.py
@@ -2,12 +2,14 @@ from leapp import reporting
from leapp.libraries.common import config, rhsm
from leapp.libraries.common.config.version import get_target_major_version
from leapp.libraries.stdlib import api
-from leapp.models import CustomTargetRepositoryFile, RHUIInfo, TargetRepositories
+from leapp.models import CustomTargetRepositoryFile, RHELTargetRepository, RHUIInfo, TargetRepositories
+from leapp.utils.deprecation import suppress_deprecation
# TODO: we need to provide this path in a shared library
CUSTOM_REPO_PATH = '/etc/leapp/files/leapp_upgrade_repositories.repo'
+@suppress_deprecation(RHELTargetRepository) # member of TargetRepositories
def _any_custom_repo_defined():
for tr in api.consume(TargetRepositories):
if tr.custom_repos:
diff --git a/repos/system_upgrade/common/actors/checktargetrepos/tests/test_checktargetrepos.py b/repos/system_upgrade/common/actors/checktargetrepos/tests/test_checktargetrepos.py
index c1ca8cd1..ea93ce7e 100644
--- a/repos/system_upgrade/common/actors/checktargetrepos/tests/test_checktargetrepos.py
+++ b/repos/system_upgrade/common/actors/checktargetrepos/tests/test_checktargetrepos.py
@@ -8,12 +8,11 @@ from leapp.libraries.stdlib import api
from leapp.models import (
CustomTargetRepository,
CustomTargetRepositoryFile,
- EnvVar,
- Report,
- RepositoryData,
+ DistroTargetRepository,
RHELTargetRepository,
TargetRepositories
)
+from leapp.utils.deprecation import suppress_deprecation
from leapp.utils.report import is_inhibitor
@@ -32,11 +31,21 @@ class MockedConsume(object):
return iter([msg for msg in self._msgs if isinstance(msg, model)])
-_RHEL_REPOS = [
- RHELTargetRepository(repoid='repo1'),
- RHELTargetRepository(repoid='repo2'),
- RHELTargetRepository(repoid='repo3'),
- RHELTargetRepository(repoid='repo4'),
+@suppress_deprecation(RHELTargetRepository)
+def _test_rhel_repos():
+ return [
+ RHELTargetRepository(repoid='repo1'),
+ RHELTargetRepository(repoid='repo2'),
+ RHELTargetRepository(repoid='repo3'),
+ RHELTargetRepository(repoid='repo4'),
+ ]
+
+
+_DISTRO_REPOS = [
+ DistroTargetRepository(repoid='repo1'),
+ DistroTargetRepository(repoid='repo2'),
+ DistroTargetRepository(repoid='repo3'),
+ DistroTargetRepository(repoid='repo4'),
]
_CUSTOM_REPOS = [
@@ -46,8 +55,10 @@ _CUSTOM_REPOS = [
CustomTargetRepository(repoid='repo4', name='repo4name', baseurl=None, enabled=True),
]
-_TARGET_REPOS_CUSTOM = TargetRepositories(rhel_repos=_RHEL_REPOS, custom_repos=_CUSTOM_REPOS)
-_TARGET_REPOS_NO_CUSTOM = TargetRepositories(rhel_repos=_RHEL_REPOS)
+_TARGET_REPOS_CUSTOM = TargetRepositories(
+ rhel_repos=_test_rhel_repos(), distro_repos=_DISTRO_REPOS, custom_repos=_CUSTOM_REPOS
+)
+_TARGET_REPOS_NO_CUSTOM = TargetRepositories(rhel_repos=_test_rhel_repos(), distro_repos=_DISTRO_REPOS)
_CUSTOM_TARGET_REPOFILE = CustomTargetRepositoryFile(file='/etc/leapp/files/leapp_upgrade_repositories.repo')
@@ -55,6 +66,7 @@ def test_checktargetrepos_rhsm(monkeypatch):
monkeypatch.setattr(reporting, 'create_report', create_report_mocked())
monkeypatch.setattr(rhsm, 'skip_rhsm', lambda: False)
monkeypatch.setattr(api, 'consume', MockedConsume())
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked())
monkeypatch.setattr(checktargetrepos, 'get_target_major_version', lambda: '8')
checktargetrepos.process()
assert reporting.create_report.called == 0
diff --git a/repos/system_upgrade/common/actors/cloud/checkrhui/libraries/checkrhui.py b/repos/system_upgrade/common/actors/cloud/checkrhui/libraries/checkrhui.py
index ea154173..5dcdd967 100644
--- a/repos/system_upgrade/common/actors/cloud/checkrhui/libraries/checkrhui.py
+++ b/repos/system_upgrade/common/actors/cloud/checkrhui/libraries/checkrhui.py
@@ -22,6 +22,7 @@ from leapp.models import (
CustomTargetRepository,
DNFPluginTask,
InstalledRPM,
+ RHELTargetRepository,
RHUIInfo,
RpmTransactionTasks,
TargetRepositories,
@@ -30,6 +31,7 @@ from leapp.models import (
TargetRHUISetupInfo,
TargetUserSpacePreupgradeTasks
)
+from leapp.utils.deprecation import suppress_deprecation
MatchingSetup = namedtuple('MatchingSetup', ['family', 'description'])
@@ -370,11 +372,12 @@ def emit_rhui_setup_tasks_based_on_config(rhui_config_dict):
api.produce(rhui_info)
+@suppress_deprecation(RHELTargetRepository) # member of TargetRepositories
def request_configured_repos_to_be_enabled(rhui_config):
config_repos_to_enable = rhui_config[RhuiTargetRepositoriesToUse.name]
custom_repos = [CustomTargetRepository(repoid=repoid) for repoid in config_repos_to_enable]
if custom_repos:
- target_repos = TargetRepositories(custom_repos=custom_repos, rhel_repos=[])
+ target_repos = TargetRepositories(custom_repos=custom_repos, rhel_repos=[], distro_repos=[])
api.produce(target_repos)
diff --git a/repos/system_upgrade/common/actors/cloud/checkrhui/tests/component_test_checkrhui.py b/repos/system_upgrade/common/actors/cloud/checkrhui/tests/component_test_checkrhui.py
index 3ac9c1b8..02ca352e 100644
--- a/repos/system_upgrade/common/actors/cloud/checkrhui/tests/component_test_checkrhui.py
+++ b/repos/system_upgrade/common/actors/cloud/checkrhui/tests/component_test_checkrhui.py
@@ -468,6 +468,7 @@ def test_request_configured_repos_to_be_enabled(monkeypatch):
target_repos = api.produce.model_instances[0]
assert isinstance(target_repos, TargetRepositories)
+ assert not target_repos.distro_repos
assert not target_repos.rhel_repos
custom_repoids = sorted(custom_repo_model.repoid for custom_repo_model in target_repos.custom_repos)
diff --git a/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos.py b/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos.py
index a6073aa3..9e5b1334 100644
--- a/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos.py
+++ b/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos.py
@@ -1,9 +1,10 @@
-
from leapp.libraries.actor import setuptargetrepos_repomap
+from leapp.libraries.common.config import get_distro_id
from leapp.libraries.common.config.version import get_source_major_version, get_source_version, get_target_version
from leapp.libraries.stdlib import api
from leapp.models import (
CustomTargetRepository,
+ DistroTargetRepository,
InstalledRPM,
RepositoriesBlacklisted,
RepositoriesFacts,
@@ -15,6 +16,7 @@ from leapp.models import (
TargetRepositories,
UsedRepositories
)
+from leapp.utils.deprecation import suppress_deprecation
RHUI_CLIENT_REPOIDS_RHEL88_TO_RHEL810 = {
'rhui-microsoft-azure-rhel8-sapapps': 'rhui-microsoft-azure-rhel8-base-sap-apps',
@@ -80,6 +82,7 @@ def _get_mapped_repoids(repomap, src_repoids):
return mapped_repoids
+@suppress_deprecation(RHELTargetRepository)
def process():
# Load relevant data from messages
used_repoids_dict = _get_used_repo_dict()
@@ -103,10 +106,11 @@ def process():
# installed packages that have mapping to prevent missing repositories that are disabled during the upgrade, but
# can be used to upgrade installed packages.
repoids_to_map = enabled_repoids.union(repoids_from_installed_packages_with_mapping)
+ is_rhel = get_distro_id() == 'rhel'
# RHEL8.10 use a different repoid for client repository, but the repomapping mechanism cannot distinguish these
# as it does not use minor versions. Therefore, we have to hardcode these changes.
- if get_source_version() == '8.10':
+ if is_rhel and get_source_version() == '8.10':
for rhel88_rhui_client_repoid, rhel810_rhui_client_repoid in RHUI_CLIENT_REPOIDS_RHEL88_TO_RHEL810.items():
if rhel810_rhui_client_repoid in repoids_to_map:
# Replace RHEL8.10 rhui client repoids with RHEL8.8 repoids,
@@ -119,9 +123,9 @@ def process():
default_channels = setuptargetrepos_repomap.get_default_repository_channels(repomap, repoids_to_map)
repomap.set_default_channels(default_channels)
- # Get target RHEL repoids based on the repomap
+ # Get target distro repoids based on the repomap
expected_repos = repomap.get_expected_target_pesid_repos(repoids_to_map)
- target_rhel_repoids = set()
+ target_distro_repoids = set()
for target_pesid, target_pesidrepo in expected_repos.items():
if not target_pesidrepo:
# NOTE this could happen only for enabled repositories part of the set,
@@ -139,7 +143,7 @@ def process():
if target_pesidrepo.repoid in excluded_repoids:
api.current_logger().debug('Skipping the {} repo (excluded).'.format(target_pesidrepo.repoid))
continue
- target_rhel_repoids.add(target_pesidrepo.repoid)
+ target_distro_repoids.add(target_pesidrepo.repoid)
# FIXME: this could possibly result into a try to enable multiple repositories
# from the same family (pesid). But unless we have a bug in previous actors,
@@ -151,7 +155,7 @@ def process():
if repo in excluded_repoids:
api.current_logger().debug('Skipping the {} repo from setup task (excluded).'.format(repo))
continue
- target_rhel_repoids.add(repo)
+ target_distro_repoids.add(repo)
# On 8.10, some RHUI setups have different names than the one computed by repomapping.
# Although such situation could be avoided (having another client repo when a single
@@ -159,12 +163,16 @@ def process():
# solution.
if get_target_version() == '8.10':
for pre_810_repoid, post_810_repoid in RHUI_CLIENT_REPOIDS_RHEL88_TO_RHEL810.items():
- if pre_810_repoid in target_rhel_repoids:
- target_rhel_repoids.remove(pre_810_repoid)
- target_rhel_repoids.add(post_810_repoid)
+ if pre_810_repoid in target_distro_repoids:
+ target_distro_repoids.remove(pre_810_repoid)
+ target_distro_repoids.add(post_810_repoid)
# create the final lists and sort them (for easier testing)
- rhel_repos = [RHELTargetRepository(repoid=repoid) for repoid in sorted(target_rhel_repoids)]
+ if is_rhel:
+ rhel_repos = [RHELTargetRepository(repoid=repoid) for repoid in sorted(target_distro_repoids)]
+ else:
+ rhel_repos = []
+ distro_repos = [DistroTargetRepository(repoid=repoid) for repoid in sorted(target_distro_repoids)]
custom_repos = [repo for repo in custom_repos if repo.repoid not in excluded_repoids]
custom_repos = sorted(custom_repos, key=lambda x: x.repoid)
@@ -179,5 +187,6 @@ def process():
api.produce(TargetRepositories(
rhel_repos=rhel_repos,
+ distro_repos=distro_repos,
custom_repos=custom_repos,
))
diff --git a/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos_repomap.py b/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos_repomap.py
index 37be03f1..343ee2ea 100644
--- a/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos_repomap.py
+++ b/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos_repomap.py
@@ -1,4 +1,4 @@
-from leapp.libraries.common.config import get_target_product_channel
+from leapp.libraries.common.config import get_distro_id, get_target_product_channel
from leapp.libraries.common.config.version import get_source_major_version, get_target_major_version
from leapp.libraries.stdlib import api
@@ -44,7 +44,7 @@ class RepoMapDataHandler(object):
# ideal for work, but there is not any significant impact..
self.repositories = repo_map.repositories
self.mapping = repo_map.mapping
- self.distro = distro or api.current_actor().configuration.os_release.release_id
+ self.distro = distro or get_distro_id()
# FIXME(pstodulk): what about default_channel -> fallback_channel
# hardcoded always as ga? instead of list of channels..
# it'd be possibly confusing naming now...
diff --git a/repos/system_upgrade/common/actors/setuptargetrepos/tests/test_setuptargetrepos.py b/repos/system_upgrade/common/actors/setuptargetrepos/tests/test_setuptargetrepos.py
index 1f898e8f..e4a30f7f 100644
--- a/repos/system_upgrade/common/actors/setuptargetrepos/tests/test_setuptargetrepos.py
+++ b/repos/system_upgrade/common/actors/setuptargetrepos/tests/test_setuptargetrepos.py
@@ -198,11 +198,23 @@ def test_repos_mapping_for_distro(monkeypatch, distro_id):
setuptargetrepos.process()
assert api.produce.called
+ distro_repos = api.produce.model_instances[0].distro_repos
rhel_repos = api.produce.model_instances[0].rhel_repos
- assert len(rhel_repos) == 3
+ assert len(distro_repos) == 3
+
+ produced_distro_repoids = {repo.repoid for repo in distro_repos}
produced_rhel_repoids = {repo.repoid for repo in rhel_repos}
- expected_rhel_repoids = {'{0}-8-for-x86_64-baseos-htb-rpms'.format(distro_id),
- '{0}-8-for-x86_64-appstream-htb-rpms'.format(distro_id),
- '{0}-8-for-x86_64-satellite-extras-rpms'.format(distro_id)}
- assert produced_rhel_repoids == expected_rhel_repoids
+
+ expected_repoids = {
+ "{0}-8-for-x86_64-baseos-htb-rpms".format(distro_id),
+ "{0}-8-for-x86_64-appstream-htb-rpms".format(distro_id),
+ "{0}-8-for-x86_64-satellite-extras-rpms".format(distro_id),
+ }
+
+ assert produced_distro_repoids == expected_repoids
+ if distro_id == 'rhel':
+ assert len(rhel_repos) == 3
+ assert produced_rhel_repoids == expected_repoids
+ else:
+ assert len(rhel_repos) == 0
diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
index 55877d05..407cb0b7 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
@@ -17,6 +17,7 @@ from leapp.models import (
CustomTargetRepositoryFile,
PkgManagerInfo,
RepositoriesFacts,
+ RHELTargetRepository,
RHSMInfo,
RHUIInfo,
StorageInfo,
@@ -967,6 +968,7 @@ def _get_rh_available_repoids(context, indata):
return rh_repoids
+@suppress_deprecation(RHELTargetRepository) # member of TargetRepositories
def gather_target_repositories(context, indata):
"""
Get available required target repositories and inhibit or raise error if basic checks do not pass.
diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py b/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
index 7853a7ad..f05e6bc2 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
@@ -1072,6 +1072,7 @@ def test_consume_data(monkeypatch, raised, no_rhsm, testdata):
@pytest.mark.skip(reason="Currently not implemented in the actor. It's TODO.")
+@suppress_deprecation(models.RHELTargetRepository)
def test_gather_target_repositories(monkeypatch):
monkeypatch.setattr(userspacegen.api, 'current_actor', CurrentActorMocked())
# The available RHSM repos
@@ -1104,6 +1105,7 @@ def test_gather_target_repositories_none_available(monkeypatch):
assert inhibitors[0].get('title', '') == 'Cannot find required basic RHEL target repositories.'
+@suppress_deprecation(models.RHELTargetRepository)
def test_gather_target_repositories_rhui(monkeypatch):
indata = testInData(
@@ -1122,6 +1124,10 @@ def test_gather_target_repositories_rhui(monkeypatch):
rhel_repos=[
models.RHELTargetRepository(repoid='rhui-1'),
models.RHELTargetRepository(repoid='rhui-2')
+ ],
+ distro_repos=[
+ models.DistroTargetRepository(repoid='rhui-1'),
+ models.DistroTargetRepository(repoid='rhui-2')
]
)
])
@@ -1130,6 +1136,7 @@ def test_gather_target_repositories_rhui(monkeypatch):
assert target_repoids == set(['rhui-1', 'rhui-2'])
+@suppress_deprecation(models.RHELTargetRepository)
def test_gather_target_repositories_baseos_appstream_not_available(monkeypatch):
# If the repos that Leapp identifies as required for the upgrade (based on the repo mapping and PES data) are not
# available, an exception shall be raised
diff --git a/repos/system_upgrade/common/models/targetrepositories.py b/repos/system_upgrade/common/models/targetrepositories.py
index 02c6c5e5..e1a0b646 100644
--- a/repos/system_upgrade/common/models/targetrepositories.py
+++ b/repos/system_upgrade/common/models/targetrepositories.py
@@ -1,4 +1,5 @@
from leapp.models import fields, Model
+from leapp.reporting import deprecated
from leapp.topics import TransactionTopic
@@ -11,10 +12,18 @@ class UsedTargetRepository(TargetRepositoryBase):
pass
+@deprecated(
+ since="2025-07-23",
+ message="This model is deprecated, use DistroTargetRepository instead.",
+)
class RHELTargetRepository(TargetRepositoryBase):
pass
+class DistroTargetRepository(TargetRepositoryBase):
+ pass
+
+
class CustomTargetRepository(TargetRepositoryBase):
name = fields.Nullable(fields.String())
baseurl = fields.Nullable(fields.String())
@@ -26,20 +35,39 @@ class TargetRepositories(Model):
Repositories supposed to be used during the IPU process
The list of the actually used repositories could be just subset
- of these repositoies. In case of `custom_repositories`, all such repositories
+ of these repositories. In case of `custom_repositories`, all such repositories
must be available otherwise the upgrade is inhibited. But in case of
- `rhel_repos`, only BaseOS and Appstream repos are required now. If others
+ `distro_repos`, only BaseOS and Appstream repos are required now. If others
are missing, upgrade can still continue.
+
+ Note: `rhel_repos` are deprecated, use `distro_repos` instead.
"""
topic = TransactionTopic
+
+ # DEPRECATED: this has been superseded by distro_repos
rhel_repos = fields.List(fields.Model(RHELTargetRepository))
"""
Expected target YUM RHEL repositories provided via RHSM
+ DEPRECATED - use distro_repos instead.
+
These repositories are stored inside /etc/yum.repos.d/redhat.repo and
are expected to be used based on the provided repositories mapping.
"""
+ distro_repos = fields.List(fields.Model(DistroTargetRepository))
+ """
+ Expected target DNF repositories provided by the distribution.
+
+ On RHEL these are the repositories provided via RHSM.
+ These repositories are stored inside /etc/yum.repos.d/redhat.repo and
+ are expected to be used based on the provided repositories mapping.
+
+ On other distributions, such as Centos Stream these are repositories
+ in /etc/yum.repos.d/ that are provided by the distribution and are expected
+ to be used based on the provided repositories mapping.
+ """
+
custom_repos = fields.List(fields.Model(CustomTargetRepository), default=[])
"""
Custom YUM repositories required to be used for the IPU
--
2.51.1

View File

@ -0,0 +1,213 @@
From 57dce775de28615260189a6612fe65e44a7d3bc9 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Sat, 29 Mar 2025 21:41:48 +0100
Subject: [PATCH 15/37] feat(ipuconfig): provide info about supported upgrade
paths
At the moment, information about supported upgrade paths is provided via
a deprecated IPUPaths message. The current solution is temporary.
This patch introduces new field in IPUConfig called
'supported_upgrade_paths' that contains a "compressed", pre-filtered,
list of upgrade paths. The decision to introduce this new field is
because we want to refactor the config.version library to not contain
its own supported upgrade paths definitions. Instead, we want to have the
information represented only once. Therefore, in order to refactor
config.version to use the information received by a message, we need
the new field on IPUConfig as we cannot force already-written actors
using config.version to add some message to their 'consumes' list.
Jira-ref: RHEL-80550
---
.../libraries/ipuworkflowconfig.py | 28 ++++++++++++++++++-
.../common/libraries/config/mock_configs.py | 14 +++++++++-
.../common/libraries/testutils.py | 20 +++++++++----
.../system_upgrade/common/models/ipuconfig.py | 22 +++++++++++++++
4 files changed, 77 insertions(+), 7 deletions(-)
diff --git a/repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py b/repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py
index 749b3347..86df709e 100644
--- a/repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py
+++ b/repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py
@@ -85,6 +85,27 @@ def check_target_major_version(curr_version, target_version):
)
+def load_raw_upgrade_paths_for_flavour(flavour='default', paths_definition_file='upgrade_paths.json'):
+ with open(api.get_common_file_path(paths_definition_file)) as fp:
+ data = json.loads(fp.read())
+
+ raw_upgrade_paths = data.get(flavour, {})
+
+ if not raw_upgrade_paths:
+ api.current_logger().warning('Cannot discover any upgrade paths for flavour: {}'.format(flavour))
+
+ return raw_upgrade_paths
+
+
+def construct_models_for_paths_matching_source_major(raw_paths, src_major_version):
+ multipaths_matching_source = []
+ for src_version, target_versions in ipu_paths.items():
+ if src_version.split('.')[0] == src_major_version:
+ source_to_targets = IPUSourceToPossibleTargets(source_version=src_version, target_versions=target_versions)
+ multipaths_matching_source.append()
+ return multipaths_matching_source
+
+
def produce_ipu_config(actor):
flavour = os.environ.get('LEAPP_UPGRADE_PATH_FLAVOUR')
target_version = os.environ.get('LEAPP_UPGRADE_PATH_TARGET_RELEASE')
@@ -93,6 +114,10 @@ def produce_ipu_config(actor):
check_target_major_version(source_version, target_version)
+ raw_upgrade_paths = load_raw_upgrade_paths_for_flavour(flavour)
+ source_major_version = source_version.split('.')[0]
+ exposed_supported_paths = construct_models_for_paths_matching_source_major(raw_upgrade_paths, source_major_version)
+
actor.produce(IPUConfig(
leapp_env_vars=get_env_vars(),
os_release=os_release,
@@ -102,5 +127,6 @@ def produce_ipu_config(actor):
target=target_version
),
kernel=get_booted_kernel(),
- flavour=flavour
+ flavour=flavour,
+ supported_upgrade_paths=exposed_supported_paths
))
diff --git a/repos/system_upgrade/common/libraries/config/mock_configs.py b/repos/system_upgrade/common/libraries/config/mock_configs.py
index ee9dd760..a1c9c0fd 100644
--- a/repos/system_upgrade/common/libraries/config/mock_configs.py
+++ b/repos/system_upgrade/common/libraries/config/mock_configs.py
@@ -6,7 +6,7 @@ The library is supposed to be used only for testing purposes. Import of the
library is expected only inside test files.
"""
-from leapp.models import EnvVar, IPUConfig, OSRelease, Version
+from leapp.models import EnvVar, IPUConfig, IPUSourceToPossibleTargets, OSRelease, Version
CONFIG = IPUConfig(
leapp_env_vars=[EnvVar(name='LEAPP_DEVEL', value='0')],
@@ -23,6 +23,9 @@ CONFIG = IPUConfig(
),
architecture='x86_64',
kernel='3.10.0-957.43.1.el7.x86_64',
+ supported_upgrade_paths=[
+ IPUSourceToPossibleTargets(source_version='7.6', target_versions=['8.0'])
+ ]
)
CONFIG_NO_NETWORK_RENAMING = IPUConfig(
@@ -40,6 +43,9 @@ CONFIG_NO_NETWORK_RENAMING = IPUConfig(
),
architecture='x86_64',
kernel='3.10.0-957.43.1.el7.x86_64',
+ supported_upgrade_paths=[
+ IPUSourceToPossibleTargets(source_version='7.6', target_versions=['8.0'])
+ ]
)
CONFIG_ALL_SIGNED = IPUConfig(
@@ -57,6 +63,9 @@ CONFIG_ALL_SIGNED = IPUConfig(
),
architecture='x86_64',
kernel='3.10.0-957.43.1.el7.x86_64',
+ supported_upgrade_paths=[
+ IPUSourceToPossibleTargets(source_version='7.6', target_versions=['8.0'])
+ ]
)
CONFIG_S390X = IPUConfig(
@@ -73,4 +82,7 @@ CONFIG_S390X = IPUConfig(
),
architecture='s390x',
kernel='3.10.0-957.43.1.el7.x86_64',
+ supported_upgrade_paths=[
+ IPUSourceToPossibleTargets(source_version='7.6', target_versions=['8.0'])
+ ]
)
diff --git a/repos/system_upgrade/common/libraries/testutils.py b/repos/system_upgrade/common/libraries/testutils.py
index afeb360a..1b3c3683 100644
--- a/repos/system_upgrade/common/libraries/testutils.py
+++ b/repos/system_upgrade/common/libraries/testutils.py
@@ -6,7 +6,7 @@ from collections import namedtuple
from leapp import reporting
from leapp.actors.config import _normalize_config, normalize_schemas
from leapp.libraries.common.config import architecture
-from leapp.models import EnvVar
+from leapp.models import EnvVar, IPUSourceToPossibleTargets
from leapp.utils.deprecation import deprecated
@@ -76,7 +76,11 @@ def _make_default_config(actor_config_schema):
class CurrentActorMocked(object): # pylint:disable=R0904
def __init__(self, arch=architecture.ARCH_X86_64, envars=None, kernel='3.10.0-957.43.1.el7.x86_64',
- release_id='rhel', src_ver='7.8', dst_ver='8.1', msgs=None, flavour='default', config=None):
+ release_id='rhel', src_ver='7.8', dst_ver='8.1', msgs=None, flavour='default', config=None,
+ supported_upgrade_paths=None):
+ """
+ :param List[IPUSourceToPossibleTargets] supported_upgrade_paths: List of supported upgrade paths.
+ """
envarsList = [EnvVar(name=k, value=v) for k, v in envars.items()] if envars else []
version = namedtuple('Version', ['source', 'target'])(src_ver, dst_ver)
release = namedtuple('OS_release', ['release_id', 'version_id'])(release_id, src_ver)
@@ -85,9 +89,15 @@ class CurrentActorMocked(object): # pylint:disable=R0904
self._common_tools_folder = '../../tools'
self._actor_folder = 'files'
self._actor_tools_folder = 'tools'
- self.configuration = namedtuple(
- 'configuration', ['architecture', 'kernel', 'leapp_env_vars', 'os_release', 'version', 'flavour']
- )(arch, kernel, envarsList, release, version, flavour)
+
+ if not supported_upgrade_paths:
+ supported_upgrade_paths = [IPUSourceToPossibleTargets(source_version=src_ver, target_versions=[dst_ver])]
+
+ ipu_conf_fields = ['architecture', 'kernel', 'leapp_env_vars', 'os_release',
+ 'version', 'flavour', 'supported_upgrade_paths']
+ config_type = namedtuple('configuration', ipu_conf_fields)
+ self.configuration = config_type(arch, kernel, envarsList, release, version, flavour, supported_upgrade_paths)
+
self._msgs = msgs or []
self.config = {} if config is None else config
diff --git a/repos/system_upgrade/common/models/ipuconfig.py b/repos/system_upgrade/common/models/ipuconfig.py
index 6e7e21b5..0a16b603 100644
--- a/repos/system_upgrade/common/models/ipuconfig.py
+++ b/repos/system_upgrade/common/models/ipuconfig.py
@@ -34,6 +34,21 @@ class Version(Model):
"""Version of the target system. E.g. '8.2.'."""
+class IPUSourceToPossibleTargets(Model):
+ """
+ Represents upgrade paths from a source system version.
+
+ This model is not supposed to be produced nor consumed directly by any actor.
+ """
+ topic = SystemInfoTopic
+
+ source_version = fields.String()
+ """Source system version."""
+
+ target_versions = fields.List(fields.String())
+ """List of defined target system versions for the `source_version` system."""
+
+
class IPUConfig(Model):
"""
IPU workflow configuration model
@@ -59,3 +74,10 @@ class IPUConfig(Model):
flavour = fields.StringEnum(('default', 'saphana'), default='default')
"""Flavour of the upgrade - Used to influence changes in supported source/target release"""
+
+ supported_upgrade_paths = fields.List(fields.Model(IPUSourceToPossibleTargets))
+ """
+ List of supported upgrade paths.
+
+ The list contains only upgrade paths for the `flavour` of the source system.
+ """
--
2.49.0

View File

@ -1,65 +0,0 @@
From e61718d44e0175bcd28c8a5ee44dc46880d74482 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Tue, 5 Aug 2025 12:20:23 +0200
Subject: [PATCH 16/55] checktargetrepos: Skip if not RHEL
Skip the target repos check on non-RHEL distros. On non-RHEL distros,
there is no subscription-manager. The base repositories (BaseOS,
AppStream, ...) should always be present.
This is checked using the seatbelts in target userspace creator.
---
.../system_upgrade/common/actors/checktargetrepos/actor.py | 4 +++-
.../actors/checktargetrepos/libraries/checktargetrepos.py | 7 ++++---
.../actors/checktargetrepos/tests/test_checktargetrepos.py | 2 --
3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/repos/system_upgrade/common/actors/checktargetrepos/actor.py b/repos/system_upgrade/common/actors/checktargetrepos/actor.py
index d61fb685..a5bdde10 100644
--- a/repos/system_upgrade/common/actors/checktargetrepos/actor.py
+++ b/repos/system_upgrade/common/actors/checktargetrepos/actor.py
@@ -6,7 +6,9 @@ from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
class Checktargetrepos(Actor):
"""
- Check whether target yum repositories are specified.
+ Check whether target dnf repositories are specified on RHEL.
+
+ NOTE: this actor does nothing on distros other than RHEL.
RHSM | RHUI | ER | CTR | CTRF || result
-----+------+----+-----+------++-------
diff --git a/repos/system_upgrade/common/actors/checktargetrepos/libraries/checktargetrepos.py b/repos/system_upgrade/common/actors/checktargetrepos/libraries/checktargetrepos.py
index 141cf8e4..ea21e1de 100644
--- a/repos/system_upgrade/common/actors/checktargetrepos/libraries/checktargetrepos.py
+++ b/repos/system_upgrade/common/actors/checktargetrepos/libraries/checktargetrepos.py
@@ -40,9 +40,10 @@ def process():
rhui_info = next(api.consume(RHUIInfo), None)
- if not rhsm.skip_rhsm() or rhui_info:
- # getting RH repositories through RHSM or RHUI; resolved by seatbelts
- # implemented in other actors
+ if config.get_distro_id() != 'rhel' or (not rhsm.skip_rhsm() or rhui_info):
+ # RHEL: getting RH repositories through RHSM or RHUI;
+ # resolved by seatbelts in other actors
+ # other: distro repos provided by the distro directly, seatbelts elsewhere
return
# rhsm skipped; take your seatbelts please
diff --git a/repos/system_upgrade/common/actors/checktargetrepos/tests/test_checktargetrepos.py b/repos/system_upgrade/common/actors/checktargetrepos/tests/test_checktargetrepos.py
index ea93ce7e..e055b3a6 100644
--- a/repos/system_upgrade/common/actors/checktargetrepos/tests/test_checktargetrepos.py
+++ b/repos/system_upgrade/common/actors/checktargetrepos/tests/test_checktargetrepos.py
@@ -65,9 +65,7 @@ _CUSTOM_TARGET_REPOFILE = CustomTargetRepositoryFile(file='/etc/leapp/files/leap
def test_checktargetrepos_rhsm(monkeypatch):
monkeypatch.setattr(reporting, 'create_report', create_report_mocked())
monkeypatch.setattr(rhsm, 'skip_rhsm', lambda: False)
- monkeypatch.setattr(api, 'consume', MockedConsume())
monkeypatch.setattr(api, 'current_actor', CurrentActorMocked())
- monkeypatch.setattr(checktargetrepos, 'get_target_major_version', lambda: '8')
checktargetrepos.process()
assert reporting.create_report.called == 0
--
2.51.1

View File

@ -0,0 +1,381 @@
From 6bfb0ae05f8ac05f34b5974a85ae5a703ada72b0 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Sat, 29 Mar 2025 21:56:07 +0100
Subject: [PATCH 16/37] feat(upgrade_paths): include information about distro
id
This patch tweaks upgrade_paths.json and the code reading it to contain
information about what for what distro are the upgrade paths defined.
This allows the upgrade tooling to possibly support also other distros,
such as CentOS Stream. However, this patch is only a small step towards
such a goal and further work is needed to support these systems.
Jira-ref: RHEL-80550
---
commands/command_utils.py | 28 ++++--
commands/tests/test_upgrade_paths.py | 15 ++--
.../libraries/ipuworkflowconfig.py | 35 +++++---
.../tests/test_ipuworkflowconfig.py | 85 ++++++++++++++++++-
.../tests/files/upgrade_paths.json | 29 ++++---
.../common/files/upgrade_paths.json | 36 +++++---
6 files changed, 177 insertions(+), 51 deletions(-)
diff --git a/commands/command_utils.py b/commands/command_utils.py
index 84b9de1b..a13ca59b 100644
--- a/commands/command_utils.py
+++ b/commands/command_utils.py
@@ -71,15 +71,24 @@ def get_upgrade_flavour():
return LEAPP_UPGRADE_FLAVOUR_DEFAULT
+def _retrieve_os_release_contents(_os_release_path='/etc/os-release'):
+ """
+ Retrieve the contents of /etc/os-release
+
+ :rtype: dict[str, str]
+ """
+ with open(_os_release_path) as os_release_handle:
+ lines = os_release_handle.readlines()
+ return dict(line.strip().split('=', 1) for line in lines if '=' in line)
+
+
def get_os_release_version_id(filepath):
"""
Retrieve data about System OS release from provided file.
:return: `str` version_id
"""
- with open(filepath) as f:
- data = dict(l.strip().split('=', 1) for l in f.readlines() if '=' in l)
- return data.get('VERSION_ID', '').strip('"')
+ return _retrieve_os_release_contents(_os_release_path=filepath).get('VERSION_ID', '').strip('"')
def get_upgrade_paths_config():
@@ -92,13 +101,13 @@ def get_upgrade_paths_config():
return upgrade_paths_map
-def get_target_versions_from_config(src_version_id, flavor):
+def get_target_versions_from_config(src_version_id, distro, flavor):
"""
Retrieve all possible target versions from upgrade_paths_map.
If no match is found returns empty list.
"""
upgrade_paths_map = get_upgrade_paths_config()
- return upgrade_paths_map.get(flavor, {}).get(src_version_id, [])
+ return upgrade_paths_map.get(distro, {}).get(flavor, {}).get(src_version_id, [])
def get_supported_target_versions(flavour=get_upgrade_flavour()):
@@ -107,14 +116,17 @@ def get_supported_target_versions(flavour=get_upgrade_flavour()):
The default value for `flavour` is `default`.
"""
- current_version_id = get_os_release_version_id('/etc/os-release')
- target_versions = get_target_versions_from_config(current_version_id, flavour)
+ os_release_contents = _retrieve_os_release_contents()
+ current_version_id = os_release_contents.get('VERSION_ID', '').strip('"')
+ distro_id = os_release_contents.get('ID', '').strip('"')
+
+ target_versions = get_target_versions_from_config(current_version_id, distro_id, flavour)
if not target_versions:
# If we cannot find a particular major.minor version in the map,
# we fallback to pick a target version just based on a major version.
# This can happen for example when testing not yet released versions
major_version = get_major_version(current_version_id)
- target_versions = get_target_versions_from_config(major_version, flavour)
+ target_versions = get_target_versions_from_config(major_version, distro_id, flavour)
return target_versions
diff --git a/commands/tests/test_upgrade_paths.py b/commands/tests/test_upgrade_paths.py
index f1312f66..c2cb09aa 100644
--- a/commands/tests/test_upgrade_paths.py
+++ b/commands/tests/test_upgrade_paths.py
@@ -8,19 +8,24 @@ from leapp.exceptions import CommandError
@mock.patch("leapp.cli.commands.command_utils.get_upgrade_paths_config",
- return_value={"default": {"7.9": ["8.4"], "8.6": ["9.0"], "7": ["8.4"], "8": ["9.0"]}})
+ return_value={'rhel': {"default": {"7.9": ["8.4"], "8.6": ["9.0"], "7": ["8.4"], "8": ["9.0"]}}})
def test_get_target_version(mock_open, monkeypatch):
-
- monkeypatch.setattr(command_utils, 'get_os_release_version_id', lambda x: '8.6')
+ etc_os_release_contents = {'ID': 'rhel', 'VERSION_ID': '8.6'}
+ monkeypatch.setattr(command_utils, '_retrieve_os_release_contents',
+ lambda *args, **kwargs: etc_os_release_contents)
assert command_utils.get_target_version('default') == '9.0'
monkeypatch.setenv('LEAPP_DEVEL_TARGET_RELEASE', '')
- monkeypatch.setattr(command_utils, 'get_os_release_version_id', lambda x: '8.6')
+ etc_os_release_contents = {'ID': 'rhel', 'VERSION_ID': '8.6'}
+ monkeypatch.setattr(command_utils, '_retrieve_os_release_contents',
+ lambda *args, **kwargs: etc_os_release_contents)
assert command_utils.get_target_version('default') == '9.0'
monkeypatch.delenv('LEAPP_DEVEL_TARGET_RELEASE', raising=True)
# unsupported path
- monkeypatch.setattr(command_utils, 'get_os_release_version_id', lambda x: '8.5')
+ etc_os_release_contents = {'ID': 'rhel', 'VERSION_ID': '8.5'}
+ monkeypatch.setattr(command_utils, '_retrieve_os_release_contents',
+ lambda *args, **kwargs: etc_os_release_contents)
assert command_utils.get_target_version('default') == '9.0'
diff --git a/repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py b/repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py
index 86df709e..35f61669 100644
--- a/repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py
+++ b/repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py
@@ -1,9 +1,10 @@
+import json
import os
import platform
from leapp.exceptions import StopActorExecutionError
-from leapp.libraries.stdlib import CalledProcessError, run
-from leapp.models import EnvVar, IPUConfig, OSRelease, Version
+from leapp.libraries.stdlib import api, CalledProcessError, run
+from leapp.models import EnvVar, IPUConfig, IPUSourceToPossibleTargets, OSRelease, Version
ENV_IGNORE = ('LEAPP_CURRENT_PHASE', 'LEAPP_CURRENT_ACTOR', 'LEAPP_VERBOSE',
'LEAPP_DEBUG')
@@ -85,24 +86,34 @@ def check_target_major_version(curr_version, target_version):
)
-def load_raw_upgrade_paths_for_flavour(flavour='default', paths_definition_file='upgrade_paths.json'):
+def load_upgrade_paths_definitions(paths_definition_file):
with open(api.get_common_file_path(paths_definition_file)) as fp:
- data = json.loads(fp.read())
+ definitions = json.loads(fp.read())
+ return definitions
- raw_upgrade_paths = data.get(flavour, {})
- if not raw_upgrade_paths:
- api.current_logger().warning('Cannot discover any upgrade paths for flavour: {}'.format(flavour))
+def load_raw_upgrade_paths_for_distro_and_flavour(distro_id, flavour, paths_definition_file='upgrade_paths.json'):
+ all_definitions = load_upgrade_paths_definitions(paths_definition_file)
+ raw_upgrade_paths_for_distro = all_definitions.get(distro_id, {})
- return raw_upgrade_paths
+ if not raw_upgrade_paths_for_distro:
+ api.current_logger().warning('No upgrade paths defined for distro \'{}\''.format(distro_id))
+
+ raw_upgrade_paths_for_flavour = raw_upgrade_paths_for_distro.get(flavour, {})
+
+ if not raw_upgrade_paths_for_flavour:
+ api.current_logger().warning('Cannot discover any upgrade paths for flavour: {}/{}'.format(distro_id, flavour))
+
+ return raw_upgrade_paths_for_flavour
def construct_models_for_paths_matching_source_major(raw_paths, src_major_version):
multipaths_matching_source = []
- for src_version, target_versions in ipu_paths.items():
+ for src_version, target_versions in raw_paths.items():
if src_version.split('.')[0] == src_major_version:
- source_to_targets = IPUSourceToPossibleTargets(source_version=src_version, target_versions=target_versions)
- multipaths_matching_source.append()
+ source_to_targets = IPUSourceToPossibleTargets(source_version=src_version,
+ target_versions=target_versions)
+ multipaths_matching_source.append(source_to_targets)
return multipaths_matching_source
@@ -114,7 +125,7 @@ def produce_ipu_config(actor):
check_target_major_version(source_version, target_version)
- raw_upgrade_paths = load_raw_upgrade_paths_for_flavour(flavour)
+ raw_upgrade_paths = load_raw_upgrade_paths_for_distro_and_flavour(os_release.release_id, flavour)
source_major_version = source_version.split('.')[0]
exposed_supported_paths = construct_models_for_paths_matching_source_major(raw_upgrade_paths, source_major_version)
diff --git a/repos/system_upgrade/common/actors/ipuworkflowconfig/tests/test_ipuworkflowconfig.py b/repos/system_upgrade/common/actors/ipuworkflowconfig/tests/test_ipuworkflowconfig.py
index a5e4d03b..d88424ce 100644
--- a/repos/system_upgrade/common/actors/ipuworkflowconfig/tests/test_ipuworkflowconfig.py
+++ b/repos/system_upgrade/common/actors/ipuworkflowconfig/tests/test_ipuworkflowconfig.py
@@ -7,7 +7,7 @@ import pytest
from leapp.exceptions import StopActorExecutionError
from leapp.libraries.actor import ipuworkflowconfig
from leapp.libraries.stdlib import CalledProcessError
-from leapp.models import OSRelease
+from leapp.models import IPUSourceToPossibleTargets, OSRelease
CUR_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -70,3 +70,86 @@ def test_get_booted_kernel(monkeypatch):
monkeypatch.setattr(ipuworkflowconfig, 'run', _raise_call_error)
with pytest.raises(StopActorExecutionError):
ipuworkflowconfig.get_booted_kernel()
+
+
+@pytest.mark.parametrize(
+ ('source_major_version', 'expected_result'),
+ (
+ ('7', []),
+ (
+ '8',
+ [
+ IPUSourceToPossibleTargets(source_version='8.10', target_versions=['9.4', '9.5', '9.6']),
+ IPUSourceToPossibleTargets(source_version='8.4', target_versions=['9.2']),
+ IPUSourceToPossibleTargets(source_version='8', target_versions=['9.4', '9.5', '9.6']),
+ ]
+ ),
+ (
+ '80',
+ [
+ IPUSourceToPossibleTargets(source_version='80.0', target_versions=['81.0']),
+ ]
+ ),
+ )
+)
+def test_construct_models_for_paths_matching_source_major(source_major_version, expected_result):
+ RAW_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']
+ }
+
+ result = ipuworkflowconfig.construct_models_for_paths_matching_source_major(RAW_PATHS, source_major_version)
+ result = sorted(result, key=lambda x: x.source_version)
+ assert result == sorted(expected_result, key=lambda x: x.source_version)
+
+
+@pytest.mark.parametrize(
+ ('distro', 'flavour', 'expected_result'),
+ (
+ ('fedora', 'default', {}),
+ (
+ 'rhel', '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']
+ }
+ ),
+ (
+ 'rhel', 'saphana',
+ {
+ '8.10': ['9.6', '9.4'],
+ '8': ['9.6', '9.4'],
+ '9.6': ['10.0'],
+ '9': ['10.0']
+ }
+ ),
+ )
+)
+def test_load_raw_upgrade_paths_for_distro_and_flavour(monkeypatch, distro, flavour, expected_result):
+ defined_upgrade_paths = {
+ 'rhel': {
+ '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']
+ }
+ }
+ }
+ monkeypatch.setattr(ipuworkflowconfig, 'load_upgrade_paths_definitions', lambda *args: defined_upgrade_paths)
+
+ result = ipuworkflowconfig.load_raw_upgrade_paths_for_distro_and_flavour(distro, flavour)
+ assert result == expected_result
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
index edd32224..b6107376 100644
--- a/repos/system_upgrade/common/actors/scandefinedipupaths/tests/files/upgrade_paths.json
+++ b/repos/system_upgrade/common/actors/scandefinedipupaths/tests/files/upgrade_paths.json
@@ -1,15 +1,22 @@
{
- "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"]
+ "rhel": {
+ "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"]
+ }
},
- "saphana": {
- "8.10": ["9.6", "9.4"],
- "8": ["9.6", "9.4"],
- "9.6": ["10.0"],
- "9": ["10.0"]
+ "centos": {
+ "default": {
+ "8": ["9"]
+ }
}
}
diff --git a/repos/system_upgrade/common/files/upgrade_paths.json b/repos/system_upgrade/common/files/upgrade_paths.json
index 1c54dae8..7ace7943 100644
--- a/repos/system_upgrade/common/files/upgrade_paths.json
+++ b/repos/system_upgrade/common/files/upgrade_paths.json
@@ -1,18 +1,26 @@
{
- "default": {
- "7.9": ["8.10"],
- "8.10": ["9.4", "9.6"],
- "9.6": ["10.0"],
- "7": ["8.10"],
- "8": ["9.4", "9.6"],
- "9": ["10.0"]
+ "rhel": {
+ "default": {
+ "7.9": ["8.10"],
+ "8.10": ["9.4", "9.6"],
+ "9.6": ["10.0"],
+ "7": ["8.10"],
+ "8": ["9.4", "9.6"],
+ "9": ["10.0"]
+ },
+ "saphana": {
+ "7.9": ["8.10"],
+ "7": ["8.10"],
+ "8.10": ["9.6", "9.4"],
+ "8": ["9.6", "9.4"],
+ "9.6": ["10.0"],
+ "9": ["10.0"]
+ }
},
- "saphana": {
- "7.9": ["8.10"],
- "7": ["8.10"],
- "8.10": ["9.6", "9.4"],
- "8": ["9.6", "9.4"],
- "9.6": ["10.0"],
- "9": ["10.0"]
+ "centos": {
+ "default": {
+ "8": ["9"],
+ "9": ["10"]
+ }
}
}
--
2.49.0

View File

@ -0,0 +1,407 @@
From 4432e62f02af820d040f45d7fc59296cf734bdc5 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Sat, 29 Mar 2025 22:00:38 +0100
Subject: [PATCH 17/37] cleanup(ipupaths): remove IPUPaths message
Drop the already deprecated IPUPaths message that was used to inform
actors about supported upgrade paths. Instead, the functionality has
been assumed by IPUConfig.
Jira-ref: RHEL-80550
---
.../common/actors/checktargetversion/actor.py | 3 +-
.../libraries/checktargetversion.py | 15 +--
.../tests/test_checktargetversion.py | 27 +++---
.../actors/scandefinedipupaths/actor.py | 31 ------
.../libraries/scandefinedipupaths.py | 43 --------
.../tests/files/upgrade_paths.json | 22 -----
.../tests/test_scandefinedipupaths.py | 97 -------------------
.../system_upgrade/common/models/ipupaths.py | 43 --------
8 files changed, 17 insertions(+), 264 deletions(-)
delete mode 100644 repos/system_upgrade/common/actors/scandefinedipupaths/actor.py
delete mode 100644 repos/system_upgrade/common/actors/scandefinedipupaths/libraries/scandefinedipupaths.py
delete mode 100644 repos/system_upgrade/common/actors/scandefinedipupaths/tests/files/upgrade_paths.json
delete mode 100644 repos/system_upgrade/common/actors/scandefinedipupaths/tests/test_scandefinedipupaths.py
delete mode 100644 repos/system_upgrade/common/models/ipupaths.py
diff --git a/repos/system_upgrade/common/actors/checktargetversion/actor.py b/repos/system_upgrade/common/actors/checktargetversion/actor.py
index 291ce3da..31375bfc 100644
--- a/repos/system_upgrade/common/actors/checktargetversion/actor.py
+++ b/repos/system_upgrade/common/actors/checktargetversion/actor.py
@@ -1,6 +1,5 @@
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
@@ -14,7 +13,7 @@ class CheckTargetVersion(Actor):
"""
name = 'check_target_version'
- consumes = (IPUPaths,)
+ consumes = ()
produces = (Report,)
tags = (ChecksPhaseTag, IPUWorkflowTag)
diff --git a/repos/system_upgrade/common/actors/checktargetversion/libraries/checktargetversion.py b/repos/system_upgrade/common/actors/checktargetversion/libraries/checktargetversion.py
index 0df1ece2..2369ae11 100644
--- a/repos/system_upgrade/common/actors/checktargetversion/libraries/checktargetversion.py
+++ b/repos/system_upgrade/common/actors/checktargetversion/libraries/checktargetversion.py
@@ -1,22 +1,15 @@
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:
+ supported_paths = api.current_actor().configuration.supported_upgrade_paths
+
+ for ipu_path in supported_paths:
if ipu_path.source_version == src_version:
return ipu_path.target_versions
@@ -28,7 +21,7 @@ def get_supported_target_versions():
.format(src_version)
)
maj_version = version.get_source_major_version()
- for ipu_path in ipu_paths.data:
+ for ipu_path in supported_paths:
if ipu_path.source_version == maj_version:
return ipu_path.target_versions
diff --git a/repos/system_upgrade/common/actors/checktargetversion/tests/test_checktargetversion.py b/repos/system_upgrade/common/actors/checktargetversion/tests/test_checktargetversion.py
index 07391e7a..6927af23 100644
--- a/repos/system_upgrade/common/actors/checktargetversion/tests/test_checktargetversion.py
+++ b/repos/system_upgrade/common/actors/checktargetversion/tests/test_checktargetversion.py
@@ -4,36 +4,33 @@ import pytest
from leapp import reporting
from leapp.libraries.actor import checktargetversion
+from leapp.libraries.common.config import architecture
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.models import IPUSourceToPossibleTargets
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'):
+ suppoted_upgrade_paths = [
+ IPUSourceToPossibleTargets(source_version='7.9', target_versions=['8.10']),
+ IPUSourceToPossibleTargets(source_version='8.10', target_versions=['9.4', '9.5', '9.6']),
+ IPUSourceToPossibleTargets(source_version='9.6', target_versions=['10.0']),
+ IPUSourceToPossibleTargets(source_version='7', target_versions=['8.10']),
+ IPUSourceToPossibleTargets(source_version='8', target_versions=['9.4', '9.5', '9.6']),
+ IPUSourceToPossibleTargets(source_version='9', target_versions=['10.0'])
+ ]
+
curr_actor_mocked = CurrentActorMocked(
src_ver=source_version,
dst_ver=target_version,
envars={'LEAPP_UNSUPPORTED': leapp_unsupported},
- msgs=[_get_upgrade_paths_data()]
+ supported_upgrade_paths=suppoted_upgrade_paths
)
monkeypatch.setattr(api, 'current_actor', curr_actor_mocked)
monkeypatch.setattr(api, 'current_logger', logger_mocked())
diff --git a/repos/system_upgrade/common/actors/scandefinedipupaths/actor.py b/repos/system_upgrade/common/actors/scandefinedipupaths/actor.py
deleted file mode 100644
index a84c85f2..00000000
--- a/repos/system_upgrade/common/actors/scandefinedipupaths/actor.py
+++ /dev/null
@@ -1,31 +0,0 @@
-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
deleted file mode 100644
index 1e39f2c8..00000000
--- a/repos/system_upgrade/common/actors/scandefinedipupaths/libraries/scandefinedipupaths.py
+++ /dev/null
@@ -1,43 +0,0 @@
-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
deleted file mode 100644
index b6107376..00000000
--- a/repos/system_upgrade/common/actors/scandefinedipupaths/tests/files/upgrade_paths.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "rhel": {
- "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"]
- }
- },
- "centos": {
- "default": {
- "8": ["9"]
- }
- }
-}
diff --git a/repos/system_upgrade/common/actors/scandefinedipupaths/tests/test_scandefinedipupaths.py b/repos/system_upgrade/common/actors/scandefinedipupaths/tests/test_scandefinedipupaths.py
deleted file mode 100644
index 9ffc9829..00000000
--- a/repos/system_upgrade/common/actors/scandefinedipupaths/tests/test_scandefinedipupaths.py
+++ /dev/null
@@ -1,97 +0,0 @@
-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
deleted file mode 100644
index 5469f25e..00000000
--- a/repos/system_upgrade/common/models/ipupaths.py
+++ /dev/null
@@ -1,43 +0,0 @@
-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.49.0

View File

@ -1,820 +0,0 @@
From 32d9c40ffc7ea8d08e2b85881579ede1fdaedb32 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Thu, 7 Aug 2025 13:40:33 +0200
Subject: [PATCH 17/55] userspacegen: Add repo gathering for non-RHEL distros
The _get_rh_available_repoids() function is replaced by the
new get_distro_repoids() function from the distro library. This function
works with all the "supported" distros.
The idea is the same as for RHEL, scan well-known distro-provided
repofiles for repositories.
For RHEL, at least for now, the existing
rhsm.get_rhsm_available_repoids() function is still used.
These changes together enable the use of repomapping on distros other
than RHEL, as before this change the --enablerepo option had to be used
to specify target repos and they were treated as custom repos.
Also, the unused _get_rhui_available_repoids() function is removed.
Jira: RHEL-107212
Move get_distro_repoids() to the distro library
---
.../libraries/userspacegen.py | 228 ++++++++++--------
.../tests/unit_test_targetuserspacecreator.py | 56 ++++-
.../system_upgrade/common/libraries/distro.py | 192 +++++++++++++++
.../common/libraries/tests/test_distro.py | 154 ++++++++++++
4 files changed, 524 insertions(+), 106 deletions(-)
create mode 100644 repos/system_upgrade/common/libraries/tests/test_distro.py
diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
index 407cb0b7..26fec2d9 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
@@ -6,7 +6,7 @@ import shutil
from leapp import reporting
from leapp.exceptions import StopActorExecution, StopActorExecutionError
from leapp.libraries.actor import constants
-from leapp.libraries.common import dnfplugin, mounting, overlaygen, repofileutils, rhsm, utils
+from leapp.libraries.common import distro, dnfplugin, mounting, overlaygen, repofileutils, rhsm, utils
from leapp.libraries.common.config import get_distro_id, get_env, get_product_type
from leapp.libraries.common.config.version import get_target_major_version
from leapp.libraries.common.gpg import get_path_to_gpg_certs, is_nogpgcheck_set
@@ -58,6 +58,7 @@ from leapp.utils.deprecation import suppress_deprecation
PROD_CERTS_FOLDER = 'prod-certs'
PERSISTENT_PACKAGE_CACHE_DIR = '/var/lib/leapp/persistent_package_cache'
DEDICATED_LEAPP_PART_URL = 'https://access.redhat.com/solutions/7011704'
+FMT_LIST_SEPARATOR = '\n - '
def _check_deprecated_rhsm_skip():
@@ -778,7 +779,7 @@ def _inhibit_on_duplicate_repos(repofiles):
list_separator_fmt = '\n - '
api.current_logger().warning(
'The following repoids are defined multiple times:{0}{1}'
- .format(list_separator_fmt, list_separator_fmt.join(duplicates))
+ .format(list_separator_fmt, list_separator_fmt.join(sorted(duplicates)))
)
reporting.create_report([
@@ -786,7 +787,7 @@ def _inhibit_on_duplicate_repos(repofiles):
reporting.Summary(
'The following repositories are defined multiple times inside the'
' "upgrade" container:{0}{1}'
- .format(list_separator_fmt, list_separator_fmt.join(duplicates))
+ .format(list_separator_fmt, list_separator_fmt.join(sorted(duplicates)))
),
reporting.Severity(reporting.Severity.MEDIUM),
reporting.Groups([reporting.Groups.REPOSITORY]),
@@ -815,21 +816,19 @@ def _get_all_available_repoids(context):
return set(repoids)
-def _get_rhsm_available_repoids(context):
- target_major_version = get_target_major_version()
+def _inhibit_if_no_base_repos(distro_repoids):
# FIXME: check that required repo IDs (baseos, appstream)
# + or check that all required RHEL repo IDs are available.
- if rhsm.skip_rhsm():
- return set()
- # Get the RHSM repos available in the target RHEL container
- # TODO: very similar thing should happens for all other repofiles in container
- #
- repoids = rhsm.get_available_repo_ids(context)
+
+ target_major_version = get_target_major_version()
# NOTE(ivasilev) For the moment at least AppStream and BaseOS repos are required. While we are still
# contemplating on what can be a generic solution to checking this, let's introduce a minimal check for
# at-least-one-appstream and at-least-one-baseos among present repoids
- if not repoids or all("baseos" not in ri for ri in repoids) or all("appstream" not in ri for ri in repoids):
+ no_baseos = all("baseos" not in ri for ri in distro_repoids)
+ no_appstream = all("appstream" not in ri for ri in distro_repoids)
+ if no_baseos or no_appstream:
reporting.create_report([
+ # TODO: Make the report distro agnostic
reporting.Title('Cannot find required basic RHEL target repositories.'),
reporting.Summary(
'This can happen when a repository ID was entered incorrectly either while using the --enablerepo'
@@ -861,21 +860,6 @@ def _get_rhsm_available_repoids(context):
title='Preparing for the upgrade')
])
raise StopActorExecution()
- return set(repoids)
-
-
-def _get_rhui_available_repoids(context, cloud_repo):
- repofiles = repofileutils.get_parsed_repofiles(context)
-
- # TODO: same refactoring as Issue #486?
- _inhibit_on_duplicate_repos(repofiles)
- repoids = []
- for rfile in repofiles:
- if rfile.file == cloud_repo and rfile.data:
- repoids = [repo.repoid for repo in rfile.data]
- repoids.sort()
- break
- return set(repoids)
def get_copy_location_from_copy_in_task(context_basepath, copy_task):
@@ -886,86 +870,106 @@ def get_copy_location_from_copy_in_task(context_basepath, copy_task):
return copy_task.dst
-def _get_rh_available_repoids(context, indata):
+def _get_rhui_available_repoids(context, rhui_info):
"""
- RH repositories are provided either by RHSM or are stored in the expected repo file provided by
- RHUI special packages (every cloud provider has itw own rpm).
+ Get repoids provided by the RHUI target clients
+
+ :rtype: set[str]
"""
+ # If we are upgrading a RHUI system, check what repositories are provided by the (already installed) target clients
+ setup_info = rhui_info.target_client_setup_info
+ target_content_access_files = set()
+ if setup_info.bootstrap_target_client:
+ target_content_access_files = _query_rpm_for_pkg_files(context, rhui_info.target_client_pkg_names)
- rh_repoids = _get_rhsm_available_repoids(context)
+ def is_repofile(path):
+ return os.path.dirname(path) == '/etc/yum.repos.d' and os.path.basename(path).endswith('.repo')
- # If we are upgrading a RHUI system, check what repositories are provided by the (already installed) target clients
- if indata and indata.rhui_info:
- setup_info = indata.rhui_info.target_client_setup_info
- target_content_access_files = set()
- if setup_info.bootstrap_target_client:
- target_content_access_files = _query_rpm_for_pkg_files(context, indata.rhui_info.target_client_pkg_names)
+ def extract_repoid_from_line(line):
+ return line.split(':', 1)[1].strip()
- def is_repofile(path):
- return os.path.dirname(path) == '/etc/yum.repos.d' and os.path.basename(path).endswith('.repo')
+ target_ver = api.current_actor().configuration.version.target
+ setup_tasks = rhui_info.target_client_setup_info.preinstall_tasks.files_to_copy_into_overlay
- def extract_repoid_from_line(line):
- return line.split(':', 1)[1].strip()
+ yum_repos_d = context.full_path('/etc/yum.repos.d')
+ all_repofiles = {os.path.join(yum_repos_d, path) for path in os.listdir(yum_repos_d) if path.endswith('.repo')}
+ api.current_logger().debug('(RHUI Setup) All available repofiles: {0}'.format(' '.join(all_repofiles)))
- target_ver = api.current_actor().configuration.version.target
- setup_tasks = indata.rhui_info.target_client_setup_info.preinstall_tasks.files_to_copy_into_overlay
+ target_access_repofiles = {
+ context.full_path(path) for path in target_content_access_files if is_repofile(path)
+ }
- yum_repos_d = context.full_path('/etc/yum.repos.d')
- all_repofiles = {os.path.join(yum_repos_d, path) for path in os.listdir(yum_repos_d) if path.endswith('.repo')}
- api.current_logger().debug('(RHUI Setup) All available repofiles: {0}'.format(' '.join(all_repofiles)))
+ # Exclude repofiles used to setup the target rhui access as on some platforms the repos provided by
+ # the client are not sufficient to install the client into target userspace (GCP)
+ rhui_setup_repofile_tasks = [task for task in setup_tasks if task.src.endswith('repo')]
+ rhui_setup_repofiles = (
+ get_copy_location_from_copy_in_task(context.base_dir, copy) for copy in rhui_setup_repofile_tasks
+ )
+ rhui_setup_repofiles = {context.full_path(repofile) for repofile in rhui_setup_repofiles}
- target_access_repofiles = {
- context.full_path(path) for path in target_content_access_files if is_repofile(path)
- }
+ foreign_repofiles = all_repofiles - target_access_repofiles - rhui_setup_repofiles
- # Exclude repofiles used to setup the target rhui access as on some platforms the repos provided by
- # the client are not sufficient to install the client into target userspace (GCP)
- rhui_setup_repofile_tasks = [task for task in setup_tasks if task.src.endswith('repo')]
- rhui_setup_repofiles = (
- get_copy_location_from_copy_in_task(context.base_dir, copy) for copy in rhui_setup_repofile_tasks
- )
- rhui_setup_repofiles = {context.full_path(repofile) for repofile in rhui_setup_repofiles}
+ api.current_logger().debug(
+ 'The following repofiles are considered as unknown to'
+ ' the target RHUI content setup and will be ignored: {0}'.format(' '.join(foreign_repofiles))
+ )
- foreign_repofiles = all_repofiles - target_access_repofiles - rhui_setup_repofiles
+ # Rename non-client repofiles so they will not be recognized when running dnf repolist
+ for foreign_repofile in foreign_repofiles:
+ os.rename(foreign_repofile, '{0}.back'.format(foreign_repofile))
- api.current_logger().debug(
- 'The following repofiles are considered as unknown to'
- ' the target RHUI content setup and will be ignored: {0}'.format(' '.join(foreign_repofiles))
+ rhui_repoids = set()
+ try:
+ dnf_cmd = [
+ 'dnf', 'repolist',
+ '--releasever', target_ver, '-v',
+ '--enablerepo', '*',
+ '--disablerepo', '*-source-*',
+ '--disablerepo', '*-debug-*',
+ ]
+ repolist_result = context.call(dnf_cmd)['stdout']
+ repoid_lines = [line for line in repolist_result.split('\n') if line.startswith('Repo-id')]
+ rhui_repoids.update({extract_repoid_from_line(line) for line in repoid_lines})
+
+ except CalledProcessError as err:
+ details = {'err': err.stderr, 'details': str(err)}
+ raise StopActorExecutionError(
+ message='Failed to retrieve repoids provided by target RHUI clients.',
+ details=details
)
- # Rename non-client repofiles so they will not be recognized when running dnf repolist
+ finally:
+ # Revert the renaming of non-client repofiles
for foreign_repofile in foreign_repofiles:
- os.rename(foreign_repofile, '{0}.back'.format(foreign_repofile))
+ os.rename('{0}.back'.format(foreign_repofile), foreign_repofile)
- try:
- dnf_cmd = [
- 'dnf', 'repolist',
- '--releasever', target_ver, '-v',
- '--enablerepo', '*',
- '--disablerepo', '*-source-*',
- '--disablerepo', '*-debug-*',
- ]
- repolist_result = context.call(dnf_cmd)['stdout']
- repoid_lines = [line for line in repolist_result.split('\n') if line.startswith('Repo-id')]
- rhui_repoids = {extract_repoid_from_line(line) for line in repoid_lines}
- rh_repoids.update(rhui_repoids)
-
- except CalledProcessError as err:
- details = {'err': err.stderr, 'details': str(err)}
- raise StopActorExecutionError(
- message='Failed to retrieve repoids provided by target RHUI clients.',
- details=details
- )
+ return rhui_repoids
- finally:
- # Revert the renaming of non-client repofiles
- for foreign_repofile in foreign_repofiles:
- os.rename('{0}.back'.format(foreign_repofile), foreign_repofile)
- api.current_logger().debug(
- 'The following repofiles are considered as provided by RedHat: {0}'.format(' '.join(rh_repoids))
- )
- return rh_repoids
+def _get_distro_available_repoids(context, indata):
+ """
+ Get repoids provided by the distribution
+
+ On RHEL: RH repositories are provided either by RHSM or are stored in the
+ expected repo file provided by RHUI special packages (every cloud
+ provider has itw own rpm).
+ On other: Repositories are provided in specific repofiles (e.g. centos.repo
+ and centos-addons.repo on CS)
+
+ :return: A set of repoids provided by distribution
+ :rtype: set[str]
+ """
+ distro_repoids = distro.get_target_distro_repoids(context)
+ distro_id = get_distro_id()
+ rhel_and_rhsm = distro_id == 'rhel' and not rhsm.skip_rhsm()
+ if distro_id != 'rhel' or rhel_and_rhsm:
+ _inhibit_if_no_base_repos(distro_repoids)
+
+ if indata and indata.rhui_info:
+ rhui_repoids = _get_rhui_available_repoids(context, indata.rhui_info)
+ distro_repoids.extend(rhui_repoids)
+
+ return set(distro_repoids)
@suppress_deprecation(RHELTargetRepository) # member of TargetRepositories
@@ -986,17 +990,31 @@ def gather_target_repositories(context, indata):
:param context: An instance of a mounting.IsolatedActions class
:type context: mounting.IsolatedActions class
:return: List of target system repoids
- :rtype: List(string)
+ :rtype: set[str]
"""
- rh_available_repoids = _get_rh_available_repoids(context, indata)
- all_available_repoids = _get_all_available_repoids(context)
- target_repoids = []
- missing_custom_repoids = []
+ distro_repoids = _get_distro_available_repoids(context, indata)
+ if distro_repoids:
+ api.current_logger().info(
+ "The following repoids are considered as provided by the '{}' distribution:{}{}".format(
+ get_distro_id(),
+ FMT_LIST_SEPARATOR,
+ FMT_LIST_SEPARATOR.join(sorted(distro_repoids)),
+ )
+ )
+ else:
+ api.current_logger().warning(
+ "No repoids provided by the {} distribution have been discovered".format(get_distro_id())
+ )
+
+ all_repoids = _get_all_available_repoids(context)
+
+ target_repoids = set()
+ missing_custom_repoids = set()
for target_repo in api.consume(TargetRepositories):
- for rhel_repo in target_repo.rhel_repos:
- if rhel_repo.repoid in rh_available_repoids:
- target_repoids.append(rhel_repo.repoid)
+ for distro_repo in target_repo.distro_repos:
+ if distro_repo.repoid in distro_repoids:
+ target_repoids.add(distro_repo.repoid)
else:
# TODO: We shall report that the RHEL repos that we deem necessary for
# the upgrade are not available; but currently it would just print bunch of
@@ -1005,12 +1023,16 @@ def gather_target_repositories(context, indata):
# of the upgrade. Let's skip it for now until it's clear how we will deal
# with it.
pass
+
for custom_repo in target_repo.custom_repos:
- if custom_repo.repoid in all_available_repoids:
- target_repoids.append(custom_repo.repoid)
+ if custom_repo.repoid in all_repoids:
+ target_repoids.add(custom_repo.repoid)
else:
- missing_custom_repoids.append(custom_repo.repoid)
- api.current_logger().debug("Gathered target repositories: {}".format(', '.join(target_repoids)))
+ missing_custom_repoids.add(custom_repo.repoid)
+ api.current_logger().debug(
+ "Gathered target repositories: {}".format(", ".join(sorted(target_repoids)))
+ )
+
if not target_repoids:
target_major_version = get_target_major_version()
reporting.create_report([
@@ -1056,7 +1078,7 @@ def gather_target_repositories(context, indata):
' while using the --enablerepo option of leapp, or in a third party actor that produces a'
' CustomTargetRepositoryMessage.\n'
'The following repositories IDs could not be found in the target configuration:\n'
- '- {}\n'.format('\n- '.join(missing_custom_repoids))
+ '- {}\n'.format('\n- '.join(sorted(missing_custom_repoids)))
),
reporting.Groups([reporting.Groups.REPOSITORY]),
reporting.Groups([reporting.Groups.INHIBITOR]),
@@ -1073,7 +1095,7 @@ def gather_target_repositories(context, indata):
))
])
raise StopActorExecution()
- return set(target_repoids)
+ return target_repoids
def _install_custom_repofiles(context, custom_repofiles):
diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py b/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
index f05e6bc2..2ae194d7 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
@@ -11,9 +11,9 @@ import pytest
from leapp import models, reporting
from leapp.exceptions import StopActorExecution, StopActorExecutionError
from leapp.libraries.actor import userspacegen
-from leapp.libraries.common import overlaygen, repofileutils, rhsm
+from leapp.libraries.common import distro, overlaygen, repofileutils, rhsm
from leapp.libraries.common.config import architecture
-from leapp.libraries.common.testutils import CurrentActorMocked, logger_mocked, produce_mocked
+from leapp.libraries.common.testutils import create_report_mocked, CurrentActorMocked, logger_mocked, produce_mocked
from leapp.libraries.stdlib import api, CalledProcessError
from leapp.utils.deprecation import suppress_deprecation
@@ -1115,7 +1115,9 @@ def test_gather_target_repositories_rhui(monkeypatch):
monkeypatch.setattr(userspacegen.api, 'current_actor', CurrentActorMocked())
monkeypatch.setattr(userspacegen, '_get_all_available_repoids', lambda x: [])
monkeypatch.setattr(
- userspacegen, '_get_rh_available_repoids', lambda x, y: ['rhui-1', 'rhui-2', 'rhui-3']
+ userspacegen,
+ "_get_distro_available_repoids",
+ lambda dummy_context, dummy_indata: {"rhui-1", "rhui-2", "rhui-3"},
)
monkeypatch.setattr(rhsm, 'skip_rhsm', lambda: True)
monkeypatch.setattr(
@@ -1195,6 +1197,54 @@ def test_gather_target_repositories_baseos_appstream_not_available(monkeypatch):
assert inhibitors[0].get('title', '') == 'Cannot find required basic RHEL target repositories.'
+def test__get_distro_available_repoids_norhsm_norhui(monkeypatch):
+ """
+ Empty set should be returned when on rhel and skip_rhsm == True.
+ """
+ monkeypatch.setattr(
+ userspacegen.api, "current_actor", CurrentActorMocked(release_id="rhel")
+ )
+ monkeypatch.setattr(userspacegen.api.current_actor(), 'produce', produce_mocked())
+
+ monkeypatch.setattr(rhsm, 'skip_rhsm', lambda: True)
+ monkeypatch.setattr(distro, 'get_target_distro_repoids', lambda ctx: [])
+
+ indata = testInData(_PACKAGES_MSGS, None, None, _XFS_MSG, _STORAGEINFO_MSG, None)
+ # NOTE: context is not used without rhsm, for simplicity setting to None
+ repoids = userspacegen._get_distro_available_repoids(None, indata)
+ assert repoids == set()
+
+
+@pytest.mark.parametrize(
+ "distro_id,skip_rhsm", [("rhel", False), ("centos", True), ("almalinux", True)]
+)
+def test__get_distro_available_repoids_nobaserepos_inhibit(
+ monkeypatch, distro_id, skip_rhsm
+):
+ """
+ Test that get_distro_available repoids reports and raises if there are no base repos.
+ """
+ monkeypatch.setattr(
+ userspacegen.api, "current_actor", CurrentActorMocked(release_id=distro_id)
+ )
+ monkeypatch.setattr(userspacegen.api.current_actor(), 'produce', produce_mocked())
+ monkeypatch.setattr(reporting, "create_report", create_report_mocked())
+
+ monkeypatch.setattr(rhsm, 'skip_rhsm', lambda: skip_rhsm)
+ monkeypatch.setattr(distro, 'get_target_distro_repoids', lambda ctx: [])
+
+ indata = testInData(_PACKAGES_MSGS, None, None, _XFS_MSG, _STORAGEINFO_MSG, None)
+ with pytest.raises(StopActorExecution):
+ # NOTE: context is not used without rhsm, for simplicity setting to None
+ userspacegen._get_distro_available_repoids(None, indata)
+
+ # TODO adjust the asserts when the report is made distro agnostic
+ assert reporting.create_report.called == 1
+ report = reporting.create_report.reports[0]
+ assert "Cannot find required basic RHEL target repositories" in report["title"]
+ assert reporting.Groups.INHIBITOR in report["groups"]
+
+
def mocked_consume_data():
packages = {'dnf', 'dnf-command(config-manager)', 'pkgA', 'pkgB'}
rhsm_info = _RHSMINFO_MSG
diff --git a/repos/system_upgrade/common/libraries/distro.py b/repos/system_upgrade/common/libraries/distro.py
index 2ed5eacd..d6a2381a 100644
--- a/repos/system_upgrade/common/libraries/distro.py
+++ b/repos/system_upgrade/common/libraries/distro.py
@@ -2,6 +2,10 @@ import json
import os
from leapp.exceptions import StopActorExecutionError
+from leapp.libraries.common import repofileutils, rhsm
+from leapp.libraries.common.config import get_distro_id
+from leapp.libraries.common.config.architecture import ARCH_ACCEPTED, ARCH_X86_64
+from leapp.libraries.common.config.version import get_target_major_version
from leapp.libraries.stdlib import api
@@ -16,3 +20,191 @@ def get_distribution_data(distribution):
raise StopActorExecutionError(
'Cannot find distribution signature configuration.',
details={'Problem': 'Distribution {} was not found in {}.'.format(distribution, distributions_path)})
+
+
+# distro -> major_version -> repofile -> tuple of architectures where it's present
+_DISTRO_REPOFILES_MAP = {
+ 'rhel': {
+ '8': {'/etc/yum.repos.d/redhat.repo': ARCH_ACCEPTED},
+ '9': {'/etc/yum.repos.d/redhat.repo': ARCH_ACCEPTED},
+ '10': {'/etc/yum.repos.d/redhat.repo': ARCH_ACCEPTED},
+ },
+ 'centos': {
+ '8': {
+ # TODO is this true on all archs?
+ 'CentOS-Linux-AppStream.repo': ARCH_ACCEPTED,
+ 'CentOS-Linux-BaseOS.repo': ARCH_ACCEPTED,
+ 'CentOS-Linux-ContinuousRelease.repo': ARCH_ACCEPTED,
+ 'CentOS-Linux-Debuginfo.repo': ARCH_ACCEPTED,
+ 'CentOS-Linux-Devel.repo': ARCH_ACCEPTED,
+ 'CentOS-Linux-Extras.repo': ARCH_ACCEPTED,
+ 'CentOS-Linux-FastTrack.repo': ARCH_ACCEPTED,
+ 'CentOS-Linux-HighAvailability.repo': ARCH_ACCEPTED,
+ 'CentOS-Linux-Media.repo': ARCH_ACCEPTED,
+ 'CentOS-Linux-Plus.repo': ARCH_ACCEPTED,
+ 'CentOS-Linux-PowerTools.repo': ARCH_ACCEPTED,
+ 'CentOS-Linux-Sources.repo': ARCH_ACCEPTED,
+ },
+ '9': {
+ '/etc/yum.repos.d/centos.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/centos-addons.repo': ARCH_ACCEPTED,
+ },
+ '10': {
+ '/etc/yum.repos.d/centos.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/centos-addons.repo': ARCH_ACCEPTED,
+ },
+ },
+ 'almalinux': {
+ '8': {
+ # TODO is this true on all archs?
+ '/etc/yum.repos.d/almalinux-ha.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-nfv.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-plus.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-powertools.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-resilientstorage.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-rt.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-sap.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-saphana.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux.repo': ARCH_ACCEPTED,
+ },
+ '9': {
+ '/etc/yum.repos.d/almalinux-appstream.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-baseos.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-crb.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-extras.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-highavailability.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-plus.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-resilientstorage.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-sap.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-saphana.repo': ARCH_ACCEPTED,
+ # RT and NFV are only on x86_64 on almalinux 9
+ '/etc/yum.repos.d/almalinux-nfv.repo': (ARCH_X86_64,),
+ '/etc/yum.repos.d/almalinux-rt.repo': (ARCH_X86_64,),
+ },
+ '10': {
+ # no resilientstorage on 10
+ '/etc/yum.repos.d/almalinux-appstream.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-baseos.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-crb.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-extras.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-highavailability.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-plus.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-sap.repo': ARCH_ACCEPTED,
+ '/etc/yum.repos.d/almalinux-saphana.repo': ARCH_ACCEPTED,
+ # RT and NFV are only on x86_64 on almalinux 10
+ '/etc/yum.repos.d/almalinux-nfv.repo': (ARCH_X86_64,),
+ '/etc/yum.repos.d/almalinux-rt.repo': (ARCH_X86_64,),
+ },
+ },
+}
+
+
+def _get_distro_repofiles(distro, major_version, arch):
+ """
+ Get distribution provided repofiles.
+
+ Note that this does not perform any validation, the caller must check
+ whether the files exist.
+
+ :param distro: The distribution to get repofiles for.
+ :type distro: str
+ :param major_version: The major version to get repofiles for.
+ :type major_version: str
+ :param arch: The architecture to get repofiles for.
+ :type arch: str
+ :return: A list of paths to repofiles provided by distribution
+ :rtype: list[str] or None if no repofiles are mapped for the arguments
+ """
+
+ distro_repofiles = _DISTRO_REPOFILES_MAP.get(distro)
+ if not distro_repofiles:
+ return None
+
+ version_repofiles = distro_repofiles.get(major_version, {})
+ if not version_repofiles:
+ return None
+
+ return [repofile for repofile, archs in version_repofiles.items() if arch in archs]
+
+
+def get_target_distro_repoids(context):
+ """
+ Get repoids defined in distro provided repofiles
+
+ See the generic :func:`_get_distro_repoids` for more details.
+
+ :param context: An instance of mounting.IsolatedActions class
+ :type context: mounting.IsolatedActions
+ :return: Repoids of distribution provided repositories
+ :type: list[str]
+ """
+
+ return get_distro_repoids(
+ context,
+ get_distro_id(),
+ get_target_major_version(),
+ api.current_actor().configuration.architecture
+ )
+
+
+def get_distro_repoids(context, distro, major_version, arch):
+ """
+ Get repoids defined in distro provided repofiles
+
+ On RHEL with RHSM this delegates to rhsm.get_available_repo_ids.
+
+ Repofiles installed by RHUI client packages are not covered by this
+ function.
+
+ :param context: An instance of mounting.IsolatedActions class
+ :type context: mounting.IsolatedActions
+ :param distro: The distro whose repoids to return
+ :type distro: str
+ :param major_version: The major version to get distro repoids for.
+ :type major_version: str
+ :param arch: The architecture to get distro repoids for.
+ :type arch: str
+ :return: Repoids of distribution provided repositories
+ :type: list[str]
+ """
+
+ if distro == 'rhel':
+ if rhsm.skip_rhsm():
+ return []
+ # Kept this todo here from the original code from
+ # userspacegen._get_rh_available_repoids:
+ # Get the RHSM repos available in the target RHEL container
+ # TODO: very similar thing should happens for all other repofiles in container
+ return rhsm.get_available_repo_ids(context)
+
+ repofiles = repofileutils.get_parsed_repofiles(context)
+ distro_repofiles = _get_distro_repofiles(distro, major_version, arch)
+ if not distro_repofiles:
+ # TODO: a different way of signaling an error would be preferred (e.g. returning None),
+ # but since rhsm.get_available_repo_ids also raises StopActorExecutionError,
+ # let's make it easier for the caller for now and use it too
+ raise StopActorExecutionError(
+ "No known distro provided repofiles mapped",
+ details={
+ "details": "distro: {}, major version: {}, architecture: {}".format(
+ distro, major_version, arch
+ )
+ },
+ )
+
+ distro_repoids = []
+ for rfile in repofiles:
+ if rfile.file in distro_repofiles:
+
+ if not os.path.exists(context.full_path(rfile.file)):
+ api.current_logger().debug(
+ "Expected distribution provided repofile does not exists: {}".format(
+ rfile
+ )
+ )
+ continue
+
+ if rfile.data:
+ distro_repoids.extend([repo.repoid for repo in rfile.data])
+
+ return sorted(distro_repoids)
diff --git a/repos/system_upgrade/common/libraries/tests/test_distro.py b/repos/system_upgrade/common/libraries/tests/test_distro.py
new file mode 100644
index 00000000..3a8f174f
--- /dev/null
+++ b/repos/system_upgrade/common/libraries/tests/test_distro.py
@@ -0,0 +1,154 @@
+import os
+
+import pytest
+
+from leapp.actors import StopActorExecutionError
+from leapp.libraries.common import distro, repofileutils, rhsm
+from leapp.libraries.common.config.architecture import ARCH_ACCEPTED, ARCH_ARM64, ARCH_PPC64LE, ARCH_S390X, ARCH_X86_64
+from leapp.libraries.common.distro import _get_distro_repofiles, get_distro_repoids
+from leapp.libraries.common.testutils import CurrentActorMocked
+from leapp.libraries.stdlib import api
+from leapp.models import RepositoryData, RepositoryFile
+
+_RHEL_REPOFILES = ['/etc/yum.repos.d/redhat.repo']
+_CENTOS_REPOFILES = [
+ "/etc/yum.repos.d/centos.repo", "/etc/yum.repos.d/centos-addons.repo"
+]
+
+
+def test_get_distro_repofiles(monkeypatch):
+ """
+ Test the functionality, not the data.
+ """
+ test_map = {
+ 'distro1': {
+ '8': {
+ 'repofile1': ARCH_ACCEPTED,
+ 'repofile2': [ARCH_X86_64],
+ },
+ '9': {
+ 'repofile3': ARCH_ACCEPTED,
+ },
+ },
+ 'distro2': {
+ '8': {},
+ '9': {
+ 'repofile2': [ARCH_X86_64],
+ 'repofile3': [ARCH_ARM64, ARCH_S390X, ARCH_PPC64LE],
+ },
+ },
+ }
+ monkeypatch.setattr(distro, '_DISTRO_REPOFILES_MAP', test_map)
+
+ # mix of all and specific arch
+ repofiles = _get_distro_repofiles('distro1', '8', ARCH_X86_64)
+ assert repofiles == ['repofile1', 'repofile2']
+
+ # match all but not x86_64
+ repofiles = _get_distro_repofiles('distro1', '8', ARCH_ARM64)
+ assert repofiles == ['repofile1']
+
+ repofiles = _get_distro_repofiles('distro2', '9', ARCH_X86_64)
+ assert repofiles == ['repofile2']
+ repofiles = _get_distro_repofiles('distro2', '9', ARCH_ARM64)
+ assert repofiles == ['repofile3']
+ repofiles = _get_distro_repofiles('distro2', '9', ARCH_S390X)
+ assert repofiles == ['repofile3']
+ repofiles = _get_distro_repofiles('distro2', '9', ARCH_PPC64LE)
+ assert repofiles == ['repofile3']
+
+ # version not mapped
+ repofiles = _get_distro_repofiles('distro2', '8', ARCH_X86_64)
+ assert repofiles is None
+
+ # distro not mapped
+ repofiles = _get_distro_repofiles('distro42', '8', ARCH_X86_64)
+ assert repofiles is None
+
+
+def _make_repo(repoid):
+ return RepositoryData(repoid=repoid, name='name {}'.format(repoid))
+
+
+def _make_repofile(rfile, data=None):
+ if data is None:
+ data = [_make_repo("{}-{}".format(rfile.split("/")[-1], i)) for i in range(3)]
+ return RepositoryFile(file=rfile, data=data)
+
+
+def _make_repofiles(rfiles):
+ return [_make_repofile(rfile) for rfile in rfiles]
+
+
+@pytest.mark.parametrize('other_rfiles', [
+ [],
+ [_make_repofile("foo")],
+ _make_repofiles(["foo", "bar"]),
+])
+@pytest.mark.parametrize(
+ "distro_id,skip_rhsm,distro_rfiles",
+ [
+ ("rhel", True, []),
+ ("rhel", True, _make_repofiles(_RHEL_REPOFILES)),
+ ("rhel", False, _make_repofiles(_RHEL_REPOFILES)),
+ ("centos", True, []),
+ ("centos", True, _make_repofiles(_CENTOS_REPOFILES)),
+ ]
+)
+def test_get_distro_repoids(
+ monkeypatch, distro_id, skip_rhsm, distro_rfiles, other_rfiles
+):
+ """
+ Tests that the correct repoids are returned
+
+ This is a little ugly because on RHEL the get_distro_repoids function still
+ delegates to rhsm.get_available_repo_ids and also has different behavior
+ with skip_rhsm
+ """
+ current_actor = CurrentActorMocked(release_id=distro_id if distro_id else 'rhel')
+ monkeypatch.setattr(api, 'current_actor', current_actor)
+ monkeypatch.setattr(rhsm, 'skip_rhsm', lambda: skip_rhsm)
+
+ repofiles = other_rfiles
+ if distro_rfiles:
+ repofiles.extend(distro_rfiles)
+ monkeypatch.setattr(repofileutils, 'get_parsed_repofiles', lambda x: repofiles)
+
+ distro_repoids = []
+ for rfile in distro_rfiles:
+ distro_repoids.extend([repo.repoid for repo in rfile.data] if rfile else [])
+ distro_repoids.sort()
+
+ monkeypatch.setattr(rhsm, 'get_available_repo_ids', lambda _: distro_repoids)
+ monkeypatch.setattr(os.path, 'exists', lambda f: f in _CENTOS_REPOFILES)
+
+ class MockedContext:
+ def full_path(self, path):
+ return path
+
+ repoids = get_distro_repoids(MockedContext(), distro_id, '9', 'x86_64')
+
+ if distro_id == 'rhel' and skip_rhsm:
+ assert repoids == []
+ else:
+ assert sorted(repoids) == distro_repoids
+
+
+@pytest.mark.parametrize('other_rfiles', [
+ [],
+ [_make_repofile("foo")],
+ _make_repofiles(["foo", "bar"]),
+])
+def test_get_distro_repoids_no_distro_repofiles(monkeypatch, other_rfiles):
+ """
+ Test that exception is thrown when there are no known distro provided repofiles.
+ """
+
+ def mocked_get_distro_repofiles(*args):
+ return []
+
+ monkeypatch.setattr(distro, '_get_distro_repofiles', mocked_get_distro_repofiles)
+ monkeypatch.setattr(repofileutils, "get_parsed_repofiles", lambda x: other_rfiles)
+
+ with pytest.raises(StopActorExecutionError):
+ get_distro_repoids(None, 'somedistro', '8', 'x86_64')
--
2.51.1

View File

@ -1,82 +0,0 @@
From ae9a953dc111c0b14a8b86b3f0aee26cea1f08b4 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Mon, 1 Sep 2025 23:43:53 +0200
Subject: [PATCH 18/55] lib/distro: Add tests for existing
get_distribution_data() function
---
.../common/libraries/tests/test_distro.py | 47 ++++++++++++++++++-
1 file changed, 46 insertions(+), 1 deletion(-)
diff --git a/repos/system_upgrade/common/libraries/tests/test_distro.py b/repos/system_upgrade/common/libraries/tests/test_distro.py
index 3a8f174f..8e866455 100644
--- a/repos/system_upgrade/common/libraries/tests/test_distro.py
+++ b/repos/system_upgrade/common/libraries/tests/test_distro.py
@@ -1,3 +1,4 @@
+import json
import os
import pytest
@@ -5,7 +6,7 @@ import pytest
from leapp.actors import StopActorExecutionError
from leapp.libraries.common import distro, repofileutils, rhsm
from leapp.libraries.common.config.architecture import ARCH_ACCEPTED, ARCH_ARM64, ARCH_PPC64LE, ARCH_S390X, ARCH_X86_64
-from leapp.libraries.common.distro import _get_distro_repofiles, get_distro_repoids
+from leapp.libraries.common.distro import _get_distro_repofiles, get_distribution_data, get_distro_repoids
from leapp.libraries.common.testutils import CurrentActorMocked
from leapp.libraries.stdlib import api
from leapp.models import RepositoryData, RepositoryFile
@@ -15,6 +16,50 @@ _CENTOS_REPOFILES = [
"/etc/yum.repos.d/centos.repo", "/etc/yum.repos.d/centos-addons.repo"
]
+_CUR_DIR = os.path.dirname(os.path.abspath(__file__))
+
+
+@pytest.mark.parametrize('distro', ['rhel', 'centos'])
+def test_get_distribution_data(monkeypatch, distro):
+ common_path = os.path.join(_CUR_DIR, "../../files/", 'distro')
+ monkeypatch.setattr(
+ api,
+ "get_common_folder_path",
+ lambda folder: common_path
+ )
+ data_path = os.path.join(common_path, distro, "gpg-signatures.json")
+
+ def exists_mocked(path):
+ assert path == data_path
+ return True
+
+ monkeypatch.setattr(os.path, 'exists', exists_mocked)
+ ret = get_distribution_data(distro)
+
+ with open(data_path) as fp:
+ assert ret == json.load(fp)
+
+
+@pytest.mark.parametrize('distro', ['rhel', 'centos'])
+def test_get_distribution_data_not_exists(monkeypatch, distro):
+ common_path = os.path.join(_CUR_DIR, "../../files/", 'distro')
+ monkeypatch.setattr(
+ api,
+ "get_common_folder_path",
+ lambda folder: common_path
+ )
+ data_path = os.path.join(common_path, distro, "gpg-signatures.json")
+
+ def exists_mocked(path):
+ assert path == data_path
+ return False
+
+ monkeypatch.setattr(os.path, 'exists', exists_mocked)
+
+ with pytest.raises(StopActorExecutionError) as err:
+ get_distribution_data(distro)
+ assert 'Cannot find distribution signature configuration.' in err
+
def test_get_distro_repofiles(monkeypatch):
"""
--
2.51.1

View File

@ -0,0 +1,123 @@
From 09ef3dee08656058d9ac4b9c69d6848b2eae6dfb Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Mon, 31 Mar 2025 09:56:58 +0200
Subject: [PATCH 18/37] libs(version): use supported_upgrade_paths
Refactor the config.version library to use actor.configuration to obtain
the list of supported upgrade paths instead of having its own (duplicit)
definitions.
Mark leapp.libraries.common.config.version.SUPPORTED_VERSIONS as
deprecated and update the documentation.
Jira-ref: RHEL-80550
---
.../libraries-and-api/deprecations-list.md | 3 +-
.../libraries/config/tests/test_version.py | 28 +++++++++----------
.../common/libraries/config/version.py | 23 +++++++++------
3 files changed, 31 insertions(+), 23 deletions(-)
diff --git a/docs/source/libraries-and-api/deprecations-list.md b/docs/source/libraries-and-api/deprecations-list.md
index 07cbf1d6..c8489af3 100644
--- a/docs/source/libraries-and-api/deprecations-list.md
+++ b/docs/source/libraries-and-api/deprecations-list.md
@@ -14,7 +14,8 @@ Only the versions in which a deprecation has been made are listed.
## Next release <span style="font-size:0.5em; font-weight:normal">(till TODO date)</span>
-- No new deprecation yet
+- Shared libraries
+ - **`leapp.libraries.common.config.version.SUPPORTED_VERSIONS`** - The `SUPPORTED_VERSIONS` dict has been deprecated as it is problematic with the new design. Use `leapp.libraries.common.config.version.is_supported_version()` or `IPUConfig.supported_upgrade_paths` instead.
## v0.20.0 <span style="font-size:0.5em; font-weight:normal">(till September 2024)</span>
- Models
diff --git a/repos/system_upgrade/common/libraries/config/tests/test_version.py b/repos/system_upgrade/common/libraries/config/tests/test_version.py
index 303e4de5..37a91c00 100644
--- a/repos/system_upgrade/common/libraries/config/tests/test_version.py
+++ b/repos/system_upgrade/common/libraries/config/tests/test_version.py
@@ -3,6 +3,7 @@ import pytest
from leapp.libraries.common.config import version
from leapp.libraries.common.testutils import CurrentActorMocked
from leapp.libraries.stdlib import api
+from leapp.models import IPUSourceToPossibleTargets
from leapp.utils.deprecation import suppress_deprecation
@@ -92,21 +93,20 @@ def test_is_rhel_alt(monkeypatch, result, kernel, release_id, src_ver):
assert version.is_rhel_alt() == result
-@pytest.mark.parametrize('result,is_alt,src_ver,saphana', [
- (True, True, '7.6', False),
- (True, False, '7.8', False),
- (False, True, '7.8', False),
- (False, False, '7.6', False),
- (True, True, '7.6', True),
- (True, False, '7.7', True),
- (False, True, '7.7', True),
- (False, False, '7.6', True),
+@pytest.mark.parametrize('result,src_ver,is_saphana', [
+ (True, '7.8', False), # default rhel
+ (False, '7.6', False),
+ (True, '7.7', True), # saphana
+ (False, '7.6', True),
])
-def test_is_supported_version(monkeypatch, result, is_alt, src_ver, saphana):
- monkeypatch.setattr(version, 'is_rhel_alt', lambda: is_alt)
- monkeypatch.setattr(version, 'is_sap_hana_flavour', lambda: saphana)
- monkeypatch.setattr(version, 'SUPPORTED_VERSIONS', {'rhel': ['7.8'], 'rhel-alt': ['7.6'], 'rhel-saphana': ['7.7']})
- monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(src_ver=src_ver))
+def test_is_supported_version(monkeypatch, result, src_ver, is_saphana):
+ if is_saphana:
+ supported_upgrade_paths = [IPUSourceToPossibleTargets(source_version='7.7', target_versions=['8.10'])]
+ else:
+ supported_upgrade_paths = [IPUSourceToPossibleTargets(source_version='7.8', target_versions=['8.10'])]
+
+ actor_mock = CurrentActorMocked(src_ver=src_ver, supported_upgrade_paths=supported_upgrade_paths)
+ monkeypatch.setattr(api, 'current_actor', actor_mock)
assert version.is_supported_version() == result
diff --git a/repos/system_upgrade/common/libraries/config/version.py b/repos/system_upgrade/common/libraries/config/version.py
index febeed36..b8fc550b 100644
--- a/repos/system_upgrade/common/libraries/config/version.py
+++ b/repos/system_upgrade/common/libraries/config/version.py
@@ -126,6 +126,12 @@ class _SupportedVersionsDict(dict):
SUPPORTED_VERSIONS = _SupportedVersionsDict()
+"""
+Deprecated since 2025-03-31.
+
+Use is_supported_version(), or IPUConfig.supported_upgrade_paths to check what source
+versions are supported for the current (release, flavour).
+"""
def _version_to_tuple(version):
@@ -319,13 +325,14 @@ def is_supported_version():
:return: `True` if the current version is supported and `False` otherwise.
:rtype: bool
"""
- release_id, version_id = current_version()
- if is_rhel_alt():
- release_id = 'rhel-alt'
- elif is_sap_hana_flavour():
- release_id = 'rhel-saphana'
+ source_version = get_source_version()
+ supported_upgrade_paths = api.current_actor().configuration.supported_upgrade_paths
- if not matches_release(SUPPORTED_VERSIONS, release_id):
- return False
+ # Check if there are any paths defined from the current source_version. If not,
+ # the upgrade version is unsupported
+ for ipu_source_to_targets in supported_upgrade_paths:
+ # No need to use matches_version - our version list is always a singleton
+ if ipu_source_to_targets.source_version == source_version:
+ return True
- return matches_version(SUPPORTED_VERSIONS[release_id], version_id)
+ return False
--
2.49.0

View File

@ -1,152 +0,0 @@
From e749dbc430099ac0d0cb06fb9dff4ec458d359b3 Mon Sep 17 00:00:00 2001
From: Daniel Diblik <ddiblik@redhat.com>
Date: Fri, 10 Oct 2025 16:51:34 +0200
Subject: [PATCH 19/55] Disable RHSM tests
Signed-off-by: Daniel Diblik <ddiblik@redhat.com>
---
.packit.yaml | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/.packit.yaml b/.packit.yaml
index 607dff93..3d1cd7ff 100644
--- a/.packit.yaml
+++ b/.packit.yaml
@@ -155,7 +155,7 @@ jobs:
tf_extra_params:
test:
tmt:
- plan_filter: 'tag:8to9 & tag:tier0 & enabled:true'
+ plan_filter: 'tag:8to9 & tag:tier0 & enabled:true & tag:-rhsm'
environments:
- tmt:
context:
@@ -182,7 +182,7 @@ jobs:
tf_extra_params:
test:
tmt:
- plan_filter: 'tag:8to9 & tag:partitioning & enabled:true'
+ plan_filter: 'tag:8to9 & tag:partitioning & enabled:true & tag:-rhsm'
environments:
- tmt:
context:
@@ -209,7 +209,7 @@ jobs:
tf_extra_params:
test:
tmt:
- plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true'
+ plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true & tag:-rhsm'
environments:
- tmt:
context:
@@ -232,7 +232,7 @@ jobs:
tf_extra_params:
test:
tmt:
- plan_filter: 'tag:8to9 & tag:tier0 & enabled:true'
+ plan_filter: 'tag:8to9 & tag:tier0 & enabled:true & tag:-rhsm'
environments:
- tmt:
context:
@@ -258,7 +258,7 @@ jobs:
tf_extra_params:
test:
tmt:
- plan_filter: 'tag:8to9 & tag:partitioning & enabled:true'
+ plan_filter: 'tag:8to9 & tag:partitioning & enabled:true & tag:-rhsm'
environments:
- tmt:
context:
@@ -284,7 +284,7 @@ jobs:
tf_extra_params:
test:
tmt:
- plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true'
+ plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true & tag:-rhsm'
environments:
- tmt:
context:
@@ -306,7 +306,7 @@ jobs:
tf_extra_params:
test:
tmt:
- plan_filter: 'tag:8to9 & tag:tier0 & enabled:true'
+ plan_filter: 'tag:8to9 & tag:tier0 & enabled:true & tag:-rhsm'
environments:
- tmt:
context:
@@ -332,7 +332,7 @@ jobs:
tf_extra_params:
test:
tmt:
- plan_filter: 'tag:8to9 & tag:partitioning & enabled:true'
+ plan_filter: 'tag:8to9 & tag:partitioning & enabled:true & tag:-rhsm'
environments:
- tmt:
context:
@@ -358,7 +358,7 @@ jobs:
tf_extra_params:
test:
tmt:
- plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true'
+ plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true & tag:-rhsm'
environments:
- tmt:
context:
@@ -434,7 +434,7 @@ jobs:
tf_extra_params:
test:
tmt:
- plan_filter: 'tag:9to10 & tag:tier0 & enabled:true'
+ plan_filter: 'tag:9to10 & tag:tier0 & enabled:true & tag:-rhsm'
environments:
- tmt:
context:
@@ -463,7 +463,7 @@ jobs:
tf_extra_params:
test:
tmt:
- plan_filter: 'tag:8to9 & tag:partitioning & enabled:true'
+ plan_filter: 'tag:8to9 & tag:partitioning & enabled:true & tag:-rhsm'
environments:
- tmt:
context:
@@ -489,7 +489,7 @@ jobs:
tf_extra_params:
test:
tmt:
- plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true'
+ plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true & tag:-rhsm'
environments:
- tmt:
context:
@@ -514,7 +514,7 @@ jobs:
tf_extra_params:
test:
tmt:
- plan_filter: 'tag:9to10 & tag:tier0 & enabled:true'
+ plan_filter: 'tag:9to10 & tag:tier0 & enabled:true & tag:-rhsm'
environments:
- tmt:
context:
@@ -543,7 +543,7 @@ jobs:
tf_extra_params:
test:
tmt:
- plan_filter: 'tag:8to9 & tag:partitioning & enabled:true'
+ plan_filter: 'tag:8to9 & tag:partitioning & enabled:true & tag:-rhsm'
environments:
- tmt:
context:
@@ -572,7 +572,7 @@ jobs:
tf_extra_params:
test:
tmt:
- plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true'
+ plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true & tag:-rhsm'
environments:
- tmt:
context:
--
2.51.1

View File

@ -0,0 +1,322 @@
From e330fef6ef748dd1ae1ca1f4ec2a4142818d1e43 Mon Sep 17 00:00:00 2001
From: Tomas Fratrik <tomasfratrik8@gmail.com>
Date: Mon, 14 Apr 2025 14:40:19 +0200
Subject: [PATCH 19/37] Remove 7to8 CI tests
Removing 7to8 CI tests because the upgrade path from RHEL-7 to RHEL-8 is no longer supported.
Jira: RHELMISC-11004
---
.github/workflows/reuse-copr-build.yml | 4 +-
.github/workflows/tmt-tests.yml | 59 ----------
.github/workflows/unit-tests.yml | 17 ---
.packit.yaml | 152 -------------------------
4 files changed, 2 insertions(+), 230 deletions(-)
diff --git a/.github/workflows/reuse-copr-build.yml b/.github/workflows/reuse-copr-build.yml
index c6702e1a..a772fb64 100644
--- a/.github/workflows/reuse-copr-build.yml
+++ b/.github/workflows/reuse-copr-build.yml
@@ -56,7 +56,7 @@ jobs:
id: copr_build
env:
COPR_CONFIG: "copr_fedora.conf"
- COPR_CHROOT: "epel-7-x86_64,epel-8-x86_64"
+ COPR_CHROOT: "epel-8-x86_64"
COPR_REPO: "@oamg/leapp"
run: |
cat << EOF > $COPR_CONFIG
@@ -122,7 +122,7 @@ jobs:
if: ${{ steps.leapp_pr_regex_match.outputs.match != '' }}
env:
COPR_CONFIG: "copr_fedora.conf"
- COPR_CHROOT: "epel-7-x86_64,epel-8-x86_64"
+ COPR_CHROOT: "epel-8-x86_64"
COPR_REPO: "@oamg/leapp"
run: |
cat << EOF > $COPR_CONFIG
diff --git a/.github/workflows/tmt-tests.yml b/.github/workflows/tmt-tests.yml
index 1fa00e60..c9f76ef7 100644
--- a/.github/workflows/tmt-tests.yml
+++ b/.github/workflows/tmt-tests.yml
@@ -10,65 +10,6 @@ jobs:
uses: ./.github/workflows/reuse-copr-build.yml
secrets: inherit
- call_workflow_tests_79to88_integration:
- needs: call_workflow_copr_build
- uses: oamg/leapp/.github/workflows/reuse-tests-7to8.yml@main
- secrets: inherit
- with:
- copr_artifacts: ${{ needs.call_workflow_copr_build.outputs.artifacts }}
- tmt_plan_regex: "^(?!.*upgrade_plugin)(?!.*tier[2-3].*)(?!.*rhsm)(?!.*c2r)(?!.*sap)(?!.*8to9)(?!.*max_sst)"
- pull_request_status_name: "7.9to8.8"
- variables: 'SOURCE_RELEASE=7.9;TARGET_RELEASE=8.8;LEAPPDATA_BRANCH=upstream'
- if: |
- github.event.issue.pull_request
- && ! startsWith(github.event.comment.body, '/rerun-sst')
- && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
-
- call_workflow_tests_79to86_integration:
- needs: call_workflow_copr_build
- uses: oamg/leapp/.github/workflows/reuse-tests-7to8.yml@main
- secrets: inherit
- with:
- copr_artifacts: ${{ needs.call_workflow_copr_build.outputs.artifacts }}
- tmt_plan_regex: "^(?!.*max_sst)(.*tier1)"
- variables: 'SOURCE_RELEASE=7.9;TARGET_RELEASE=8.6;LEAPPDATA_BRANCH=upstream'
- pull_request_status_name: "7.9to8.6"
- if: |
- github.event.issue.pull_request
- && ! startsWith(github.event.comment.body, '/rerun-sst')
- && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
-
- call_workflow_tests_79to88_sst:
- needs: call_workflow_copr_build
- uses: oamg/leapp/.github/workflows/reuse-tests-7to8.yml@main
- secrets: inherit
- with:
- copr_artifacts: ${{ needs.call_workflow_copr_build.outputs.artifacts }}
- tmt_plan_regex: "^(?!.*tier[2-3].*)(.*max_sst.*)"
- pull_request_status_name: "7.9to8.8-sst"
- update_pull_request_status: 'false'
- variables: 'SOURCE_RELEASE=7.9;TARGET_RELEASE=8.8;LEAPPDATA_BRANCH=upstream'
- if: |
- github.event.issue.pull_request
- && startsWith(github.event.comment.body, '/rerun-sst')
- && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
-
- call_workflow_tests_7to8_aws:
- needs: call_workflow_copr_build
- uses: oamg/leapp/.github/workflows/reuse-tests-7to8.yml@main
- secrets: inherit
- with:
- copr_artifacts: ${{ needs.call_workflow_copr_build.outputs.artifacts }}
- tmt_plan_regex: "^(?!.*upgrade_plugin)(?!.*tier[2-3].*)(?!.*rhsm)(?!.*c2r)(?!.*sap)(?!.*8to9)(.*e2e)"
- compose: "RHEL-7.9-rhui"
- environment_settings: '{"provisioning": {"post_install_script": "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys; echo 42; yum-config-manager --enable rhel-7-server-rhui-optional-rpms"}}'
- pull_request_status_name: "7to8-aws-e2e"
- variables: "SOURCE_RELEASE=7.9;TARGET_RELEASE=8.6;RHUI=aws;LEAPPDATA_BRANCH=upstream"
- if: |
- github.event.issue.pull_request
- && ! startsWith(github.event.comment.body, '/rerun-sst')
- && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
-
call_workflow_tests_86to90_integration:
needs: call_workflow_copr_build
uses: oamg/leapp/.github/workflows/reuse-tests-8to9.yml@main
diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml
index 42b72b8d..37748396 100644
--- a/.github/workflows/unit-tests.yml
+++ b/.github/workflows/unit-tests.yml
@@ -49,23 +49,6 @@ jobs:
python: python3.6
repos: 'el8toel9,common'
container: ubi8-lint
- # 7to8
- - name: Run unit tests for el7toel8 and common repositories on python 3.6
- python: python3.6
- repos: 'el7toel8,common'
- container: ubi8
- - name: Run python linters for el7toel8 and common repositories on python 3.6
- python: python3.6
- repos: 'el7toel8,common'
- container: ubi8-lint
- - name: Run unit tests for el7toel8 and common repositories on python 2.7
- python: python2.7
- repos: 'el7toel8,common'
- container: ubi7
- - name: Run python linters for el7toel8 and common repositories on python 2.7
- python: python2.7
- repos: 'el7toel8,common'
- container: ubi7-lint
steps:
- name: Checkout code
diff --git a/.packit.yaml b/.packit.yaml
index dd17303a..75788a25 100644
--- a/.packit.yaml
+++ b/.packit.yaml
@@ -32,7 +32,6 @@ jobs:
owner: "@oamg"
project: leapp
targets:
- - epel-7-x86_64
- epel-8-x86_64
- epel-9-x86_64
actions:
@@ -53,7 +52,6 @@ jobs:
owner: "@oamg"
project: leapp
targets:
- - epel-7-x86_64
- epel-8-x86_64
- epel-9-x86_64
actions:
@@ -73,7 +71,6 @@ jobs:
owner: "@oamg"
project: leapp
targets:
- - epel-7-x86_64
- epel-8-x86_64
- epel-9-x86_64
actions:
@@ -95,155 +92,6 @@ jobs:
# >7tox path https://gitlab.cee.redhat.com/oamg/leapp-tests/-/blob/main/config.yaml
# Available only to RH Employees.
-# ###################################################################### #
-# ############################### 7 TO 8 ############################### #
-# ###################################################################### #
-
-# ###################################################################### #
-# ### Abstract job definitions to make individual tests/jobs smaller ### #
-# ###################################################################### #
-- &sanity-abstract-7to8
- job: tests
- trigger: ignore
- fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
- fmf_ref: "rhel7"
- use_internal_tf: True
- labels:
- - sanity
- targets:
- epel-7-x86_64:
- distros: [RHEL-7.9-ZStream]
- identifier: sanity-abstract-7to8
- tmt_plan: ""
-
-- &sanity-abstract-7to8-aws
- <<: *sanity-abstract-7to8
- labels:
- - sanity
- - aws
- targets:
- epel-7-x86_64:
- distros: [RHEL-7.9-rhui]
- identifier: sanity-abstract-7to8-aws
-
-# On-demand minimal beaker tests
-- &beaker-minimal-7to8-abstract-ondemand
- <<: *sanity-abstract-7to8
- manual_trigger: True
- labels:
- - beaker-minimal
- identifier: beaker-minimal-7to8-abstract-ondemand
-
-# On-demand kernel-rt tests
-- &kernel-rt-abstract-7to8-ondemand
- <<: *beaker-minimal-7to8-abstract-ondemand
- labels:
- - kernel-rt
- identifier: sanity-7to8-kernel-rt-abstract-ondemand
-
-# ###################################################################### #
-# ######################### Individual tests ########################### #
-# ###################################################################### #
-
-# Tests: 7.9 -> 8.10
-- &sanity-79to810
- <<: *sanity-abstract-7to8
- trigger: pull_request
- identifier: sanity-7.9to8.10
- tf_extra_params:
- test:
- tmt:
- plan_filter: 'tag:7to8 & tag:sanity & enabled:true'
- environments:
- - tmt:
- context:
- distro: "rhel-7.9"
- distro_target: "rhel-8.10"
- settings:
- provisioning:
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
- env:
- SOURCE_RELEASE: "7.9"
- TARGET_RELEASE: "8.10"
-
-- &sanity-79to810-aws
- <<: *sanity-abstract-7to8-aws
- trigger: pull_request
- identifier: sanity-7.9to8.10-aws
- tf_extra_params:
- test:
- tmt:
- plan_filter: 'tag:7to8 & tag:upgrade_happy_path & enabled:true'
- environments:
- - tmt:
- context:
- distro: "rhel-7.9"
- distro_target: "rhel-8.10"
- settings:
- provisioning:
- post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
- env:
- SOURCE_RELEASE: "7.9"
- TARGET_RELEASE: "8.10"
- RHUI: "aws"
- LEAPPDATA_BRANCH: "upstream"
- LEAPP_NO_RHSM: "1"
- USE_CUSTOM_REPOS: rhui
-
-- &beaker-minimal-79to810
- <<: *beaker-minimal-7to8-abstract-ondemand
- trigger: pull_request
- labels:
- - beaker-minimal
- - beaker-minimal-7.9to8.10
- - 7.9to8.10
- identifier: sanity-7.9to8.10-beaker-minimal-ondemand
- tf_extra_params:
- test:
- tmt:
- plan_filter: 'tag:7to8 & tag:partitioning & enabled:true'
- environments:
- - tmt:
- context:
- distro: "rhel-7.9"
- distro_target: "rhel-8.10"
- settings:
- provisioning:
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
- env:
- SOURCE_RELEASE: "7.9"
- TARGET_RELEASE: "8.10"
-
-- &kernel-rt-79to810
- <<: *kernel-rt-abstract-7to8-ondemand
- trigger: pull_request
- labels:
- - kernel-rt
- - kernel-rt-7.9to8.10
- - 7.9to8.10
- identifier: sanity-7.9to8.10-kernel-rt-ondemand
- tf_extra_params:
- test:
- tmt:
- plan_filter: 'tag:7to8 & tag:kernel-rt & enabled:true'
- environments:
- - tmt:
- context:
- distro: "rhel-7.9"
- distro_target: "rhel-8.10"
- settings:
- provisioning:
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
- env:
- SOURCE_RELEASE: "7.9"
- TARGET_RELEASE: "8.10"
-
-
# ###################################################################### #
# ############################## 8 TO 9 ################################ #
# ###################################################################### #
--
2.49.0

View File

@ -0,0 +1,45 @@
From 9dd50a2fc3f30d3f5a00998ed9fc96d34129426d Mon Sep 17 00:00:00 2001
From: karolinku <kkula@redhat.com>
Date: Fri, 25 Apr 2025 14:23:20 +0200
Subject: [PATCH 20/37] Fix lint in Makefile for docs
isort is failing when getting empty list of arguments, what takes
place when only doc files was modified in a commit. This fix handles
that issue.
JIRA: RHELMISC-11679
---
Makefile | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/Makefile b/Makefile
index 3e090159..ceb013ab 100644
--- a/Makefile
+++ b/Makefile
@@ -356,16 +356,17 @@ lint:
echo "--- Linting done. ---"; \
fi
- if [[ "`git rev-parse --abbrev-ref HEAD`" != "$(MASTER_BRANCH)" ]] && [[ -n "`git diff $(MASTER_BRANCH) --name-only --diff-filter AMR`" ]]; then \
+ if [[ "`git rev-parse --abbrev-ref HEAD`" != "$(MASTER_BRANCH)" ]]; then \
. $(VENVNAME)/bin/activate; \
- git diff $(MASTER_BRANCH) --name-only --diff-filter AMR | grep -v "^docs/" | xargs isort -c --diff || \
- { \
+ files_to_sort=`git diff main --name-only --diff-filter AMR | grep -v "^docs/"`; \
+ if [ -n "$$files_to_sort" ]; then \
+ echo "$$files_to_sort" | xargs isort -c --diff || { \
echo; \
- echo "------------------------------------------------------------------------------"; \
- echo "Hint: Apply the required changes."; \
+ echo "Hint: Apply the required changes.";\
echo " Execute the following command to apply them automatically: make lint_fix"; \
exit 1; \
- } && echo "--- isort check done. ---"; \
+ } && echo "--- isort check done. ---"; \
+ fi \
fi
lint_fix:
--
2.49.0

View File

@ -1,462 +0,0 @@
From 6a38e8a3373bdc41a04538a090531ba0ccf8fa96 Mon Sep 17 00:00:00 2001
From: karolinku <kkula@redhat.com>
Date: Tue, 14 Oct 2025 15:11:02 +0200
Subject: [PATCH 20/55] Update packit config
Introduce refactor of labels and introduce 8.10 -> 9.6 AWS tests.
---
.packit.yaml | 285 ++++++++++++++++++++++++++-------------------------
1 file changed, 143 insertions(+), 142 deletions(-)
diff --git a/.packit.yaml b/.packit.yaml
index 3d1cd7ff..720d07a7 100644
--- a/.packit.yaml
+++ b/.packit.yaml
@@ -104,6 +104,8 @@ jobs:
# is the last RHEL 8 release and all new future tests will start from this
# one release.
+# This job is never triggered - we define abstract anchor that are reused in jobs that 'inherit'
+# and have actionable triggers
- &sanity-abstract-8to9
job: tests
trigger: ignore
@@ -116,6 +118,47 @@ jobs:
epel-8-x86_64:
distros: [RHEL-8.10.0-Nightly]
identifier: sanity-abstract-8to9
+ tf_extra_params:
+ test:
+ tmt:
+ plan_filter: 'tag:8to9'
+ environments:
+ - &tmt-env-settings-810to94
+ tmt:
+ context: &tmt-context-810to94
+ distro: "rhel-8.10"
+ distro_target: "rhel-9.4"
+ settings:
+ provisioning:
+ tags:
+ BusinessUnit: sst_upgrades@leapp_upstream_test
+ - &tmt-env-settings-810to96
+ tmt:
+ context: &tmt-context-810to96
+ distro: "rhel-8.10"
+ distro_target: "rhel-9.6"
+ settings:
+ provisioning:
+ tags:
+ BusinessUnit: sst_upgrades@leapp_upstream_test
+ - &tmt-env-settings-810to97
+ tmt:
+ context: &tmt-context-810to97
+ distro: "rhel-8.10"
+ distro_target: "rhel-9.7"
+ settings:
+ provisioning:
+ tags:
+ BusinessUnit: sst_upgrades@leapp_upstream_test
+ - &tmt-env-settings-810to98
+ tmt:
+ context: &tmt-context-810to98
+ distro: "rhel-8.10"
+ distro_target: "rhel-9.8"
+ settings:
+ provisioning:
+ tags:
+ BusinessUnit: sst_upgrades@leapp_upstream_test
- &sanity-abstract-8to9-aws
<<: *sanity-abstract-8to9
@@ -147,7 +190,10 @@ jobs:
# ######################### Individual tests ########################### #
# ###################################################################### #
-# Tests: 8.10 -> 9.4
+# ###################################################################### #
+# ############################# 8.10 > 9.4 ############################# #
+# ###################################################################### #
+
- &sanity-810to94
<<: *sanity-abstract-8to9
trigger: pull_request
@@ -157,15 +203,8 @@ jobs:
tmt:
plan_filter: 'tag:8to9 & tag:tier0 & enabled:true & tag:-rhsm'
environments:
- - tmt:
- context:
- distro: "rhel-8.10"
- distro_target: "rhel-9.4"
- settings:
- provisioning:
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
- env:
+ - *tmt-env-settings-810to94
+ env: &env-810to94
SOURCE_RELEASE: "8.10"
TARGET_RELEASE: "9.4"
LEAPP_TARGET_PRODUCT_CHANNEL: "EUS"
@@ -184,18 +223,9 @@ jobs:
tmt:
plan_filter: 'tag:8to9 & tag:partitioning & enabled:true & tag:-rhsm'
environments:
- - tmt:
- context:
- distro: "rhel-8.10"
- distro_target: "rhel-9.4"
- settings:
- provisioning:
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
+ - *tmt-env-settings-810to94
env:
- SOURCE_RELEASE: "8.10"
- TARGET_RELEASE: "9.4"
- LEAPP_TARGET_PRODUCT_CHANNEL: "EUS"
+ <<: *env-810to94
# On-demand kernel-rt tests
- &kernel-rt-810to94
@@ -212,19 +242,19 @@ jobs:
plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true & tag:-rhsm'
environments:
- tmt:
- context:
- distro: "rhel-8.10"
- distro_target: "rhel-9.4"
+ context: *tmt-context-810to94
settings:
provisioning:
tags:
BusinessUnit: sst_upgrades@leapp_upstream_test
env:
- SOURCE_RELEASE: "8.10"
- TARGET_RELEASE: "9.4"
- LEAPP_TARGET_PRODUCT_CHANNEL: "EUS"
+ <<: *env-810to94
+
+
+# ###################################################################### #
+# ############################# 8.10 > 9.6 ############################# #
+# ###################################################################### #
-# Tests: 8.10 -> 9.6
- &sanity-810to96
<<: *sanity-abstract-8to9
trigger: pull_request
@@ -234,15 +264,8 @@ jobs:
tmt:
plan_filter: 'tag:8to9 & tag:tier0 & enabled:true & tag:-rhsm'
environments:
- - tmt:
- context:
- distro: "rhel-8.10"
- distro_target: "rhel-9.6"
- settings:
- provisioning:
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
- env:
+ - *tmt-env-settings-810to96
+ env: &env-810to96
SOURCE_RELEASE: "8.10"
TARGET_RELEASE: "9.6"
@@ -260,17 +283,9 @@ jobs:
tmt:
plan_filter: 'tag:8to9 & tag:partitioning & enabled:true & tag:-rhsm'
environments:
- - tmt:
- context:
- distro: "rhel-8.10"
- distro_target: "rhel-9.6"
- settings:
- provisioning:
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
+ - *tmt-env-settings-810to96
env:
- SOURCE_RELEASE: "8.10"
- TARGET_RELEASE: "9.6"
+ <<: *env-810to96
# On-demand kernel-rt tests
- &kernel-rt-810to96
@@ -285,20 +300,37 @@ jobs:
test:
tmt:
plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true & tag:-rhsm'
+ environments:
+ - *tmt-env-settings-810to96
+ env:
+ <<: *env-810to96
+
+- &sanity-810to96-aws
+ <<: *sanity-abstract-8to9-aws
+ trigger: pull_request
+ targets:
+ epel-8-x86_64:
+ distros: [RHEL-8.10-rhui]
+ identifier: sanity-8.10to9.6-aws
+ tf_extra_params:
+ test:
+ tmt:
+ plan_filter: 'tag:8to9 & tag:rhui-aws-tier0 & enabled:true & tag:-rhsm'
environments:
- tmt:
- context:
- distro: "rhel-8.10"
- distro_target: "rhel-9.6"
+ context: *tmt-context-810to96
settings:
provisioning:
tags:
BusinessUnit: sst_upgrades@leapp_upstream_test
env:
- SOURCE_RELEASE: "8.10"
- TARGET_RELEASE: "9.6"
+ <<: *env-810to96
+
+
+# ###################################################################### #
+# ############################# 8.10 > 9.7 ############################# #
+# ###################################################################### #
-# Tests: 8.10 -> 9.7
- &sanity-810to97
<<: *sanity-abstract-8to9
trigger: pull_request
@@ -308,15 +340,8 @@ jobs:
tmt:
plan_filter: 'tag:8to9 & tag:tier0 & enabled:true & tag:-rhsm'
environments:
- - tmt:
- context:
- distro: "rhel-8.10"
- distro_target: "rhel-9.7"
- settings:
- provisioning:
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
- env:
+ - *tmt-env-settings-810to97
+ env: &env-810to97
SOURCE_RELEASE: "8.10"
TARGET_RELEASE: "9.7"
@@ -334,17 +359,9 @@ jobs:
tmt:
plan_filter: 'tag:8to9 & tag:partitioning & enabled:true & tag:-rhsm'
environments:
- - tmt:
- context:
- distro: "rhel-8.10"
- distro_target: "rhel-9.7"
- settings:
- provisioning:
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
+ - *tmt-env-settings-810to97
env:
- SOURCE_RELEASE: "8.10"
- TARGET_RELEASE: "9.7"
+ <<: *env-810to97
# On-demand kernel-rt tests
- &kernel-rt-810to97
@@ -360,17 +377,9 @@ jobs:
tmt:
plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true & tag:-rhsm'
environments:
- - tmt:
- context:
- distro: "rhel-8.10"
- distro_target: "rhel-9.7"
- settings:
- provisioning:
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
+ - *tmt-env-settings-810to97
env:
- SOURCE_RELEASE: "8.10"
- TARGET_RELEASE: "9.7"
+ <<: *env-810to97
# ###################################################################### #
# ############################## 9 TO 10 ################################ #
@@ -392,6 +401,38 @@ jobs:
epel-9-x86_64:
distros: [RHEL-9.6.0-Nightly]
identifier: sanity-abstract-9to10
+ tf_extra_params:
+ test:
+ tmt:
+ plan_filter: 'tag:9to10'
+ environments:
+ - &tmt-env-settings-96to100
+ tmt:
+ context: &tmt-context-96to100
+ distro: "rhel-9.6"
+ distro_target: "rhel-10.0"
+ settings:
+ provisioning:
+ tags:
+ BusinessUnit: sst_upgrades@leapp_upstream_test
+ - &tmt-env-settings-97to101
+ tmt:
+ context: &tmt-context-97to101
+ distro: "rhel-9.7"
+ distro_target: "rhel-10.1"
+ settings:
+ provisioning:
+ tags:
+ BusinessUnit: sst_upgrades@leapp_upstream_test
+ - &tmt-env-settings-98to102
+ tmt:
+ context: &tmt-context-98to102
+ distro: "rhel-9.8"
+ distro_target: "rhel-10.2"
+ settings:
+ provisioning:
+ tags:
+ BusinessUnit: sst_upgrades@leapp_upstream_test
- &sanity-abstract-9to10-aws
<<: *sanity-abstract-9to10
@@ -423,7 +464,10 @@ jobs:
# ######################### Individual tests ########################### #
# ###################################################################### #
-# Tests: 9.6 -> 10.0
+# ###################################################################### #
+# ############################# 9.6 > 10.0 ############################# #
+# ###################################################################### #
+
- &sanity-96to100
<<: *sanity-abstract-9to10
trigger: pull_request
@@ -436,15 +480,8 @@ jobs:
tmt:
plan_filter: 'tag:9to10 & tag:tier0 & enabled:true & tag:-rhsm'
environments:
- - tmt:
- context:
- distro: "rhel-9.6"
- distro_target: "rhel-10.0"
- settings:
- provisioning:
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
- env:
+ - *tmt-env-settings-96to100
+ env: &env-96to100
SOURCE_RELEASE: "9.6"
TARGET_RELEASE: "10.0"
@@ -465,17 +502,9 @@ jobs:
tmt:
plan_filter: 'tag:8to9 & tag:partitioning & enabled:true & tag:-rhsm'
environments:
- - tmt:
- context:
- distro: "rhel-9.6"
- distro_target: "rhel-10.0"
- settings:
- provisioning:
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
+ - *tmt-env-settings-96to100
env:
- SOURCE_RELEASE: "9.6"
- TARGET_RELEASE: "10.0"
+ <<: *env-96to100
# On-demand kernel-rt tests
- &kernel-rt-96to100
@@ -491,19 +520,14 @@ jobs:
tmt:
plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true & tag:-rhsm'
environments:
- - tmt:
- context:
- distro: "rhel-9.6"
- distro_target: "rhel-10.0"
- settings:
- provisioning:
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
+ - *tmt-env-settings-96to100
env:
- SOURCE_RELEASE: "9.6"
- TARGET_RELEASE: "10.0"
+ <<: *env-96to100
+
+# ###################################################################### #
+# ############################# 9.7 > 10.1 ############################# #
+# ###################################################################### #
-# Tests: 9.7 -> 10.1
- &sanity-97to101
<<: *sanity-abstract-9to10
trigger: pull_request
@@ -516,15 +540,8 @@ jobs:
tmt:
plan_filter: 'tag:9to10 & tag:tier0 & enabled:true & tag:-rhsm'
environments:
- - tmt:
- context:
- distro: "rhel-9.7"
- distro_target: "rhel-10.1"
- settings:
- provisioning:
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
- env:
+ - *tmt-env-settings-97to101
+ env: &env-97to101
SOURCE_RELEASE: "9.7"
TARGET_RELEASE: "10.1"
@@ -545,17 +562,9 @@ jobs:
tmt:
plan_filter: 'tag:8to9 & tag:partitioning & enabled:true & tag:-rhsm'
environments:
- - tmt:
- context:
- distro: "rhel-9.7"
- distro_target: "rhel-10.1"
- settings:
- provisioning:
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
+ - *tmt-env-settings-97to101
env:
- SOURCE_RELEASE: "9.7"
- TARGET_RELEASE: "10.1"
+ <<: *env-97to101
# On-demand kernel-rt tests
- &kernel-rt-97to101
@@ -574,14 +583,6 @@ jobs:
tmt:
plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true & tag:-rhsm'
environments:
- - tmt:
- context:
- distro: "rhel-9.7"
- distro_target: "rhel-10.1"
- settings:
- provisioning:
- tags:
- BusinessUnit: sst_upgrades@leapp_upstream_test
+ - *tmt-env-settings-97to101
env:
- SOURCE_RELEASE: "9.7"
- TARGET_RELEASE: "10.1"
+ <<: *env-97to101
--
2.51.1

View File

@ -0,0 +1,41 @@
From 47f37314e26fe0e899b8fdd2fe280f2f8ebf15b5 Mon Sep 17 00:00:00 2001
From: Tomas Fratrik <tomasfratrik8@gmail.com>
Date: Mon, 28 Apr 2025 14:32:54 +0200
Subject: [PATCH 21/37] Improve report of removed kernel drivers
* Insert target RHEL version in report KCS titles for removed kernel drivers.
Jira: RHEL-49402
---
.../libraries/checkdddd.py | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/repos/system_upgrade/common/actors/checkdetecteddevicesanddrivers/libraries/checkdddd.py b/repos/system_upgrade/common/actors/checkdetecteddevicesanddrivers/libraries/checkdddd.py
index defe3f9a..1f01adde 100644
--- a/repos/system_upgrade/common/actors/checkdetecteddevicesanddrivers/libraries/checkdddd.py
+++ b/repos/system_upgrade/common/actors/checkdetecteddevicesanddrivers/libraries/checkdddd.py
@@ -37,13 +37,17 @@ def create_inhibitors(inhibiting_entries):
),
reporting.ExternalLink(
url='https://access.redhat.com/solutions/6971716',
- title='Leapp preupgrade getting "Inhibitor: Detected loaded kernel drivers which have been '
- 'removed in RHEL 8. Upgrade cannot proceed." '
+ title=('Leapp preupgrade getting "Inhibitor: Detected loaded kernel drivers which have been '
+ 'removed in RHEL {target}. Upgrade cannot proceed."').format(target=get_target_major_version())
),
reporting.ExternalLink(
url='https://access.redhat.com/solutions/5436131',
- title='Leapp upgrade fail with error "Inhibitor: Detected loaded kernel drivers which '
- 'have been removed in RHEL 8. Upgrade cannot proceed."'
+ title=(
+ 'Leapp upgrade fail with error "Inhibitor: Detected loaded kernel drivers which '
+ 'have been removed in RHEL {target}. Upgrade cannot proceed."'
+ ).format(
+ target=get_target_major_version()
+ )
),
reporting.Audience('sysadmin'),
reporting.Groups([reporting.Groups.KERNEL, reporting.Groups.DRIVERS]),
--
2.49.0

View File

@ -1,880 +0,0 @@
From 06afa61c2508f18937244787440c709c5ee0a285 Mon Sep 17 00:00:00 2001
From: karolinku <kkula@redhat.com>
Date: Tue, 14 Oct 2025 15:56:11 +0200
Subject: [PATCH 21/55] Update upgrade paths: 8.10 -> 9.8 -> 10.2 with
certificates
Jira: RHEL-108025
---
.packit.yaml | 119 ++++++++++++++++++
.../common/files/prod-certs/10.2/279.pem | 35 ++++++
.../common/files/prod-certs/10.2/362.pem | 36 ++++++
.../common/files/prod-certs/10.2/363.pem | 35 ++++++
.../common/files/prod-certs/10.2/419.pem | 35 ++++++
.../common/files/prod-certs/10.2/433.pem | 35 ++++++
.../common/files/prod-certs/10.2/479.pem | 35 ++++++
.../common/files/prod-certs/10.2/486.pem | 35 ++++++
.../common/files/prod-certs/10.2/72.pem | 35 ++++++
.../common/files/prod-certs/9.8/279.pem | 35 ++++++
.../common/files/prod-certs/9.8/362.pem | 36 ++++++
.../common/files/prod-certs/9.8/363.pem | 35 ++++++
.../common/files/prod-certs/9.8/419.pem | 35 ++++++
.../common/files/prod-certs/9.8/433.pem | 35 ++++++
.../common/files/prod-certs/9.8/479.pem | 35 ++++++
.../common/files/prod-certs/9.8/486.pem | 35 ++++++
.../common/files/prod-certs/9.8/72.pem | 35 ++++++
.../common/files/upgrade_paths.json | 10 +-
18 files changed, 687 insertions(+), 4 deletions(-)
create mode 100644 repos/system_upgrade/common/files/prod-certs/10.2/279.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/10.2/362.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/10.2/363.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/10.2/419.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/10.2/433.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/10.2/479.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/10.2/486.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/10.2/72.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.8/279.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.8/362.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.8/363.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.8/419.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.8/433.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.8/479.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.8/486.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.8/72.pem
diff --git a/.packit.yaml b/.packit.yaml
index 720d07a7..0c3f682a 100644
--- a/.packit.yaml
+++ b/.packit.yaml
@@ -381,6 +381,60 @@ jobs:
env:
<<: *env-810to97
+# ###################################################################### #
+# ############################# 8.10 > 9.8 ############################# #
+# ###################################################################### #
+
+- &sanity-810to98
+ <<: *sanity-abstract-8to9
+ trigger: pull_request
+ identifier: sanity-8.10to9.8
+ tf_extra_params:
+ test:
+ tmt:
+ plan_filter: 'tag:8to9 & tag:tier0 & enabled:true'
+ environments:
+ - *tmt-env-settings-810to98
+ env: &env-810to98
+ SOURCE_RELEASE: "8.10"
+ TARGET_RELEASE: "9.8"
+
+# On-demand minimal beaker tests
+- &beaker-minimal-810to98
+ <<: *beaker-minimal-8to9-abstract-ondemand
+ trigger: pull_request
+ labels:
+ - beaker-minimal
+ - beaker-minimal-8.10to9.8
+ - 8.10to9.8
+ identifier: sanity-8.10to9.8-beaker-minimal-ondemand
+ tf_extra_params:
+ test:
+ tmt:
+ plan_filter: 'tag:8to9 & tag:partitioning & enabled:true'
+ environments:
+ - *tmt-env-settings-810to98
+ env:
+ <<: *env-810to98
+
+# On-demand kernel-rt tests
+- &kernel-rt-810to98
+ <<: *kernel-rt-abstract-8to9-ondemand
+ trigger: pull_request
+ labels:
+ - kernel-rt
+ - kernel-rt-8.10to9.8
+ - 8.10to9.8
+ identifier: sanity-8.10to9.8-kernel-rt-ondemand
+ tf_extra_params:
+ test:
+ tmt:
+ plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true'
+ environments:
+ - *tmt-env-settings-810to98
+ env:
+ <<: *env-810to98
+
# ###################################################################### #
# ############################## 9 TO 10 ################################ #
# ###################################################################### #
@@ -586,3 +640,68 @@ jobs:
- *tmt-env-settings-97to101
env:
<<: *env-97to101
+
+
+# ###################################################################### #
+# ############################# 9.8 > 10.2 ############################# #
+# ###################################################################### #
+
+- &sanity-98to102
+ <<: *sanity-abstract-9to10
+ trigger: pull_request
+ identifier: sanity-9.8to10.2
+ targets:
+ epel-9-x86_64:
+ distros: [RHEL-9.8.0-Nightly]
+ tf_extra_params:
+ test:
+ tmt:
+ plan_filter: 'tag:9to10 & tag:tier0 & enabled:true & tag:-rhsm'
+ environments:
+ - *tmt-env-settings-98to102
+ env: &env-98to102
+ SOURCE_RELEASE: "9.8"
+ TARGET_RELEASE: "10.2"
+
+# On-demand minimal beaker tests
+- &beaker-minimal-98to102
+ <<: *beaker-minimal-9to10-abstract-ondemand
+ trigger: pull_request
+ labels:
+ - beaker-minimal
+ - beaker-minimal-9.8to10.2
+ - 9.8to10.2
+ identifier: sanity-9.8to10.2-beaker-minimal-ondemand
+ targets:
+ epel-9-x86_64:
+ distros: [RHEL-9.8-Nightly]
+ tf_extra_params:
+ test:
+ tmt:
+ plan_filter: 'tag:8to9 & tag:partitioning & enabled:true & tag:-rhsm'
+ environments:
+ - *tmt-env-settings-98to102
+ env:
+ <<: *env-98to102
+
+# On-demand kernel-rt tests
+- &kernel-rt-98to102
+ <<: *kernel-rt-abstract-9to10-ondemand
+ trigger: pull_request
+ labels:
+ - kernel-rt
+ - kernel-rt-9.8to10.2
+ - 9.8to10.2
+ identifier: sanity-9.8to10.2-kernel-rt-ondemand
+ targets:
+ epel-9-x86_64:
+ distros: [RHEL-9.8-Nightly]
+ tf_extra_params:
+ test:
+ tmt:
+ plan_filter: 'tag:8to9 & tag:kernel-rt & enabled:true & tag:-rhsm'
+ environments:
+ - *tmt-env-settings-98to102
+ env:
+ <<: *env-98to102
+
diff --git a/repos/system_upgrade/common/files/prod-certs/10.2/279.pem b/repos/system_upgrade/common/files/prod-certs/10.2/279.pem
new file mode 100644
index 00000000..76336f82
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/10.2/279.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGKDCCBBCgAwIBAgIJALDxRLt/tVBkMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDcwODExMjQ0NloXDTQ1MDcw
+ODExMjQ0NlowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFsyOWJlMDI0
+My03NGU1LTRiNDctYjEwNy1iZjhkNjRjYmNjNDhdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBsTCBrjAJBgNVHRMEAjAAMEMGDCsGAQQBkggJAYIXAQQzDDFSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIFBvd2VyLCBsaXR0bGUgZW5kaWFuMBYGDCsG
+AQQBkggJAYIXAgQGDAQxMC4yMBkGDCsGAQQBkggJAYIXAwQJDAdwcGM2NGxlMCkG
+DCsGAQQBkggJAYIXBAQZDBdyaGVsLTEwLHJoZWwtMTAtcHBjNjRsZTANBgkqhkiG
+9w0BAQsFAAOCAgEAGouNVN3DdCE2cqv3lKMNC3jit5mHi7QQt7fqN/KX4fQfArb6
+IQ9M0GaGJM8W9rj+9s+Q9LOFjys24Pcdb9qbQWpfwvn9FY60uQw3TIXAerJaVb98
+doxrFHjVptm0/VX2xnOa/dY97dmMT4Amwe5+y4RYlMEsYqY8dpJkVuKNdGtCg+Uf
+f9hb6XjDqRevADgskHNprXrjF65Ib3a92qJRfttnVUfqqeDkTPntIPbau9hZwLeR
+oMl8pn4kMIYLz1IolSAC8yBFe9sLxllGu8qIFqH4Efzx8BOtHkPUH/VqtgvUej+j
+boJ0EEpwYjvYbz00mZmJHFNkUheW6cDUPWmMoTzYibPzRTrBcAIfvybpeuPjFGfl
+gYZa/DpEG68hlEnSxB4TNpVCx9qfiqXvNcukmeX3Jr7DS1uC2ePBFDQKewx6WdAa
+bAmuANmBUB+NX1WMuNTfxxIzxfIoShaChiFRVjsRTkLo1ZPuMkvXOXYfyfW1PKQN
+PXHEdY9wprn8ZY2qhMwmE1sDdndNpSxB3boI9FQBUVDzbSG6KwbPfSdmrte+Wdrh
+QCIGU+0x7ulF68yOkMkz1spPNgrTXt0efaCSWqUK0nqv1s1Gh2Q6iJaE0yETpSG7
+hFeHpENftckpmuKcJM0v/uBBeIX7X8plrL7Fkm4ND/e61tEiDwvnhxGhtBE=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/10.2/362.pem b/repos/system_upgrade/common/files/prod-certs/10.2/362.pem
new file mode 100644
index 00000000..ebeb065c
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/10.2/362.pem
@@ -0,0 +1,36 @@
+-----BEGIN CERTIFICATE-----
+MIIGNzCCBB+gAwIBAgIJALDxRLt/tVBTMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDcwODExMjQzMVoXDTQ1MDcw
+ODExMjQzMVowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFthMmU1N2Ix
+MS03ZDBiLTRiNGYtOGE5ZC03MmRkNGM2NDA2NzJdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBwDCBvTAJBgNVHRMEAjAAMEgGDCsGAQQBkggJAYJqAQQ4DDZSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIFBvd2VyLCBsaXR0bGUgZW5kaWFuIEJldGEw
+GwYMKwYBBAGSCAkBgmoCBAsMCTEwLjIgQmV0YTAZBgwrBgEEAZIICQGCagMECQwH
+cHBjNjRsZTAuBgwrBgEEAZIICQGCagQEHgwccmhlbC0xMCxyaGVsLTEwLWJldGEt
+cHBjNjRsZTANBgkqhkiG9w0BAQsFAAOCAgEAgQC6qqfeW79hSj2S+OfBT5ccNNZa
+8blVYtVJU5iTfhX29VQTdGus/ROWGqfgDe8MMOCJyt0eNeqGO70KRJsT3pGeeKcM
+UbDfdqzopgD7+/6IL1c1fw/8HijOorW+CMAzeOBdnjMwRjhZxcDlFSqxNCWtngnp
+XlDMIlUR3m0rlBwzNfUMk7KYPUESmyEiBWMSKmqRDeiUg3BSP6Ci0x3Ufnf0xTBv
+VPVKO/h3ta3+pAYzeFy/ageJ/sR9tLRZQZXzvxYvIY+8/EehafPJCHDHH3uCTpdZ
+JAeXDLf2QcOBZnl8uONdev+KaE1JFRCRmqwhliUsARv/t24CY+UBoEzzaj/py2bR
+RQqfE5WI1JSdj6HoQ6YHbtR6SF+UedfvMQoSF4zPiXAPNebiIiLkc1rtb/ycUi1f
+bUjkRfgRqlDwUcgfHrKhSDp5/XhjgxVXiESNcDe2ltKvVr09qAaPBarLolWeIXkN
+n2csdFxyiDZIhk6tFL8lUtpmXWpeEn/iBPwaiBIYoBnIbaqN4OZngwfi2QtTdl+s
+9iCuYgbGQiEZnV3g7HLsYXrAagPuJxXs0FMYJZ8x6biREgUQATwTzZMQ8vWRMmYY
+kteQBaOCDzNpb8OUgbPxgncl9kgr4NIBn+5oGeMitb+I1XvWqoCFsA7Uii6oygdk
+iE+YZEA6e/4057M=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/10.2/363.pem b/repos/system_upgrade/common/files/prod-certs/10.2/363.pem
new file mode 100644
index 00000000..865fbda6
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/10.2/363.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGKTCCBBGgAwIBAgIJALDxRLt/tVBSMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDcwODExMjQzMVoXDTQ1MDcw
+ODExMjQzMVowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs0NjJhNDRj
+ZC1jNWUzLTQzZGItYTExNy0zZjA5ZGU1ZDRmMzNdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBsjCBrzAJBgNVHRMEAjAAMDoGDCsGAQQBkggJAYJrAQQqDChSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIEFSTSA2NCBCZXRhMBsGDCsGAQQBkggJAYJr
+AgQLDAkxMC4yIEJldGEwGQYMKwYBBAGSCAkBgmsDBAkMB2FhcmNoNjQwLgYMKwYB
+BAGSCAkBgmsEBB4MHHJoZWwtMTAscmhlbC0xMC1iZXRhLWFhcmNoNjQwDQYJKoZI
+hvcNAQELBQADggIBAC/KEEZ85rdWnL/CK9q3uT/d4reNZc1WD5oWYcpj+J31u4sw
+pjAvmq/eA6DmzqGjhfEGhwu5MDbVg77OAPCcfm7qqGSDcnjqnO3ZogDjyzat1WS5
+J2uuRcPbF6DIk/LkgIc/FgvSFG8Vc93hM+P56wTzTbnPYSRyJq3BBm8ZjSiFO5jq
+V9WOganzxsVKzifTK8RoSdWLyB0JpvL/LZKa4G97ahUctYVilhJBHCgd+uT6/IVn
+ppETnw4xo6SXg0+O+fC1P+90+GZrWWzeHeHnEgmZ8B+RTDQbx/KHQHU4UhqU5qnT
+6VngqL1453IxmlxVxwKlkwzV4SYrQnmEZPvugMhlenbx0T9pJvwg/xvWYJJTGjUy
+1l9p0LtyUHmFJxtbq50++oooUdDtQ6RDD5jtxnvWMF5PFLYGxf6gXFFCJVSgwonP
+BtqoBH2PWp8/nwumAOquzks41m+bqzaMALhp0GUGTKKTITrM4gsLVHqKh2WTCOPs
+s6mdXOyVma/o5Jri8Ec12/HGyIRlQQleb6vcC68PK3X088LZi/zENi2Bq31W5Hip
+R03YxVzmjZA3kJsA8Vim4zaG7e6puLGuXmQLawN7oScBFlvVLvZD2ycZsYLOesCz
+VSxJkmqDMb6To9RRbSmN0csPFKWNkdD8D5iBei4IaGWXyOB3GGJJ2ME/Qv65
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/10.2/419.pem b/repos/system_upgrade/common/files/prod-certs/10.2/419.pem
new file mode 100644
index 00000000..42986ccc
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/10.2/419.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGGjCCBAKgAwIBAgIJALDxRLt/tVBjMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDcwODExMjQ0NloXDTQ1MDcw
+ODExMjQ0NlowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs0MjIwNzhj
+OS1mY2MzLTQwMWQtOGM2Yi0yZGUwNWRmZGEyN2NdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBozCBoDAJBgNVHRMEAjAAMDUGDCsGAQQBkggJAYMjAQQlDCNSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIEFSTSA2NDAWBgwrBgEEAZIICQGDIwIEBgwE
+MTAuMjAZBgwrBgEEAZIICQGDIwMECQwHYWFyY2g2NDApBgwrBgEEAZIICQGDIwQE
+GQwXcmhlbC0xMCxyaGVsLTEwLWFhcmNoNjQwDQYJKoZIhvcNAQELBQADggIBAAvn
+gY6rJIku70uFkod9Xc45wNgPNMkim2p+dCOQXl5GG7rSLqBp/e6MhBOu+VfvXddF
+zEndO84pb7Evc3PjjtnBietvvcmcoJjMTrGF2oKcJWJP+x/SKMzN2qPPoQu4QoZj
+OTuaemuHLCkA9cnvRj2qxW9ZpINmr6H72jCHPoYGWD8Omupnctyt3/uu/MG7KT4y
+8B5hXLmFeuF1vgOkKnoqjZRgZ86xsJ4dig/vLWkAKdsWPlRlV0SICwgVALqFmTge
+Hgrz0A6F2BM7f0vYNFUTRv0qQwHR7EA/jEHCQByNc73cvDtHZFyODTqvEBoLFVOw
+2fad9K5EID1GKj9U1NGYAlAvEpbrgs2Xd2ugFyN5mtbSLon+VeXm5q9fB/Ca0j7z
+vvfdoKsd89R822m2Y+HB0eei63zGE6Ykr4aaTQNjQyTu5K8pUNG/y5UGWIpSM1IR
+YqOsdJvCyavBlQ98K7OfL9yqOiZFXB9VkmXPPiT1ljNgpYzK63ZWidjXkpG2I7g1
+YoCIT0JE5xX6x2U5Ia79OFug/g9SwQn6izVYrLCgqqNqeld0WokeFBPnyZkXSYt1
+pzY4HAjXjaDGbF1O4SmoCTtagB2vNmi1wUPazizA5SESifVcYfPeaWRk10PJT9MR
+p3EFR/BSg/hvmehuGSEfRNFV8g9Deo3EN1LHEhTY
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/10.2/433.pem b/repos/system_upgrade/common/files/prod-certs/10.2/433.pem
new file mode 100644
index 00000000..932dbf7a
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/10.2/433.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGLDCCBBSgAwIBAgIJALDxRLt/tVBUMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDcwODExMjQzMVoXDTQ1MDcw
+ODExMjQzMVowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFsxNzhhMzJi
+NC0xZWNjLTRmZDEtOTA2NS0wMGZkMjQzZDEzYzBdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBtTCBsjAJBgNVHRMEAjAAMEEGDCsGAQQBkggJAYMxAQQxDC9SZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIElCTSB6IFN5c3RlbXMgQmV0YTAbBgwrBgEE
+AZIICQGDMQIECwwJMTAuMiBCZXRhMBcGDCsGAQQBkggJAYMxAwQHDAVzMzkweDAs
+BgwrBgEEAZIICQGDMQQEHAwacmhlbC0xMCxyaGVsLTEwLWJldGEtczM5MHgwDQYJ
+KoZIhvcNAQELBQADggIBAAUwQwSc0A1Q5SiC7N5xSS1ZegZQT1hER7SRDs5p6drK
+Riayu5bER7kpQnJc/ww1/iTmHHH/H180pSP+EZEPqCLumqYmf1vW60SAR4BMklyh
+QuYqVkJCxA7uloA59cLZcPnEu+xHLfnhSQdTIXhi1uLK960mEIiexCT8xMkQ5E5A
+ZUajyEhdLp4ca8K+nUWzSzYQBpGYpkiQtniLZ/i4kzaYTfHpFGJNQQCrPlB2lMCa
+vZKseaPlFzExXfq5MJ5IX1lc2RNqeaf22p49Bia6CgVLMagsFnAr909zZ9NAaZWV
+kYqjLVMJ5EY25OJS21So0fI//lOsRVBxlfqOS7v9hYBnuLhPuiIiHEaNcQyNBI/7
+DgT5xCmL8IDzvsBJLZ/AqolO1fo5lSVOZ5PCbwIZj7bBZJwf8gTSUu2cuhbN2Gxi
+s7R2QFVco+AAPcuoWOISG4cKwX4wDUR+rHqQMCKJM6mQGlnB2OXBwZX1fYo7k82d
+b7BygRhEML6INaweUe2Do7v8phz6TXM2lFJCQYnja2lO6GxSlaXgRNb4Rnc6ty79
+O5S6K2g3uEc4Uc8F7echBFAudl9KQqu9il9cb3f0fI+kYX2j9ib4isdF8qIusZVp
+F191fHyl1Y6pp4eWKA48uO8Op8uO320UIX8HQnNGi74eEOvCqvZtfKZE5+Za/YT+
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/10.2/479.pem b/repos/system_upgrade/common/files/prod-certs/10.2/479.pem
new file mode 100644
index 00000000..2c4b8db2
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/10.2/479.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGGDCCBACgAwIBAgIJALDxRLt/tVBmMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDcwODExMjQ0NloXDTQ1MDcw
+ODExMjQ0NlowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs5OTUxYjVm
+NC0yZTE4LTQ1OGEtYTc4ZC05NGNkZDhkN2I1ZWVdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBoTCBnjAJBgNVHRMEAjAAMDUGDCsGAQQBkggJAYNfAQQlDCNSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIHg4Nl82NDAWBgwrBgEEAZIICQGDXwIEBgwE
+MTAuMjAYBgwrBgEEAZIICQGDXwMECAwGeDg2XzY0MCgGDCsGAQQBkggJAYNfBAQY
+DBZyaGVsLTEwLHJoZWwtMTAteDg2XzY0MA0GCSqGSIb3DQEBCwUAA4ICAQDUoyHm
+MM07NncLVGO9xO6qa3cxy8NyJO95LScKCAzlx3dHrgW+v1CcxZEzMsV6Rtpch0kH
+De61DOCn50JgQ6s7e6Cxk6nMovcxYMi5q4JxYoIlCFTbeRRGdTQv8SmndmSd7rh2
+6mDUWoDxbw1fpeNxiWAOq8IQXrcmrEnVIpOQP4Fc+yNw/Sdsqz23o9VBlP0yBJ4W
+a6zGCwRzcisLsNOc+8mRtuirG11Zqm07V0xt2YVXlV13Wu/Dy0qKW49tPJD8WceO
+hCC/alSRh1s4YV50gVlA0IRyyezAwU/0Al+lMKfMeqqedg81QGMBiy6qzDjXllcK
+XfKYsWC2egkofpvxb5jVU0EXdl0kE+RGQfK3fVq09YwNim41n9qgJTlA1vIBrq8o
+1NMwyrbQdfndyGZLSpzWxLHpYUCe2lJomgJTNvrA6+xTnlpfEPOn2zDUxJ7CSfoQ
+ZkPhdO4UsrvJOPLt5oY5R5Q6tXLVR7xL24WeUw5FXtzFMibOaE3kT9ib0o8zluMS
+ly290tfnl8Wq7fgjFT8mt0NIH/rXC4COBw87EjLbhxUCbEHnbJiOj+JT2QRxKjWg
+9icCBbU5TEY0V8rC+vx54JCcx8NGaJDDKDmv6tgEOA0u9YEpGw44fk6RxqeNaysW
+glkF2dUoSBDKWSqiroYrjEgaFWvdSaalOSJQuA==
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/10.2/486.pem b/repos/system_upgrade/common/files/prod-certs/10.2/486.pem
new file mode 100644
index 00000000..181b7a98
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/10.2/486.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGJzCCBA+gAwIBAgIJALDxRLt/tVBVMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDcwODExMjQzMVoXDTQ1MDcw
+ODExMjQzMVowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs2OWQ5ZGY5
+Yy1mMGFmLTRjY2UtYTRhMi0zZDA4MDM1YjJmYjFdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBsDCBrTAJBgNVHRMEAjAAMDoGDCsGAQQBkggJAYNmAQQqDChSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIHg4Nl82NCBCZXRhMBsGDCsGAQQBkggJAYNm
+AgQLDAkxMC4yIEJldGEwGAYMKwYBBAGSCAkBg2YDBAgMBng4Nl82NDAtBgwrBgEE
+AZIICQGDZgQEHQwbcmhlbC0xMCxyaGVsLTEwLWJldGEteDg2XzY0MA0GCSqGSIb3
+DQEBCwUAA4ICAQA00Q5BALEU5y1CJwF7ru1xNujrtjZvwOdXeNl+esZIqlZQqITP
+Rr6Xww0/mcMcvqEHu/PlJ2xyWC8VYrhZ+/LC6EtTbPEKSDEAHE914MU934pC02tP
+QE+a7BKsHPGhh4SyvMrZ0vWoxnwcug5g8V5uXNOQYSgnOAHdNQxMeMh8LCHO76np
+fjWL7en5dUMWHOB9W1kyZO87f2WBGhFrTyNnFTcg99G/MNMkMD5rLc+Qg8GhY1Zt
+8+AN4c5HprFI1cUz8/4osj2ZBW1xxH+mcps2oy3L8UNFceiAdewVpTmwlBN0HEUk
+3+NB64+QXLf13EowJnAunJrVms+bQbB1Y2zOL1ymiCLF6iQu4mIdEP2yqzk7lowa
+RmuxEOI/S279n+YtilUuWKoeaLcGqPd0rPS5B01M049+KXW0Vv/6OOakA0rltB76
++RBeE4UTnPCOIBfyVCHdoCTDFaI5GavVZGTr1bLQR9FdIRzQs+nx3VUYf6o2ZHOW
+R1I794GHADaLwNfD5b5oo1XwIkuDxcvrF5kFlhnI3X9cVFDhk6uvMTzKEHPsdoYY
+Oe2PdTNfyaiAZs5RzE7If+DAK1zCHrO3GHN4tRyQEwG5p/1F91iw2/Kj67zosH38
+Wvm4FSL0ENRPIIUt+p0zT4FBPXOr4YwQGBn0PuaIob5mymAdbUI6Q3CHqA==
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/10.2/72.pem b/repos/system_upgrade/common/files/prod-certs/10.2/72.pem
new file mode 100644
index 00000000..3d15c146
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/10.2/72.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGGTCCBAGgAwIBAgIJALDxRLt/tVBlMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDcwODExMjQ0NloXDTQ1MDcw
+ODExMjQ0NlowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFtmM2M4ZTQ0
+OC1lYmY4LTQxN2MtOTI5My01ZmE5NjU2YTI4YjJdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBojCBnzAJBgNVHRMEAjAAMDsGCysGAQQBkggJAUgBBCwMKlJlZCBIYXQg
+RW50ZXJwcmlzZSBMaW51eCBmb3IgSUJNIHogU3lzdGVtczAVBgsrBgEEAZIICQFI
+AgQGDAQxMC4yMBYGCysGAQQBkggJAUgDBAcMBXMzOTB4MCYGCysGAQQBkggJAUgE
+BBcMFXJoZWwtMTAscmhlbC0xMC1zMzkweDANBgkqhkiG9w0BAQsFAAOCAgEAMT/B
+VjMEkJIvwAShBe9XhWj1lNvd58VQNaet8eMebCOy2CN32v50zquH9QgQH4Sf/aBm
+X8HfQWl23zAQApCjMr2Sawmjmy05Oj7UGghkbANDvwHV2VKg1nOIoy4oaRvQj86m
+Hn7g0t4Iz1/kTCioZkRgj1PULeDKa7u/GKiYgpc1HVjxUUwJsC2JQwjZ1CwRsNPc
+AV6sDLveJn0doggYrxbC/+9oGYSxxUrkvaPzMmuvHa5F50NHuwgcNTL47uVkglIV
++GBQaBaOq9c/8yWbqLVVDbXu1JD6zgzGj6BYiziJEpU7cqYfCOF9qPIYTD9AnZLx
+43LHz33E6dRRCD9yTuMQEHE3uUoFi/G+yQvf/paSddE5FBX2d35jPSKk5um/x30g
+EiFhQKSuHqWIz/cfucwFBQJRHIPj/yN93RqE9u+uJQrSk8KorEg3fVTumBT6bTYh
+QprOvJBrV6UZg7oHnUC9byiyHzHRHktHv2HOPGbywbIZd0TM5R0KWaEQEVg0OAJG
+KgwEeuiEufQZGq29EZTEtyDpDIP9wNiC4pBHe9B1UpE6EdzfoZWlJb6wbUMRtTqw
+RS1ijNAFzvYy2Yuz0/aRi163qek95YwoXeeZn2QbDN+YgFjJZq6pHjNxYTyDthos
+uWfveDk3xJRFp+Ja5WbgEK9FxzdFz34OZKFlre4=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.8/279.pem b/repos/system_upgrade/common/files/prod-certs/9.8/279.pem
new file mode 100644
index 00000000..8757b9b0
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.8/279.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGJTCCBA2gAwIBAgIJALDxRLt/tVAaMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDcwODExMjI0MloXDTQ1MDcw
+ODExMjI0MlowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFtkZDJiN2Jk
+OS01NmJkLTQ3YzctOWQxOS1jNWYyNmE5YWQwZTJdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBrjCBqzAJBgNVHRMEAjAAMEMGDCsGAQQBkggJAYIXAQQzDDFSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIFBvd2VyLCBsaXR0bGUgZW5kaWFuMBUGDCsG
+AQQBkggJAYIXAgQFDAM5LjgwGQYMKwYBBAGSCAkBghcDBAkMB3BwYzY0bGUwJwYM
+KwYBBAGSCAkBghcEBBcMFXJoZWwtOSxyaGVsLTktcHBjNjRsZTANBgkqhkiG9w0B
+AQsFAAOCAgEAEzlRfJCOY32tUEuMY4Z/cBUoJjM3/IoKY+7tA1xjzNWzL0hPWXcP
+Ifb2iYXG7rINxRkGk56PiFYReGjxlkhkUWRiciAZc6oHfbpw3IyeWnCgSHJXQqTc
+kUEWcUG0CJOlE9OBegvqK+PSydRx2JYhaAFza3zMvIYrdtmOvqhP3/GvuN+nnI4G
+F7GgJkOyalbaSTOWlH2+wxuXeAnlEtUTytRFBEsBywuyi6NIpBL6Oj+QoBFQdCOE
+Ot2Q3v0N4Q5+aiu5UsYPHs97NV8DPkuA0I2qDZr9j/PgxwftbMt14QHG+G9LW3Cz
+DSRIXeKfXGo0GbR7E4ZZBLpp/3LMmH5w/K13skoGtnfWC5x/yoHFRPGmSb1Rrzx2
+kre8EMrXrFFZn4hXu/huQwLTxpg8Hn5pPzDphEksTKQxLeUF0lRj5b3NtqJbQ4he
+NDBAA9cgpifdfaFO8Ax/zppiUeoEizAyst4FFGMDC5u4EFPNQJLjh6vc/2rvP1bk
+KwH2FRxd/jyCcu6bEF4Fv/O/dpddkYtmSPQs3DLX9g9N30uOdOp9TM3W9lt/HFQE
+VpqG7mXTu+f4hx5LFqJXR1pSLzCjVPl03sVi05rjD0Tjkt//pRybpzf/66wMQ1wE
+LWoT869L+7EiL5aSPE3dX7D6IsNzqHvIPKuFAO8T2ZXdiwidAlpXlyA=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.8/362.pem b/repos/system_upgrade/common/files/prod-certs/9.8/362.pem
new file mode 100644
index 00000000..cb1b7c00
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.8/362.pem
@@ -0,0 +1,36 @@
+-----BEGIN CERTIFICATE-----
+MIIGNDCCBBygAwIBAgIJALDxRLt/tVAGMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDcwODExMjIxOVoXDTQ1MDcw
+ODExMjIxOVowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFswMGIwYzc0
+MS0xMDQyLTRiZGUtOTYyYy1kZjRjOGVlMmNiNjBdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBvTCBujAJBgNVHRMEAjAAMEgGDCsGAQQBkggJAYJqAQQ4DDZSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIFBvd2VyLCBsaXR0bGUgZW5kaWFuIEJldGEw
+GgYMKwYBBAGSCAkBgmoCBAoMCDkuOCBCZXRhMBkGDCsGAQQBkggJAYJqAwQJDAdw
+cGM2NGxlMCwGDCsGAQQBkggJAYJqBAQcDBpyaGVsLTkscmhlbC05LWJldGEtcHBj
+NjRsZTANBgkqhkiG9w0BAQsFAAOCAgEAvtSvgFTBFe30H/WQcgvDjJe2ucROmr6B
+AW3OF3hvamcwciLMjzMgVyf4dwRDCsKL0q9cRmFXlMR0H36iNQnYkZU1p/sWfCIB
+HtPDPlSr3miELB6FTvod/L4zn+CqbjgN2D3wJJKVfldbQzOTV3kEFed96yB8exTV
+ObdCIzyadhtULog9mtUCe+8IxG8oDzpjAaaYfwkyq6tY3VzbvRS76292yFVQe6rG
+wc9kxhwCfprnvzH7+dTlbMJlvk7PQB7xH1CvSmrIf7C5tfLf/BrsygFtqnq8KLTx
+v644hMGkOvMBdEw5Ry3jMPAlmL+Eyc5751XkN3b5yujXA+T71t1/F0i99DM8XTO8
+WovLAH4KjX+gvHugdsEQs0ujRpxPDgkv9/RFWs0kkBgzhUlFqOGBsi3HyGoqq770
+/e4Fvnj/XxHzs4G3FgiyGnsKLOaKm7eFTwhePsscIckGr/6oq7U0VQF1xOc77I7n
+uPFdSXso5TUUO2UVhqmeq71hhj000wpw4vKQ71rEfgTtMiC7Et93hpk4y4iwuk9w
+mDGTksyr50QNgS9ZNWGLu2JejT3s9RcjROEJ6VOWJxorDWxEY/LXl683FtRXPEM2
+UjHyhx8twhxbIlcD3a8S0R4BfcWCLvhtpdnmOtFGACYMaYd9TAdOG/AZoc/jBOpy
+s2OKIQwKXPY=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.8/363.pem b/repos/system_upgrade/common/files/prod-certs/9.8/363.pem
new file mode 100644
index 00000000..fa09ec7c
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.8/363.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGJjCCBA6gAwIBAgIJALDxRLt/tVAFMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDcwODExMjIxOVoXDTQ1MDcw
+ODExMjIxOVowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs0MTFmZDc4
+NC00ZTc4LTQ5YWQtOTNiOC0zNjc2OWY0ZDFlZTVdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBrzCBrDAJBgNVHRMEAjAAMDoGDCsGAQQBkggJAYJrAQQqDChSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIEFSTSA2NCBCZXRhMBoGDCsGAQQBkggJAYJr
+AgQKDAg5LjggQmV0YTAZBgwrBgEEAZIICQGCawMECQwHYWFyY2g2NDAsBgwrBgEE
+AZIICQGCawQEHAwacmhlbC05LHJoZWwtOS1iZXRhLWFhcmNoNjQwDQYJKoZIhvcN
+AQELBQADggIBAFzGv13LCdYf3XkOt3TjwVwY2ldFVMxf2Sx/uNjLFG4I1mhYwZZ9
+0Pyz7J771yMxyhyKb8rc8XMAYxi8lOKfOpp1PpPRVC+NtKo2pdrbZhWy2qKomfyL
+S6jN/hEgg7P6LHGEnvT1Bm9e+BoED3gmOVAmupL4xKv2eRxgXuwuPHrvE6oo63SB
+xtrYIo/pmYgVFgl/d7X5vXqerF4pwLR2DwtK6O84DSyVRf35ghNET09GYm6G+URQ
+eGWi1/h0YCpS9LCXOOOv/J4MM8zr+NLbDyJWxmaG83/zvAQhX65bzJ0bBtb0avJ0
+cgos6LBCDxt+kmipnAMqz5Cb+HVifgdBz1ep3EcoxHwmwBDpHewq0zNtPgMyjzhi
+uwB0inlcCk7JKdjdO36H7RdUYvrM7WEDUKAXtMgOXxr3o6h9v9jZKTfbk5Af91/D
+epoMULy0sErnEuzHAq9sdh3HTmDTHsMNcUpxwC+93VGaCGGrbyM2yQtdLg7dhHQK
+7d9Z9BJEzKReIy+R354M1jQsLGLQ3B8uY476dmP0G0Q01m86rsJ/gjxa8vrJpafO
+t1Up9YexwbVtEtKG7koCz4fwxPv2cauGncuUTdyHJDoS5FpPLMlaWXAfwD0Udbiv
+gZke/PD+39I+UPrxtM+XIXGoJPeZdM5Kv0+3/suvKHGqtkFa8YiK2EHA
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.8/419.pem b/repos/system_upgrade/common/files/prod-certs/9.8/419.pem
new file mode 100644
index 00000000..9ad33fd1
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.8/419.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGFzCCA/+gAwIBAgIJALDxRLt/tVAZMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDcwODExMjI0MloXDTQ1MDcw
+ODExMjI0MlowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFtiOWY4OWYx
+OC0xNjAzLTRlZDUtYTFmOS0xN2YyMmEwNDdlODNdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBoDCBnTAJBgNVHRMEAjAAMDUGDCsGAQQBkggJAYMjAQQlDCNSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIEFSTSA2NDAVBgwrBgEEAZIICQGDIwIEBQwD
+OS44MBkGDCsGAQQBkggJAYMjAwQJDAdhYXJjaDY0MCcGDCsGAQQBkggJAYMjBAQX
+DBVyaGVsLTkscmhlbC05LWFhcmNoNjQwDQYJKoZIhvcNAQELBQADggIBAFu1LxAU
+wPUs7/e6mFAzT/JIzq1fQ6kMHxbrf9nS+g9pO0G0z7Imwj85Rk7qOpJpEjKaLVDy
+OJ9fXV20TNidKDvjZuL+F209NLam64MEpy7q40LgOaDYsr9tvGfJJFAQRKRszbrC
+/CGj7l/q09ym1FB3LXgpn4vHR8jD7LloGFEWq19UpRLe+L+1Frh16apy03WNYTnk
+JLALo274I3+kgO69sEemXZF+WD/O+4ySugY/ImbrIlrY1SAeAWTd/kudLMLVLYnN
+JlmB7OPUGE2ZAR0aOTvTeoDBZPz1EGItbJg2hlx4vrhrnGG9kKu+/cDOOAJ7+bgx
+fgc64NOoLTSc+9QIgKKhDt5jShXHfFjpwWbJ08/U29bTZmntcRO0h6F0WBS3ptgW
+hocfN2nDN7pPvivnrUUo+kRY7jKE57im3+mznHHw97em6YCREuvc/NwLIxi4LSiU
+cJgOQ3ltljrFSMKlv4p6evMxlX/QOwgeE+hf/QYjCODoHe/66h5bnKkLGnFdPHxk
+6btQfVePn8UpMUO64OgIcPuGyAEXu1m9N/PFL3S5JUVmfjF9COhmZQEW1x5HBF/u
+mAfwI79++xKH1nmVsgDUjm5HMVZ3qj0y3miAKtC3Ses9Ym6JawpvPSld3xFGF5Mc
+BiYQsv12swSrLy3IzdvJViXRFUFE3dWuVdG1
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.8/433.pem b/repos/system_upgrade/common/files/prod-certs/9.8/433.pem
new file mode 100644
index 00000000..eaf93d90
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.8/433.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGKTCCBBGgAwIBAgIJALDxRLt/tVAHMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDcwODExMjIxOVoXDTQ1MDcw
+ODExMjIxOVowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFsyYjk5MzMx
+OC0xZjFiLTRlY2UtODJiMS0wODEzYmFjOGFkNGJdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBsjCBrzAJBgNVHRMEAjAAMEEGDCsGAQQBkggJAYMxAQQxDC9SZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIElCTSB6IFN5c3RlbXMgQmV0YTAaBgwrBgEE
+AZIICQGDMQIECgwIOS44IEJldGEwFwYMKwYBBAGSCAkBgzEDBAcMBXMzOTB4MCoG
+DCsGAQQBkggJAYMxBAQaDBhyaGVsLTkscmhlbC05LWJldGEtczM5MHgwDQYJKoZI
+hvcNAQELBQADggIBACjKAgygB5V2mVD3S5snrHjFTpP2x1ODX1GdSgwrXFZ/ehom
+hf1SI9zIsmm+s96ns/Gc5BDrqS2TSil083OqG5YZ98ap+NkQPI/XqIhMRSw2z+QK
+p1i7e/Si6VZyiitnutCrbX/b1RzWCSOAfIU2m41iptvT7HATw0y/6CQpQNrhZ3wR
+TubEIEypmxO5stJt4CO/bqkU3vX+U3FdQdSJWJn3qpvErJ4qNFdwl8zX9WGoaueh
+gNbYrz2EWARVbvedp+ylB1VNdpYXQ+LUI/KwHI4Sxizgg16+IxcFoKJVCYNOH7Wh
+IoMZc7eW91oAzm57yS36RF/Z50S1x8JHHg2hgev+2czDG9dgRTsLvvAXqsnrUHuD
+lRPMDjgaSooUWJmKwIXQ7yJDAPHoxZAXWtMEc1kNLZGEPVDQbT73j4eDOxzZDZrr
+agWGoWJ3kuY9AVvv/RTi6z5VWs7ySJER7RxQcGhH8TctysW7gIMjHfgnTGN2bW5U
+mV5Ds+/i9AiA9/V+rWWsv8riz+MfEa23/J/EvOdBBCd5MuzsqkXn2gde8WP3cjes
+sgqUKQzOy7Rqr5LHT1IQl5SkyYr1QV1InghJ8dh7BjRLvWUaw0uqPRvxX1c6K1l/
+NFsCie9RwuhdE8OBwHuBjB28k3Zs9SPaVzYRe70qwi0epbCrhwcGOkTNfCcz
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.8/479.pem b/repos/system_upgrade/common/files/prod-certs/9.8/479.pem
new file mode 100644
index 00000000..a0ff7061
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.8/479.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGFTCCA/2gAwIBAgIJALDxRLt/tVAcMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDcwODExMjI0MloXDTQ1MDcw
+ODExMjI0MlowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs4ZmM5YTM4
+Ni0wYzkzLTQ0MjctYTlhOC1kMTdkMzAwZGJmZDZdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBnjCBmzAJBgNVHRMEAjAAMDUGDCsGAQQBkggJAYNfAQQlDCNSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIHg4Nl82NDAVBgwrBgEEAZIICQGDXwIEBQwD
+OS44MBgGDCsGAQQBkggJAYNfAwQIDAZ4ODZfNjQwJgYMKwYBBAGSCAkBg18EBBYM
+FHJoZWwtOSxyaGVsLTkteDg2XzY0MA0GCSqGSIb3DQEBCwUAA4ICAQC6vt8EEay9
+CjdRGHmseXosuo03ub+bUt61uYVpf15IoVUV+7XT6ZHff8cPZbKBjoRbuWNILvR2
+rCdl11bm3prCxfLNJh5u8hqNXv+iIB4k4qhCSrhPFQEf3HNJma2J67U/8Mt7oM4B
+RqpZ1CCw9VTHQSB+iraKzE+BFr9kNlQfZu75Clsgv5dZaT1WK5hKiuQy8kc2CBKy
+CuiL6i0PK2tzNtNH4ON/tMU3AM+edIiUFV6C376kewwO/omArY6FYmJVcPLKWh3h
+TSUt81CmaHmyW+XKJ2pM3f2hfHdq1Lf7lInjgw5Rolyhm/Xqrrj8j19SrUSru/tw
+WcmLMhhEyU2/jwfipbbzB9AC3tIXZjKv8539e4omsBmHwHQno1NAjq0+alGxr9pK
+AZywsuMhiGyznbYdIANGZyMUN3sULIsG649UcEsmzM5q9g1TVyuJH9m+OJSK2PGk
+UnorgDlGs1AiJhsqZuW8zxzy3nfQmniO/o/6wZbqlKiyLjQY7Fxa4Rb0hXbBJkZ7
+TkHkjlAObUEkcjg0jUHb8sFRQ7hXx+Tk4tGk549crSZCCg951SITV5By9bAxm7fu
+DHGXgY7tOwHII51sfBfryuvIKs+JmzF9Evzssf3kLBSXylyS6pr/8dKN6sF7Pw4M
+Fe/gvJ3J/pARSVP41wR6tI0zYvqkO/ULQg==
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.8/486.pem b/repos/system_upgrade/common/files/prod-certs/9.8/486.pem
new file mode 100644
index 00000000..84461ed8
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.8/486.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGJDCCBAygAwIBAgIJALDxRLt/tVAIMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDcwODExMjIxOVoXDTQ1MDcw
+ODExMjIxOVowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFtkZjUwNWIw
+ZS02Y2E4LTRkODQtOTY0Mi0wNGRlYTg5NjY0MzNdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBrTCBqjAJBgNVHRMEAjAAMDoGDCsGAQQBkggJAYNmAQQqDChSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIHg4Nl82NCBCZXRhMBoGDCsGAQQBkggJAYNm
+AgQKDAg5LjggQmV0YTAYBgwrBgEEAZIICQGDZgMECAwGeDg2XzY0MCsGDCsGAQQB
+kggJAYNmBAQbDBlyaGVsLTkscmhlbC05LWJldGEteDg2XzY0MA0GCSqGSIb3DQEB
+CwUAA4ICAQCNeDKnDjuvHBE0Fa0cMAFM96OWn3b3wTtAx7i9BCaCe4NsRTjEMJTw
+jO4KwkfzCQWpOJuFHnOKmVZBXVZZ8aOLCfYTyQZ6nZ1UsiekL7l9sdIFCHrbgKkL
+zBFe+8cVtUMwb9f7fORPp960ImtYpvt8ERihHf2LvIBUI+BGRz/D/3NW1ehVggGI
+0VCe270sgLSl3y8lR5BrNXtKbigeI4mNMasndf/TDMFeCk5OH4FJ+DyiY0zma2IT
+x0PwQmEeI4my1KTmQSUDgIOmHtKbq1tCR2wMIh/ju/HOrvVeOnzEsBgQTiTh92qJ
+U7/++7Ayqw/6PfPCd+gOMqIPS1+Aef7w54I+zWyYeHQcXXCxcffPwO7sZV3zQJyh
+clfLJv13Oe6G5mB7ZCH+tB4LdaVBURz9G0MkLwXGfTWfnU5N61Kne8hjOriSBWP4
+2FZEP+2BQ/1Z7aIssbQKegdRvvMd/KqJjIeiFtrz9AVSodEUZgJlxiZ9KDSysG18
+hmZcPuk2mc9nwWQ9gHZWzatGs+uONS92QqFvXxlY7TWMDIdlscubcjV/bbDHm69P
++pqGilb3zJz8msBwFpdO+h4l8eUMMMsLzdUdH499q/enZrH3VSdmNtWtoVm9R7rp
+khFJ4DdORE9/P5lfqAObt8KNO72BQ2/KcK0FZ1lLxKWG/4dZ5oAdGw==
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.8/72.pem b/repos/system_upgrade/common/files/prod-certs/9.8/72.pem
new file mode 100644
index 00000000..724e0a62
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.8/72.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGFjCCA/6gAwIBAgIJALDxRLt/tVAbMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDcwODExMjI0MloXDTQ1MDcw
+ODExMjI0MlowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFtlYjMyYzY1
+Ny00OGY0LTRiZjUtYmY3Yy1mYjMwNWU1YjgyMDFdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBnzCBnDAJBgNVHRMEAjAAMDsGCysGAQQBkggJAUgBBCwMKlJlZCBIYXQg
+RW50ZXJwcmlzZSBMaW51eCBmb3IgSUJNIHogU3lzdGVtczAUBgsrBgEEAZIICQFI
+AgQFDAM5LjgwFgYLKwYBBAGSCAkBSAMEBwwFczM5MHgwJAYLKwYBBAGSCAkBSAQE
+FQwTcmhlbC05LHJoZWwtOS1zMzkweDANBgkqhkiG9w0BAQsFAAOCAgEADCKqieee
+Hvj06J4U23K/Wr5zn+d6AtA2vfhpicAYh5jzYqLAJHmB9T5Ql6pFqJ9lMLI2EGSg
+jhLD+lzDP9A2vk+rFWK0BEGnqlPrQtM5atTBeihRVRci1ymspPBrLwu+Zu3jromg
+I14r86EZwSXpPZLaNUsOjOi4Euc50Q3wsUJGvXCpoU4SgnnAIER3lq9HSNFDZkmp
+AjW+VHAhPIOTujm9PhCFIn5bB0jsygHHYyqV7KvQSmxoPTaLMxFpva+Xy0QNKlwg
+NXKw/JYAHX1yaskeZviqwZzhKpnvycyEgWF9f7cBD6O8Adxx9qkqXqer7YsQ/wgR
+cHjGCAKbV2OTIgyQEDie1gdPLdSUPzrbzJ9C1I85tSJH3ujdACiGG/aHPtspLb3Z
+M6265fbXDbXOqjFuP/njDUqal3WgUgw34w4Xi2JLCcqLvHLQhTmZSKiD0SJbRDL1
+smcle/yKhTc4+7zJqQV8faR9LVEAkaLzjG3ZRiTUDq4RASr9tN/A0AfXqggG9nGL
+06m6QcXRxHM0OVgLHLksKsj3rG3VX0v3aQm353GW1sxxX0hqFnoOnGWA410GUG9S
+rg897hshyti1pn045uhhFjbpxYRKu/JY9VNNyRW0KqL1hyz4TY7OQxJxGDAPX7uJ
+7NGSWW9EsYMZNMxEee6br9lWVwGWnc8DWhA=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/upgrade_paths.json b/repos/system_upgrade/common/files/upgrade_paths.json
index 22e0fd7d..61bb73c0 100644
--- a/repos/system_upgrade/common/files/upgrade_paths.json
+++ b/repos/system_upgrade/common/files/upgrade_paths.json
@@ -2,9 +2,10 @@
"rhel": {
"default": {
"7.9": ["8.10"],
- "8.10": ["9.4", "9.6", "9.7"],
+ "8.10": ["9.4", "9.6", "9.7", "9.8"],
"9.6": ["10.0"],
"9.7": ["10.1"],
+ "9.8": ["10.2"],
"7": ["8.10"],
"8": ["9.4", "9.6"],
"9": ["10.0"]
@@ -15,6 +16,7 @@
"8.10": ["9.6", "9.4"],
"8": ["9.6", "9.4"],
"9.6": ["10.0"],
+ "9.8": ["10.2"],
"9": ["10.0"]
}
},
@@ -25,13 +27,13 @@
},
"_virtual_versions": {
"8": "8.10",
- "9": "9.7",
- "10": "10.1"
+ "9": "9.8",
+ "10": "10.2"
}
},
"almalinux": {
"default": {
- "8.10": ["9.0", "9.1", "9.2", "9.3", "9.4", "9.5", "9.6", "9.7"],
+ "8.10": ["9.0", "9.1", "9.2", "9.3", "9.4", "9.5", "9.6", "9.7","9.8"],
"9.7": ["10.0", "10.1"]
}
}
--
2.51.1

View File

@ -1,48 +0,0 @@
From b41d5b386f3369cf714cff9f3277863f6f601bc1 Mon Sep 17 00:00:00 2001
From: denli <denli@redhat.com>
Date: Mon, 6 Oct 2025 12:25:07 -0400
Subject: [PATCH 22/55] Add kpatch actor to el9toel10
---
.../actors/kernel/checkkpatch/actor.py | 29 +++++++++++++++++++
1 file changed, 29 insertions(+)
create mode 100644 repos/system_upgrade/el9toel10/actors/kernel/checkkpatch/actor.py
diff --git a/repos/system_upgrade/el9toel10/actors/kernel/checkkpatch/actor.py b/repos/system_upgrade/el9toel10/actors/kernel/checkkpatch/actor.py
new file mode 100644
index 00000000..e7f6179c
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/kernel/checkkpatch/actor.py
@@ -0,0 +1,29 @@
+from leapp.actors import Actor
+from leapp.libraries.common.rpms import has_package
+from leapp.libraries.stdlib import api
+from leapp.models import CopyFile, DistributionSignedRPM, TargetUserSpacePreupgradeTasks
+from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
+
+PLUGIN_PKGNAME = "kpatch-dnf"
+CONFIG_PATH = "/etc/dnf/plugins/kpatch.conf"
+
+
+class CheckKpatch(Actor):
+ """
+ Carry over kpatch-dnf and it's config into the container
+
+ Check is kpatch-dnf plugin is installed and if it is, install it and copy
+ over the config file so that the plugin can make a decision on whether any
+ kpatch-patch packages need to be installed during in-place upgrade.
+ """
+
+ name = 'check_kpatch'
+ consumes = (DistributionSignedRPM,)
+ produces = (TargetUserSpacePreupgradeTasks,)
+ tags = (IPUWorkflowTag, ChecksPhaseTag)
+
+ def process(self):
+ if has_package(DistributionSignedRPM, PLUGIN_PKGNAME):
+ api.produce(TargetUserSpacePreupgradeTasks(
+ install_rpms=[PLUGIN_PKGNAME],
+ copy_files=[CopyFile(src=CONFIG_PATH)]))
--
2.51.1

View File

@ -0,0 +1,151 @@
From daaf3cea58f4065e9e938c0c76ecd5d302ec7969 Mon Sep 17 00:00:00 2001
From: Tomas Fratrik <tomasfratrik8@gmail.com>
Date: Mon, 28 Apr 2025 14:19:01 +0200
Subject: [PATCH 22/37] Improve report of unsupported network configuration
* Remove KCS from summary since it is present in the related links.
* Generalize KCS title when using Kernel-Assigned NIC Names.
* Show KCS about unsupported network configuration device types only when IPU 8 -> 9.
* Adjust unit tests to reflect this change.
Jira: RHEL-77175
---
.../actors/persistentnetnamesdisable/actor.py | 24 ++++++----
.../tests/test_persistentnetnamesdisable.py | 46 +++++++++++++++++--
2 files changed, 56 insertions(+), 14 deletions(-)
diff --git a/repos/system_upgrade/common/actors/persistentnetnamesdisable/actor.py b/repos/system_upgrade/common/actors/persistentnetnamesdisable/actor.py
index 1f7f1413..1add3588 100644
--- a/repos/system_upgrade/common/actors/persistentnetnamesdisable/actor.py
+++ b/repos/system_upgrade/common/actors/persistentnetnamesdisable/actor.py
@@ -2,6 +2,7 @@ import re
from leapp import reporting
from leapp.actors import Actor
+from leapp.libraries.common.config.version import get_target_major_version
from leapp.models import KernelCmdlineArg, PersistentNetNamesFacts
from leapp.reporting import create_report, Report
from leapp.tags import FactsPhaseTag, IPUWorkflowTag
@@ -39,26 +40,31 @@ class PersistentNetNamesDisable(Actor):
if self.single_eth0(interfaces):
self.disable_persistent_naming()
elif len(interfaces) > 1 and self.ethX_count(interfaces) > 0:
- create_report([
+ report_entries = [
reporting.Title('Unsupported network configuration'),
reporting.Summary(
'Detected multiple physical network interfaces where one or more use kernel naming (e.g. eth0). '
'Upgrade process can not continue because stability of names can not be guaranteed. '
- 'Please read the article at https://access.redhat.com/solutions/4067471 for more information.'
),
reporting.ExternalLink(
- title='How to perform an in-place upgrade to RHEL 8 when using kernel NIC names on RHEL 7',
+ title='How to Perform an In-Place Upgrade when Using Kernel-Assigned NIC Names',
url='https://access.redhat.com/solutions/4067471'
),
- reporting.ExternalLink(
- title='RHEL 8 to RHEL 9: inplace upgrade fails at '
- '"Network configuration for unsupported device types detected"',
- url='https://access.redhat.com/solutions/7009239'
- ),
reporting.Remediation(
hint='Rename all ethX network interfaces following the attached KB solution article.'
),
reporting.Severity(reporting.Severity.HIGH),
reporting.Groups([reporting.Groups.NETWORK]),
reporting.Groups([reporting.Groups.INHIBITOR])
- ])
+ ]
+
+ if get_target_major_version() == '9':
+ report_entries.append(
+ reporting.ExternalLink(
+ title='RHEL 8 to RHEL 9: inplace upgrade fails at '
+ '"Network configuration for unsupported device types detected"',
+ url='https://access.redhat.com/solutions/7009239'
+ )
+ )
+
+ create_report(report_entries)
diff --git a/repos/system_upgrade/common/actors/persistentnetnamesdisable/tests/test_persistentnetnamesdisable.py b/repos/system_upgrade/common/actors/persistentnetnamesdisable/tests/test_persistentnetnamesdisable.py
index 96768da9..95b695c0 100644
--- a/repos/system_upgrade/common/actors/persistentnetnamesdisable/tests/test_persistentnetnamesdisable.py
+++ b/repos/system_upgrade/common/actors/persistentnetnamesdisable/tests/test_persistentnetnamesdisable.py
@@ -1,3 +1,6 @@
+import pytest
+
+from leapp.libraries.common.config import version
from leapp.models import Interface, KernelCmdlineArg, PCIAddress, PersistentNetNamesFacts
from leapp.reporting import Report
from leapp.snactor.fixture import current_actor_context
@@ -14,7 +17,11 @@ def test_actor_single_eth0(current_actor_context):
assert not current_actor_context.consume(Report)
-def test_actor_more_ethX(current_actor_context):
+@pytest.mark.parametrize(
+ 'target_version', ['9', '10']
+)
+def test_actor_more_ethX(monkeypatch, current_actor_context, target_version):
+ monkeypatch.setattr(version, 'get_target_major_version', lambda: target_version)
pci1 = PCIAddress(domain="0000", bus="3e", function="00", device="PCI bridge")
pci2 = PCIAddress(domain="0000", bus="3d", function="00", device="Serial controller")
interface = [Interface(name="eth0", mac="52:54:00:0b:4a:6d", vendor="redhat",
@@ -25,8 +32,20 @@ def test_actor_more_ethX(current_actor_context):
devpath="/devices/hidraw/hidraw0")]
current_actor_context.feed(PersistentNetNamesFacts(interfaces=interface))
current_actor_context.run()
- assert current_actor_context.consume(Report)
- assert is_inhibitor(current_actor_context.consume(Report)[0].report)
+
+ report_fields = current_actor_context.consume(Report)[0].report
+ assert is_inhibitor(report_fields)
+
+ external_links = report_fields.get('detail', {}).get('external', [])
+
+ rhel8to9_present = any(
+ 'RHEL 8 to RHEL 9' in link.get('title', '') for link in external_links
+ )
+
+ if target_version == '9':
+ assert rhel8to9_present
+ else:
+ assert not rhel8to9_present
def test_actor_single_int_not_ethX(current_actor_context):
@@ -39,7 +58,11 @@ def test_actor_single_int_not_ethX(current_actor_context):
assert not current_actor_context.consume(Report)
-def test_actor_ethX_and_not_ethX(current_actor_context):
+@pytest.mark.parametrize(
+ 'target_version', ['9', '10']
+)
+def test_actor_ethX_and_not_ethX(monkeypatch, current_actor_context, target_version):
+ monkeypatch.setattr(version, 'get_target_major_version', lambda: target_version)
pci1 = PCIAddress(domain="0000", bus="3e", function="00", device="PCI bridge")
pci2 = PCIAddress(domain="0000", bus="3d", function="00", device="Serial controller")
interface = [Interface(name="virbr0", mac="52:54:00:0b:4a:6d", vendor="redhat",
@@ -51,4 +74,17 @@ def test_actor_ethX_and_not_ethX(current_actor_context):
current_actor_context.feed(PersistentNetNamesFacts(interfaces=interface))
current_actor_context.run()
assert current_actor_context.consume(Report)
- assert is_inhibitor(current_actor_context.consume(Report)[0].report)
+
+ report_fields = current_actor_context.consume(Report)[0].report
+ assert is_inhibitor(report_fields)
+
+ external_links = report_fields.get('detail', {}).get('external', [])
+
+ rhel8to9_present = any(
+ 'RHEL 8 to RHEL 9' in link.get('title', '') for link in external_links
+ )
+
+ if target_version == '9':
+ assert rhel8to9_present
+ else:
+ assert not rhel8to9_present
--
2.49.0

View File

@ -0,0 +1,35 @@
From d3793ab2546148d3fc9832e5164a2f0a7de80352 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Wed, 30 Apr 2025 13:29:40 +0200
Subject: [PATCH 23/37] DOCS: add missing envar LEAPP_OVL_IMG_FS_EXT4
The LEAPP_OVL_IMG_FS_EXT4 has not been documented and it can be
quite useful on some systems.
---
docs/source/configuring-ipu/envars.md | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/docs/source/configuring-ipu/envars.md b/docs/source/configuring-ipu/envars.md
index 61a50b82..a042ba4a 100644
--- a/docs/source/configuring-ipu/envars.md
+++ b/docs/source/configuring-ipu/envars.md
@@ -47,6 +47,16 @@ Set the path to the target OS ISO image that should be used for the IPU. Its
#### LEAPP_TARGET_PRODUCT_CHANNEL
The alternative to the --channel leapp option. As a parameter accepts a channel acronym. E.g. `eus` or `e4s`. For more info, see the leapp preupgrade --help. In case the beta channel is required, use the `LEAPP_DEVEL_TARGET_PRODUCT_TYPE` envar instead.
+#### LEAPP_OVL_IMG_FS_EXT4
+During the execution of IPUWorkflow the process requires creation of internal
+disk images for the correct virtualisation of the host storage and creation
+of OverlayFS (OVL) layer. During that time these images are formatted with
+XFS filesystem by default. However for some system setups this could be
+problematic and could lead sometimes to issues. For these uncommon problems
+it is possible to specify `LEAPP_OVL_IMG_FS_EXT4=1` when running leapp to
+instruct the use of the EXT4 file system instead.
+
+
### Development variables
```{note}
To use development variables, the LEAPP_UNSUPPORTED variable has to be set.
--
2.49.0

View File

@ -1,54 +0,0 @@
From 0cf9d8adb12b40f4cdcd423e6c55c11e0fbacff5 Mon Sep 17 00:00:00 2001
From: denli <denli@redhat.com>
Date: Tue, 7 Oct 2025 08:09:58 -0400
Subject: [PATCH 23/55] move kpatch actor to common repo
---
.../actors/kernel/checkkpatch/actor.py | 0
.../actors/kernel/checkkpatch/actor.py | 29 -------------------
2 files changed, 29 deletions(-)
rename repos/system_upgrade/{el8toel9 => common}/actors/kernel/checkkpatch/actor.py (100%)
delete mode 100644 repos/system_upgrade/el9toel10/actors/kernel/checkkpatch/actor.py
diff --git a/repos/system_upgrade/el8toel9/actors/kernel/checkkpatch/actor.py b/repos/system_upgrade/common/actors/kernel/checkkpatch/actor.py
similarity index 100%
rename from repos/system_upgrade/el8toel9/actors/kernel/checkkpatch/actor.py
rename to repos/system_upgrade/common/actors/kernel/checkkpatch/actor.py
diff --git a/repos/system_upgrade/el9toel10/actors/kernel/checkkpatch/actor.py b/repos/system_upgrade/el9toel10/actors/kernel/checkkpatch/actor.py
deleted file mode 100644
index e7f6179c..00000000
--- a/repos/system_upgrade/el9toel10/actors/kernel/checkkpatch/actor.py
+++ /dev/null
@@ -1,29 +0,0 @@
-from leapp.actors import Actor
-from leapp.libraries.common.rpms import has_package
-from leapp.libraries.stdlib import api
-from leapp.models import CopyFile, DistributionSignedRPM, TargetUserSpacePreupgradeTasks
-from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
-
-PLUGIN_PKGNAME = "kpatch-dnf"
-CONFIG_PATH = "/etc/dnf/plugins/kpatch.conf"
-
-
-class CheckKpatch(Actor):
- """
- Carry over kpatch-dnf and it's config into the container
-
- Check is kpatch-dnf plugin is installed and if it is, install it and copy
- over the config file so that the plugin can make a decision on whether any
- kpatch-patch packages need to be installed during in-place upgrade.
- """
-
- name = 'check_kpatch'
- consumes = (DistributionSignedRPM,)
- produces = (TargetUserSpacePreupgradeTasks,)
- tags = (IPUWorkflowTag, ChecksPhaseTag)
-
- def process(self):
- if has_package(DistributionSignedRPM, PLUGIN_PKGNAME):
- api.produce(TargetUserSpacePreupgradeTasks(
- install_rpms=[PLUGIN_PKGNAME],
- copy_files=[CopyFile(src=CONFIG_PATH)]))
--
2.51.1

View File

@ -1,41 +0,0 @@
From 3128ca5df81b4c7591af189c9e2ae02f96c88fb4 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Fri, 17 Oct 2025 09:00:20 +0200
Subject: [PATCH 24/55] Makefile: Do not copy unnecessary files to test
containers
In addition to tut/, docs/, packaging/, .git/ and all the __pycache__
directories (and .pyc files) are excluded. This makes for a significant
speedup in container setup (output with -v added to rsync) as a lot less
needs to be copied:
Without this patch:
sent 2,405,488 bytes received 19,754 bytes 194,019.36 bytes/sec
total size is 165,333,162 speedup is 68.17
With this patch:
sent 551,179 bytes received 4,067 bytes 100,953.82 bytes/sec
total size is 23,280,513 speedup is 41.93
Some other small files and directories are still unnecessarily copied,
but those don't really affect the copied size that much.
---
Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 754c2c63..1bfbc3ac 100644
--- a/Makefile
+++ b/Makefile
@@ -447,7 +447,7 @@ test_container:
export _CONT_NAME="leapp-repo-tests-$(_TEST_CONTAINER)-cont"; \
$(_CONTAINER_TOOL) ps -q -f name=$$_CONT_NAME && { $(_CONTAINER_TOOL) kill $$_CONT_NAME; $(_CONTAINER_TOOL) rm $$_CONT_NAME; }; \
$(_CONTAINER_TOOL) run -di --name $$_CONT_NAME -v "$$PWD":/repo:Z -e PYTHON_VENV=$$_VENV $$TEST_IMAGE && \
- $(_CONTAINER_TOOL) exec $$_CONT_NAME rsync -aur --delete --exclude "tut*" /repo/ /repocopy && \
+ $(_CONTAINER_TOOL) exec $$_CONT_NAME rsync -aur --delete --exclude 'tut/' --exclude 'docs/' --exclude '**/__pycache__/' --exclude 'packaging/' --exclude '.git/' /repo/ /repocopy && \
export res=0; \
case $$_VENV in \
python3.6) \
--
2.51.1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,701 @@
From 5fe6b4df9cfde15f527b5ecf52fda4e7fec6dfe5 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Mon, 5 May 2025 13:55:35 +0200
Subject: [PATCH 25/37] Add RHEL 10.1 and 9.7 product certificates
---
.../common/files/prod-certs/10.1/279.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/10.1/362.pem | 36 +++++++++++++++++++
.../common/files/prod-certs/10.1/363.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/10.1/419.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/10.1/433.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/10.1/479.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/10.1/486.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/10.1/72.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/9.7/279.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/9.7/362.pem | 36 +++++++++++++++++++
.../common/files/prod-certs/9.7/363.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/9.7/419.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/9.7/433.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/9.7/479.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/9.7/486.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/9.7/72.pem | 35 ++++++++++++++++++
16 files changed, 562 insertions(+)
create mode 100644 repos/system_upgrade/common/files/prod-certs/10.1/279.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/10.1/362.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/10.1/363.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/10.1/419.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/10.1/433.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/10.1/479.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/10.1/486.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/10.1/72.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.7/279.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.7/362.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.7/363.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.7/419.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.7/433.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.7/479.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.7/486.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.7/72.pem
diff --git a/repos/system_upgrade/common/files/prod-certs/10.1/279.pem b/repos/system_upgrade/common/files/prod-certs/10.1/279.pem
new file mode 100644
index 00000000..958d5716
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/10.1/279.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGKDCCBBCgAwIBAgIJALDxRLt/tU/zMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDEyOTEyNDkwM1oXDTQ1MDEy
+OTEyNDkwM1owRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs3YzNhZTNl
+ZC01M2U1LTQ3MjYtOGM4Ny1kNGIwZjk4MTU5MjNdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBsTCBrjAJBgNVHRMEAjAAMEMGDCsGAQQBkggJAYIXAQQzDDFSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIFBvd2VyLCBsaXR0bGUgZW5kaWFuMBYGDCsG
+AQQBkggJAYIXAgQGDAQxMC4xMBkGDCsGAQQBkggJAYIXAwQJDAdwcGM2NGxlMCkG
+DCsGAQQBkggJAYIXBAQZDBdyaGVsLTEwLHJoZWwtMTAtcHBjNjRsZTANBgkqhkiG
+9w0BAQsFAAOCAgEAfVg6glBn6Igkl0ynxbwfLLrR7D3HcWhIBpcFFfw9btjx74Zi
+Pi7RcQeV8xR03S7SQO0B+84yTAy48DMtv0jTGZacqovv9iXNqJBuXhfFZgSvYnr/
+cqAXExpQc5PvCzDW0/6JKWkGJsrxS++KtRRwPjZKV/Ie9Xa0P/LnVhraDZUGHRLt
+fo5lbElmpy0GvYnOp/xVMfP/R7Gy/rC3AfrTxrTUY911eguT4ziJftzTVbq0Bpn4
+tEBqPQ9B0NBpgwiQJteLHtwHjm8c46E+bzb5JHRNtHVUX6ukG9FPPpehJyJmgILu
+tNadbee3gpRvNpVTInDZyftIcXHZzh+rirWg8oC9b0kj/z7Cr+OBx5BHAlcFzJNb
+KX49ezONhjWgSlKGTu90fcJk60TvrWfYymXpym0B70uCKZbKXTAwDTtg2gIydFS/
+YZydCgY6h6/s4Vk7NeccIHRz7xSQ/eiVSGk7TM/DbACjp1pl9CVX2BMn5p1GNn3W
+oS0c9DY/pbphdlGVDrcDRmYjuAZ6fNtmy7zDqtUSJnen0A+PrcRIc5ICEoTXUE9l
+RtxUFT2Caja3PWVumVu1kNGzjbNAvFRD9FHQt80ADpSLgEcG0HEaFUdevYN3glKb
+7J1RXTKEhhnBBCI9qfrl4SIz3VvLrxW4AeJ87h/7FPJZFAJrkKQmQPeyadA=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/10.1/362.pem b/repos/system_upgrade/common/files/prod-certs/10.1/362.pem
new file mode 100644
index 00000000..6382f50a
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/10.1/362.pem
@@ -0,0 +1,36 @@
+-----BEGIN CERTIFICATE-----
+MIIGNzCCBB+gAwIBAgIJALDxRLt/tU/gMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDEyOTEyNDg0NFoXDTQ1MDEy
+OTEyNDg0NFowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs0MGFlYjVl
+ZC0yZjNiLTRiZWYtOTRjYi00YjgzMDkyZmEzY2NdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBwDCBvTAJBgNVHRMEAjAAMEgGDCsGAQQBkggJAYJqAQQ4DDZSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIFBvd2VyLCBsaXR0bGUgZW5kaWFuIEJldGEw
+GwYMKwYBBAGSCAkBgmoCBAsMCTEwLjEgQmV0YTAZBgwrBgEEAZIICQGCagMECQwH
+cHBjNjRsZTAuBgwrBgEEAZIICQGCagQEHgwccmhlbC0xMCxyaGVsLTEwLWJldGEt
+cHBjNjRsZTANBgkqhkiG9w0BAQsFAAOCAgEA1SukDSn9NakDXTq8UO5TatAHiSu+
+qWNgEtddX3XUZ1nB8S3n8QDhk4RoQIs2e66w95vOYyNipBO93gqVeJbEK7Krxgbl
+Xx6s08kPuwcdG8FxgqPC8jote7eVEHmrMnlhOyNz9WRYULyz6IlfQ6gQe7SmeSrC
+lsla8bykzN2/7MnDPqjByF0zbdtdoZ9U5JXlqJn2UuTIe+Z65jDqSwBv8bQF+F8g
+EiZtesy4n7sxXpINSFBkh24ohRd0ur8BXCoOLpzS96YkyHvXXdqaJcCoSJ6abqe0
+Q7IFWYfUIU7GCwtSL4M9ODjc8Cr5YUJgnsnlC1qYekOB1pGfROMC/9qEAU2TsOYp
+8yOZN+NmrsmSnaBLHEN9lhwpt+2It5Dm9B/SAW64fil/oVyHUj3qfIDXSzbD+l0q
+LQ6l66epVP/b3UU1R7+JzDDLUDm2bBWFr205L4CKkcpaReK+mXM3eTuMtiHWnLkY
+MQ6jgDAM+5GGGHqq/iJmBWM+Trp5HfyI3XEVWsXDBJ2zEDAAEwByWwhwGFI58SFy
+Zv3x3vpv56b7MW5fALXYFKkHzwjVw9YVXnhJmXO09GN7auPVYsFEPl3QUS/OiXPL
+suQmwYd7aS8Bua3kgAfg204O6OppflhkExzroRvvr7FT/9LftaaBI+HLDnvOdd2n
+y+Nqehto96G/A6A=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/10.1/363.pem b/repos/system_upgrade/common/files/prod-certs/10.1/363.pem
new file mode 100644
index 00000000..2b7eeb6d
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/10.1/363.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGKTCCBBGgAwIBAgIJALDxRLt/tU/fMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDEyOTEyNDg0NFoXDTQ1MDEy
+OTEyNDg0NFowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs4MGRiNGJj
+MC1hZTY1LTRhMjgtODRjNC1hZTgwZWFjZDQ2M2VdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBsjCBrzAJBgNVHRMEAjAAMDoGDCsGAQQBkggJAYJrAQQqDChSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIEFSTSA2NCBCZXRhMBsGDCsGAQQBkggJAYJr
+AgQLDAkxMC4xIEJldGEwGQYMKwYBBAGSCAkBgmsDBAkMB2FhcmNoNjQwLgYMKwYB
+BAGSCAkBgmsEBB4MHHJoZWwtMTAscmhlbC0xMC1iZXRhLWFhcmNoNjQwDQYJKoZI
+hvcNAQELBQADggIBAJ1siyraC4EY80gYkCaBag7l8BaLUuXcVgk67a4VNsCytxnn
+Pe0RGLoNcfI1p3Y3S2rDXCNQeAkMaJkraAt2TWxJz16pQY2XL2jS4J3wH3cD3MWc
+inEyJOxNRtx7vT2+2dWCKtgyLlg/GCu8q3Eojd97krId3Uz6f2obDcgawkmhvZZc
+QmwLncbhc9knDQX/Dxeep53i3QGgojOfCqRWj/xY/9L3Fq7KcHupMrXx8IktHEZL
+8yvFLx3QoqtYGKckxRC91RqKWG4edk8LYeL2mUSuONwzGpXvqKcfIMyWAhLaVfnG
+AqC7keoSm4RyGA47tL3dIFPuu5IYMa+Kdr4lyNGNmAfSYiPhkjte8YxMz9Y3fGBX
+BTRrWMN5LvvodEz33prFFfHl647sq4j7Qq6GSDBllV5B0nlJZvDIiBLGa/rpnJie
+dD76DhtNdtWr1ghqZTS0dQ+vxI3bZBcqYWxFoV30+3e700Xq2p+C4peY9fWGupVC
+w79WsJHj0aF2GBUtJlhqYo1ReZm4YH6CDv+DHDNEVmtu7bR0klTEpmFznuni6/Kr
++z/9FFnAYzVkECKA5zzQ52EfqclkYscADhlnBqY/knVDaAJAXZD5QIFlcGeXMxiS
+zIhD+K2P9GM4Z4n1CoYZceTwIaCDogRGo/2gO20dB0AZW2tPjvr/RpfI7zpR
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/10.1/419.pem b/repos/system_upgrade/common/files/prod-certs/10.1/419.pem
new file mode 100644
index 00000000..906b58e2
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/10.1/419.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGGjCCBAKgAwIBAgIJALDxRLt/tU/yMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDEyOTEyNDkwM1oXDTQ1MDEy
+OTEyNDkwM1owRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs4ZDMyOWZh
+MS0wYTgyLTRlMTktYmUxMy1mYzFiNWUxNDVhYzhdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBozCBoDAJBgNVHRMEAjAAMDUGDCsGAQQBkggJAYMjAQQlDCNSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIEFSTSA2NDAWBgwrBgEEAZIICQGDIwIEBgwE
+MTAuMTAZBgwrBgEEAZIICQGDIwMECQwHYWFyY2g2NDApBgwrBgEEAZIICQGDIwQE
+GQwXcmhlbC0xMCxyaGVsLTEwLWFhcmNoNjQwDQYJKoZIhvcNAQELBQADggIBAHgs
+Io5uxwPYpQFtIBiQ/wTzNfokMoBcL2eBt/pnCXMPBmAlscm1l96P92pB9b+uGxXx
+WWUPlwwsn87WABQkIVJJgW2Y723ZqJungj4duhuQB/c8pXqy6bEOIkSFqoiez3n+
+49adg2Fr/uXSj1NBbY+CGFU3QStKLNbDfFQJEEwvFbajTE4jp1e9Db0B60H4nX4n
+Z09Rl7IrBC+AO3d/bIc4Ed2Uk5oTozR+vVx6/JFewAE5aEYdrdqXVj+NHpLBbVpE
+KDlHJ41LdPu7HKXcqw/sqTyYuZJHqi5AZ2eLbBB6+0FRfgZC4B29LFokTlAoDTCM
+C0q7e2NwITdDDULLJq37DZlZiHBdDRrwyBNM5O4P5Ufyy6y5djN/93P/OxNhXMum
+n2J/yAQNvmzONEgz4g8Rfl+EIdNRaXMYdEHzQ4Rn0ba6f68hAilqVUgIdUdiLFG9
+ni0ISWWPQefkMRAWpOZymD0cumQUI2s+2nkzwVzTsmrQPAyFwHpIn+yfbUUDNBUR
+osnW+tTG51K7b2RVTkh6/ecXTGgaxHlltg6FILj/sS7umphD2CEmDSAK0eqLvUaE
+SqjtntlkgwbEGdHSvoMBVdl232yXCvxTX612VauD3e3HGr01Z2/lXqDq/5lZfZe9
+5YO65vQQLn1D8bNvKJ5hhI9m0qc4vYVbvwNqztLh
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/10.1/433.pem b/repos/system_upgrade/common/files/prod-certs/10.1/433.pem
new file mode 100644
index 00000000..b834a5f4
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/10.1/433.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGLDCCBBSgAwIBAgIJALDxRLt/tU/hMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDEyOTEyNDg0NFoXDTQ1MDEy
+OTEyNDg0NFowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFsxMWVlMzk5
+MC1lNmJiLTQzMDUtOWNiMi0zYTk1OGQ2OTJlYzBdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBtTCBsjAJBgNVHRMEAjAAMEEGDCsGAQQBkggJAYMxAQQxDC9SZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIElCTSB6IFN5c3RlbXMgQmV0YTAbBgwrBgEE
+AZIICQGDMQIECwwJMTAuMSBCZXRhMBcGDCsGAQQBkggJAYMxAwQHDAVzMzkweDAs
+BgwrBgEEAZIICQGDMQQEHAwacmhlbC0xMCxyaGVsLTEwLWJldGEtczM5MHgwDQYJ
+KoZIhvcNAQELBQADggIBACwo67Ht6qWmhyumMwWHpdlU7yzLc/s4oGTixAYsNEjf
++wtcCNtoO89crtwd6upsrK0V/qaDRpqugk40QyoGwDKGN7J9GLqrSBDTtMwKv5vY
+gE0GNiK/AUmE65uT6qAHq35OCAsNphGHyvOhDSEnLdAeU0VAMAOxi3Rb2KxmquE9
+mpjledsrBHUTHxUYobHKKEVSRS3JmVTIxcuLEKnIS69k4jq3hnbbd7y9jyadZQWB
+3ASqCnrm+1jKg4U8sYdF1yRdkh9TTU1XS+7z5MZ3tB6Fdzd67SJCkvH2XQGLdx/8
+4AL7Dm09uJrYWBunjs3DRKSIJ7As+l8iE99C4yfgR1rqogQmss57+24uI0UTC3O2
+4q1G+MfPXqF3N4NUuQmuO/M2ATfCXAfM3T6pkdS4g4XhWrpn5Pm5LvLhjU3/3/GM
+I8fANCW84MZmadnPjx77MJphF/mJzvwbkp8sCNUYy5Lbk/vleWOClGG/sgqrUlBj
+k8lI2ngkuIV3+tk0wfIZDOGIt67r3HZ9hP17jhmOR5olSaB36EB1q6OHktEO19uX
+xSRKHqgNMP7KQT/YmxKJb4lz49yQEj8XUiEt+K0r18OmA4QDJrl4jQ37yerlZLQj
+tKniBp5H/p7UN1dO5bKQ5Dp0p4YjXpqp6/K4kpJs6eVZh0Ikp3KcSO5afv604/aF
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/10.1/479.pem b/repos/system_upgrade/common/files/prod-certs/10.1/479.pem
new file mode 100644
index 00000000..23ff46a9
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/10.1/479.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGGDCCBACgAwIBAgIJALDxRLt/tU/1MA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDEyOTEyNDkwM1oXDTQ1MDEy
+OTEyNDkwM1owRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFszMWE2MzI1
+Zi1mOTE3LTQzNjgtOGM2MC05ODYwMDgyNWQzOThdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBoTCBnjAJBgNVHRMEAjAAMDUGDCsGAQQBkggJAYNfAQQlDCNSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIHg4Nl82NDAWBgwrBgEEAZIICQGDXwIEBgwE
+MTAuMTAYBgwrBgEEAZIICQGDXwMECAwGeDg2XzY0MCgGDCsGAQQBkggJAYNfBAQY
+DBZyaGVsLTEwLHJoZWwtMTAteDg2XzY0MA0GCSqGSIb3DQEBCwUAA4ICAQAEY2Oc
+fkUeiHFmZFf9Pb9nnCZqfRmrYl19aQeM8fVf4EKQVTy0WSadu6COTUngPl3Nsv3L
+nTl5rhvNXqVLN7kILZVbUBkzLeC89VrdwT0i9IoiINFDIOYxi55Ul8d/mS5o2Vla
+j3gy9cEOJBX/gfgTTG72nOp0f9B6CI2DmSjNVdA4ClOCfX0VRP+QhvOasEvKp4xg
+8b9lTi1lhE5E/axIpCtkc9JsPcp6sqLD4He8xSmNyuqOUowmDcYU2P2WSKSFNS8o
+kKL6EPMWk9W8QnirdjzBqNbIZY2qr9Pc9+Lk8kZ7T0JHGxfccaDLlunWOzEPQWtl
+AtTmzLVSKs3kCuxM4kiOd8sbMjIUth+G56bECD+lCYtsK8GdkAy+ACRN/7knirEC
+pv2eOYDnIaaWyI7kTUrN3fiCrSeQ9PydZ4nonL1VjiY5GS+2+LjmD8XGFJiEnWll
+tyvjvio2PjhqwayEOR1dOzsdgDko5fAnfdxA/pPCYB9uyXxE/pjE5sH6m2qIhCSw
+UcDIgpWpHnBPjw2sstnSRIdOkN4lb086vorvHph3YuEMa00SIWR2QAOY3cAYeqn0
+7RHCUVVdHHo5BlQjU4Fzpsxft8lmdzVsvMDI2fuT4at9UEe0ViTPKIBohVIgp5hz
+WQpi9eB/4PJNIWup9hrcVQxNWiid/Zk9IKpSyw==
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/10.1/486.pem b/repos/system_upgrade/common/files/prod-certs/10.1/486.pem
new file mode 100644
index 00000000..c66eae07
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/10.1/486.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGJzCCBA+gAwIBAgIJALDxRLt/tU/iMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDEyOTEyNDg0NFoXDTQ1MDEy
+OTEyNDg0NFowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFthYThkMTI0
+NS1kODY4LTQwYzYtODg4MS02OWM3MGIyZGI0NmFdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBsDCBrTAJBgNVHRMEAjAAMDoGDCsGAQQBkggJAYNmAQQqDChSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIHg4Nl82NCBCZXRhMBsGDCsGAQQBkggJAYNm
+AgQLDAkxMC4xIEJldGEwGAYMKwYBBAGSCAkBg2YDBAgMBng4Nl82NDAtBgwrBgEE
+AZIICQGDZgQEHQwbcmhlbC0xMCxyaGVsLTEwLWJldGEteDg2XzY0MA0GCSqGSIb3
+DQEBCwUAA4ICAQCWsIqn8Ff5r9SSNzKwMgRHaDjg/RXN9Zhau1DKDwpqp4m40+cK
+bdKYcS6WrZ2UGgJ1bQ0xHZf7Fh6FYd8wOH9zs0rtfUYuRQwbUlCmipVhhf5EY2FW
+vMTRj8DW1RdOQv7cEo9w4QWFSFQnsTvhR6DZuS8/WK4Z+8i8TV5KoQy6z4nVPdVu
+NiclCJNkjGZgYMqWA3yfmrhh1kxTCnvRdRro+tbTEkdC9oLKrGCrACucjHhAyuK5
+2xfr0q7rmHvxia2oc/9HjB3HV/xai1b/DiWuOb4mjLj/3SS7Ua07a14TZIlEDUrM
+YEzZBFIha+241FVdF434jFr4mAYSbm6yhNahSsPswV2O3vDMGz5tNOc1caWmQXkT
+UC/EXzfyrmy6fBQN32lacDr0OOD9LdVz28IT90brVIAVkFyRtGLLGwId/aDxoJJe
+M+TLHMGf+LfvP/jiwbpZxa6yfXDp6J0rHofNYLCYkeSa6TH55qYDWbi7DosCjpWj
+NnqN8aiDKf3f0OO0tRo1zcGCEMnfG3UzDjp37CWyVYZ/TUq8/ygJrcIxjXg0K1SH
+v01NOwphvkXlsNvjapGIgZTuo3/nASIjC92WP14MjdWv/nKhRkJ4ZMJtKSc6FgLC
+SXF8MHwPmaIyne4k3+tJ0AlmQenPqBs6GCB5xBd01wxhRTf7qxIF/+yr6A==
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/10.1/72.pem b/repos/system_upgrade/common/files/prod-certs/10.1/72.pem
new file mode 100644
index 00000000..fa452aa5
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/10.1/72.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGGTCCBAGgAwIBAgIJALDxRLt/tU/0MA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDEyOTEyNDkwM1oXDTQ1MDEy
+OTEyNDkwM1owRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFswMjNkYTRj
+Zi0xNTgwLTRkYTYtYWFhMy0yMGE1ZDZkMjE1OWNdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBojCBnzAJBgNVHRMEAjAAMDsGCysGAQQBkggJAUgBBCwMKlJlZCBIYXQg
+RW50ZXJwcmlzZSBMaW51eCBmb3IgSUJNIHogU3lzdGVtczAVBgsrBgEEAZIICQFI
+AgQGDAQxMC4xMBYGCysGAQQBkggJAUgDBAcMBXMzOTB4MCYGCysGAQQBkggJAUgE
+BBcMFXJoZWwtMTAscmhlbC0xMC1zMzkweDANBgkqhkiG9w0BAQsFAAOCAgEAM0cP
+KmcFfsVzBVVDZVZRLsQcWTnoZ8Hhufc8rNdE/LkoV1xGXIsN9ejsxZyfVhYvF8G9
+YP41uvQbR2jnXMAQyB7UNxf6I73hIu3yoJ4s6EqX53o9YfejIFFh0V802WpX4yJ8
+1UCKmQVNxnQCwH2Ybxess13F9oKjh7Ni1MMBpQc8i1vEXfkA/vroKS50tvO6vQgT
+Xh72DJ2dKjdnnMNHnuSq0sVcpEbmvPLR3PFrHAxTm0jzngN3S4JCcstiiHsKCCrV
+muSxW3ydQlC27C3Rdd/gB/fc5rxl9xh9Piq6a9UHDuqrXb83hMXL+nuvDbt+eERX
+j2Y7NA0BVgQTwW/zERNgIa8j4X7VtRtoeF7X6BF0gdHAsILzOIAIanZXXld6IiKS
+2m6ackoXPUvdUt3jnYTqYyXQmrpvYs13+AhzENdF+AaJGbcxKf4aAbSe5GEbGe9T
+jxoM2+FR+8zOIc8nVcEGaCryPc8kmNEYEVlCqD0DREB+LXeAYtI4MbGeezpQyfEu
+6jgf1njPd2mGihAlNUVePLdF9W96bc1RjOhiVzbjg9lwIWupTu5fPAeoxPNxSvJc
+nijOHvW5tr+ijG32dMSAKVwBSeFAGB+HssPr3hVoebNYniDIlKPIrv/cUkxwQNKL
+rifVE8bFrfYMm83IIR9pNy+wKjArX6S1OIW8A+A=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.7/279.pem b/repos/system_upgrade/common/files/prod-certs/9.7/279.pem
new file mode 100644
index 00000000..d03c3bb3
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.7/279.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGJTCCBA2gAwIBAgIJALDxRLt/tU/KMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDEyOTEyNDc1NVoXDTQ1MDEy
+OTEyNDc1NVowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFtkMjU0NzVk
+Ni1kZTI1LTQ1ZWItYjQwOC1kNzQ2ZDJiYjE2NjddMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBrjCBqzAJBgNVHRMEAjAAMEMGDCsGAQQBkggJAYIXAQQzDDFSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIFBvd2VyLCBsaXR0bGUgZW5kaWFuMBUGDCsG
+AQQBkggJAYIXAgQFDAM5LjcwGQYMKwYBBAGSCAkBghcDBAkMB3BwYzY0bGUwJwYM
+KwYBBAGSCAkBghcEBBcMFXJoZWwtOSxyaGVsLTktcHBjNjRsZTANBgkqhkiG9w0B
+AQsFAAOCAgEAdT5r3gd+2xXBetsU7BFxMZBiHkgkR642GW0U1jvhX0nMIo6CYJav
+i776Be1aRLprzThI5ZpXZtRgyp9aytmKBKw31WdfccI9jHDpn6HMzWBmO7cyQQ+4
+px3Z9kl2N07YXoZrQZpr3/vahoKTyEpsRWK9GcG6oSKeg5//mGXPlWz+cu6Yj6i5
+WRD//ppcERv1Qrzzog8xgAn7J77dcl57WArlflZRL4QJDKPMDl5f/VwrLPaZ+9LB
+YVUVvn6iYebK9yfM/mkaqXmjTFTmIcblcnC7He0lWCnlPvCDr8T3qXM2xJX42/Dk
+PRDY+/E84LrvURx8hbFUgj4YXEPnk/O7nJf3tTHp3l05GAB52gDycQ/AnvhOcwf7
+KHjUnTqvSnMbgtlbg4rhutn3Ag/vuVEwd+gTMT6pF2lE8eA4ILttcCH6wHrv4Rs1
+dyDkRPxVFPoYCJ8NMU/dRdhZoyfOKYVYGXD80ynjWH+lV4O+wVgRj+cMXzs2Y78l
+4WnBcBlTGFk6ZWuFgurZWelhSUXK/hkhxDIX1eMh3HZoUwu8fP6H3q0r2qsCCRhV
+g6yzu4uzd5sgNVaOS99573Hvcga+3tZJZbX49xb2lgVlnbyNzINEQxrPqVXi9CsZ
+r5vbXJg9DCJ1SVRxTSjUDcjkQ1TmAWzOt0QUN8iJYLyRpy/Y+NEPRZk=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.7/362.pem b/repos/system_upgrade/common/files/prod-certs/9.7/362.pem
new file mode 100644
index 00000000..41c163cf
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.7/362.pem
@@ -0,0 +1,36 @@
+-----BEGIN CERTIFICATE-----
+MIIGNDCCBBygAwIBAgIJALDxRLt/tU+0MA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDEyOTEyNDczNFoXDTQ1MDEy
+OTEyNDczNFowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFtjYjlhMGM4
+NS05NDliLTRmMTUtYTlhNS03MjNhNmExMzY3NTRdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBvTCBujAJBgNVHRMEAjAAMEgGDCsGAQQBkggJAYJqAQQ4DDZSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIFBvd2VyLCBsaXR0bGUgZW5kaWFuIEJldGEw
+GgYMKwYBBAGSCAkBgmoCBAoMCDkuNyBCZXRhMBkGDCsGAQQBkggJAYJqAwQJDAdw
+cGM2NGxlMCwGDCsGAQQBkggJAYJqBAQcDBpyaGVsLTkscmhlbC05LWJldGEtcHBj
+NjRsZTANBgkqhkiG9w0BAQsFAAOCAgEARIGB5FE60xrKLHZinX4m6eqq5lAFqvus
+HM3jS0R5qrg1QcoPuQGoZdOI3BlBDZXkuaR/K34e2+dCB+qu7LAOs5FqrUBGxL1V
+gOVeMehWZN5mDAgEtJNE7rIKa6DlPNGqW1WXcnWqCCpduppGDaHKO6jSqlkxJxrQ
+SadszgeVPifp7t1xq4vaFUDEGMZJlYov2uL1WQC2tuLaRJMBQv6OyZvEbC/fxYKX
+xena2M9FccS8yr8xJ7SRN/2v3uaPBxjHDUbbGDzoeXCIVPyF0cVDeO3MblANVkcf
+RNCu2WUkWGM78wBLVdavwp2Cal++J6kSzImuetCoPaJvRpS4mc/nRMOpcz8ly4DF
+4HwNieBT8sJmKlcOXYLyUywvpFdLKQgnSPMEUyAqfhiPsSqy7xQOvgOQ/Cjf5Q6p
+xVhEhvi86Puxh80kpbHM+LNFXDmcgVgnsbdBriO4mW+9hnelsa4J+7vn5q43Hsbg
+z4LlZpS1PqcNRNa8b65FmEWsvjd74vLowL2SWe0xSbyeqvtWZR5KglOHK9ggsGBz
+dKb5vvLTeSXCogtDgl2qkaDSXqYu3Af5/0Zwe57c5MC3k5+0jW91ZjzoTunRgHWo
+cDgpyvABKiglu/xKlVzE3Te/Cr11zV1jBwFxsASuIWmI4VPYAtWCAxtG6XrJKfPi
+iDaGn3oBNKU=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.7/363.pem b/repos/system_upgrade/common/files/prod-certs/9.7/363.pem
new file mode 100644
index 00000000..eb822e4d
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.7/363.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGJjCCBA6gAwIBAgIJALDxRLt/tU+zMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDEyOTEyNDczNFoXDTQ1MDEy
+OTEyNDczNFowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs3NTU2NjYw
+Ny1mNzBiLTRhNjYtYmI3YS1iOWJlYzU1NTAyY2FdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBrzCBrDAJBgNVHRMEAjAAMDoGDCsGAQQBkggJAYJrAQQqDChSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIEFSTSA2NCBCZXRhMBoGDCsGAQQBkggJAYJr
+AgQKDAg5LjcgQmV0YTAZBgwrBgEEAZIICQGCawMECQwHYWFyY2g2NDAsBgwrBgEE
+AZIICQGCawQEHAwacmhlbC05LHJoZWwtOS1iZXRhLWFhcmNoNjQwDQYJKoZIhvcN
+AQELBQADggIBAJrJftJS2xfoJVxLo76MMFZ6F2RBW+IgyFq45GphNNN8nUUixGTN
+exzgAI1TgqqhKvFpDHk49PlSq2syzOWqUuAn1dnxU8W5pfWZuBOs/NxdhCKgGUxT
+GrkiRi+RUVoUi9+Qx2P/UvNS/URCrOxyB1HC2x7Pl5r3NaQjf3s6JAfIsxPzptZa
+4x/RsRGu2Q41VQgX/ItAzFrPfZh6O94OfwXBP+FwEjSCVA00EGXO+m8BfHE4/eEm
+E1C4uw54BwlW5SIy2VCiv96MD+u0YlTITQEMqa+6fXXhiWi9FMjvsfPbldP9iScc
+6GXf+hbyUrjhilxva0AuxneBkJb3u7maCNPUEpJ9fhm+A3bPtyhDPG+0AwQCW637
+mNrjEGowbGehw4wO+T2+CxdAhR2WPpeLKQgwHxiJgH52OeI0wn7+nkI8I1TK/r6q
+JVwGEXi/I5wY0z8oYF5MeU+oE0pA06t471/bM0zTVnzVSFd0UUnVe+1nKjehPtDf
+1EI8XCbuTK1lyEiYMMx92T39jrXRjt+mkW3OJRzSCTef8wfbyNxaBo6FTyJG5Jvm
+EEaiVpsZs7UEx0CHdCbPJ+gb5SZ7nsmPT2GdJyfhO928dwmJzANYcI1mlDWFjjyx
+DJYI+otDEDl3TFh6LXMjM7fPvnIoTq9vvxCgMohrgFWLiUOdcdZSdH4I
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.7/419.pem b/repos/system_upgrade/common/files/prod-certs/9.7/419.pem
new file mode 100644
index 00000000..43c22d13
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.7/419.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGFzCCA/+gAwIBAgIJALDxRLt/tU/JMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDEyOTEyNDc1NVoXDTQ1MDEy
+OTEyNDc1NVowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs2NjU1MzE5
+Zi1kYWE2LTQyZjQtYmVlYS05OGUwNWJkZDJlMjhdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBoDCBnTAJBgNVHRMEAjAAMDUGDCsGAQQBkggJAYMjAQQlDCNSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIEFSTSA2NDAVBgwrBgEEAZIICQGDIwIEBQwD
+OS43MBkGDCsGAQQBkggJAYMjAwQJDAdhYXJjaDY0MCcGDCsGAQQBkggJAYMjBAQX
+DBVyaGVsLTkscmhlbC05LWFhcmNoNjQwDQYJKoZIhvcNAQELBQADggIBAG1dALly
+8sSax1sy31WsbXTtDkiLyzUMOLCWQtEVo77l8MWse76+LEyvUnSCyYB2V3w6IK5P
+IfRGqGPksWGnPHoRgAVvAIwa0DDH9UQl/se4J3dOSLfnkRFAthMew9eLBFzCltCl
+fZWmBsR84qfOha4m45QMwogysbIxTPBr6JqrpN0qkc87zBkx2SrtjavTf83g7lGE
+0XmRqY8Pyr5SSdHDUmxHSxoDvx1+/Rt2b3d3+nwRrhUgXU+4Ev7P0YyS3T22jZ8g
+GVZ330tXOhhIhFWmB5hI7eAwU8IIkxhH+TEsHHWbF4yaGveDnpgIpyGThGnsK3pB
+M2BTeB0UiY2COFg6Mm4iODJ2GuM2mDPR0ZAhphGV/JSqZE3N9vSm1rO8tZjc8sDv
+xIdHSVQupm5Dbbs6iO31vl+PkQ23WpHtNEVkKhhkUNS5g3rO9P3ULZeFigAWtWuw
++IClKc/8R2ksGegS69H4wXXVh1Ie3sHEyWlkB8pgzQmvS0VCX+EhaIs6P8QCu90Z
+NLscEhCeLT+pBDISXuf58R6W+DOyetwpFBh7Z5glcw8bmCkne5Su06/9+crfULup
+i8/1NtQO28KMvuDdHchtZ6arn0xHSkcwW9NyRBnnjAUjDH0nOvkJVJqzubvNj8uW
+7+Bph5JIcD945pirT4gt1WAEhLUPqdBoFfKw
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.7/433.pem b/repos/system_upgrade/common/files/prod-certs/9.7/433.pem
new file mode 100644
index 00000000..c3309765
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.7/433.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGKTCCBBGgAwIBAgIJALDxRLt/tU+1MA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDEyOTEyNDczNFoXDTQ1MDEy
+OTEyNDczNFowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFtmYzhkZWI4
+OS0xZTJjLTRhOWEtOTRlZS01MzBmYWRhNDA0YTddMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBsjCBrzAJBgNVHRMEAjAAMEEGDCsGAQQBkggJAYMxAQQxDC9SZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIElCTSB6IFN5c3RlbXMgQmV0YTAaBgwrBgEE
+AZIICQGDMQIECgwIOS43IEJldGEwFwYMKwYBBAGSCAkBgzEDBAcMBXMzOTB4MCoG
+DCsGAQQBkggJAYMxBAQaDBhyaGVsLTkscmhlbC05LWJldGEtczM5MHgwDQYJKoZI
+hvcNAQELBQADggIBALijiB6VwIQ1IscN4cQJATyy4IP2ZqPq4Uu2v2c+bxlmFSIK
+7paz9pWmXYmOSmBQgLYkZ1hkAXQdlj7ECmp5Q/rWscu8yw0obwFk1ned/4PnHf+/
+gn3osXUqixnj6RiT2SWlBtTnTqomiwpIeKc/JN0zNcsWagNx/B2Uw+kxfGDW4jF/
+L9rw9meOiQQwdzxbQJbiaCQQq1xE0Kx1yDoDDV/7Zg3eDfwzAUUwj1aE6xt9rms2
+ZhiP/ATlKYbePgIdqaO2sKLoRBugaaUEUSXSyZA6Q+8B7cO66rTtqsGqf83RjIOi
+i5nFTYZwALbUtNFvKN2nhP6ovBPYCX4rTHQ18WqoIzJLEGdO66hchPUP7LnwUJ0i
+vHgLrmiVwzh/LjtrXFt6+MMsvqfrxfre+U5OhjMwtyajjwvw7uJJ9tZjkXkDJs2J
+cZZCSKbj9T/bU7Rnak0eit2Fw75o3eLXaBOeBGUJgCVLlehSaema997V2LeAXtfU
+AcGXvS44YawXXbJHPawW5nXHtHVQnR0M0ksJObvji4DXZndp/TIl0paF5TRPwk7k
+XdNzVDx+2MDTo+hrs8CisMhdV+vIHtdRkXLpmgPlsHCrhBcqYiW37h37tYK9EuZP
+zViezq0rOn/mroAjemIfo1ZdjTDdQn+xQ/W0MCYk5QKf092PKjplsAYoF87H
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.7/479.pem b/repos/system_upgrade/common/files/prod-certs/9.7/479.pem
new file mode 100644
index 00000000..e38d2e54
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.7/479.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGFTCCA/2gAwIBAgIJALDxRLt/tU/MMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDEyOTEyNDc1NVoXDTQ1MDEy
+OTEyNDc1NVowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFsxMmVmNTE1
+ZC03OWJhLTRkZjAtYmExMC01ZjE4OGJkYWQ5NGFdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBnjCBmzAJBgNVHRMEAjAAMDUGDCsGAQQBkggJAYNfAQQlDCNSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIHg4Nl82NDAVBgwrBgEEAZIICQGDXwIEBQwD
+OS43MBgGDCsGAQQBkggJAYNfAwQIDAZ4ODZfNjQwJgYMKwYBBAGSCAkBg18EBBYM
+FHJoZWwtOSxyaGVsLTkteDg2XzY0MA0GCSqGSIb3DQEBCwUAA4ICAQDXiXDrVOMw
+eIApNOeZcaveYY6XSkeWv5Kb9/yZShZ00gp3thOawaGWz6/1lwV7TOlp6XLe4OiB
+NOWpeA6YNfOjQjIkrjzXIzXc/PhahJEddXq7OaGnHYkL8+vbZQurIHxEZVGnloJi
+IbvHWgjXkx0CJ4dX5IEpbBTJYVT+XvO4xgTayipG7c38XvIQif91xwoUBjznxhSh
+6e0deGAE/+ho5ouOgDCssD+jz2f7ekCOR3ehe5+9U3u/3cfQ/QnkW7LGRAvr7Vcz
+RJx1N49AnsJ+I5FdUxIEMgw0xpXA9WyKRUzImgiMboW+Qw6DaQPIyF8eXj6AKFjs
+dFHvi24891HjF7vNBrwLS9jMdrwoNo7+MBGN3M4Q8E6q0K+eRccpYEIt5tLqTBiU
+LrP/RPfY7wZaiHrXNFtuHFdBMdgG9SXMAVjThBsSB22LIYeIHbtvXoF5NRF7F2x8
+f1BuGRkTpWERDeO0iQCm1feSzhnfpmZ4uqrGKINr98SqHaRv7NyWcEAq8BZ8iMsq
+iSmpwRnpK3Y3Z7JZaa5qOyhANvdJjhiV42QNZ9B3WESB5Y22uf643RqcquCSnKTd
+RmXymDyyO7NNBUWdBceTdomAOEviDl0FNv5nhGs++eEJHMfKL2rFXYvRyqSwVkIm
+Y6MmDGFEYYvHybEKh25m3wrwoZai3LGX4g==
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.7/486.pem b/repos/system_upgrade/common/files/prod-certs/9.7/486.pem
new file mode 100644
index 00000000..a9c3a580
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.7/486.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGJDCCBAygAwIBAgIJALDxRLt/tU+2MA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDEyOTEyNDczNFoXDTQ1MDEy
+OTEyNDczNFowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFtkMGEzYzRj
+Zi01ZDZjLTQ5OWMtYTQ5Zi01OTFhNzg3ZTI2MWVdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBrTCBqjAJBgNVHRMEAjAAMDoGDCsGAQQBkggJAYNmAQQqDChSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIHg4Nl82NCBCZXRhMBoGDCsGAQQBkggJAYNm
+AgQKDAg5LjcgQmV0YTAYBgwrBgEEAZIICQGDZgMECAwGeDg2XzY0MCsGDCsGAQQB
+kggJAYNmBAQbDBlyaGVsLTkscmhlbC05LWJldGEteDg2XzY0MA0GCSqGSIb3DQEB
+CwUAA4ICAQBTdLKi7NjqPmP+Sy9Bd0xQRQDNS0Tpvs4OR11rYuBRvQl04maKij4X
+OiYWp0/PeQdkT2GMRcU4Yvs3oFtnj9jIAUmDAxT4wCrPUGgxRiwve5RJSRpXwaYt
+eCXJVa0TkJ9CPy1h1am5r8/tD+5amftuy5ActB5R1yuiUhtao+ii12BscFBa0GxL
+xBYD9Kp0+/bgXWY5vLQfcAdRmCGWnWD7DiH6+63o100RdMM7NKiErzC88GEtzbJJ
+hEkBB+BkxhKP+LTiJOXQWwstd6u7E0yk9t5vyCuZmWVUdF1ZEP60+GrY7j4wB1uX
+hQ62x2aXnTalx2mFiRJWt3enF9Si2fH+2UOwZm9iRLeblhf+C7N6bpxO/mXkPWEq
+cInjmpRzJh8w7nqZU7HFdt0v71ZHDr+Ppu61gStbebJyUNU4R93jqXqatEfzmhTB
+beuLeTwf5M0gYt19PHFE5ls8qsjCNbppxNTo4FmpTi8XvSSYoe/FjzoChTZWD8La
+w5MQrKxqlScRkI2yWMoNJNfS/0mTE7e7DoEnwbbDWQVdb6Kx7bi5HVMW+PLPsX+U
+aeDYf2i6Vlqhr8mtLcV+9HUdDP+a13OOKjIqNRMGnq4Ks+h5XbFpUa10ZTdtqbQJ
+Xj72H08QzoBwcZfFwWDODjU5co0X7QAhQ6D6b9b1OrGtt1lXurS53w==
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.7/72.pem b/repos/system_upgrade/common/files/prod-certs/9.7/72.pem
new file mode 100644
index 00000000..4c6e257c
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.7/72.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGFjCCA/6gAwIBAgIJALDxRLt/tU/LMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTI1MDEyOTEyNDc1NVoXDTQ1MDEy
+OTEyNDc1NVowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFtlOWQyNzc3
+Mi1hMmFlLTQ1YTUtYjYxMS1jZDViZmY3Y2Y4NTNdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBnzCBnDAJBgNVHRMEAjAAMDsGCysGAQQBkggJAUgBBCwMKlJlZCBIYXQg
+RW50ZXJwcmlzZSBMaW51eCBmb3IgSUJNIHogU3lzdGVtczAUBgsrBgEEAZIICQFI
+AgQFDAM5LjcwFgYLKwYBBAGSCAkBSAMEBwwFczM5MHgwJAYLKwYBBAGSCAkBSAQE
+FQwTcmhlbC05LHJoZWwtOS1zMzkweDANBgkqhkiG9w0BAQsFAAOCAgEAdVhrTT0k
+0sBZOpLSW3fWCbIdJ0lChyYtPCii6O4vj5hE1oCV0tHmCGcfEp4j49GXwB6zs3F7
+cZsJO2aGrMEZkiGPMTPGW0VV+QKJIq7wo23ogWw/fxF3K3QbFTDNbfdv/E8MRkcN
+P9bLgTGqcs9VpNKp48+TovpxtjYeF9/XQi+h5wll5gqEfFnq8VaKi6P9eZvbGuue
+DhdItkN+RdHMj8AQpMAezKyOb3QURCBUJMtbvZgJk6tRCHnhF3NSig/h9lbrVqmu
+Wd7b/+uw/ElzXsLr6ekHuVH5oI9A9F+4SEFBKjCVvwEkd+FK+P2iudF6YR3Ods6t
+uXMBcI9e9bXdzzn3XLKHcpgeDURkPgD8xW/ICut1pFeqO/YnR8xodJ7X+8h4JJpn
+yNOFlaqEV0t9BTRGX7vfCSFZ8k07RQLmTvRFUC/OniL50hfUw+L2fedpTD2JtTRN
+aeMBN2kiAzKn7K28Ejv6BJcDnohXDMWNfmL85i5jvQ/BMxu7pvFiAuPsGeCZ1Yj5
+1s3kQxKzQ/nCE/ZBDLG+B7hlRGNYPoYvfxcNjEaKbYny9jkvb8JqPgRBmowsLcxC
+jukhm6gp+R/kkp0nQjnYsoan49ai/YTU4pY0uyDAAfM9h6owwKkO/1PWTiXCqVJK
+Rm6ezgUGOYAUA/i4p+LLyIArOUqHwRxJ2S4=
+-----END CERTIFICATE-----
--
2.49.0

View File

@ -1,42 +0,0 @@
From 7d9ae2c0adcef2eac7cb09fd9acf74f9a6011d64 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Fri, 17 Oct 2025 09:08:02 +0200
Subject: [PATCH 25/55] Makefile: Properly copy commands dir to test containers
During a containerized tests run, the commands/ directory is not used
when running the commands tests. Instead, the commands are imported from
tut/lib/python3.X/site-packages/leapp/cli/commands/ where python3.X is
the python used in the tut/ virtualenv.
When there are changes breaking the commands tests, the test are still
passing because the files are not being updated in the directory
mentioned above. This can be currently fixed by rebuilding the container
which takes a lot of time.
This patch adds copying of the commands/ dir to the
tut/lib/python3.X/site-packages/leapp/cli/commands/.
This helped while working on #1438 because I caught the failing tests
only after opening a the PR. The CI containerized tests are always
created from scratch so it works there.
---
Makefile | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 1bfbc3ac..9774a475 100644
--- a/Makefile
+++ b/Makefile
@@ -447,7 +447,8 @@ test_container:
export _CONT_NAME="leapp-repo-tests-$(_TEST_CONTAINER)-cont"; \
$(_CONTAINER_TOOL) ps -q -f name=$$_CONT_NAME && { $(_CONTAINER_TOOL) kill $$_CONT_NAME; $(_CONTAINER_TOOL) rm $$_CONT_NAME; }; \
$(_CONTAINER_TOOL) run -di --name $$_CONT_NAME -v "$$PWD":/repo:Z -e PYTHON_VENV=$$_VENV $$TEST_IMAGE && \
- $(_CONTAINER_TOOL) exec $$_CONT_NAME rsync -aur --delete --exclude 'tut/' --exclude 'docs/' --exclude '**/__pycache__/' --exclude 'packaging/' --exclude '.git/' /repo/ /repocopy && \
+ $(_CONTAINER_TOOL) exec $$_CONT_NAME rsync -aur --delete --exclude 'tut/' --exclude 'docs/' --exclude '**/__pycache__/' --exclude 'packaging/' --exclude '.git/' --exclude 'commands/' /repo/ /repocopy && \
+ $(_CONTAINER_TOOL) exec $$_CONT_NAME rsync -aur --delete --exclude '**/__pycache__/' /repo/commands/ /repocopy/tut/lib/$$_VENV/site-packages/leapp/cli/commands/ && \
export res=0; \
case $$_VENV in \
python3.6) \
--
2.51.1

View File

@ -0,0 +1,178 @@
From 9c621a91199c093f603ef30ba3daf59010c20e47 Mon Sep 17 00:00:00 2001
From: karolinku <kkula@redhat.com>
Date: Thu, 10 Apr 2025 09:14:51 +0200
Subject: [PATCH 26/37] Add handling of shorten PCI ID and lowercases
HW data file is inconsistent and sometimes contains both upper/lower
cases so this patch is unifying it. Also PCI ID can be passed as full
ID: Vendor:Device:SVendor:SDevice, but also in shorten version:
Vendor:Device. This patch introduce handling of both cases.
The data comming from DDDD file was sanitised.
JIRA: RHEL-72544
---
.../deviceanddriverdeprecationdataload.py | 9 +++
.../libraries/pcidevicesscanner.py | 19 ++++--
.../tests/test_pcidevicesscanner.py | 64 +++++++++++++++++--
3 files changed, 81 insertions(+), 11 deletions(-)
diff --git a/repos/system_upgrade/common/actors/loaddevicedriverdeprecationdata/libraries/deviceanddriverdeprecationdataload.py b/repos/system_upgrade/common/actors/loaddevicedriverdeprecationdata/libraries/deviceanddriverdeprecationdataload.py
index b12e77c9..acea583d 100644
--- a/repos/system_upgrade/common/actors/loaddevicedriverdeprecationdata/libraries/deviceanddriverdeprecationdataload.py
+++ b/repos/system_upgrade/common/actors/loaddevicedriverdeprecationdata/libraries/deviceanddriverdeprecationdataload.py
@@ -25,6 +25,15 @@ def process():
docs_url='',
docs_title='')
+ # Unify all device ids to lowercase
+ try:
+ for entry in deprecation_data['data']:
+ if "device_id" in entry.keys():
+ entry["device_id"] = entry.get("device_id").lower()
+ except (KeyError, AttributeError, TypeError):
+ # this may happen if receiving invalid data
+ pass
+
try:
api.produce(
DeviceDriverDeprecationData(
diff --git a/repos/system_upgrade/common/actors/pcidevicesscanner/libraries/pcidevicesscanner.py b/repos/system_upgrade/common/actors/pcidevicesscanner/libraries/pcidevicesscanner.py
index eb063abb..285a8a21 100644
--- a/repos/system_upgrade/common/actors/pcidevicesscanner/libraries/pcidevicesscanner.py
+++ b/repos/system_upgrade/common/actors/pcidevicesscanner/libraries/pcidevicesscanner.py
@@ -60,7 +60,7 @@ def parse_pci_device(textual_block, numeric_block):
driver=device['Driver'],
modules=device['Module'],
numa_node=device['NUMANode'],
- pci_id=":".join(PCI_ID_REG.findall(numeric_block))
+ pci_id=(":".join(PCI_ID_REG.findall(numeric_block)).lower())
)
@@ -78,14 +78,19 @@ def parse_pci_devices(pci_textual, pci_numeric):
def produce_detected_devices(devices):
prefix_re = re.compile('0x')
entry_lookup = {
- prefix_re.sub('', entry.device_id): entry
+ prefix_re.sub('', entry.device_id.lower()): entry
for message in api.consume(DeviceDriverDeprecationData) for entry in message.entries
}
- api.produce(*[
- DetectedDeviceOrDriver(**entry_lookup[device.pci_id].dump())
- for device in devices
- if device.pci_id in entry_lookup
- ])
+
+ device_list = []
+ for device in devices:
+ shorten_pci_id = ":".join(device.pci_id.split(':')[:-2])
+ if device.pci_id in entry_lookup:
+ device_list.append(DetectedDeviceOrDriver(**entry_lookup[device.pci_id].dump()))
+ elif shorten_pci_id in entry_lookup:
+ device_list.append(DetectedDeviceOrDriver(**entry_lookup[shorten_pci_id].dump()))
+
+ api.produce(*device_list)
def produce_detected_drivers(devices):
diff --git a/repos/system_upgrade/common/actors/pcidevicesscanner/tests/test_pcidevicesscanner.py b/repos/system_upgrade/common/actors/pcidevicesscanner/tests/test_pcidevicesscanner.py
index 4bd545ba..2bfde232 100644
--- a/repos/system_upgrade/common/actors/pcidevicesscanner/tests/test_pcidevicesscanner.py
+++ b/repos/system_upgrade/common/actors/pcidevicesscanner/tests/test_pcidevicesscanner.py
@@ -2,8 +2,16 @@ import os
import pytest
-from leapp.libraries.actor.pcidevicesscanner import parse_pci_devices, produce_pci_devices
-from leapp.models import PCIDevice, PCIDevices
+from leapp.libraries.actor.pcidevicesscanner import parse_pci_devices, produce_detected_devices, produce_pci_devices
+from leapp.libraries.common.testutils import CurrentActorMocked, produce_mocked
+from leapp.libraries.stdlib import api
+from leapp.models import (
+ DetectedDeviceOrDriver,
+ DeviceDriverDeprecationData,
+ DeviceDriverDeprecationEntry,
+ PCIDevice,
+ PCIDevices
+)
def test_parse_pci_devices():
@@ -37,9 +45,9 @@ Module: ata_generic
'''
devices_numeric = '''Slot: 00:00.0
Class: Host bridge
-Vendor: 15b45
+Vendor: 15B45
Device: 0724
-SVendor: 15b46
+SVendor: 15B46
SDevice: 0725
PhySlot: 3
Rev: 02
@@ -76,6 +84,7 @@ Module: ata_generic
assert dev.progif == '80'
assert dev.driver == 'ata_piix'
assert dev.pci_id == '15b43:0722'
+ assert dev.pci_id.islower() is True
assert len(dev.modules) == 3
assert 'ata_piix' in dev.modules
assert 'pata_acpi' in dev.modules
@@ -206,6 +215,53 @@ def test_produce_no_devices():
assert not output[0].devices
+def test_shorten_id(monkeypatch):
+
+ input_data = [PCIDevice(
+ slot='b765:00:02.0',
+ dev_cls='Ethernet controller',
+ vendor='Mellanox Technologies',
+ name='MT27500/MT27520 Family [ConnectX-3/ConnectX-3 Pro Virtual Function]',
+ subsystem_vendor='Mellanox Technologies',
+ subsystem_name='Device 61b0',
+ physical_slot='2',
+ rev='',
+ progif='',
+ driver='mlx4_core',
+ modules=['mlx4_core'],
+ numa_node='0',
+ pci_id='15b3:1004:15b3:61b0'
+ )]
+
+ messages = [DeviceDriverDeprecationData(entries=[DeviceDriverDeprecationEntry(
+ available_in_rhel=[7, 8, 9],
+ deprecation_announced="",
+ device_id="0x15B3:0x1004",
+ device_name="Mellanox Technologies: MT27500 Family [ConnectX-3 Virtual Function]",
+ device_type="pci",
+ driver_name="mlx4_core",
+ maintained_in_rhel=[7, 8]
+ )])]
+
+ expected_output = DetectedDeviceOrDriver(
+ available_in_rhel=[7, 8, 9],
+ deprecation_announced="",
+ device_id="0x15B3:0x1004",
+ device_name="Mellanox Technologies: MT27500 Family [ConnectX-3 Virtual Function]",
+ device_type="pci",
+ driver_name="mlx4_core",
+ maintained_in_rhel=[7, 8]
+ )
+
+ current_actor = CurrentActorMocked(msgs=messages, src_ver='8.10', dst_ver='9.6')
+ monkeypatch.setattr(api, 'current_actor', current_actor)
+ monkeypatch.setattr(api, 'produce', produce_mocked())
+
+ produce_detected_devices(input_data)
+ assert api.produce.model_instances
+ assert expected_output == api.produce.model_instances[0]
+
+
# TODO(pstodulk): update the test - drop current_actor_context and use monkeypatch
@pytest.mark.skipif(not os.path.exists('/usr/sbin/lspci'), reason='lspci not installed on the system')
def test_actor_execution(current_actor_context):
--
2.49.0

View File

@ -1,42 +0,0 @@
From 1ba6d4301602c8a253ba92263fd829e385463182 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Fri, 17 Oct 2025 15:19:03 +0200
Subject: [PATCH 26/55] livemode: update obsoleted log msg about config
The original livemode configuration was located in
/etc/leapp/files/leapp-livemode.ini
However, this file has been replaced by new configuration for actors,
represented by variable filename under /etc/leapp/actor_conf.d/
I decided to keep the info log, but dropped the information about the
file path.
---
.../livemode_config_scanner/libraries/scan_livemode_config.py | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/libraries/scan_livemode_config.py b/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/libraries/scan_livemode_config.py
index 26fd9d09..7d72204c 100644
--- a/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/libraries/scan_livemode_config.py
+++ b/repos/system_upgrade/common/actors/livemode/livemode_config_scanner/libraries/scan_livemode_config.py
@@ -5,7 +5,6 @@ from leapp.libraries.common.rpms import has_package
from leapp.libraries.stdlib import api
from leapp.models import InstalledRPM, LiveModeConfig
-LIVEMODE_CONFIG_LOCATION = '/etc/leapp/files/devel-livemode.ini'
DEFAULT_SQUASHFS_PATH = '/var/lib/leapp/live-upgrade.img'
@@ -39,8 +38,7 @@ def scan_config_and_emit_message():
if not should_scan_config():
return
- api.current_logger().info('Loading livemode config from %s', LIVEMODE_CONFIG_LOCATION)
-
+ api.current_logger().info('Loading the livemode configuration.')
config = api.current_actor().config[livemode_config_lib.LIVEMODE_CONFIG_SECTION]
# Mapping from model field names to configuration fields - because we might have
--
2.51.1

View File

@ -0,0 +1,125 @@
From d7d37caae69e27caec73d35236bedb6e1e70bcd4 Mon Sep 17 00:00:00 2001
From: karolinku <kkula@redhat.com>
Date: Wed, 7 May 2025 13:35:37 +0200
Subject: [PATCH 27/37] Prevent device list from containing incorrent content
Some PCI devices got from lspci output do not have to neccessarily
provide SVendor and SDevice fields. PCI ID of such devices is
composed in the pci_device_scanner actor just from:
Vendor:Device
instead of the full id:
Vendor:Device:SVendor:SDevice
The recent change comparing such devices with bundled DDDD
data drops last two fragments from the composed PCI ID,
which led to the situation when the `shortened_pci_id`
resulted in an empty string and it has been incorrectly
matched with one of (consider random) drivers and possibly
inhibited the in-place upgrade.
So let's ensure that we do not match any PCI device with
any entry from DDDD undefined PCI ID.
JIRA: RHEL-72544
---
.../libraries/pcidevicesscanner.py | 1 +
.../tests/test_pcidevicesscanner.py | 71 +++++++++++++++++++
2 files changed, 72 insertions(+)
diff --git a/repos/system_upgrade/common/actors/pcidevicesscanner/libraries/pcidevicesscanner.py b/repos/system_upgrade/common/actors/pcidevicesscanner/libraries/pcidevicesscanner.py
index 285a8a21..36e4f7e0 100644
--- a/repos/system_upgrade/common/actors/pcidevicesscanner/libraries/pcidevicesscanner.py
+++ b/repos/system_upgrade/common/actors/pcidevicesscanner/libraries/pcidevicesscanner.py
@@ -80,6 +80,7 @@ def produce_detected_devices(devices):
entry_lookup = {
prefix_re.sub('', entry.device_id.lower()): entry
for message in api.consume(DeviceDriverDeprecationData) for entry in message.entries
+ if entry.device_id
}
device_list = []
diff --git a/repos/system_upgrade/common/actors/pcidevicesscanner/tests/test_pcidevicesscanner.py b/repos/system_upgrade/common/actors/pcidevicesscanner/tests/test_pcidevicesscanner.py
index 2bfde232..e8e4bb99 100644
--- a/repos/system_upgrade/common/actors/pcidevicesscanner/tests/test_pcidevicesscanner.py
+++ b/repos/system_upgrade/common/actors/pcidevicesscanner/tests/test_pcidevicesscanner.py
@@ -262,6 +262,77 @@ def test_shorten_id(monkeypatch):
assert expected_output == api.produce.model_instances[0]
+def test_cut_pci_id(monkeypatch):
+
+ input_data = [
+ PCIDevice(
+ slot='00:03.0',
+ dev_cls='Ethernet controller',
+ vendor='Intel Corporation',
+ name='82599 Ethernet Controller Virtual Function',
+ subsystem_vendor='',
+ subsystem_name='',
+ physical_slot='3',
+ rev='01',
+ progif='',
+ driver='ixgbevf',
+ modules=['ixgbevf'],
+ numa_node='',
+ pci_id='8086:10ed'
+ ),
+ PCIDevice(
+ slot='b765:00:02.0',
+ dev_cls='Ethernet controller',
+ vendor='Mellanox Technologies',
+ name='MT27500/MT27520 Family [ConnectX-3/ConnectX-3 Pro Virtual Function]',
+ subsystem_vendor='Mellanox Technologies',
+ subsystem_name='Device 61b0',
+ physical_slot='2',
+ rev='',
+ progif='',
+ driver='mlx4_core',
+ modules=['mlx4_core'],
+ numa_node='0',
+ pci_id='15b3:1004:15b3:61b0'
+ )]
+
+ messages = [DeviceDriverDeprecationData(entries=[DeviceDriverDeprecationEntry(
+ available_in_rhel=[7],
+ deprecation_announced='',
+ device_id='',
+ device_name='',
+ device_type='pci',
+ driver_name='wil6210',
+ maintained_in_rhel=[]
+ ),
+ DeviceDriverDeprecationEntry(
+ available_in_rhel=[7, 8, 9],
+ deprecation_announced="",
+ device_id="0x15B3:0x1004",
+ device_name="Mellanox Technologies: MT27500 Family [ConnectX-3 Virtual Function]",
+ device_type="pci",
+ driver_name="mlx4_core",
+ maintained_in_rhel=[7, 8])]
+ )]
+
+ expected_output = DetectedDeviceOrDriver(
+ available_in_rhel=[7, 8, 9],
+ deprecation_announced="",
+ device_id="0x15B3:0x1004",
+ device_name="Mellanox Technologies: MT27500 Family [ConnectX-3 Virtual Function]",
+ device_type="pci",
+ driver_name="mlx4_core",
+ maintained_in_rhel=[7, 8]
+ )
+ current_actor = CurrentActorMocked(msgs=messages, src_ver='8.10', dst_ver='9.6')
+ monkeypatch.setattr(api, 'current_actor', current_actor)
+ monkeypatch.setattr(api, 'produce', produce_mocked())
+
+ produce_detected_devices(input_data)
+ assert api.produce.model_instances
+ assert expected_output == api.produce.model_instances[0]
+
+
# TODO(pstodulk): update the test - drop current_actor_context and use monkeypatch
@pytest.mark.skipif(not os.path.exists('/usr/sbin/lspci'), reason='lspci not installed on the system')
def test_actor_execution(current_actor_context):
--
2.49.0

View File

@ -1,147 +0,0 @@
From 37409349656c12efd4033e0cb5a3c25d10e6630d Mon Sep 17 00:00:00 2001
From: Mark Huth <mhuth@redhat.com>
Date: Mon, 15 Sep 2025 16:29:02 +1000
Subject: [PATCH 27/55] chore(RHINENG-19596): Rebrand Insights to Lightspeed
---
commands/preupgrade/__init__.py | 2 +-
commands/upgrade/__init__.py | 2 +-
docs/source/configuring-ipu/envars.md | 2 +-
.../common/actors/checkinsightsautoregister/actor.py | 2 +-
.../libraries/checkinsightsautoregister.py | 5 +++--
.../common/actors/insightsautoregister/actor.py | 2 +-
.../insightsautoregister/libraries/insightsautoregister.py | 6 +++---
.../insightsautoregister/tests/test_insightsautoregister.py | 2 +-
8 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/commands/preupgrade/__init__.py b/commands/preupgrade/__init__.py
index 6443bd8a..f24e779a 100644
--- a/commands/preupgrade/__init__.py
+++ b/commands/preupgrade/__init__.py
@@ -26,7 +26,7 @@ from leapp.utils.output import beautify_actor_exception, report_errors, report_i
help='Use only custom repositories and skip actions with Red Hat Subscription Manager.'
' This only has effect on Red Hat Enterprise Linux systems.'
)
-@command_opt('no-insights-register', is_flag=True, help='Do not register into Red Hat Insights')
+@command_opt('no-insights-register', is_flag=True, help='Do not register into Red Hat Lightspeed')
@command_opt('no-rhsm-facts', is_flag=True, help='Do not store migration information using Red Hat '
'Subscription Manager. Automatically implied by --no-rhsm.')
@command_opt('enablerepo', action='append', metavar='<repoid>',
diff --git a/commands/upgrade/__init__.py b/commands/upgrade/__init__.py
index 36be0719..c5900c0d 100644
--- a/commands/upgrade/__init__.py
+++ b/commands/upgrade/__init__.py
@@ -32,7 +32,7 @@ from leapp.utils.output import beautify_actor_exception, report_errors, report_i
help='Use only custom repositories and skip actions with Red Hat Subscription Manager.'
' This only has effect on Red Hat Enterprise Linux systems.'
)
-@command_opt('no-insights-register', is_flag=True, help='Do not register into Red Hat Insights')
+@command_opt('no-insights-register', is_flag=True, help='Do not register into Red Hat Lightspeed')
@command_opt('no-rhsm-facts', is_flag=True, help='Do not store migration information using Red Hat '
'Subscription Manager. Automatically implied by --no-rhsm.')
@command_opt('enablerepo', action='append', metavar='<repoid>',
diff --git a/docs/source/configuring-ipu/envars.md b/docs/source/configuring-ipu/envars.md
index a042ba4a..09634df2 100644
--- a/docs/source/configuring-ipu/envars.md
+++ b/docs/source/configuring-ipu/envars.md
@@ -21,7 +21,7 @@ Overrides the automatically detected storage device with GRUB core (e.g. /dev/sd
Set to 1 to disable RPM GPG checks (same as yum/dnf nogpgckeck option). Its equivalent to the --nogpgcheck leapp option.
#### LEAPP_NO_INSIGHTS_REGISTER
-If set to `1`, Leapp does not register the system into Red Hat Insights automatically. Its equivalent to the --no-insights-register leapp option.
+If set to `1`, Leapp does not register the system into Red Hat Lightspeed automatically. Its equivalent to the --no-insights-register leapp option.
#### LEAPP_NO_NETWORK_RENAMING
If set to `1`, the actor responsible to handle NICs names ends without doing anything. The actor usually creates UDEV rules to preserve original NICs in case they are changed. However, in some cases its not wanted and it leads in malfunction network configuration (e.g. in case the bonding is configured on the system). Its expected that NICs have to be handled manually if needed.
diff --git a/repos/system_upgrade/common/actors/checkinsightsautoregister/actor.py b/repos/system_upgrade/common/actors/checkinsightsautoregister/actor.py
index 70b3b670..52108566 100644
--- a/repos/system_upgrade/common/actors/checkinsightsautoregister/actor.py
+++ b/repos/system_upgrade/common/actors/checkinsightsautoregister/actor.py
@@ -7,7 +7,7 @@ from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
class CheckInsightsAutoregister(Actor):
"""
- Checks if system can be automatically registered into Red Hat Insights
+ Checks if system can be automatically registered into Red Hat Lightspeed
The registration is skipped if NO_INSIGHTS_REGISTER=1 environment variable
is set, the --no-insights-register command line argument present. if the
diff --git a/repos/system_upgrade/common/actors/checkinsightsautoregister/libraries/checkinsightsautoregister.py b/repos/system_upgrade/common/actors/checkinsightsautoregister/libraries/checkinsightsautoregister.py
index 762f3c08..8e26485b 100644
--- a/repos/system_upgrade/common/actors/checkinsightsautoregister/libraries/checkinsightsautoregister.py
+++ b/repos/system_upgrade/common/actors/checkinsightsautoregister/libraries/checkinsightsautoregister.py
@@ -24,9 +24,9 @@ def _ensure_package(package):
def _report_registration_info(installing_client):
pkg_msg = " The '{}' package required for the registration will be installed during the upgrade."
- title = "Automatic registration into Red Hat Insights"
+ title = "Automatic registration into Red Hat Lightspeed"
summary = (
- "After the upgrade, this system will be automatically registered into Red Hat Insights."
+ "After the upgrade, this system will be automatically registered into Red Hat Lightspeed."
"{}"
" To skip the automatic registration, use the '--no-insights-register' command line option or"
" set the LEAPP_NO_INSIGHTS_REGISTER environment variable."
@@ -38,6 +38,7 @@ def _report_registration_info(installing_client):
reporting.Summary(summary),
reporting.Severity(reporting.Severity.INFO),
reporting.Groups([reporting.Groups.SERVICES]),
+ reporting.Key('693963253195f418526f045b6d630a1f4c7a193d'),
]
)
diff --git a/repos/system_upgrade/common/actors/insightsautoregister/actor.py b/repos/system_upgrade/common/actors/insightsautoregister/actor.py
index a81b434c..56615390 100644
--- a/repos/system_upgrade/common/actors/insightsautoregister/actor.py
+++ b/repos/system_upgrade/common/actors/insightsautoregister/actor.py
@@ -7,7 +7,7 @@ from leapp.tags import FirstBootPhaseTag, IPUWorkflowTag
class InsightsAutoregister(Actor):
"""
- Automatically registers system into Red Hat Insights
+ Automatically registers system into Red Hat Lightspeed
The registration is skipped if NO_INSIGHTS_REGISTER=1 environment variable
is set, the --no-insights-register command line argument present or the
diff --git a/repos/system_upgrade/common/actors/insightsautoregister/libraries/insightsautoregister.py b/repos/system_upgrade/common/actors/insightsautoregister/libraries/insightsautoregister.py
index 2134a8bb..bd113a1f 100644
--- a/repos/system_upgrade/common/actors/insightsautoregister/libraries/insightsautoregister.py
+++ b/repos/system_upgrade/common/actors/insightsautoregister/libraries/insightsautoregister.py
@@ -6,18 +6,18 @@ from leapp.libraries.stdlib import api, CalledProcessError, run
def _insights_register():
try:
run(['insights-client', '--register'])
- api.current_logger().info('Automatically registered into Red Hat Insights')
+ api.current_logger().info('Automatically registered into Red Hat Lightspeed')
except (CalledProcessError) as err:
# TODO(mmatuska) produce post-upgrade report?
api.current_logger().error(
- 'Automatic registration into Red Hat Insights failed: {}'.format(err)
+ 'Automatic registration into Red Hat Lightspeed failed: {}'.format(err)
)
def process():
if rhsm.skip_rhsm() or get_env('LEAPP_NO_INSIGHTS_REGISTER', '0') == '1':
api.current_logger().debug(
- 'Skipping registration into Insights due to --no-insights-register'
+ 'Skipping registration into Red Hat Lightspeed due to --no-insights-register'
' or LEAPP_NO_INSIGHTS_REGISTER=1 set'
)
return
diff --git a/repos/system_upgrade/common/actors/insightsautoregister/tests/test_insightsautoregister.py b/repos/system_upgrade/common/actors/insightsautoregister/tests/test_insightsautoregister.py
index 0a039455..d5e6ba20 100644
--- a/repos/system_upgrade/common/actors/insightsautoregister/tests/test_insightsautoregister.py
+++ b/repos/system_upgrade/common/actors/insightsautoregister/tests/test_insightsautoregister.py
@@ -41,7 +41,7 @@ def test_insights_register_success_logged(monkeypatch):
def run_mocked(cmd, **kwargs):
return {
- 'stdout': 'Successfully registered into Insights',
+ 'stdout': 'Successfully registered into Red Hat Lightspeed',
'stderr': '',
'exit_code': 0
}
--
2.51.1

View File

@ -1,131 +0,0 @@
From ddefdee20a97d9b5e08502e4348d92212a702cc7 Mon Sep 17 00:00:00 2001
From: Lukas Bezdicka <lbezdick@redhat.com>
Date: Fri, 16 Feb 2024 14:58:02 +0100
Subject: [PATCH 28/55] [ceph][luks] Fix ceph cephvolumescan for cephadm
For cephadm the containers are named ceph-<hash>-osd... while
ceph-ansible still uses the ceph-osd-...
Other issue is that OSDs can have multiple volumes in them so filtering
just for the first one is wrong and we need to check each volume for
the encryption.
Resolves: rhbz#2264543
Fixes: https://issues.redhat.com/browse/RHEL-25838
---
.../libraries/cephvolumescan.py | 5 +-
.../tests/test_cephvolumescan.py | 50 +++++++++++++++++--
2 files changed, 50 insertions(+), 5 deletions(-)
diff --git a/repos/system_upgrade/common/actors/cephvolumescan/libraries/cephvolumescan.py b/repos/system_upgrade/common/actors/cephvolumescan/libraries/cephvolumescan.py
index b2364104..a9bff005 100644
--- a/repos/system_upgrade/common/actors/cephvolumescan/libraries/cephvolumescan.py
+++ b/repos/system_upgrade/common/actors/cephvolumescan/libraries/cephvolumescan.py
@@ -8,7 +8,7 @@ from leapp.libraries.stdlib import api, CalledProcessError, run
from leapp.models import InstalledRPM
CEPH_CONF = "/etc/ceph/ceph.conf"
-CONTAINER = "ceph-osd"
+CONTAINER = "ceph-.*osd"
def select_osd_container(engine):
@@ -63,7 +63,8 @@ def encrypted_osds_list():
output = get_ceph_lvm_list()
if output is not None:
try:
- result = [output[key][0]['lv_uuid'] for key in output if output[key][0]['tags']['ceph.encrypted']]
+ for key in output:
+ result.extend([element['lv_uuid'] for element in output[key] if element['tags']['ceph.encrypted']])
except KeyError:
# TODO: possibly raise a report item with a medium risk factor
# TODO: possibly create list of problematic osds, extend the cephinfo
diff --git a/repos/system_upgrade/common/actors/cephvolumescan/tests/test_cephvolumescan.py b/repos/system_upgrade/common/actors/cephvolumescan/tests/test_cephvolumescan.py
index f3811c45..168b8fc2 100644
--- a/repos/system_upgrade/common/actors/cephvolumescan/tests/test_cephvolumescan.py
+++ b/repos/system_upgrade/common/actors/cephvolumescan/tests/test_cephvolumescan.py
@@ -8,6 +8,8 @@ from leapp.reporting import Report
CONT_PS_COMMAND_OUTPUT = {
"stdout":
"""CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
+ b5a3d8ef25b9 undercloud-0.ctlplane.redhat.local:8787/rh-osbs/rhceph:5 "-n osd.8 -f --set..." \
+ 2 hours ago Up 2 hours ago ceph-bea1a933-0846-4aaa-8223-62cb8cb2873c-osd-8
50d96fe72019 registry.redhat.io/rhceph/rhceph-4-rhel8:latest "/opt/ceph-contain..." \
2 weeks ago Up 2 weeks ceph-osd-0
f93c17b49c40 registry.redhat.io/rhceph/rhceph-4-rhel8:latest "/opt/ceph-contain..." \
@@ -41,6 +43,32 @@ CEPH_VOLUME_OUTPUT = {
"type":"block",
"vg_name":"ceph-a696c40d-6b1d-448d-a40e-fadca22b64bc"
}
+ ],
+ "8":[
+ {
+ "devices": [
+ "/dev/nvme0n1"
+ ],
+ "lv_name": "osd-db-b04857a0-a2a2-40c3-a490-cbe1f892a76c",
+ "lv_uuid": "zcvGix-drzz-JwzP-6ktU-Od6W-N5jL-kxRFa3",
+ "tags":{
+ "ceph.encrypted":"1"
+ },
+ "type": "db",
+ "vg_name": "ceph-b78309b3-bd80-4399-87a3-ac647b216b63"
+ },
+ {
+ "devices": [
+ "/dev/sdb"
+ ],
+ "lv_name": "osd-block-477c303f-5eaf-4be8-b5cc-f6073eb345bf",
+ "lv_uuid": "Mz1dep-D715-Wxh1-zUuS-0cOA-mKXE-UxaEM3",
+ "tags":{
+ "ceph.encrypted":"1"
+ },
+ "type": "block",
+ "vg_name": "ceph-e3e0345b-8be1-40a7-955a-378ba967f954"
+ }
]
}"""
}
@@ -51,7 +79,19 @@ CEPH_LVM_LIST = {
'lv_uuid': 'Tyc0TH-RDxr-ebAF-9mWF-Kh5R-YnvJ-cEcGVn',
'tags': {'ceph.encrypted': '1'},
'type': 'block',
- 'vg_name': 'ceph-a696c40d-6b1d-448d-a40e-fadca22b64bc'}]
+ 'vg_name': 'ceph-a696c40d-6b1d-448d-a40e-fadca22b64bc'}],
+ '8': [{'devices': ['/dev/nvme0n1'],
+ 'lv_name': 'osd-db-b04857a0-a2a2-40c3-a490-cbe1f892a76c',
+ 'lv_uuid': 'zcvGix-drzz-JwzP-6ktU-Od6W-N5jL-kxRFa3',
+ 'tags': {'ceph.encrypted': '1'},
+ 'type': 'db',
+ 'vg_name': 'ceph-b78309b3-bd80-4399-87a3-ac647b216b63'},
+ {'devices': ['/dev/sdb'],
+ 'lv_name': 'osd-block-477c303f-5eaf-4be8-b5cc-f6073eb345bf',
+ 'lv_uuid': 'Mz1dep-D715-Wxh1-zUuS-0cOA-mKXE-UxaEM3',
+ 'tags': {'ceph.encrypted': '1'},
+ 'type': 'block',
+ 'vg_name': 'ceph-e3e0345b-8be1-40a7-955a-378ba967f954'}]
}
@@ -60,7 +100,7 @@ def test_select_osd_container(m_run):
m_run.return_value = CONT_PS_COMMAND_OUTPUT
- assert cephvolumescan.select_osd_container('docker') == "ceph-osd-0"
+ assert cephvolumescan.select_osd_container('docker') == "ceph-bea1a933-0846-4aaa-8223-62cb8cb2873c-osd-8"
@patch('leapp.libraries.actor.cephvolumescan.has_package')
@@ -82,4 +122,8 @@ def test_encrypted_osds_list(m_get_ceph_lvm_list, m_isfile):
m_get_ceph_lvm_list.return_value = CEPH_LVM_LIST
m_isfile.return_value = True
- assert cephvolumescan.encrypted_osds_list() == ['Tyc0TH-RDxr-ebAF-9mWF-Kh5R-YnvJ-cEcGVn']
+ assert cephvolumescan.encrypted_osds_list() == [
+ 'Tyc0TH-RDxr-ebAF-9mWF-Kh5R-YnvJ-cEcGVn',
+ 'zcvGix-drzz-JwzP-6ktU-Od6W-N5jL-kxRFa3',
+ 'Mz1dep-D715-Wxh1-zUuS-0cOA-mKXE-UxaEM3'
+ ]
--
2.51.1

View File

@ -0,0 +1,206 @@
From 097981dd9505d1609b91fbed4e6d28e960161926 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Mon, 14 Apr 2025 13:02:40 +0200
Subject: [PATCH 28/37] feat(command_utils): allow missing minor/major version
for CentOS
CentOS versioning consists only of the major version number. Therefore,
in case we are running on CentOS, we do not want to enforce version to
have the format MAJOR.MINOR. Rather, we want to check that the version
is of the form MAJOR. This patch introduces the necessary
infrastructure, allowing easy extensibility of version format checking
for also other distributions. In case we do not know what version
format should a distro use, we default to MINOR.MAJOR.
Jira-ref: RHEL-80334
---
commands/command_utils.py | 92 ++++++++++++++++++++++++++++++---------
commands/upgrade/util.py | 4 +-
2 files changed, 74 insertions(+), 22 deletions(-)
diff --git a/commands/command_utils.py b/commands/command_utils.py
index a13ca59b..155bacad 100644
--- a/commands/command_utils.py
+++ b/commands/command_utils.py
@@ -3,6 +3,8 @@ import json
import os
import re
import resource
+from collections import namedtuple
+from enum import Enum
from leapp.actors import config as actor_config
from leapp.exceptions import CommandError
@@ -16,26 +18,52 @@ LEAPP_UPGRADE_FLAVOUR_DEFAULT = 'default'
LEAPP_UPGRADE_FLAVOUR_SAP_HANA = 'saphana'
LEAPP_UPGRADE_PATHS = 'upgrade_paths.json'
-VERSION_REGEX = re.compile(r"^([1-9]\d*)\.(\d+)$")
+_VersionFormat = namedtuple('VersionFormat', ('human_readable', 'regex'))
-def check_version(version):
+
+class VersionFormats(Enum):
+ MAJOR_ONLY = _VersionFormat('MAJOR_VER', re.compile(r'^[1-9]\d*$'))
+ MAJOR_MINOR = _VersionFormat('MAJOR_VER.MINOR_VER', re.compile(r"^([1-9]\d*)\.(\d+)$"))
+
+
+class _VersionKind(str, Enum):
+ """ Enum encoding information whether the given OS version is source or target. """
+ SOURCE = 'source'
+ TARGET = 'target'
+
+
+class DistroIDs(str, Enum):
+ RHEL = 'rhel'
+ CENTOS = 'centos'
+
+
+_DISTRO_VERSION_FORMATS = {
+ DistroIDs.RHEL: VersionFormats.MAJOR_MINOR,
+ DistroIDs.CENTOS: VersionFormats.MAJOR_ONLY,
+}
+"""
+Maps distro ID to the expected OS version format.
+
+If a distro is not listed in the dictionary, then VersionFormats.MAJOR_MINOR
+is used as a default.
+"""
+
+
+def assert_version_format(version_str, desired_format, version_kind):
"""
- Versioning schema: MAJOR.MINOR
- In case version contains an invalid version string, an CommandError will be raised.
+ Check whether a given version_str has the given desired format.
+
+ In case the version does not conform to the desired_format, an CommandError will be raised.
:raises: CommandError
- :return: release tuple
"""
- if not re.match(VERSION_REGEX, version):
- raise CommandError(
- "Unexpected format of target version: {}. "
- "The required format is 'X.Y' (major and minor version).".format(version)
- )
- return version.split('.')
+ if not re.match(desired_format.regex, version_str):
+ error_str = 'Unexpected format of target version: {0}. The required format is \'{1}\'.'
+ raise CommandError(error_str.format(version_str, desired_format.human_readable))
-def get_major_version(version):
+def get_major_version_from_a_valid_version(version):
"""
Return the major version from the given version string.
@@ -45,7 +73,7 @@ def get_major_version(version):
:rtype: str
:returns: The major version from the given version string.
"""
- return str(check_version(version)[0])
+ return version.split('.')[0]
def detect_sap_hana():
@@ -71,7 +99,7 @@ def get_upgrade_flavour():
return LEAPP_UPGRADE_FLAVOUR_DEFAULT
-def _retrieve_os_release_contents(_os_release_path='/etc/os-release'):
+def _retrieve_os_release_contents(_os_release_path='/etc/os-release', strip_double_quotes=True):
"""
Retrieve the contents of /etc/os-release
@@ -79,7 +107,20 @@ def _retrieve_os_release_contents(_os_release_path='/etc/os-release'):
"""
with open(_os_release_path) as os_release_handle:
lines = os_release_handle.readlines()
- return dict(line.strip().split('=', 1) for line in lines if '=' in line)
+
+ os_release_contents = {}
+ for line in lines:
+ if '=' not in line:
+ continue
+
+ key, value = line.strip().split('=', 1)
+
+ if strip_double_quotes:
+ value = value.strip('"')
+
+ os_release_contents[key] = value
+
+ return os_release_contents
def get_os_release_version_id(filepath):
@@ -88,7 +129,7 @@ def get_os_release_version_id(filepath):
:return: `str` version_id
"""
- return _retrieve_os_release_contents(_os_release_path=filepath).get('VERSION_ID', '').strip('"')
+ return _retrieve_os_release_contents(_os_release_path=filepath).get('VERSION_ID', '')
def get_upgrade_paths_config():
@@ -117,15 +158,20 @@ def get_supported_target_versions(flavour=get_upgrade_flavour()):
"""
os_release_contents = _retrieve_os_release_contents()
- current_version_id = os_release_contents.get('VERSION_ID', '').strip('"')
- distro_id = os_release_contents.get('ID', '').strip('"')
+ current_version_id = os_release_contents.get('VERSION_ID', '')
+ distro_id = os_release_contents.get('ID', '')
+
+ # We want to guarantee our actors that if they see 'centos'/'rhel'/...
+ # then they will always see expected version format
+ expected_version_format = _DISTRO_VERSION_FORMATS.get(distro_id, VersionFormats.MAJOR_MINOR).value
+ assert_version_format(current_version_id, expected_version_format, _VersionKind.SOURCE)
target_versions = get_target_versions_from_config(current_version_id, distro_id, flavour)
if not target_versions:
# If we cannot find a particular major.minor version in the map,
# we fallback to pick a target version just based on a major version.
# This can happen for example when testing not yet released versions
- major_version = get_major_version(current_version_id)
+ major_version = get_major_version_from_a_valid_version(current_version_id)
target_versions = get_target_versions_from_config(major_version, distro_id, flavour)
return target_versions
@@ -145,9 +191,15 @@ def vet_upgrade_path(args):
"""
flavor = get_upgrade_flavour()
env_version_override = os.getenv('LEAPP_DEVEL_TARGET_RELEASE')
+
if env_version_override:
- check_version(env_version_override)
+ os_release_contents = _retrieve_os_release_contents()
+ distro_id = os_release_contents.get('ID', '')
+ expected_version_format = _DISTRO_VERSION_FORMATS.get(distro_id, VersionFormats.MAJOR_MINOR).value
+ assert_version_format(env_version_override, expected_version_format, _VersionKind.TARGET)
+
return (env_version_override, flavor)
+
target_release = args.target or get_target_version(flavor)
return (target_release, flavor)
diff --git a/commands/upgrade/util.py b/commands/upgrade/util.py
index 6cdfa6d8..b54b0b34 100644
--- a/commands/upgrade/util.py
+++ b/commands/upgrade/util.py
@@ -260,8 +260,8 @@ def prepare_configuration(args):
current_version = command_utils.get_os_release_version_id('/etc/os-release')
os.environ['LEAPP_IPU_IN_PROGRESS'] = '{source}to{target}'.format(
- source=command_utils.get_major_version(current_version),
- target=command_utils.get_major_version(target_version)
+ source=command_utils.get_major_version_from_a_valid_version(current_version),
+ target=command_utils.get_major_version_from_a_valid_version(target_version)
)
configuration = {
--
2.49.0

View File

@ -1,36 +0,0 @@
From bf1b5f5f537ff163470b29d8bb7ba452901368eb Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Wed, 22 Oct 2025 17:52:52 +0200
Subject: [PATCH 29/55] Makefile: Do copy commands/ dir in containerized tests
In 7d9ae2c0 the commands dir copying was changed to copy the dir to
tut/lib/$$_VENV/site-packages/leapp/cli/commands/ instead of the normal
location in the container.
This fixed the problem that modifications on the host were not reflected
in the testing containers. However a new problem was introduced -
modifications to tests in the commands directory are not getting
reflected in the testing containers.
This patch fixes that by copying the entire commands directory both to
the normal location and the virtual env (path above).
---
Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 9774a475..64115006 100644
--- a/Makefile
+++ b/Makefile
@@ -447,7 +447,7 @@ test_container:
export _CONT_NAME="leapp-repo-tests-$(_TEST_CONTAINER)-cont"; \
$(_CONTAINER_TOOL) ps -q -f name=$$_CONT_NAME && { $(_CONTAINER_TOOL) kill $$_CONT_NAME; $(_CONTAINER_TOOL) rm $$_CONT_NAME; }; \
$(_CONTAINER_TOOL) run -di --name $$_CONT_NAME -v "$$PWD":/repo:Z -e PYTHON_VENV=$$_VENV $$TEST_IMAGE && \
- $(_CONTAINER_TOOL) exec $$_CONT_NAME rsync -aur --delete --exclude 'tut/' --exclude 'docs/' --exclude '**/__pycache__/' --exclude 'packaging/' --exclude '.git/' --exclude 'commands/' /repo/ /repocopy && \
+ $(_CONTAINER_TOOL) exec $$_CONT_NAME rsync -aur --delete --exclude 'tut/' --exclude 'docs/' --exclude '**/__pycache__/' --exclude 'packaging/' --exclude '.git/' /repo/ /repocopy && \
$(_CONTAINER_TOOL) exec $$_CONT_NAME rsync -aur --delete --exclude '**/__pycache__/' /repo/commands/ /repocopy/tut/lib/$$_VENV/site-packages/leapp/cli/commands/ && \
export res=0; \
case $$_VENV in \
--
2.51.1

View File

@ -0,0 +1,62 @@
From d450430eb06a9649ea924fa8b0ba4f123197dd27 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Mon, 21 Apr 2025 20:15:34 +0200
Subject: [PATCH 29/37] refactor(versions/config): rename _simple_versions
Rename the function _simple_versions to _are_comparison_operators_used
with **negated semantics**. The new name should make it clear what is
being checked in the version list.
---
.../common/libraries/config/tests/test_version.py | 6 +++---
repos/system_upgrade/common/libraries/config/version.py | 7 ++++---
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/repos/system_upgrade/common/libraries/config/tests/test_version.py b/repos/system_upgrade/common/libraries/config/tests/test_version.py
index 37a91c00..3cb6479c 100644
--- a/repos/system_upgrade/common/libraries/config/tests/test_version.py
+++ b/repos/system_upgrade/common/libraries/config/tests/test_version.py
@@ -17,9 +17,9 @@ def test_validate_versions():
assert version._validate_versions(['7.6', 'z.z'])
-def test_simple_versions():
- assert version._simple_versions(['7.6', '7.7'])
- assert not version._simple_versions(['7.6', '< 7.7'])
+def test_comparison_operator_detection():
+ assert not version._are_comparison_operators_used(['7.6', '7.7'])
+ assert version._are_comparison_operators_used(['7.6', '< 7.7'])
def test_cmp_versions():
diff --git a/repos/system_upgrade/common/libraries/config/version.py b/repos/system_upgrade/common/libraries/config/version.py
index b8fc550b..24bb7729 100644
--- a/repos/system_upgrade/common/libraries/config/version.py
+++ b/repos/system_upgrade/common/libraries/config/version.py
@@ -149,9 +149,9 @@ def _validate_versions(versions):
"but provided was '{}'".format(versions))
-def _simple_versions(versions):
+def _are_comparison_operators_used(versions):
"""Return ``True`` if provided versions are list of strings without comparison operators."""
- return all(len(v.split()) == 1 for v in versions)
+ return not all(len(v.split()) == 1 for v in versions)
def _cmp_versions(versions):
@@ -190,10 +190,11 @@ def matches_version(match_list, detected):
"but provided was {}: '{}'".format(type(detected), detected))
_validate_versions([detected])
- if _simple_versions(match_list):
+ if not _are_comparison_operators_used(match_list):
# match_list = ['7.6', '7.7', '7.8', '7.9']
_validate_versions(match_list)
return detected in match_list
+
if _cmp_versions(match_list):
detected = _version_to_tuple(detected)
# match_list = ['>= 7.6', '< 7.10']
--
2.49.0

View File

@ -0,0 +1,40 @@
From 70557869df83660a1a0c31808cf9c97a2704aa9a Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Mon, 21 Apr 2025 20:40:11 +0200
Subject: [PATCH 30/37] fix(lib/version): broken _validate_version on RHEL 10
The validate version used to split a given version on `.` and then
check that every fragment is a digit, which is false for RHEL 10
since `10` is not a digit.
---
repos/system_upgrade/common/libraries/config/version.py | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/repos/system_upgrade/common/libraries/config/version.py b/repos/system_upgrade/common/libraries/config/version.py
index 24bb7729..2e837a61 100644
--- a/repos/system_upgrade/common/libraries/config/version.py
+++ b/repos/system_upgrade/common/libraries/config/version.py
@@ -1,4 +1,5 @@
import operator
+import re
import six
@@ -141,10 +142,10 @@ def _version_to_tuple(version):
def _validate_versions(versions):
- """Raise ``TypeError`` if provided versions are not strings in the form ``<integer>.<integer>``."""
- for ver in versions:
- split = ver.split('.')
- if not len(split) == 2 or not all(x.isdigit() for x in split):
+ """Raise ``ValueError`` if provided versions are not strings in the form ``<integer>.<integer>``."""
+ version_format_regex = re.compile(r'^([1-9]\d*)\.(\d+)$')
+ for version in versions:
+ if not re.match(version_format_regex, version):
raise ValueError("Versions have to be in the form of '<integer>.<integer>' "
"but provided was '{}'".format(versions))
--
2.49.0

View File

@ -1,70 +0,0 @@
From 87f584d8f9b957b9ae0138d6963077d87ccb2067 Mon Sep 17 00:00:00 2001
From: Peter Mocary <pmocary@redhat.com>
Date: Mon, 20 Oct 2025 11:40:04 +0200
Subject: [PATCH 30/55] skip pre-generation of systemd fstab mount units during
LiveMode upgrade
The new storage initialization solution interfered with LiveMode. Since
LiveMode is a different upgrade approach, we now skip pre-generation of
systemd fstab mount units (mount_unit_generator actor) when
upgrading this way.
---
.../actors/initramfs/mount_units_generator/actor.py | 5 ++++-
.../libraries/mount_unit_generator.py | 8 ++++++--
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/actor.py b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/actor.py
index 5fe25515..dd667513 100644
--- a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/actor.py
+++ b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/actor.py
@@ -1,16 +1,19 @@
from leapp.actors import Actor
from leapp.libraries.actor import mount_unit_generator as mount_unit_generator_lib
-from leapp.models import TargetUserSpaceInfo, UpgradeInitramfsTasks
+from leapp.models import LiveModeConfig, TargetUserSpaceInfo, UpgradeInitramfsTasks
from leapp.tags import InterimPreparationPhaseTag, IPUWorkflowTag
class MountUnitGenerator(Actor):
"""
Sets up storage initialization using systemd's mount units in the upgrade container.
+
+ Note that this storage initialization is skipped when the LiveMode is enabled.
"""
name = 'mount_unit_generator'
consumes = (
+ LiveModeConfig,
TargetUserSpaceInfo,
)
produces = (
diff --git a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/libraries/mount_unit_generator.py b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/libraries/mount_unit_generator.py
index e1060559..943bddd4 100644
--- a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/libraries/mount_unit_generator.py
+++ b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/libraries/mount_unit_generator.py
@@ -5,7 +5,7 @@ import tempfile
from leapp.exceptions import StopActorExecutionError
from leapp.libraries.common import mounting
from leapp.libraries.stdlib import api, CalledProcessError, run
-from leapp.models import TargetUserSpaceInfo, UpgradeInitramfsTasks
+from leapp.models import LiveModeConfig, TargetUserSpaceInfo, UpgradeInitramfsTasks
def run_systemd_fstab_generator(output_directory):
@@ -295,8 +295,12 @@ def request_units_inclusion_in_initramfs(files_to_include):
def setup_storage_initialization():
- userspace_info = next(api.consume(TargetUserSpaceInfo), None)
+ livemode_config = next(api.consume(LiveModeConfig), None)
+ if livemode_config and livemode_config.is_enabled:
+ api.current_logger().debug('Pre-generation of systemd fstab mount units skipped: The LiveMode is enabled.')
+ return
+ userspace_info = next(api.consume(TargetUserSpaceInfo), None)
with mounting.NspawnActions(base_dir=userspace_info.path) as upgrade_container_ctx:
with tempfile.TemporaryDirectory(dir='/var/lib/leapp/', prefix='tmp_systemd_fstab_') as workspace_path:
run_systemd_fstab_generator(workspace_path)
--
2.51.1

View File

@ -1,56 +0,0 @@
From 827e28de7b707f9fc458e1f5fdad9fffd7474abe Mon Sep 17 00:00:00 2001
From: Tomas Fratrik <tfratrik@redhat.com>
Date: Tue, 12 Aug 2025 16:59:01 +0200
Subject: [PATCH 31/55] pylint: enable consider-using-set-comprehension
Fixed occurrences of list comprehensions wrapped in set() by using
set comprehensions directly, removing disables for
consider-using-set-comprehension added for Python 2 compatibility.
Jira: RHELMISC-16038
---
.pylintrc | 1 -
.../checkconsumedassets/tests/test_asset_version_checking.py | 2 +-
.../common/actors/selinux/selinuxapplycustom/actor.py | 4 +---
3 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/.pylintrc b/.pylintrc
index 5d75df40..e54d9a54 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -45,7 +45,6 @@ disable=
too-many-positional-arguments, # we cannot set yet max-possitional-arguments unfortunately
# new for python3 version of pylint
useless-object-inheritance,
- consider-using-set-comprehension, # pylint3 force to use comprehension in place we don't want (py2 doesnt have these options, for inline skip)
unnecessary-pass,
invalid-envvar-default, # pylint3 warnings envvar returns str/none by default
bad-option-value, # python 2 doesn't have import-outside-toplevel, but in some case we need to import outside toplevel
diff --git a/repos/system_upgrade/common/actors/checkconsumedassets/tests/test_asset_version_checking.py b/repos/system_upgrade/common/actors/checkconsumedassets/tests/test_asset_version_checking.py
index 9c324b44..f37dcea4 100644
--- a/repos/system_upgrade/common/actors/checkconsumedassets/tests/test_asset_version_checking.py
+++ b/repos/system_upgrade/common/actors/checkconsumedassets/tests/test_asset_version_checking.py
@@ -44,4 +44,4 @@ def test_make_report_entries_with_unique_urls():
docs_url_to_title_map = {'/path/to/asset1': ['asset1_title1', 'asset1_title2'],
'/path/to/asset2': ['asset2_title']}
report_urls = check_consumed_assets_lib.make_report_entries_with_unique_urls(docs_url_to_title_map)
- assert set([ru.value['url'] for ru in report_urls]) == {'/path/to/asset1', '/path/to/asset2'}
+ assert {ru.value['url'] for ru in report_urls} == {'/path/to/asset1', '/path/to/asset2'}
diff --git a/repos/system_upgrade/common/actors/selinux/selinuxapplycustom/actor.py b/repos/system_upgrade/common/actors/selinux/selinuxapplycustom/actor.py
index 4856f36a..db8fe8ac 100644
--- a/repos/system_upgrade/common/actors/selinux/selinuxapplycustom/actor.py
+++ b/repos/system_upgrade/common/actors/selinux/selinuxapplycustom/actor.py
@@ -40,9 +40,7 @@ class SELinuxApplyCustom(Actor):
return
# get list of policy modules after the upgrade
- installed_modules = set(
- [module[0] for module in selinuxapplycustom.list_selinux_modules()]
- )
+ installed_modules = {module[0] for module in selinuxapplycustom.list_selinux_modules()}
# import custom SElinux modules
for semodules in self.consume(SELinuxModules):
--
2.51.1

View File

@ -0,0 +1,37 @@
From a633641884f50fc917668cf1c8bd80d6c88297c7 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Fri, 2 May 2025 16:29:10 +0200
Subject: [PATCH 31/37] upgrade_paths: add information about centos virtual
versions
Add additional field to upgrade paths for CentOS that maps CentOS
versions consisting only of a major version number to corresponding
RHEL versions of the form MAJOR.MINOR ("virtual version"). This
information is inteded to be used by leapp to in version checks
to obtain a MAJOR.MINOR version so that code written for RHEL can work
as expected also on CentOS.
Jira-ref: RHEL-80334
---
repos/system_upgrade/common/files/upgrade_paths.json | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/repos/system_upgrade/common/files/upgrade_paths.json b/repos/system_upgrade/common/files/upgrade_paths.json
index 7ace7943..279e6eaa 100644
--- a/repos/system_upgrade/common/files/upgrade_paths.json
+++ b/repos/system_upgrade/common/files/upgrade_paths.json
@@ -21,6 +21,11 @@
"default": {
"8": ["9"],
"9": ["10"]
+ },
+ "_virtual_versions": {
+ "8": "8.10",
+ "9": "9.6",
+ "10": "10.0"
}
}
}
--
2.49.0

View File

@ -0,0 +1,334 @@
From 5f569408469d4e43ff559c5b90c3cc068d59d3a4 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Fri, 2 May 2025 16:35:18 +0200
Subject: [PATCH 32/37] models(ipuconfig): extend Version class to contain
virtual versions
Add virtual_{source,target}_version fields to the Version model. These
fields store a virtual MAJOR.MINOR CentOS version so that
version-specific checks originally written for RHEL can work as expected
also on CentOS. On non-CentOS system, the value of these fields should
be the same as source/target versions. The ipuworkflowconfig actor is
modified accordingly to populate the newly added fields.
Jira-ref: RHEL-80334
---
.../checksaphana/tests/test_checksaphana.py | 4 ++
.../libraries/ipuworkflowconfig.py | 51 +++++++++++++++++--
.../tests/test_ipuworkflowconfig.py | 41 ++++++++++++++-
.../common/libraries/config/mock_configs.py | 16 ++++--
.../libraries/config/tests/test_version.py | 12 +++--
.../common/libraries/testutils.py | 13 ++++-
.../system_upgrade/common/models/ipuconfig.py | 15 ++++++
7 files changed, 137 insertions(+), 15 deletions(-)
diff --git a/repos/system_upgrade/common/actors/checksaphana/tests/test_checksaphana.py b/repos/system_upgrade/common/actors/checksaphana/tests/test_checksaphana.py
index 1417b00a..1e43f403 100644
--- a/repos/system_upgrade/common/actors/checksaphana/tests/test_checksaphana.py
+++ b/repos/system_upgrade/common/actors/checksaphana/tests/test_checksaphana.py
@@ -181,6 +181,8 @@ class MockSAPHanaVersionInstance(object):
)
)
def test_checksaphana__fullfills_rhel86_hana_min_version(monkeypatch, major, rev, patchlevel, result):
+ monkeypatch.setattr(checksaphana.api, 'current_actor', testutils.CurrentActorMocked())
+
monkeypatch.setattr(version, 'get_target_major_version', lambda: '8')
monkeypatch.setattr(version, 'get_target_version', lambda: '8.6')
monkeypatch.setattr(checksaphana, 'SAP_HANA_RHEL86_REQUIRED_PATCH_LEVELS', ((4, 48, 2), (5, 52, 0)))
@@ -213,6 +215,8 @@ def test_checksaphana__fullfills_rhel86_hana_min_version(monkeypatch, major, rev
)
)
def test_checksaphana__fullfills_hana_rhel90_min_version(monkeypatch, major, rev, patchlevel, result):
+ monkeypatch.setattr(checksaphana.api, 'current_actor', testutils.CurrentActorMocked())
+
monkeypatch.setattr(version, 'get_target_major_version', lambda: '9')
monkeypatch.setattr(version, 'get_target_version', lambda: '9.0')
monkeypatch.setattr(checksaphana, 'SAP_HANA_RHEL90_REQUIRED_PATCH_LEVELS', ((5, 59, 4), (6, 63, 0)))
diff --git a/repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py b/repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py
index 35f61669..f76677fd 100644
--- a/repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py
+++ b/repos/system_upgrade/common/actors/ipuworkflowconfig/libraries/ipuworkflowconfig.py
@@ -10,6 +10,7 @@ ENV_IGNORE = ('LEAPP_CURRENT_PHASE', 'LEAPP_CURRENT_ACTOR', 'LEAPP_VERBOSE',
'LEAPP_DEBUG')
ENV_MAPPING = {'LEAPP_DEVEL_DM_DISABLE_UDEV': 'DM_DISABLE_UDEV'}
+CENTOS_VIRTUAL_VERSIONS_KEY = '_virtual_versions'
def get_env_vars():
@@ -92,8 +93,7 @@ def load_upgrade_paths_definitions(paths_definition_file):
return definitions
-def load_raw_upgrade_paths_for_distro_and_flavour(distro_id, flavour, paths_definition_file='upgrade_paths.json'):
- all_definitions = load_upgrade_paths_definitions(paths_definition_file)
+def extract_upgrade_paths_for_distro_and_flavour(all_definitions, distro_id, flavour):
raw_upgrade_paths_for_distro = all_definitions.get(distro_id, {})
if not raw_upgrade_paths_for_distro:
@@ -117,6 +117,39 @@ def construct_models_for_paths_matching_source_major(raw_paths, src_major_versio
return multipaths_matching_source
+def construct_virtual_versions(all_upgrade_path_defs, distro_id, source_version, target_version):
+ if distro_id.lower() != 'centos':
+ return (source_version, target_version)
+
+ centos_upgrade_paths = all_upgrade_path_defs.get('centos', {})
+ if not centos_upgrade_paths:
+ raise StopActorExecutionError('There are no upgrade paths defined for CentOS.')
+
+ virtual_versions = centos_upgrade_paths.get(CENTOS_VIRTUAL_VERSIONS_KEY, {})
+ if not virtual_versions: # Unlikely, only if using old upgrade_paths.json, but the user should not touch the file
+ details = {'details': 'The file does not contain any information about virtual versions of CentOS'}
+ raise StopActorExecutionError('The internal upgrade_paths.json file is malformed.')
+
+ source_virtual_version = virtual_versions.get(source_version)
+ target_virtual_version = virtual_versions.get(target_version)
+
+ if not source_virtual_version or not target_virtual_version:
+ if not source_virtual_version and not target_virtual_version:
+ what_is_missing = 'CentOS {} (source) and CentOS {} (target)'.format(source_virtual_version,
+ target_virtual_version)
+ elif not source_virtual_version:
+ what_is_missing = 'CentOS {} (source)'.format(source_virtual_version)
+ else:
+ what_is_missing = 'CentOS {} (target)'.format(target_virtual_version)
+
+ details_msg = 'The {} field in upgrade path definitions does not provide any information for {}'
+ details = {'details': details_msg.format(CENTOS_VIRTUAL_VERSIONS_KEY, what_is_missing)}
+ raise StopActorExecutionError('Failed to identify virtual minor version number for the system.',
+ details=details)
+
+ return (source_virtual_version, target_virtual_version)
+
+
def produce_ipu_config(actor):
flavour = os.environ.get('LEAPP_UPGRADE_PATH_FLAVOUR')
target_version = os.environ.get('LEAPP_UPGRADE_PATH_TARGET_RELEASE')
@@ -125,17 +158,27 @@ def produce_ipu_config(actor):
check_target_major_version(source_version, target_version)
- raw_upgrade_paths = load_raw_upgrade_paths_for_distro_and_flavour(os_release.release_id, flavour)
+ all_upgrade_path_defs = load_upgrade_paths_definitions('upgrade_paths.json')
+ raw_upgrade_paths = extract_upgrade_paths_for_distro_and_flavour(all_upgrade_path_defs,
+ os_release.release_id,
+ flavour)
source_major_version = source_version.split('.')[0]
exposed_supported_paths = construct_models_for_paths_matching_source_major(raw_upgrade_paths, source_major_version)
+ virtual_source_version, virtual_target_version = construct_virtual_versions(all_upgrade_path_defs,
+ os_release.release_id,
+ source_version,
+ target_version)
+
actor.produce(IPUConfig(
leapp_env_vars=get_env_vars(),
os_release=os_release,
architecture=platform.machine(),
version=Version(
source=source_version,
- target=target_version
+ target=target_version,
+ virtual_source_version=virtual_source_version,
+ virtual_target_version=virtual_target_version,
),
kernel=get_booted_kernel(),
flavour=flavour,
diff --git a/repos/system_upgrade/common/actors/ipuworkflowconfig/tests/test_ipuworkflowconfig.py b/repos/system_upgrade/common/actors/ipuworkflowconfig/tests/test_ipuworkflowconfig.py
index d88424ce..6184121b 100644
--- a/repos/system_upgrade/common/actors/ipuworkflowconfig/tests/test_ipuworkflowconfig.py
+++ b/repos/system_upgrade/common/actors/ipuworkflowconfig/tests/test_ipuworkflowconfig.py
@@ -149,7 +149,44 @@ def test_load_raw_upgrade_paths_for_distro_and_flavour(monkeypatch, distro, flav
}
}
}
- monkeypatch.setattr(ipuworkflowconfig, 'load_upgrade_paths_definitions', lambda *args: defined_upgrade_paths)
- result = ipuworkflowconfig.load_raw_upgrade_paths_for_distro_and_flavour(distro, flavour)
+ result = ipuworkflowconfig.extract_upgrade_paths_for_distro_and_flavour(defined_upgrade_paths,
+ distro, flavour)
assert result == expected_result
+
+
+@pytest.mark.parametrize(
+ ('construction_params', 'expected_versions'),
+ [
+ (('centos', '8', '9'), ('8.10', '9.5')),
+ (('rhel', '8.10', '9.4'), ('8.10', '9.4')),
+ ]
+)
+def test_virtual_version_construction(construction_params, expected_versions):
+ defined_upgrade_paths = {
+ 'rhel': {
+ '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']
+ }
+ },
+ 'centos': {
+ '8': ['9'],
+ '_virtual_versions': {
+ '8': '8.10',
+ '9': '9.5',
+ }
+ },
+ }
+
+ result = ipuworkflowconfig.construct_virtual_versions(defined_upgrade_paths, *construction_params)
+ assert result == expected_versions
diff --git a/repos/system_upgrade/common/libraries/config/mock_configs.py b/repos/system_upgrade/common/libraries/config/mock_configs.py
index a1c9c0fd..a7ee0000 100644
--- a/repos/system_upgrade/common/libraries/config/mock_configs.py
+++ b/repos/system_upgrade/common/libraries/config/mock_configs.py
@@ -19,7 +19,9 @@ CONFIG = IPUConfig(
),
version=Version(
source='7.6',
- target='8.0'
+ target='8.0',
+ virtual_source_version='7.6',
+ virtual_target_version='8.0'
),
architecture='x86_64',
kernel='3.10.0-957.43.1.el7.x86_64',
@@ -39,7 +41,9 @@ CONFIG_NO_NETWORK_RENAMING = IPUConfig(
),
version=Version(
source='7.6',
- target='8.0'
+ target='8.0',
+ virtual_source_version='7.6',
+ virtual_target_version='8.0'
),
architecture='x86_64',
kernel='3.10.0-957.43.1.el7.x86_64',
@@ -59,7 +63,9 @@ CONFIG_ALL_SIGNED = IPUConfig(
),
version=Version(
source='7.6',
- target='8.0'
+ target='8.0',
+ virtual_source_version='7.6',
+ virtual_target_version='8.0'
),
architecture='x86_64',
kernel='3.10.0-957.43.1.el7.x86_64',
@@ -78,7 +84,9 @@ CONFIG_S390X = IPUConfig(
),
version=Version(
source='7.6',
- target='8.0'
+ target='8.0',
+ virtual_source_version='7.6',
+ virtual_target_version='8.0'
),
architecture='s390x',
kernel='3.10.0-957.43.1.el7.x86_64',
diff --git a/repos/system_upgrade/common/libraries/config/tests/test_version.py b/repos/system_upgrade/common/libraries/config/tests/test_version.py
index 3cb6479c..a8a1023e 100644
--- a/repos/system_upgrade/common/libraries/config/tests/test_version.py
+++ b/repos/system_upgrade/common/libraries/config/tests/test_version.py
@@ -27,7 +27,9 @@ def test_cmp_versions():
assert not version._cmp_versions(['>= 7.6', '& 7.7'])
-def test_matches_version_wrong_args():
+def test_matches_version_wrong_args(monkeypatch):
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked())
+
with pytest.raises(TypeError):
version.matches_version('>= 7.6', '7.7')
with pytest.raises(TypeError):
@@ -42,7 +44,9 @@ def test_matches_version_wrong_args():
version.matches_version(['>= 7.6', '& 7.7'], '7.7')
-def test_matches_version_fail():
+def test_matches_version_fail(monkeypatch):
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked())
+
assert not version.matches_version(['> 7.6', '< 7.7'], '7.6')
assert not version.matches_version(['> 7.6', '< 7.7'], '7.7')
assert not version.matches_version(['> 7.6', '< 7.10'], '7.6')
@@ -50,7 +54,9 @@ def test_matches_version_fail():
assert not version.matches_version(['7.6', '7.7', '7.10'], '7.8')
-def test_matches_version_pass():
+def test_matches_version_pass(monkeypatch):
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked())
+
assert version.matches_version(['7.6', '7.7', '7.10'], '7.7')
assert version.matches_version(['> 7.6', '< 7.10'], '7.7')
diff --git a/repos/system_upgrade/common/libraries/testutils.py b/repos/system_upgrade/common/libraries/testutils.py
index 1b3c3683..3e145d91 100644
--- a/repos/system_upgrade/common/libraries/testutils.py
+++ b/repos/system_upgrade/common/libraries/testutils.py
@@ -74,15 +74,24 @@ def _make_default_config(actor_config_schema):
return _normalize_config({}, merged_schema) # Will fill default values during normalization
+# Note: The constructor of the following class takes in too many arguments (R0913). A builder-like
+# pattern would be nice here. Ideally, the builder should actively prevent the developer from setting fields
+# that do not affect actor's behavior in __setattr__.
class CurrentActorMocked(object): # pylint:disable=R0904
- def __init__(self, arch=architecture.ARCH_X86_64, envars=None, kernel='3.10.0-957.43.1.el7.x86_64',
+ def __init__(self, arch=architecture.ARCH_X86_64, envars=None, # pylint:disable=R0913
+ kernel='3.10.0-957.43.1.el7.x86_64',
release_id='rhel', src_ver='7.8', dst_ver='8.1', msgs=None, flavour='default', config=None,
+ virtual_source_version=None, virtual_target_version=None,
supported_upgrade_paths=None):
"""
:param List[IPUSourceToPossibleTargets] supported_upgrade_paths: List of supported upgrade paths.
"""
envarsList = [EnvVar(name=k, value=v) for k, v in envars.items()] if envars else []
- version = namedtuple('Version', ['source', 'target'])(src_ver, dst_ver)
+
+ version_fields = ['source', 'target', 'virtual_source_version', 'virtual_target_version']
+ version_values = [src_ver, dst_ver, virtual_source_version or src_ver, virtual_target_version or dst_ver]
+ version = namedtuple('Version', version_fields)(*version_values)
+
release = namedtuple('OS_release', ['release_id', 'version_id'])(release_id, src_ver)
self._common_folder = '../../files'
diff --git a/repos/system_upgrade/common/models/ipuconfig.py b/repos/system_upgrade/common/models/ipuconfig.py
index 0a16b603..379ac13f 100644
--- a/repos/system_upgrade/common/models/ipuconfig.py
+++ b/repos/system_upgrade/common/models/ipuconfig.py
@@ -33,6 +33,21 @@ class Version(Model):
target = fields.String()
"""Version of the target system. E.g. '8.2.'."""
+ virtual_source_version = fields.String()
+ """
+ Source OS version used when checking whether to execute version-dependent code.
+
+ On RHEL and other systems that have version of the form MINOR.MAJOR, `virtual_source_version`
+ matches `source_version`.
+
+ CentOS has version of the form MAJOR, lacking the minor version number. The
+ `virtual_source_version` value is obtained by combining CentOS major
+ version number with a minor version number stored internally in the upgrade_paths.json file.
+ """
+
+ virtual_target_version = fields.String()
+ """ See :py:attr:`virtual_source_version` """
+
class IPUSourceToPossibleTargets(Model):
"""
--
2.49.0

View File

@ -1,165 +0,0 @@
From 006517ea2d69d3f0d9e3de2eb67bfb4d32f20551 Mon Sep 17 00:00:00 2001
From: Tomas Fratrik <tfratrik@redhat.com>
Date: Wed, 13 Aug 2025 10:46:10 +0200
Subject: [PATCH 32/55] pylint: enable consider-using-with
Emitted when a resource-allocating assignment or call could be replaced
by a 'with' block. Enabling this warning enforces using 'with' to ensure
resources are properly released even if an exception occurs.
* ifcfgscanner: use StringIO in tests instead of mock_open for iteration support with 'with open'
Jira: RHELMISC-16038
---
.pylintrc | 1 -
.../ifcfgscanner/libraries/ifcfgscanner.py | 27 +++++++++----------
.../tests/unit_test_ifcfgscanner.py | 8 +++---
.../luksscanner/tests/test_luksdump_parser.py | 8 +++---
.../scansaphana/tests/test_scansaphana.py | 6 ++---
.../system_upgrade/common/libraries/guards.py | 2 +-
6 files changed, 25 insertions(+), 27 deletions(-)
diff --git a/.pylintrc b/.pylintrc
index e54d9a54..fd770061 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -51,7 +51,6 @@ disable=
super-with-arguments, # required in python 2
raise-missing-from, # no 'raise from' in python 2
use-a-generator, # cannot be modified because of Python2 support
- consider-using-with, # on bunch spaces we cannot change that...
duplicate-string-formatting-argument, # TMP: will be fixed in close future
consider-using-f-string, # sorry, not gonna happen, still have to support py2
use-dict-literal,
diff --git a/repos/system_upgrade/common/actors/ifcfgscanner/libraries/ifcfgscanner.py b/repos/system_upgrade/common/actors/ifcfgscanner/libraries/ifcfgscanner.py
index 683327b3..f0c8b847 100644
--- a/repos/system_upgrade/common/actors/ifcfgscanner/libraries/ifcfgscanner.py
+++ b/repos/system_upgrade/common/actors/ifcfgscanner/libraries/ifcfgscanner.py
@@ -18,23 +18,22 @@ def process_ifcfg(filename, secrets=False):
return None
properties = []
- for line in open(filename).readlines():
- try:
- (name, value) = line.split("#")[0].strip().split("=")
+ with open(filename) as f:
+ for line in f:
+ try:
+ (name, value) = line.split("#")[0].strip().split("=")
+ except ValueError:
+ # We're not interested in lines that are not
+ # simple assignments. Play it safe.
+ continue
+
if secrets:
value = None
- except ValueError:
- # We're not interested in lines that are not
- # simple assignments. Play it safe.
- continue
-
- # Deal with simple quoting. We don't expand anything, nor do
- # multiline strings or anything of that sort.
- if value is not None and len(value) > 1 and value[0] == value[-1]:
- if value.startswith('"') or value.startswith("'"):
+ elif len(value) > 1 and value[0] in ('"', "'") and value[0] == value[-1]:
+ # Deal with simple quoting. We don't expand anything, nor do
+ # multiline strings or anything of that sort.
value = value[1:-1]
-
- properties.append(IfCfgProperty(name=name, value=value))
+ properties.append(IfCfgProperty(name=name, value=value))
return properties
diff --git a/repos/system_upgrade/common/actors/ifcfgscanner/tests/unit_test_ifcfgscanner.py b/repos/system_upgrade/common/actors/ifcfgscanner/tests/unit_test_ifcfgscanner.py
index d3b4846f..d996de84 100644
--- a/repos/system_upgrade/common/actors/ifcfgscanner/tests/unit_test_ifcfgscanner.py
+++ b/repos/system_upgrade/common/actors/ifcfgscanner/tests/unit_test_ifcfgscanner.py
@@ -1,5 +1,6 @@
import errno
import textwrap
+from io import StringIO
from os.path import basename
import mock
@@ -63,8 +64,7 @@ def test_ifcfg1(monkeypatch):
KEY_TYPE=key
""")
- mock_config = mock.mock_open(read_data=ifcfg_file)
- with mock.patch(_builtins_open, mock_config):
+ with mock.patch(_builtins_open, return_value=StringIO(ifcfg_file)):
monkeypatch.setattr(ifcfgscanner, "listdir", _listdir_ifcfg)
monkeypatch.setattr(ifcfgscanner.path, "exists", _exists_ifcfg)
monkeypatch.setattr(api, "produce", produce_mocked())
@@ -110,8 +110,8 @@ def test_ifcfg_key(monkeypatch):
Report ifcfg secrets from keys- file.
"""
- mock_config = mock.mock_open(read_data="KEY_PASSPHRASE1=Hell0")
- with mock.patch(_builtins_open, mock_config):
+ file_data = "KEY_PASSPHRASE1=Hell0"
+ with mock.patch(_builtins_open, side_effect=lambda *a, **k: StringIO(file_data)):
monkeypatch.setattr(ifcfgscanner, "listdir", _listdir_ifcfg)
monkeypatch.setattr(ifcfgscanner.path, "exists", _exists_keys)
monkeypatch.setattr(api, "produce", produce_mocked())
diff --git a/repos/system_upgrade/common/actors/luksscanner/tests/test_luksdump_parser.py b/repos/system_upgrade/common/actors/luksscanner/tests/test_luksdump_parser.py
index 4b190149..f0482eef 100644
--- a/repos/system_upgrade/common/actors/luksscanner/tests/test_luksdump_parser.py
+++ b/repos/system_upgrade/common/actors/luksscanner/tests/test_luksdump_parser.py
@@ -7,8 +7,8 @@ CUR_DIR = os.path.dirname(os.path.abspath(__file__))
def test_luksdump_parser_luks1(current_actor_context):
- f = open(os.path.join(CUR_DIR, 'files/luksDump_nvme0n1p3_luks1.txt'))
- parsed_dict = LuksDumpParser.parse(f.readlines())
+ with open(os.path.join(CUR_DIR, 'files/luksDump_nvme0n1p3_luks1.txt')) as f:
+ parsed_dict = LuksDumpParser.parse(f.readlines())
assert parsed_dict["Version"] == "1"
assert parsed_dict["Cipher name"] == "aes"
@@ -39,8 +39,8 @@ def test_luksdump_parser_luks1(current_actor_context):
def test_luksdump_parser_luks2_tokens(current_actor_context):
- f = open(os.path.join(CUR_DIR, 'files/luksDump_nvme0n1p3_luks2_tokens.txt'))
- parsed_dict = LuksDumpParser.parse(f.readlines())
+ with open(os.path.join(CUR_DIR, 'files/luksDump_nvme0n1p3_luks2_tokens.txt')) as f:
+ parsed_dict = LuksDumpParser.parse(f.readlines())
assert parsed_dict["Version"] == "2"
assert parsed_dict["Epoch"] == "9"
diff --git a/repos/system_upgrade/common/actors/scansaphana/tests/test_scansaphana.py b/repos/system_upgrade/common/actors/scansaphana/tests/test_scansaphana.py
index 0b55c9fb..38a1cae7 100644
--- a/repos/system_upgrade/common/actors/scansaphana/tests/test_scansaphana.py
+++ b/repos/system_upgrade/common/actors/scansaphana/tests/test_scansaphana.py
@@ -77,9 +77,9 @@ class SubprocessCall(object):
assert args[0][0:3] == ['sudo', '-u', self.admusername]
cmd = args[0][3:]
kwargs.pop('checked', None)
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
- p.wait()
- return {'exit_code': p.returncode, 'stdout': p.stdout.read()}
+ with subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as p:
+ stdout, stderr = p.communicate()
+ return {'exit_code': p.returncode, 'stdout': stdout.decode('utf-8'), 'stderr': stderr.decode('utf-8')}
def test_scansaphana_get_instance_status(monkeypatch):
diff --git a/repos/system_upgrade/common/libraries/guards.py b/repos/system_upgrade/common/libraries/guards.py
index c8001817..ea2bf4dd 100644
--- a/repos/system_upgrade/common/libraries/guards.py
+++ b/repos/system_upgrade/common/libraries/guards.py
@@ -34,7 +34,7 @@ def guarded_execution(*guards):
def connection_guard(url='https://example.com'):
def closure():
try:
- urlopen(url)
+ urlopen(url) # pylint: disable=consider-using-with
return None
except URLError as e:
cause = '''Failed to open url '{url}' with error: {error}'''.format(url=url, error=e)
--
2.51.1

View File

@ -0,0 +1,101 @@
From 9a48ac590bf9594ea7e9eefdaa668af5f7c75976 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Fri, 2 May 2025 17:12:55 +0200
Subject: [PATCH 33/37] libs(common, version): autocorrect centos versions into
MAJOR.MINOR
When executing version.matches_version on CentOS, autocorrect versions
of the form MAJOR into MAJOR.MINOR using virtual versions available in
IPU configuration. Autocorrection is implemented only if a used version
matches source/target version. For example, if match_list contains '8'
on a CentOS 8 system, the version will be autocorrected to '8.10'.
However, if a version that does not match the source/target version is
present, it will be left untouched.
Jira-ref: RHEL-80334
---
.../libraries/config/tests/test_version.py | 15 ++++++++
.../common/libraries/config/version.py | 34 +++++++++++++++++++
2 files changed, 49 insertions(+)
diff --git a/repos/system_upgrade/common/libraries/config/tests/test_version.py b/repos/system_upgrade/common/libraries/config/tests/test_version.py
index a8a1023e..420571c0 100644
--- a/repos/system_upgrade/common/libraries/config/tests/test_version.py
+++ b/repos/system_upgrade/common/libraries/config/tests/test_version.py
@@ -61,6 +61,21 @@ def test_matches_version_pass(monkeypatch):
assert version.matches_version(['> 7.6', '< 7.10'], '7.7')
+def test_matches_version_centos_autocorrect(monkeypatch):
+ actor_mock = CurrentActorMocked(release_id='centos',
+ src_ver='8', dst_ver='9',
+ virtual_source_version='8.10', virtual_target_version='9.5')
+ monkeypatch.setattr(api, 'current_actor', actor_mock)
+
+ assert version.matches_version(['8'], '8.10')
+ assert version.matches_version(['9'], '9.5')
+ assert not version.matches_version(['8'], '9.5')
+
+ assert version.matches_version(['> 8', '<= 9'], '9.5')
+
+ assert version.matches_version(['> 8.10', '<= 9.7'], '9')
+
+
@pytest.mark.parametrize('result,version_list', [
(True, ['7.6', '7.7']),
(True, ['7.6']),
diff --git a/repos/system_upgrade/common/libraries/config/version.py b/repos/system_upgrade/common/libraries/config/version.py
index 2e837a61..4b6e616c 100644
--- a/repos/system_upgrade/common/libraries/config/version.py
+++ b/repos/system_upgrade/common/libraries/config/version.py
@@ -164,6 +164,15 @@ def _cmp_versions(versions):
return all(s[0] in OP_MAP for s in split)
+def _autocorrect_centos_version(version_to_correct):
+ version_cfg = api.current_actor().configuration.version
+ if version_to_correct == version_cfg.source:
+ version_to_correct = version_cfg.virtual_source_version
+ elif version_to_correct == version_cfg.target:
+ version_to_correct = version_cfg.virtual_target_version
+ return version_to_correct
+
+
def matches_version(match_list, detected):
"""
Check if the `detected` version meets the criteria specified in `match_list`.
@@ -189,6 +198,31 @@ def matches_version(match_list, detected):
if not isinstance(detected, six.string_types):
raise TypeError("Detected version has to be a string "
"but provided was {}: '{}'".format(type(detected), detected))
+
+ # If we are on CentOS, and we are provided with a version of the form MAJOR, try to correct
+ # the version into MAJOR.MINOR using virtual versions
+ if api.current_actor().configuration.os_release.release_id == 'centos':
+ new_detected = _autocorrect_centos_version(detected)
+ # We might have a matchlist ['> 8', '<= 9'] that, e.g., results from blindly using source/target versions
+ # to make a matchlist. Our `detected` version might be some fixed string, e.g., `9.1`. So we need to
+ # also autocorrect the matchlist. Due to how autocorrection works, no changes are done to matchlist
+ # parts that contain full versions.
+ new_matchlist = []
+ for predicate in match_list:
+ if ' ' in predicate:
+ op, version = predicate.split(' ', 1)
+ version = _autocorrect_centos_version(version)
+ new_matchlist.append('{} {}'.format(op, version))
+ else:
+ version = _autocorrect_centos_version(predicate)
+ new_matchlist.append(version)
+
+ msg = 'Performed autocorrection from matches_version(%s, %s) to matches_version(%s, %s)'
+ api.current_logger().debug(msg, match_list, detected, new_matchlist, new_detected)
+
+ match_list = new_matchlist
+ detected = new_detected
+
_validate_versions([detected])
if not _are_comparison_operators_used(match_list):
--
2.49.0

View File

@ -1,41 +0,0 @@
From 21bf23c218966040d4c3104d04ce0bcc39d0fb3d Mon Sep 17 00:00:00 2001
From: Tomas Fratrik <tfratrik@redhat.com>
Date: Wed, 13 Aug 2025 11:36:36 +0200
Subject: [PATCH 33/55] pylint: duplicate-string-formatting-argument
Jira: RHELMISC-16038
---
.pylintrc | 1 -
repos/system_upgrade/common/libraries/fetch.py | 4 ++--
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/.pylintrc b/.pylintrc
index fd770061..aaa5d99e 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -51,7 +51,6 @@ disable=
super-with-arguments, # required in python 2
raise-missing-from, # no 'raise from' in python 2
use-a-generator, # cannot be modified because of Python2 support
- duplicate-string-formatting-argument, # TMP: will be fixed in close future
consider-using-f-string, # sorry, not gonna happen, still have to support py2
use-dict-literal,
redundant-u-string-prefix, # still have py2 to support
diff --git a/repos/system_upgrade/common/libraries/fetch.py b/repos/system_upgrade/common/libraries/fetch.py
index 82bf4ff3..baf2c4eb 100644
--- a/repos/system_upgrade/common/libraries/fetch.py
+++ b/repos/system_upgrade/common/libraries/fetch.py
@@ -56,8 +56,8 @@ def _request_data(service_path, cert, proxies, timeout=REQUEST_TIMEOUT):
timeout = (timeout[0], timeout[1] + 10)
if attempt > MAX_ATTEMPTS:
logger.warning(
- 'Attempt {} of {} to get {} failed: {}.'
- .format(MAX_ATTEMPTS, MAX_ATTEMPTS, service_path, etype_msg)
+ 'Attempt {max} of {max} to get {service} failed: {error}.'
+ .format(max=MAX_ATTEMPTS, service=service_path, error=etype_msg)
)
raise
--
2.51.1

View File

@ -0,0 +1,127 @@
From c82153f14d9391c72d914c80d764de0d7ef7ff1e Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Wed, 7 May 2025 22:23:21 +0200
Subject: [PATCH 34/37] Introduce distro-based rpm-gpg trusted directory
The original trusted rpm-gpg directories under
files/rpm-gpg/
is not flexible when considering other distributions as well.
The new path pattern will be:
files/distro/<DISTRO>/rpm-gpg/
Removing files/rpm-gpg directory with the included RHEL GPG keys
in favor of the new distro based directory.
jira: RHEL-80335
Signed-off-by: Petr Stodulka <pstodulk@redhat.com>
---
.../rpm-gpg/10/RPM-GPG-KEY-redhat-release | 0
.../rpm-gpg/10beta/RPM-GPG-KEY-redhat-release | 0
.../rpm-gpg/8/RPM-GPG-KEY-redhat-release | 0
.../rpm-gpg/8beta/RPM-GPG-KEY-redhat-beta | 0
.../rpm-gpg/9/RPM-GPG-KEY-redhat-release | 0
.../rpm-gpg/9beta/RPM-GPG-KEY-redhat-beta | 0
repos/system_upgrade/common/libraries/gpg.py | 8 ++++++-
.../common/libraries/tests/test_gpg.py | 21 +++++++++++--------
8 files changed, 19 insertions(+), 10 deletions(-)
rename repos/system_upgrade/common/files/{ => distro/rhel}/rpm-gpg/10/RPM-GPG-KEY-redhat-release (100%)
rename repos/system_upgrade/common/files/{ => distro/rhel}/rpm-gpg/10beta/RPM-GPG-KEY-redhat-release (100%)
rename repos/system_upgrade/common/files/{ => distro/rhel}/rpm-gpg/8/RPM-GPG-KEY-redhat-release (100%)
rename repos/system_upgrade/common/files/{ => distro/rhel}/rpm-gpg/8beta/RPM-GPG-KEY-redhat-beta (100%)
rename repos/system_upgrade/common/files/{ => distro/rhel}/rpm-gpg/9/RPM-GPG-KEY-redhat-release (100%)
rename repos/system_upgrade/common/files/{ => distro/rhel}/rpm-gpg/9beta/RPM-GPG-KEY-redhat-beta (100%)
diff --git a/repos/system_upgrade/common/files/rpm-gpg/10/RPM-GPG-KEY-redhat-release b/repos/system_upgrade/common/files/distro/rhel/rpm-gpg/10/RPM-GPG-KEY-redhat-release
similarity index 100%
rename from repos/system_upgrade/common/files/rpm-gpg/10/RPM-GPG-KEY-redhat-release
rename to repos/system_upgrade/common/files/distro/rhel/rpm-gpg/10/RPM-GPG-KEY-redhat-release
diff --git a/repos/system_upgrade/common/files/rpm-gpg/10beta/RPM-GPG-KEY-redhat-release b/repos/system_upgrade/common/files/distro/rhel/rpm-gpg/10beta/RPM-GPG-KEY-redhat-release
similarity index 100%
rename from repos/system_upgrade/common/files/rpm-gpg/10beta/RPM-GPG-KEY-redhat-release
rename to repos/system_upgrade/common/files/distro/rhel/rpm-gpg/10beta/RPM-GPG-KEY-redhat-release
diff --git a/repos/system_upgrade/common/files/rpm-gpg/8/RPM-GPG-KEY-redhat-release b/repos/system_upgrade/common/files/distro/rhel/rpm-gpg/8/RPM-GPG-KEY-redhat-release
similarity index 100%
rename from repos/system_upgrade/common/files/rpm-gpg/8/RPM-GPG-KEY-redhat-release
rename to repos/system_upgrade/common/files/distro/rhel/rpm-gpg/8/RPM-GPG-KEY-redhat-release
diff --git a/repos/system_upgrade/common/files/rpm-gpg/8beta/RPM-GPG-KEY-redhat-beta b/repos/system_upgrade/common/files/distro/rhel/rpm-gpg/8beta/RPM-GPG-KEY-redhat-beta
similarity index 100%
rename from repos/system_upgrade/common/files/rpm-gpg/8beta/RPM-GPG-KEY-redhat-beta
rename to repos/system_upgrade/common/files/distro/rhel/rpm-gpg/8beta/RPM-GPG-KEY-redhat-beta
diff --git a/repos/system_upgrade/common/files/rpm-gpg/9/RPM-GPG-KEY-redhat-release b/repos/system_upgrade/common/files/distro/rhel/rpm-gpg/9/RPM-GPG-KEY-redhat-release
similarity index 100%
rename from repos/system_upgrade/common/files/rpm-gpg/9/RPM-GPG-KEY-redhat-release
rename to repos/system_upgrade/common/files/distro/rhel/rpm-gpg/9/RPM-GPG-KEY-redhat-release
diff --git a/repos/system_upgrade/common/files/rpm-gpg/9beta/RPM-GPG-KEY-redhat-beta b/repos/system_upgrade/common/files/distro/rhel/rpm-gpg/9beta/RPM-GPG-KEY-redhat-beta
similarity index 100%
rename from repos/system_upgrade/common/files/rpm-gpg/9beta/RPM-GPG-KEY-redhat-beta
rename to repos/system_upgrade/common/files/distro/rhel/rpm-gpg/9beta/RPM-GPG-KEY-redhat-beta
diff --git a/repos/system_upgrade/common/libraries/gpg.py b/repos/system_upgrade/common/libraries/gpg.py
index a8071329..c9c3f1fc 100644
--- a/repos/system_upgrade/common/libraries/gpg.py
+++ b/repos/system_upgrade/common/libraries/gpg.py
@@ -121,7 +121,13 @@ def get_path_to_gpg_certs():
# only beta is special in regards to the GPG signing keys
if target_product_type == 'beta':
certs_dir = '{}beta'.format(target_major_version)
- return os.path.join(api.get_common_folder_path(GPG_CERTS_FOLDER), certs_dir)
+ distro = api.current_actor().configuration.os_release.release_id
+ return os.path.join(
+ api.get_common_folder_path('distro'),
+ distro,
+ GPG_CERTS_FOLDER,
+ certs_dir
+ )
def is_nogpgcheck_set():
diff --git a/repos/system_upgrade/common/libraries/tests/test_gpg.py b/repos/system_upgrade/common/libraries/tests/test_gpg.py
index 7cf37fa2..82b51abb 100644
--- a/repos/system_upgrade/common/libraries/tests/test_gpg.py
+++ b/repos/system_upgrade/common/libraries/tests/test_gpg.py
@@ -11,14 +11,16 @@ from leapp.libraries.stdlib import api
from leapp.models import GpgKey, InstalledRPM, RPM
-@pytest.mark.parametrize('target, product_type, exp', [
- ('8.6', 'beta', '../../files/rpm-gpg/8beta'),
- ('8.8', 'htb', '../../files/rpm-gpg/8'),
- ('9.0', 'beta', '../../files/rpm-gpg/9beta'),
- ('9.2', 'ga', '../../files/rpm-gpg/9'),
+@pytest.mark.parametrize('target, product_type, distro, exp', [
+ ('8.6', 'beta', 'rhel', '../../files/distro/rhel/rpm-gpg/8beta'),
+ ('8.8', 'htb', 'rhel', '../../files/distro/rhel/rpm-gpg/8'),
+ ('9.0', 'beta', 'rhel', '../../files/distro/rhel/rpm-gpg/9beta'),
+ ('9.2', 'ga', 'rhel', '../../files/distro/rhel/rpm-gpg/9'),
+ ('10.0', 'ga', 'rhel', '../../files/distro/rhel/rpm-gpg/10'),
+ ('10', 'ga', 'centos', '../../files/distro/centos/rpm-gpg/10'),
])
-def test_get_path_to_gpg_certs(monkeypatch, target, product_type, exp):
- current_actor = CurrentActorMocked(dst_ver=target,
+def test_get_path_to_gpg_certs(monkeypatch, target, product_type, distro, exp):
+ current_actor = CurrentActorMocked(dst_ver=target, release_id=distro,
envars={'LEAPP_DEVEL_TARGET_PRODUCT_TYPE': product_type})
monkeypatch.setattr(api, 'current_actor', current_actor)
@@ -33,7 +35,7 @@ def is_rhel7():
@pytest.mark.skipif(distro.id() not in ("rhel", "centos"), reason="Requires RHEL or CentOS for valid results.")
def test_gpg_show_keys(loaded_leapp_repository, monkeypatch):
src = '7.9' if is_rhel7() else '8.6'
- current_actor = CurrentActorMocked(src_ver=src)
+ current_actor = CurrentActorMocked(src_ver=src, release_id='rhel')
monkeypatch.setattr(api, 'current_actor', current_actor)
# python2 compatibility :/
@@ -78,7 +80,8 @@ def test_gpg_show_keys(loaded_leapp_repository, monkeypatch):
# with some test data now -- rhel9 release key
# rhel9_key_path = os.path.join(api.get_common_folder_path('rpm-gpg'), '9')
cur_dir = os.path.dirname(os.path.abspath(__file__))
- rhel9_key_path = os.path.join(cur_dir, '..', '..', 'files', 'rpm-gpg', '9',
+ rhel9_key_path = os.path.join(cur_dir, '..', '..', 'files',
+ 'distro', 'rhel', 'rpm-gpg', '9',
'RPM-GPG-KEY-redhat-release')
res = gpg._gpg_show_keys(rhel9_key_path)
finally:
--
2.49.0

View File

@ -1,25 +0,0 @@
From 9cd95f0fb90a60b650ddc5bd05df6807f0e80a60 Mon Sep 17 00:00:00 2001
From: Tomas Fratrik <tfratrik@redhat.com>
Date: Wed, 13 Aug 2025 13:13:24 +0200
Subject: [PATCH 34/55] pylint: enable use-dict-literal
Jira: RHELMISC-16038
---
.pylintrc | 1 -
1 file changed, 1 deletion(-)
diff --git a/.pylintrc b/.pylintrc
index aaa5d99e..bc051513 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -52,7 +52,6 @@ disable=
raise-missing-from, # no 'raise from' in python 2
use-a-generator, # cannot be modified because of Python2 support
consider-using-f-string, # sorry, not gonna happen, still have to support py2
- use-dict-literal,
redundant-u-string-prefix, # still have py2 to support
logging-format-interpolation,
logging-not-lazy,
--
2.51.1

View File

@ -0,0 +1,227 @@
From cacee2edb7d93fa4418e9795ab3462a707868937 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Wed, 7 May 2025 22:31:35 +0200
Subject: [PATCH 35/37] Add official Centos Stream 9 and 10 RPM GPG keys
These keys are obtained from centos-gpg-keys packages on 7th May
jira: RHEL-80335
Signed-off-by: Petr Stodulka <pstodulk@redhat.com>
---
.../10/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512 | 37 +++++++++++++++++++
.../10/RPM-GPG-KEY-centosofficial-SHA256 | 30 +++++++++++++++
.../rpm-gpg/9/RPM-GPG-KEY-CentOS-SIG-Extras | 37 +++++++++++++++++++
.../9/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512 | 37 +++++++++++++++++++
.../rpm-gpg/9/RPM-GPG-KEY-centosofficial | 30 +++++++++++++++
5 files changed, 171 insertions(+)
create mode 100644 repos/system_upgrade/common/files/distro/centos/rpm-gpg/10/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
create mode 100644 repos/system_upgrade/common/files/distro/centos/rpm-gpg/10/RPM-GPG-KEY-centosofficial-SHA256
create mode 100644 repos/system_upgrade/common/files/distro/centos/rpm-gpg/9/RPM-GPG-KEY-CentOS-SIG-Extras
create mode 100644 repos/system_upgrade/common/files/distro/centos/rpm-gpg/9/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
create mode 100644 repos/system_upgrade/common/files/distro/centos/rpm-gpg/9/RPM-GPG-KEY-centosofficial
diff --git a/repos/system_upgrade/common/files/distro/centos/rpm-gpg/10/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512 b/repos/system_upgrade/common/files/distro/centos/rpm-gpg/10/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
new file mode 100644
index 00000000..e15f9a82
--- /dev/null
+++ b/repos/system_upgrade/common/files/distro/centos/rpm-gpg/10/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
@@ -0,0 +1,37 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2.0.22 (GNU/Linux)
+
+mQENBGG65jsBCADef7Fspss6f2PKrlrxufWlBaQI+kcdSDbY7o/dyyjpT7dcX8t8
+Ou73irjiShK3q0pdrh1Wy/mXc7RIJwAbCt9OVgyx4PV6AW5LfU7P7xyEAbTgLhz9
+lLPjBGhBvfRpW+7naPqkTcIKxpVR8Khq6fsvThGCNzNkGa46F1srE3mf1zC9wdVR
+VtXO7gHEZ2LrNcl195jZkBQOLcXANcSOFh5eRfhumULmk4XgCGmZQT5UNFofqOmn
+aWQGBq3XaU7RWjl7RH+IS2EW0rAtz9Le+cH+j0aFhzo7jBMOxGYG62rUaHdxssjV
+S1CrfpYT6NeG5i/1hiP4hO9suezJw4yuXNZ3ABEBAAG0VkNlbnRPUyBFeHRyYXMg
+U0lHIChodHRwczovL3dpa2kuY2VudG9zLm9yZy9TcGVjaWFsSW50ZXJlc3RHcm91
+cCkgPHNlY3VyaXR5QGNlbnRvcy5vcmc+iQE5BBMBCgAjAhsvBwsJCAcDAgEGFQgC
+CQoLBBYCAwECHgECF4AFAmIePKwACgkQH/aiFx2ZdmgUpAgAt1Y139EUQOLd013m
+jZx3shUVHRWCU0SaWLuXLupdxqhe/Iygen48aiDWfAtWr9neAJKKZFboDXXPyxDy
+9529aDgJnjwGRSFAcmvsuMaEMse6PZepTFtwhg2A/N0sDLVJSWagbQmTHdpkgEwn
+rrwO/TEaqjJ2+vZG67IIvw2rgtF3sQC28I1z7c1cPH5/NNf7dOZ29vtn44juMFFs
+o2Kd2FjZ0WP4wRmFF646nS5S1WHGS32K0xvDJMXO3MBXhaATVg+5i5ICA6fx6F3Y
+FFLJrXjx/LBtsY3EbJ0OddeZQtaAHFM1Xm6e0UHpnfjG9EGl9QrC5qzLSng0YMrG
+emhIy7kBDQRhuuY7AQgAs+enJDbwE/Iln3BnxodDQ3/1t9ULlMLJLiV+FgS7yREZ
+QvhVQxFWaJqbiPV6EJVxEP5lUHND2DAE2ZTr60y0rI3ZAY52go+QYHXb+M5HC12H
+HbhIDTWaETNo5heq/qyVSRT1u0g/yKCxQdyqnVsL86bro0wgrpj7XuApQifFhy16
+AkDjhcB0C0dXkfvEnHJylWiHpp7upfSgOcGwQ+yRHOZWJnyF+OMrFfNiwD74/zEN
+4RoNFgpqJZ81TF0qCdllTYGAXXUdYsJlg64dH0u84naTOFIuInywCmNyPmC8e8/0
+g56hCV2L7bRJGjBCa6VH+TgvVGnkFsoMM9ijhuTIIQARAQABiQI+BBgBCgAJAhsu
+BQJiHjnNASnAXSAEGQECAAYFAmG65jsACgkQi1yBEfyl0P9m/QgAh2KmBA4h/slx
+aZeWLb2cV53B1jVElsrEAE/a8yKhhcNeNOQsEWwT2/i6mdWchnIQzojKs3ypoRUY
+xsICIb4b4AFzc//aYhaOWThNRHh0UwaueNu0YBqVF3URUlf/Hw1Wv16v4QwkNhHQ
++EohCRltR2PBjAHRHXDImy9OxV/uTnZjTXegj2Jl3ueQ5nF4pleqUctt/V9JjqzO
+YcQZW78s1jyBRzefbPxQHKKp4na6etTmIvgVDjkMChRZPRjZYEVZNi8kJM0aaK4q
+ugGoL6cWBR6RYka+/eEFMd3kSrng9ahbNX0F4ztdZ2alPrrE6BvJ7n/Mt6tZKgL7
+x9V0GpbstAkQH/aiFx2ZdmgN/gf+PEUa1LT98RS28fyNPaXYGx5vLWYxUtAdeN9a
+TfugGHCVhVsowbIEnuFUHE1JmTJ1hDaFYXqkgG9zDo81JVz/yCHpNIQO0YF2h+qX
+BXiKP7PQ+iT/PjQHidlYUuz73hjDwRl3AhLafcwVHeD3cCgo/ZP/Vi9Y9iBFVZDl
+jGHxAIe0PWbEAUuqNJOgrlVmmCtSqVkN1Neihx1zjpw3rqfUQzwvhvcsOfkKfnBs
+Boc66IZ0J5pmSzgJnSbLrr2dv1/jYHaolA24vkMqMxKzJbz+GeQ/SqBZ5/rA37VL
+x90Tu9UVSfbyEbwS9Zj1sVmc3mdm1kn6dmTlOfTDIqehfHBlnQ==
+=jx2B
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/repos/system_upgrade/common/files/distro/centos/rpm-gpg/10/RPM-GPG-KEY-centosofficial-SHA256 b/repos/system_upgrade/common/files/distro/centos/rpm-gpg/10/RPM-GPG-KEY-centosofficial-SHA256
new file mode 100644
index 00000000..ceee67dd
--- /dev/null
+++ b/repos/system_upgrade/common/files/distro/centos/rpm-gpg/10/RPM-GPG-KEY-centosofficial-SHA256
@@ -0,0 +1,30 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2.0.22 (GNU/Linux)
+
+mQINBFzMWxkBEADHrskpBgN9OphmhRkc7P/YrsAGSvvl7kfu+e9KAaU6f5MeAVyn
+rIoM43syyGkgFyWgjZM8/rur7EMPY2yt+2q/1ZfLVCRn9856JqTIq0XRpDUe4nKQ
+8BlA7wDVZoSDxUZkSuTIyExbDf0cpw89Tcf62Mxmi8jh74vRlPy1PgjWL5494b3X
+5fxDidH4bqPZyxTBqPrUFuo+EfUVEqiGF94Ppq6ZUvrBGOVo1V1+Ifm9CGEK597c
+aevcGc1RFlgxIgN84UpuDjPR9/zSndwJ7XsXYvZ6HXcKGagRKsfYDWGPkA5cOL/e
+f+yObOnC43yPUvpggQ4KaNJ6+SMTZOKikM8yciyBwLqwrjo8FlJgkv8Vfag/2UR7
+JINbyqHHoLUhQ2m6HXSwK4YjtwidF9EUkaBZWrrskYR3IRZLXlWqeOi/+ezYOW0m
+vufrkcvsh+TKlVVnuwmEPjJ8mwUSpsLdfPJo1DHsd8FS03SCKPaXFdD7ePfEjiYk
+nHpQaKE01aWVSLUiygn7F7rYemGqV9Vt7tBw5pz0vqSC72a5E3zFzIIuHx6aANry
+Gat3aqU3qtBXOrA/dPkX9cWE+UR5wo/A2UdKJZLlGhM2WRJ3ltmGT48V9CeS6N9Y
+m4CKdzvg7EWjlTlFrd/8WJ2KoqOE9leDPeXRPncubJfJ6LLIHyG09h9kKQARAQAB
+tDpDZW50T1MgKENlbnRPUyBPZmZpY2lhbCBTaWduaW5nIEtleSkgPHNlY3VyaXR5
+QGNlbnRvcy5vcmc+iQI3BBMBCAAhAhsDBgsJCAcDAgYVCAIJCgsDFgIBAh4BAheA
+BQJczFsaAAoJEAW1VbOEg8ZdvOgQAMFTGIQokADy5+CynFKjfO7R0VVpJxmYGVr1
+TjnKaHmjxnJaYqoha9ukGgmLu0r+lJ42Kk6nREk1vlxfRAfiWd00Zkm+K3IMq1/D
+E0heC2vX8qqjsLJs3jzq0hgNvo9X0uHDaA4J1BHsD8sE5in/f4SivjbngvFovRGU
+1XLNCgoqpFNcROP18LqKUw8WtqgWdnYBa5i6D5qx+WMRX0NHNwcCMy1lz+sTFxIU
+9mW6cLsMaacPGD8pUXIVli8P9Vlv3jBk1wFIqRgQPW01ph/3bM7pf9hyM9FAfU4X
+AFcyb1oYI4/82EkICUe6jeuZrz67dPeLVAlYrGW4hp/825g0fqJHxPDp25GS4rAa
+4RqyibLzNjSGdXYeLj2NcB/8OqaP+T1hv3JDaqe70QoYa/GIC4rh15NyXVbUP+LG
+V4vUiL7mb9ynzvF5zYHJbcg4R7dOsiZHrMFwy7FZesQaVrXeJlxRcEj65rpm1ZtZ
+mwAE1k2LsRkvLyr9hpZkXnMeOKYIPwpdmBjXNVNVbq7097OxZOYPPos+iZKMWfl4
+UQnMsCVxonZtamdI4qEc3jMkSZPJKgOplGOms5jdY+EdSvsFWEQ0Snd3dChfU7DV
+o4Rbcy5klwHrvuZIOLaovhyxuRPhP6gV9+gzpTK/7vrvDlFbbZE6s212mDZ13RWB
+mTfAxz4h
+=agO/
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/repos/system_upgrade/common/files/distro/centos/rpm-gpg/9/RPM-GPG-KEY-CentOS-SIG-Extras b/repos/system_upgrade/common/files/distro/centos/rpm-gpg/9/RPM-GPG-KEY-CentOS-SIG-Extras
new file mode 100644
index 00000000..5ea1515a
--- /dev/null
+++ b/repos/system_upgrade/common/files/distro/centos/rpm-gpg/9/RPM-GPG-KEY-CentOS-SIG-Extras
@@ -0,0 +1,37 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2.0.22 (GNU/Linux)
+
+mQENBGG65jsBCADef7Fspss6f2PKrlrxufWlBaQI+kcdSDbY7o/dyyjpT7dcX8t8
+Ou73irjiShK3q0pdrh1Wy/mXc7RIJwAbCt9OVgyx4PV6AW5LfU7P7xyEAbTgLhz9
+lLPjBGhBvfRpW+7naPqkTcIKxpVR8Khq6fsvThGCNzNkGa46F1srE3mf1zC9wdVR
+VtXO7gHEZ2LrNcl195jZkBQOLcXANcSOFh5eRfhumULmk4XgCGmZQT5UNFofqOmn
+aWQGBq3XaU7RWjl7RH+IS2EW0rAtz9Le+cH+j0aFhzo7jBMOxGYG62rUaHdxssjV
+S1CrfpYT6NeG5i/1hiP4hO9suezJw4yuXNZ3ABEBAAG0VkNlbnRPUyBFeHRyYXMg
+U0lHIChodHRwczovL3dpa2kuY2VudG9zLm9yZy9TcGVjaWFsSW50ZXJlc3RHcm91
+cCkgPHNlY3VyaXR5QGNlbnRvcy5vcmc+iQE5BBMBAgAjBQJhuuY7AhsvBwsJCAcD
+AgEGFQgCCQoLBBYCAwECHgECF4AACgkQH/aiFx2ZdmjUtwf9GX3exQy6bC/A7miq
+I0yfoBR+jvZQKy7+U8vexbr0cgkYDTJ2zN3y+JL1391Y9CS0oDNqYLIv1BwHXAmX
+EarpQV/YyEocnYXwcVLugKCnbIN92vMTiyb/NESx1vHbduK+B8wWo3bp3sPK+Ha/
+zXrHXWSEgUeCBY/b7Tbl3GW8NX9Pr+yY0zHcvTfLByVH0KpNNLsyOsrCdk4MSKMl
+IBZWDaUYVAbyHXB92wZlQOKp+HqRxNhceGHTzeXBymK1LadntlCYTaqsg3ErRq8p
+ZwkpeyAi/avjIPYc53QE3dKGw2cUjZxkMOe6BoMbeLlO3+INdJBc/gcW4xUsQ28Y
+QtY8jLkBDQRhuuY7AQgAs+enJDbwE/Iln3BnxodDQ3/1t9ULlMLJLiV+FgS7yREZ
+QvhVQxFWaJqbiPV6EJVxEP5lUHND2DAE2ZTr60y0rI3ZAY52go+QYHXb+M5HC12H
+HbhIDTWaETNo5heq/qyVSRT1u0g/yKCxQdyqnVsL86bro0wgrpj7XuApQifFhy16
+AkDjhcB0C0dXkfvEnHJylWiHpp7upfSgOcGwQ+yRHOZWJnyF+OMrFfNiwD74/zEN
+4RoNFgpqJZ81TF0qCdllTYGAXXUdYsJlg64dH0u84naTOFIuInywCmNyPmC8e8/0
+g56hCV2L7bRJGjBCa6VH+TgvVGnkFsoMM9ijhuTIIQARAQABiQI+BBgBAgAJBQJh
+uuY7AhsuASkJEB/2ohcdmXZowF0gBBkBAgAGBQJhuuY7AAoJEItcgRH8pdD/Zv0I
+AIdipgQOIf7JcWmXli29nFedwdY1RJbKxABP2vMioYXDXjTkLBFsE9v4upnVnIZy
+EM6IyrN8qaEVGMbCAiG+G+ABc3P/2mIWjlk4TUR4dFMGrnjbtGAalRd1EVJX/x8N
+Vr9er+EMJDYR0PhKIQkZbUdjwYwB0R1wyJsvTsVf7k52Y013oI9iZd7nkOZxeKZX
+qlHLbf1fSY6szmHEGVu/LNY8gUc3n2z8UByiqeJ2unrU5iL4FQ45DAoUWT0Y2WBF
+WTYvJCTNGmiuKroBqC+nFgUekWJGvv3hBTHd5Eq54PWoWzV9BeM7XWdmpT66xOgb
+ye5/zLerWSoC+8fVdBqW7LSEqggAzRaID+mLFPTe2LbQkaBkmIpqeoDOy700Xy6K
+VW05GndH0E0t86DbQClFyzucYLzX2dXyV2DWjoWDIevQnS51zzsd+lWyuKPICKte
++K+yk5QEiwgaDf5oPmI8WL2zIAfiwVHlU0epMLU1pZLAQYotsQ6m5qPPMVXcfIqF
+3UJwZEnZRccfOKq1hHSS2/Ns4ihAfkrfes1IFLSzbyvinXQUqFVrY8oZCKhNPSRd
+IXXPIx0KvnlI9e0EittvsrQxebAa2MwLXOVYL8WVvOLY7oNTrOxe45jOdzMz2+rK
+dodVWwuBwNKuwSE6b5A0dwUj8ZEo/5L4noufZF6aGOLdbVcoUg==
+=RGYd
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/repos/system_upgrade/common/files/distro/centos/rpm-gpg/9/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512 b/repos/system_upgrade/common/files/distro/centos/rpm-gpg/9/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
new file mode 100644
index 00000000..e15f9a82
--- /dev/null
+++ b/repos/system_upgrade/common/files/distro/centos/rpm-gpg/9/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
@@ -0,0 +1,37 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2.0.22 (GNU/Linux)
+
+mQENBGG65jsBCADef7Fspss6f2PKrlrxufWlBaQI+kcdSDbY7o/dyyjpT7dcX8t8
+Ou73irjiShK3q0pdrh1Wy/mXc7RIJwAbCt9OVgyx4PV6AW5LfU7P7xyEAbTgLhz9
+lLPjBGhBvfRpW+7naPqkTcIKxpVR8Khq6fsvThGCNzNkGa46F1srE3mf1zC9wdVR
+VtXO7gHEZ2LrNcl195jZkBQOLcXANcSOFh5eRfhumULmk4XgCGmZQT5UNFofqOmn
+aWQGBq3XaU7RWjl7RH+IS2EW0rAtz9Le+cH+j0aFhzo7jBMOxGYG62rUaHdxssjV
+S1CrfpYT6NeG5i/1hiP4hO9suezJw4yuXNZ3ABEBAAG0VkNlbnRPUyBFeHRyYXMg
+U0lHIChodHRwczovL3dpa2kuY2VudG9zLm9yZy9TcGVjaWFsSW50ZXJlc3RHcm91
+cCkgPHNlY3VyaXR5QGNlbnRvcy5vcmc+iQE5BBMBCgAjAhsvBwsJCAcDAgEGFQgC
+CQoLBBYCAwECHgECF4AFAmIePKwACgkQH/aiFx2ZdmgUpAgAt1Y139EUQOLd013m
+jZx3shUVHRWCU0SaWLuXLupdxqhe/Iygen48aiDWfAtWr9neAJKKZFboDXXPyxDy
+9529aDgJnjwGRSFAcmvsuMaEMse6PZepTFtwhg2A/N0sDLVJSWagbQmTHdpkgEwn
+rrwO/TEaqjJ2+vZG67IIvw2rgtF3sQC28I1z7c1cPH5/NNf7dOZ29vtn44juMFFs
+o2Kd2FjZ0WP4wRmFF646nS5S1WHGS32K0xvDJMXO3MBXhaATVg+5i5ICA6fx6F3Y
+FFLJrXjx/LBtsY3EbJ0OddeZQtaAHFM1Xm6e0UHpnfjG9EGl9QrC5qzLSng0YMrG
+emhIy7kBDQRhuuY7AQgAs+enJDbwE/Iln3BnxodDQ3/1t9ULlMLJLiV+FgS7yREZ
+QvhVQxFWaJqbiPV6EJVxEP5lUHND2DAE2ZTr60y0rI3ZAY52go+QYHXb+M5HC12H
+HbhIDTWaETNo5heq/qyVSRT1u0g/yKCxQdyqnVsL86bro0wgrpj7XuApQifFhy16
+AkDjhcB0C0dXkfvEnHJylWiHpp7upfSgOcGwQ+yRHOZWJnyF+OMrFfNiwD74/zEN
+4RoNFgpqJZ81TF0qCdllTYGAXXUdYsJlg64dH0u84naTOFIuInywCmNyPmC8e8/0
+g56hCV2L7bRJGjBCa6VH+TgvVGnkFsoMM9ijhuTIIQARAQABiQI+BBgBCgAJAhsu
+BQJiHjnNASnAXSAEGQECAAYFAmG65jsACgkQi1yBEfyl0P9m/QgAh2KmBA4h/slx
+aZeWLb2cV53B1jVElsrEAE/a8yKhhcNeNOQsEWwT2/i6mdWchnIQzojKs3ypoRUY
+xsICIb4b4AFzc//aYhaOWThNRHh0UwaueNu0YBqVF3URUlf/Hw1Wv16v4QwkNhHQ
++EohCRltR2PBjAHRHXDImy9OxV/uTnZjTXegj2Jl3ueQ5nF4pleqUctt/V9JjqzO
+YcQZW78s1jyBRzefbPxQHKKp4na6etTmIvgVDjkMChRZPRjZYEVZNi8kJM0aaK4q
+ugGoL6cWBR6RYka+/eEFMd3kSrng9ahbNX0F4ztdZ2alPrrE6BvJ7n/Mt6tZKgL7
+x9V0GpbstAkQH/aiFx2ZdmgN/gf+PEUa1LT98RS28fyNPaXYGx5vLWYxUtAdeN9a
+TfugGHCVhVsowbIEnuFUHE1JmTJ1hDaFYXqkgG9zDo81JVz/yCHpNIQO0YF2h+qX
+BXiKP7PQ+iT/PjQHidlYUuz73hjDwRl3AhLafcwVHeD3cCgo/ZP/Vi9Y9iBFVZDl
+jGHxAIe0PWbEAUuqNJOgrlVmmCtSqVkN1Neihx1zjpw3rqfUQzwvhvcsOfkKfnBs
+Boc66IZ0J5pmSzgJnSbLrr2dv1/jYHaolA24vkMqMxKzJbz+GeQ/SqBZ5/rA37VL
+x90Tu9UVSfbyEbwS9Zj1sVmc3mdm1kn6dmTlOfTDIqehfHBlnQ==
+=jx2B
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/repos/system_upgrade/common/files/distro/centos/rpm-gpg/9/RPM-GPG-KEY-centosofficial b/repos/system_upgrade/common/files/distro/centos/rpm-gpg/9/RPM-GPG-KEY-centosofficial
new file mode 100644
index 00000000..30235a86
--- /dev/null
+++ b/repos/system_upgrade/common/files/distro/centos/rpm-gpg/9/RPM-GPG-KEY-centosofficial
@@ -0,0 +1,30 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2.0.22 (GNU/Linux)
+
+mQINBFzMWxkBEADHrskpBgN9OphmhRkc7P/YrsAGSvvl7kfu+e9KAaU6f5MeAVyn
+rIoM43syyGkgFyWgjZM8/rur7EMPY2yt+2q/1ZfLVCRn9856JqTIq0XRpDUe4nKQ
+8BlA7wDVZoSDxUZkSuTIyExbDf0cpw89Tcf62Mxmi8jh74vRlPy1PgjWL5494b3X
+5fxDidH4bqPZyxTBqPrUFuo+EfUVEqiGF94Ppq6ZUvrBGOVo1V1+Ifm9CGEK597c
+aevcGc1RFlgxIgN84UpuDjPR9/zSndwJ7XsXYvZ6HXcKGagRKsfYDWGPkA5cOL/e
+f+yObOnC43yPUvpggQ4KaNJ6+SMTZOKikM8yciyBwLqwrjo8FlJgkv8Vfag/2UR7
+JINbyqHHoLUhQ2m6HXSwK4YjtwidF9EUkaBZWrrskYR3IRZLXlWqeOi/+ezYOW0m
+vufrkcvsh+TKlVVnuwmEPjJ8mwUSpsLdfPJo1DHsd8FS03SCKPaXFdD7ePfEjiYk
+nHpQaKE01aWVSLUiygn7F7rYemGqV9Vt7tBw5pz0vqSC72a5E3zFzIIuHx6aANry
+Gat3aqU3qtBXOrA/dPkX9cWE+UR5wo/A2UdKJZLlGhM2WRJ3ltmGT48V9CeS6N9Y
+m4CKdzvg7EWjlTlFrd/8WJ2KoqOE9leDPeXRPncubJfJ6LLIHyG09h9kKQARAQAB
+tDpDZW50T1MgKENlbnRPUyBPZmZpY2lhbCBTaWduaW5nIEtleSkgPHNlY3VyaXR5
+QGNlbnRvcy5vcmc+iQI3BBMBAgAhBQJczFsZAhsDBgsJCAcDAgYVCAIJCgsDFgIB
+Ah4BAheAAAoJEAW1VbOEg8ZdjOsP/2ygSxH9jqffOU9SKyJDlraL2gIutqZ3B8pl
+Gy/Qnb9QD1EJVb4ZxOEhcY2W9VJfIpnf3yBuAto7zvKe/G1nxH4Bt6WTJQCkUjcs
+N3qPWsx1VslsAEz7bXGiHym6Ay4xF28bQ9XYIokIQXd0T2rD3/lNGxNtORZ2bKjD
+vOzYzvh2idUIY1DgGWJ11gtHFIA9CvHcW+SMPEhkcKZJAO51ayFBqTSSpiorVwTq
+a0cB+cgmCQOI4/MY+kIvzoexfG7xhkUqe0wxmph9RQQxlTbNQDCdaxSgwbF2T+gw
+byaDvkS4xtR6Soj7BKjKAmcnf5fn4C5Or0KLUqMzBtDMbfQQihn62iZJN6ZZ/4dg
+q4HTqyVpyuzMXsFpJ9L/FqH2DJ4exGGpBv00ba/Zauy7GsqOc5PnNBsYaHCply0X
+407DRx51t9YwYI/ttValuehq9+gRJpOTTKp6AjZn/a5Yt3h6jDgpNfM/EyLFIY9z
+V6CXqQQ/8JRvaik/JsGCf+eeLZOw4koIjZGEAg04iuyNTjhx0e/QHEVcYAqNLhXG
+rCTTbCn3NSUO9qxEXC+K/1m1kaXoCGA0UWlVGZ1JSifbbMx0yxq/brpEZPUYm+32
+o8XfbocBWljFUJ+6aljTvZ3LQLKTSPW7TFO+GXycAOmCGhlXh2tlc6iTc41PACqy
+yy+mHmSv
+=kkH7
+-----END PGP PUBLIC KEY BLOCK-----
--
2.49.0

View File

@ -1,43 +0,0 @@
From d99c059cb0eae4d720a2d48fb39acf6e93bc0b0e Mon Sep 17 00:00:00 2001
From: Tomas Fratrik <tfratrik@redhat.com>
Date: Wed, 13 Aug 2025 13:19:58 +0200
Subject: [PATCH 35/55] pylint: enable redundant-u-string-prefix
Jira: RHELMISC-16038
---
.pylintrc | 1 -
.../common/actors/rootscanner/tests/test_rootscanner.py | 6 +++---
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/.pylintrc b/.pylintrc
index bc051513..7d938715 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -52,7 +52,6 @@ disable=
raise-missing-from, # no 'raise from' in python 2
use-a-generator, # cannot be modified because of Python2 support
consider-using-f-string, # sorry, not gonna happen, still have to support py2
- redundant-u-string-prefix, # still have py2 to support
logging-format-interpolation,
logging-not-lazy,
use-yield-from # yield from cannot be used until we require python 3.3 or greater
diff --git a/repos/system_upgrade/common/actors/rootscanner/tests/test_rootscanner.py b/repos/system_upgrade/common/actors/rootscanner/tests/test_rootscanner.py
index 659a3017..07ce5da8 100644
--- a/repos/system_upgrade/common/actors/rootscanner/tests/test_rootscanner.py
+++ b/repos/system_upgrade/common/actors/rootscanner/tests/test_rootscanner.py
@@ -9,9 +9,9 @@ from leapp.libraries.actor.rootscanner import scan_dir
@pytest.mark.parametrize("filename,symlink,count_invalid",
- [(u'a_utf_file'.encode('utf-8'), u"utf8_symlink".encode('utf-8'), 0),
- (u'простофайл'.encode('koi8-r'), u"этонеутф8".encode('koi8-r'), 2),
- (u'a_utf_file'.encode('utf-8'), u"этонеутф8".encode('koi8-r'), 1)])
+ [('a_utf_file'.encode('utf-8'), "utf8_symlink".encode('utf-8'), 0),
+ ('простофайл'.encode('koi8-r'), "этонеутф8".encode('koi8-r'), 2),
+ ('a_utf_file'.encode('utf-8'), "этонеутф8".encode('koi8-r'), 1)])
def test_invalid_symlinks(filename, symlink, count_invalid):
# Let's create a directory with both valid utf-8 and non-utf symlinks
# NOTE(ivasilev) As this has to run for python2 as well can't use the nice tempfile.TemporaryDirectory way
--
2.51.1

View File

@ -0,0 +1,53 @@
From fe6d00b01d667a23964fe273a15ee9e457f85bf7 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Wed, 7 May 2025 21:13:04 +0200
Subject: [PATCH 36/37] Deprecate is_rhel_alt from share libraries
The function has no value anymore as RHEL-ALT 7 is EOL for years
and RHEL 7 is not longer maintained in this project neither.
I have considered the direct removal as this function is really
old (it's not even used anywhere in the project anymore).
But as it is just one small function without additional impact
and another rhel-alt artifacts became deprecated this month,
I consider it better to fulfill our promise and add it on the
deprecation list for 6months instead.
Signed-off-by: Petr Stodulka <pstodulk@redhat.com>
---
docs/source/libraries-and-api/deprecations-list.md | 2 ++
repos/system_upgrade/common/libraries/config/version.py | 5 +++++
2 files changed, 7 insertions(+)
diff --git a/docs/source/libraries-and-api/deprecations-list.md b/docs/source/libraries-and-api/deprecations-list.md
index c8489af3..b3abfc5d 100644
--- a/docs/source/libraries-and-api/deprecations-list.md
+++ b/docs/source/libraries-and-api/deprecations-list.md
@@ -16,6 +16,8 @@ Only the versions in which a deprecation has been made are listed.
- Shared libraries
- **`leapp.libraries.common.config.version.SUPPORTED_VERSIONS`** - The `SUPPORTED_VERSIONS` dict has been deprecated as it is problematic with the new design. Use `leapp.libraries.common.config.version.is_supported_version()` or `IPUConfig.supported_upgrade_paths` instead.
+ - **`leapp.libraries.common.config.version.is_rhel_alt()`** - The function can return only `False` nowadays as RHEL-ALT 7 is EOL for years and future version of leapp-repository will not support RHEL 7 anymore.
+
## v0.20.0 <span style="font-size:0.5em; font-weight:normal">(till September 2024)</span>
- Models
diff --git a/repos/system_upgrade/common/libraries/config/version.py b/repos/system_upgrade/common/libraries/config/version.py
index 4b6e616c..7f29c9cd 100644
--- a/repos/system_upgrade/common/libraries/config/version.py
+++ b/repos/system_upgrade/common/libraries/config/version.py
@@ -314,6 +314,11 @@ def is_sap_hana_flavour():
return api.current_actor().configuration.flavour == 'saphana'
+@deprecated(since='2025-05-31', message=(
+ 'RHEL-ALT reached EOL years ago and it is connected just to RHEL 7 systems.'
+ 'As such the function is useless nowadays and will return always False.'
+ 'The function is going to be removed in the next leapp-repository release.'
+))
def is_rhel_alt():
"""
Check if the current system is RHEL-ALT or not (only for RHEL 7)
--
2.49.0

View File

@ -1,110 +0,0 @@
From 078ba51a5851e388abe1357a552b981cba1acca9 Mon Sep 17 00:00:00 2001
From: Tomas Fratrik <tfratrik@redhat.com>
Date: Wed, 13 Aug 2025 13:43:04 +0200
Subject: [PATCH 36/55] pylint: enable logging-not-lazy
Jira: RHELMISC-16038
---
.pylintrc | 1 -
.../rpmtransactionconfigtaskscollector.py | 5 +++--
.../storagescanner/libraries/storagescanner.py | 8 ++++++--
.../common/libraries/persistentnetnames.py | 2 +-
.../libraries/multipathconfread.py | 14 +++++++++-----
5 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/.pylintrc b/.pylintrc
index 7d938715..f7f4b25d 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -53,7 +53,6 @@ disable=
use-a-generator, # cannot be modified because of Python2 support
consider-using-f-string, # sorry, not gonna happen, still have to support py2
logging-format-interpolation,
- logging-not-lazy,
use-yield-from # yield from cannot be used until we require python 3.3 or greater
[FORMAT]
diff --git a/repos/system_upgrade/common/actors/rpmtransactionconfigtaskscollector/libraries/rpmtransactionconfigtaskscollector.py b/repos/system_upgrade/common/actors/rpmtransactionconfigtaskscollector/libraries/rpmtransactionconfigtaskscollector.py
index 43ac1fc4..84895f83 100644
--- a/repos/system_upgrade/common/actors/rpmtransactionconfigtaskscollector/libraries/rpmtransactionconfigtaskscollector.py
+++ b/repos/system_upgrade/common/actors/rpmtransactionconfigtaskscollector/libraries/rpmtransactionconfigtaskscollector.py
@@ -29,8 +29,9 @@ def load_tasks(base_dir, logger):
filtered = set(to_install) - set(to_install_filtered)
if filtered:
api.current_logger().debug(
- 'The following packages from "to_install" file will be ignored as they are already installed:'
- '\n- ' + '\n- '.join(filtered))
+ 'The following packages from "to_install" file will be ignored as they are already installed:\n- %s',
+ '\n- '.join(filtered)
+ )
return RpmTransactionTasks(
to_install=to_install_filtered,
diff --git a/repos/system_upgrade/common/actors/storagescanner/libraries/storagescanner.py b/repos/system_upgrade/common/actors/storagescanner/libraries/storagescanner.py
index cae38731..e2d869da 100644
--- a/repos/system_upgrade/common/actors/storagescanner/libraries/storagescanner.py
+++ b/repos/system_upgrade/common/actors/storagescanner/libraries/storagescanner.py
@@ -35,7 +35,7 @@ def _is_file_readable(path):
def _get_cmd_output(cmd, delim, expected_len):
""" Verify if command exists and return output """
if not any(os.access(os.path.join(path, cmd[0]), os.X_OK) for path in os.environ['PATH'].split(os.pathsep)):
- api.current_logger().warning("'%s': command not found" % cmd[0])
+ api.current_logger().warning("'%s': command not found", cmd[0])
return
try:
@@ -45,7 +45,11 @@ def _get_cmd_output(cmd, delim, expected_len):
output = subprocess.check_output(cmd, env={'LVM_SUPPRESS_FD_WARNINGS': '1', 'PATH': os.environ['PATH']})
except subprocess.CalledProcessError as e:
- api.current_logger().debug("Command '%s' return non-zero exit status: %s" % (" ".join(cmd), e.returncode))
+ api.current_logger().debug(
+ "Command '%s' returned non-zero exit status: %s",
+ " ".join(cmd),
+ e.returncode
+ )
return
if bytes is not str:
diff --git a/repos/system_upgrade/common/libraries/persistentnetnames.py b/repos/system_upgrade/common/libraries/persistentnetnames.py
index 8769712c..7fdf7eaa 100644
--- a/repos/system_upgrade/common/libraries/persistentnetnames.py
+++ b/repos/system_upgrade/common/libraries/persistentnetnames.py
@@ -50,7 +50,7 @@ def interfaces():
except Exception as e: # pylint: disable=broad-except
# FIXME(msekleta): We should probably handle errors more granularly
# Maybe we should inhibit upgrade process at this point
- api.current_logger().warning('Failed to gather information about network interface: ' + str(e))
+ api.current_logger().warning('Failed to gather information about network interface: %s', e)
continue
yield Interface(**attrs)
diff --git a/repos/system_upgrade/el8toel9/actors/multipathconfread/libraries/multipathconfread.py b/repos/system_upgrade/el8toel9/actors/multipathconfread/libraries/multipathconfread.py
index e5b3f06c..5b1cef50 100644
--- a/repos/system_upgrade/el8toel9/actors/multipathconfread/libraries/multipathconfread.py
+++ b/repos/system_upgrade/el8toel9/actors/multipathconfread/libraries/multipathconfread.py
@@ -68,12 +68,16 @@ def _parse_config_dir(config_dir):
res.append(conf)
except OSError as e:
if e.errno == errno.ENOENT:
- api.current_logger().debug('Multipath conf directory ' +
- '"{}" doesn\'t exist'.format(config_dir))
+ api.current_logger().debug(
+ 'Multipath conf directory "%s" doesn\'t exist',
+ config_dir
+ )
else:
- api.current_logger().warning('Failed to read multipath config ' +
- 'directory ' +
- '"{}": {}'.format(config_dir, e))
+ api.current_logger().warning(
+ 'Failed to read multipath config directory "%s": %s',
+ config_dir,
+ e
+ )
return res
--
2.51.1

File diff suppressed because it is too large Load Diff

View File

@ -1,87 +0,0 @@
From 1104e25977b728a7059fc1ef4613ef55d1e0a9d7 Mon Sep 17 00:00:00 2001
From: Tomas Fratrik <tfratrik@redhat.com>
Date: Wed, 13 Aug 2025 13:51:34 +0200
Subject: [PATCH 37/55] pylint: enable use-yield-from
Jira: RHELMISC-16038
---
.pylintrc | 3 +--
.../mount_units_generator/tests/test_mount_unit_generation.py | 3 +--
.../actors/storagescanner/tests/unit_test_storagescanner.py | 3 +--
.../tests/unit_test_targetuserspacecreator.py | 3 +--
repos/system_upgrade/common/libraries/config/version.py | 3 +--
5 files changed, 5 insertions(+), 10 deletions(-)
diff --git a/.pylintrc b/.pylintrc
index f7f4b25d..15a69461 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -52,8 +52,7 @@ disable=
raise-missing-from, # no 'raise from' in python 2
use-a-generator, # cannot be modified because of Python2 support
consider-using-f-string, # sorry, not gonna happen, still have to support py2
- logging-format-interpolation,
- use-yield-from # yield from cannot be used until we require python 3.3 or greater
+ logging-format-interpolation
[FORMAT]
# Maximum number of characters on a single line.
diff --git a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/tests/test_mount_unit_generation.py b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/tests/test_mount_unit_generation.py
index b814f6ce..9d75a31d 100644
--- a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/tests/test_mount_unit_generation.py
+++ b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/tests/test_mount_unit_generation.py
@@ -196,8 +196,7 @@ def test_copy_units_mixed_content(monkeypatch):
('/source/dir', ['local-fs.target.requires'], ['unit1.mount', 'unit2.mount']),
('/source/dir/local-fs.target.requires', [], ['unit1.mount', 'unit2.mount']),
]
- for i in tuples_to_yield:
- yield i
+ yield from tuples_to_yield
def mock_isdir(path):
return 'local-fs.target.requires' in path
diff --git a/repos/system_upgrade/common/actors/storagescanner/tests/unit_test_storagescanner.py b/repos/system_upgrade/common/actors/storagescanner/tests/unit_test_storagescanner.py
index 456e40ec..3c7fcbd6 100644
--- a/repos/system_upgrade/common/actors/storagescanner/tests/unit_test_storagescanner.py
+++ b/repos/system_upgrade/common/actors/storagescanner/tests/unit_test_storagescanner.py
@@ -268,8 +268,7 @@ def test_get_lsblk_info(monkeypatch):
'crypt', '', '/dev/nvme0n1p1'],
['/dev/nvme0n1p1', '259:1', '0', str(39 * bytes_per_gb), '0', 'part', '', '/dev/nvme0n1'],
]
- for output_line_parts in output_lines_split_on_whitespace:
- yield output_line_parts
+ yield from output_lines_split_on_whitespace
elif len(cmd) == 5 and cmd[:4] == ['lsblk', '-nr', '--output', 'NAME,KNAME,SIZE']:
# We cannot have the output in a list, since the command is called per device. Therefore, we have to map
# each device path to its output.
diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py b/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
index 2ae194d7..e78c3ac7 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
@@ -95,8 +95,7 @@ def traverse_structure(structure, root=Path('/')):
filepath = root / filename
if isinstance(links_to, dict):
- for pair in traverse_structure(links_to, filepath):
- yield pair
+ yield from traverse_structure(links_to, root=filepath)
else:
yield (filepath, links_to)
diff --git a/repos/system_upgrade/common/libraries/config/version.py b/repos/system_upgrade/common/libraries/config/version.py
index 00ce3ec8..5efa932d 100644
--- a/repos/system_upgrade/common/libraries/config/version.py
+++ b/repos/system_upgrade/common/libraries/config/version.py
@@ -106,8 +106,7 @@ class _SupportedVersionsDict(dict):
def __iter__(self):
self._feed_supported_versions()
- for d in self.data:
- yield d
+ yield from self.data
def __repr__(self):
self._feed_supported_versions()
--
2.51.1

View File

@ -0,0 +1,91 @@
From 397975d6b63ff70755ea41b8ec8fc413966218e4 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Fri, 30 May 2025 14:13:35 +0200
Subject: [PATCH 38/43] Makefile: Non-zero exit code on failed tests in
container
Previously all exit codes from execution of tests inside
container have been ignored and make command ended with zero always.
Also drop testing of el7toel8 repository for Python 3.6 on RHEL 8.
The test started to fail for unknown reason (changes in pytest or
another nonstandard python module?). As we are in the middle of
dropping all el7toel8 and python2 related content, let's just drop
it. Keeping the full removal of Py2 and el7toel8 content on separate
PR.
---
Makefile | 29 ++++++++++++++++-------------
1 file changed, 16 insertions(+), 13 deletions(-)
diff --git a/Makefile b/Makefile
index ceb013ab..6769b2f3 100644
--- a/Makefile
+++ b/Makefile
@@ -164,9 +164,9 @@ help:
@echo " PR=7 SUFFIX='my_additional_suffix' make <target>"
@echo " MR=6 COPR_CONFIG='path/to/the/config/copr/file' make <target>"
@echo " ACTOR=<actor> TEST_LIBS=y make test"
- @echo " BUILD_CONTAINER=el7 make build_container"
+ @echo " BUILD_CONTAINER=rhel8 make build_container"
@echo " TEST_CONTAINER=f34 make test_container"
- @echo " CONTAINER_TOOL=docker TEST_CONTAINER=rhel7 make test_container_no_lint"
+ @echo " CONTAINER_TOOL=docker TEST_CONTAINER=rhel8 make test_container_no_lint"
@echo ""
clean:
@@ -459,30 +459,33 @@ test_container:
$(_CONTAINER_TOOL) ps -q -f name=$$_CONT_NAME && { $(_CONTAINER_TOOL) kill $$_CONT_NAME; $(_CONTAINER_TOOL) rm $$_CONT_NAME; }; \
$(_CONTAINER_TOOL) run -di --name $$_CONT_NAME -v "$$PWD":/repo:Z -e PYTHON_VENV=$$_VENV $$TEST_IMAGE && \
$(_CONTAINER_TOOL) exec $$_CONT_NAME rsync -aur --delete --exclude "tut*" /repo/ /repocopy && \
+ export res=0; \
case $$_VENV in \
python2.7) \
- TEST_CONT_IPU=el7toel8 $(MAKE) _test_container_ipu; \
+ TEST_CONT_IPU=el7toel8 $(MAKE) _test_container_ipu || res=1; \
;;\
python3.6) \
- TEST_CONT_IPU=el7toel8 $(MAKE) _test_container_ipu; \
- TEST_CONT_IPU=el8toel9 $(MAKE) _test_container_ipu; \
+ echo "INFO: Skipping testing of el7toel8 repository. Obsoleted"; \
+ TEST_CONT_IPU=el8toel9 $(MAKE) _test_container_ipu || res=1; \
;; \
python3.9) \
- TEST_CONT_IPU=el8toel9 $(MAKE) _test_container_ipu; \
- TEST_CONT_IPU=el9toel10 $(MAKE) _test_container_ipu; \
+ TEST_CONT_IPU=el8toel9 $(MAKE) _test_container_ipu || res=1; \
+ TEST_CONT_IPU=el9toel10 $(MAKE) _test_container_ipu || res=1; \
;; \
python3.12) \
- TEST_CONT_IPU=el9toel10 $(MAKE) _test_container_ipu; \
+ TEST_CONT_IPU=el9toel10 $(MAKE) _test_container_ipu || res=1; \
;; \
*) \
- TEST_CONT_IPU=el8toel9 $(MAKE) _test_container_ipu; \
- ;;\
+ TEST_CONT_IPU=el8toel9 $(MAKE) _test_container_ipu || res=1; \
+ ;; \
esac; \
$(_CONTAINER_TOOL) kill $$_CONT_NAME; \
- $(_CONTAINER_TOOL) rm $$_CONT_NAME
+ $(_CONTAINER_TOOL) rm $$_CONT_NAME; \
+ [ $$res -ne 0 ] && echo "TIP: If you do not see an error in the end of logs, scroll up. Multiple tests could be executed." ; \
+ exit $$res
test_container_all:
- @for container in "f34" "rhel7" "rhel8"; do \
+ @for container in "f34" "rhel7" "rhel8" "rhel9"; do \
TEST_CONTAINER=$$container $(MAKE) test_container || exit 1; \
done
@@ -490,7 +493,7 @@ test_container_no_lint:
@_TEST_CONT_TARGET="test_no_lint" $(MAKE) test_container
test_container_all_no_lint:
- @for container in "f34" "rhel7" "rhel8"; do \
+ @for container in "f34" "rhel7" "rhel8" "rhel9"; do \
TEST_CONTAINER=$$container $(MAKE) test_container_no_lint || exit 1; \
done
--
2.49.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,82 @@
From 4e87908b2e17d87b69bcec29ba1e9b777439a0fe Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Fri, 30 May 2025 15:02:53 +0200
Subject: [PATCH 39/43] CI: Unit-tests: Rename tasks & tests executions
Previous name have been very long, repeating, and it has been
problem to read the whole informatino about what tests are performed
as the description has been shortened in WebUI, e.g.:
Unit Tests / Run unit tests in containers (Run python linters for el8toel9 and common repositories on p...
Let's change the name so it's shortened and easier read what test
has been actually performed. Also, no need to mention that tests are
running in container anymore, as we are not running unit-tests outside
of the container in upstream. Example of new style names:
Unit Tests / Run: Linters (python:3.9; repos:el9toel10,common) (pull_request)
Unit Tests / Run: Unit Tests (python:3.9; repos:el9toel10,common) (pull_request)
---
.github/workflows/unit-tests.yml | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml
index 37748396..ed82e0e5 100644
--- a/.github/workflows/unit-tests.yml
+++ b/.github/workflows/unit-tests.yml
@@ -9,43 +9,43 @@ on:
jobs:
test:
- name: Run unit tests in containers
+ name: 'Run: ${{ matrix.scenarios.name }}'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
scenarios:
# 9to10
- - name: Run unit tests for el9toel10 and common repositories on python 3.12
+ - name: 'Unit tests (python:3.12; repos:el9toel10,common)'
python: python3.12
repos: 'el9toel10,common'
container: ubi9
- - name: Run python linters for el9toel10 and common repositories on python 3.12
+ - name: 'Linters (python:3.12; repos:el9toel10,common)'
python: python3.12
repos: 'el9toel10,common'
container: ubi9-lint
- - name: Run unit tests for el9toel10 and common repositories on python 3.9
+ - name: 'Unit tests (python:3.9; repos:el9toel10,common)'
python: python3.9
repos: 'el9toel10,common'
container: ubi9
- - name: Run python linters for el9toel10 and common repositories on python 3.9
+ - name: 'Linters (python:3.9; repos:el9toel10,common)'
python: python3.9
repos: 'el9toel10,common'
container: ubi9-lint
# 8to9
- - name: Run unit tests for el8toel9 and common repositories on python 3.9
+ - name: 'Unit tests (python:3.9; repos:el8toel9,common)'
python: python3.9
repos: 'el8toel9,common'
container: ubi9
- - name: Run python linters for el8toel9 and common repositories on python 3.9
+ - name: 'Linters (python:3.9; repos:el8toel9,common)'
python: python3.9
repos: 'el8toel9,common'
container: ubi9-lint
- - name: Run unit tests for el8toel9 and common repositories on python 3.6
+ - name: 'Unit tests (python:3.6; repos:el8toel9,common)'
python: python3.6
repos: 'el8toel9,common'
container: ubi8
- - name: Run python linters for el8toel9 and common repositories on python 3.6
+ - name: 'Linters (python:3.6; repos:el8toel9,common)'
python: python3.6
repos: 'el8toel9,common'
container: ubi8-lint
--
2.49.0

View File

@ -1,127 +0,0 @@
From e530472760f0df186531bf3d17323ee082c7fba8 Mon Sep 17 00:00:00 2001
From: Tomas Fratrik <tfratrik@redhat.com>
Date: Mon, 18 Aug 2025 13:12:24 +0200
Subject: [PATCH 39/55] pylint: enable invalid-envvar-default
Jira: RHELMISC-16038
---
.pylintrc | 1 -
.../removeresumeservice/tests/test_removeresumeservice.py | 2 +-
.../tests/test_scheduleselinuxrelabeling.py | 4 ++--
.../tests/component_test_selinuxapplycustom.py | 2 +-
.../tests/component_test_selinuxcontentscanner.py | 2 +-
.../selinuxprepare/tests/component_test_selinuxprepare.py | 2 +-
.../setpermissiveselinux/tests/test_setpermissiveselinux.py | 4 ++--
7 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/.pylintrc b/.pylintrc
index d98ab151..7a373e3d 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -45,7 +45,6 @@ disable=
too-many-positional-arguments, # we cannot set yet max-possitional-arguments unfortunately
# new for python3 version of pylint
unnecessary-pass,
- invalid-envvar-default, # pylint3 warnings envvar returns str/none by default
bad-option-value, # python 2 doesn't have import-outside-toplevel, but in some case we need to import outside toplevel
super-with-arguments, # required in python 2
raise-missing-from, # no 'raise from' in python 2
diff --git a/repos/system_upgrade/common/actors/removeresumeservice/tests/test_removeresumeservice.py b/repos/system_upgrade/common/actors/removeresumeservice/tests/test_removeresumeservice.py
index ea803856..d59ef346 100644
--- a/repos/system_upgrade/common/actors/removeresumeservice/tests/test_removeresumeservice.py
+++ b/repos/system_upgrade/common/actors/removeresumeservice/tests/test_removeresumeservice.py
@@ -11,7 +11,7 @@ import pytest
'under the root user.',
)
# TODO make the test not destructive
-@pytest.mark.skipif(os.getenv("DESTRUCTIVE_TESTING", False) in [False, "0"],
+@pytest.mark.skipif(os.getenv("DESTRUCTIVE_TESTING", "0").lower() in ["false", "0"],
reason='Test disabled by default because it would modify the system')
def test_remove_resume_service(current_actor_context):
service_name = 'leapp_resume.service'
diff --git a/repos/system_upgrade/common/actors/scheduleselinuxrelabeling/tests/test_scheduleselinuxrelabeling.py b/repos/system_upgrade/common/actors/scheduleselinuxrelabeling/tests/test_scheduleselinuxrelabeling.py
index 595b9985..8603bd97 100644
--- a/repos/system_upgrade/common/actors/scheduleselinuxrelabeling/tests/test_scheduleselinuxrelabeling.py
+++ b/repos/system_upgrade/common/actors/scheduleselinuxrelabeling/tests/test_scheduleselinuxrelabeling.py
@@ -9,7 +9,7 @@ from leapp.snactor.fixture import current_actor_context
@pytest.mark.skipif(
- os.getenv("DESTRUCTIVE_TESTING", False) in [False, "0"],
+ os.getenv("DESTRUCTIVE_TESTING", "0").lower() in ["false", "0"],
reason='Test disabled by default because it would modify the system',
)
def test_schedule_no_relabel(current_actor_context):
@@ -19,7 +19,7 @@ def test_schedule_no_relabel(current_actor_context):
@pytest.mark.skipif(
- os.getenv("DESTRUCTIVE_TESTING", False) in [False, "0"],
+ os.getenv("DESTRUCTIVE_TESTING", "0").lower() in ["false", "0"],
reason='Test disabled by default because it would modify the system',
)
def test_schedule_relabel(current_actor_context):
diff --git a/repos/system_upgrade/common/actors/selinux/selinuxapplycustom/tests/component_test_selinuxapplycustom.py b/repos/system_upgrade/common/actors/selinux/selinuxapplycustom/tests/component_test_selinuxapplycustom.py
index 8a4665c1..aab18e58 100644
--- a/repos/system_upgrade/common/actors/selinux/selinuxapplycustom/tests/component_test_selinuxapplycustom.py
+++ b/repos/system_upgrade/common/actors/selinux/selinuxapplycustom/tests/component_test_selinuxapplycustom.py
@@ -72,7 +72,7 @@ def destructive_selinux_env():
"Failed to remove SELinux customizations after testing")
-@pytest.mark.skipif(os.getenv("DESTRUCTIVE_TESTING", False) in [False, "0"],
+@pytest.mark.skipif(os.getenv("DESTRUCTIVE_TESTING", "0").lower() in ["false", "0"],
reason='Test disabled by default because it would modify the system')
def test_SELinuxApplyCustom(current_actor_context, destructive_selinux_teardown):
diff --git a/repos/system_upgrade/common/actors/selinux/selinuxcontentscanner/tests/component_test_selinuxcontentscanner.py b/repos/system_upgrade/common/actors/selinux/selinuxcontentscanner/tests/component_test_selinuxcontentscanner.py
index faa2e1b0..802e038a 100644
--- a/repos/system_upgrade/common/actors/selinux/selinuxcontentscanner/tests/component_test_selinuxcontentscanner.py
+++ b/repos/system_upgrade/common/actors/selinux/selinuxcontentscanner/tests/component_test_selinuxcontentscanner.py
@@ -76,7 +76,7 @@ def find_semanage_rule(rules, rule):
return next((r for r in rules if all(word in r for word in rule)), None)
-@pytest.mark.skipif(os.getenv("DESTRUCTIVE_TESTING", False) in [False, "0"],
+@pytest.mark.skipif(os.getenv("DESTRUCTIVE_TESTING", "false") in ["False", "false", "0"],
reason='Test disabled by default because it would modify the system')
def test_SELinuxContentScanner(current_actor_context, destructive_selinux_env):
diff --git a/repos/system_upgrade/common/actors/selinux/selinuxprepare/tests/component_test_selinuxprepare.py b/repos/system_upgrade/common/actors/selinux/selinuxprepare/tests/component_test_selinuxprepare.py
index bad1baa2..d124675a 100644
--- a/repos/system_upgrade/common/actors/selinux/selinuxprepare/tests/component_test_selinuxprepare.py
+++ b/repos/system_upgrade/common/actors/selinux/selinuxprepare/tests/component_test_selinuxprepare.py
@@ -76,7 +76,7 @@ def destructive_selinux_env():
_run_cmd(semodule_command)
-@pytest.mark.skipif(os.getenv('DESTRUCTIVE_TESTING', False) in [False, '0'],
+@pytest.mark.skipif(os.getenv('DESTRUCTIVE_TESTING', '0').lower() in ['false', '0'],
reason='Test disabled by default because it would modify the system')
def test_SELinuxPrepare(current_actor_context, semodule_lfull_initial, semanage_export_initial,
destructive_selinux_env):
diff --git a/repos/system_upgrade/common/actors/setpermissiveselinux/tests/test_setpermissiveselinux.py b/repos/system_upgrade/common/actors/setpermissiveselinux/tests/test_setpermissiveselinux.py
index efa4e550..9acdf39a 100644
--- a/repos/system_upgrade/common/actors/setpermissiveselinux/tests/test_setpermissiveselinux.py
+++ b/repos/system_upgrade/common/actors/setpermissiveselinux/tests/test_setpermissiveselinux.py
@@ -6,7 +6,7 @@ from leapp.models import SelinuxPermissiveDecision
@pytest.mark.skipif(
- os.getenv("DESTRUCTIVE_TESTING", False) in [False, "0"],
+ os.getenv("DESTRUCTIVE_TESTING", "0").lower() in ["0", "false"],
reason='Test disabled by default because it would modify the system')
def check_permissive_in_conf():
""" Check if we have set permissive in SElinux conf file """
@@ -19,7 +19,7 @@ def check_permissive_in_conf():
@pytest.mark.skipif(
- os.getenv("DESTRUCTIVE_TESTING", False) in [False, "0"],
+ os.getenv("DESTRUCTIVE_TESTING", "false").lower() in ["0", "false"],
reason='Test disabled by default because it would modify the system')
def test_set_selinux_permissive(current_actor_context):
current_actor_context.feed(SelinuxPermissiveDecision(set_permissive=True))
--
2.51.1

View File

@ -0,0 +1,166 @@
From 2646484407bef15688fb4838c2f61d06f2098f81 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Wed, 30 Apr 2025 12:54:22 +0200
Subject: [PATCH 40/43] Fix parsing of the kernel cmdline
Original parsing has been splitting string tokens by "=" without a
limit, means that e.g.
root=UUID=some-id
has been split to
(root, UUID, some-id)
and and stored just "root" and "UUID" strings in the parsed msg,
instead of "root" and "UUID=some-id".
So split the key=value just based on the first occurence of "="
instead.
JIRA: RHELMISC-12490
Co-Authored-By: Karolina Kula <kkula@redhat.com>
---
.../common/actors/scankernelcmdline/actor.py | 16 ++---
.../libraries/scankernelcmdline.py | 23 +++++++
.../tests/test_scankernelcmdline.py | 67 +++++++++++++++++++
3 files changed, 94 insertions(+), 12 deletions(-)
create mode 100644 repos/system_upgrade/common/actors/scankernelcmdline/libraries/scankernelcmdline.py
create mode 100644 repos/system_upgrade/common/actors/scankernelcmdline/tests/test_scankernelcmdline.py
diff --git a/repos/system_upgrade/common/actors/scankernelcmdline/actor.py b/repos/system_upgrade/common/actors/scankernelcmdline/actor.py
index 9f8fef30..2f1a5ae2 100644
--- a/repos/system_upgrade/common/actors/scankernelcmdline/actor.py
+++ b/repos/system_upgrade/common/actors/scankernelcmdline/actor.py
@@ -1,12 +1,12 @@
from leapp.actors import Actor
-from leapp.libraries.stdlib import run
-from leapp.models import KernelCmdline, KernelCmdlineArg
+from leapp.libraries.actor import scankernelcmdline
+from leapp.models import KernelCmdline
from leapp.tags import FactsPhaseTag, IPUWorkflowTag
class ScanKernelCmdline(Actor):
"""
- No documentation has been provided for the scan_kernel_cmdline actor.
+ Scan the kernel command line of the booted system.
"""
name = 'scan_kernel_cmdline'
@@ -15,12 +15,4 @@ class ScanKernelCmdline(Actor):
tags = (FactsPhaseTag, IPUWorkflowTag)
def process(self):
- cmdline = run(['cat', '/proc/cmdline'])['stdout'].strip()
- parameters = []
- for parameter in cmdline.split(' '):
- if '=' in parameter:
- kv = parameter.split('=')
- parameters.append(KernelCmdlineArg(key=kv[0], value=kv[1]))
- else:
- parameters.append(KernelCmdlineArg(key=parameter))
- self.produce(KernelCmdline(parameters=parameters))
+ scankernelcmdline.parse_cmdline_input()
diff --git a/repos/system_upgrade/common/actors/scankernelcmdline/libraries/scankernelcmdline.py b/repos/system_upgrade/common/actors/scankernelcmdline/libraries/scankernelcmdline.py
new file mode 100644
index 00000000..9cffa70e
--- /dev/null
+++ b/repos/system_upgrade/common/actors/scankernelcmdline/libraries/scankernelcmdline.py
@@ -0,0 +1,23 @@
+from leapp.libraries.stdlib import api, CalledProcessError, run
+from leapp.models import KernelCmdline, KernelCmdlineArg
+
+
+def get_cmdline_input():
+ try:
+ cmdline_input = run(['cat', '/proc/cmdline'])['stdout'].strip()
+ return cmdline_input
+ except (OSError, CalledProcessError):
+ api.current_logger().debug('Executing `cat /proc/cmdline` failed', exc_info=True)
+ return ''
+
+
+def parse_cmdline_input():
+ cmdline = get_cmdline_input()
+ parameters = []
+ for parameter in cmdline.split(' '):
+ if '=' in parameter:
+ kv = parameter.split('=', 1)
+ parameters.append(KernelCmdlineArg(key=kv[0], value=kv[1]))
+ else:
+ parameters.append(KernelCmdlineArg(key=parameter))
+ api.produce(KernelCmdline(parameters=parameters))
diff --git a/repos/system_upgrade/common/actors/scankernelcmdline/tests/test_scankernelcmdline.py b/repos/system_upgrade/common/actors/scankernelcmdline/tests/test_scankernelcmdline.py
new file mode 100644
index 00000000..ff79054f
--- /dev/null
+++ b/repos/system_upgrade/common/actors/scankernelcmdline/tests/test_scankernelcmdline.py
@@ -0,0 +1,67 @@
+import pytest
+
+from leapp.libraries.actor import scankernelcmdline
+from leapp.libraries.common.testutils import CurrentActorMocked, produce_mocked
+from leapp.libraries.stdlib import api, CalledProcessError
+from leapp.models import KernelCmdline, KernelCmdlineArg
+
+
+def mock_cmd_output():
+ expected_cmd_output = (
+ 'BOOT_IMAGE=(hd0,msdos1)/vmlinuz-xxx root=UUID=some_uid ro console=tty0'
+ ' console=ttyS0,115200 rd_NO_PLYMOUTH biosdevname=0 net.ifnames=0 crashkernel=auto'
+ )
+ return expected_cmd_output
+
+
+def test_cmdline_output(monkeypatch):
+
+ monkeypatch.setattr(scankernelcmdline, 'get_cmdline_input', mock_cmd_output)
+ current_actor = CurrentActorMocked(src_ver='8.10', dst_ver='9.6')
+ monkeypatch.setattr(api, 'current_actor', current_actor)
+ monkeypatch.setattr(api, 'produce', produce_mocked())
+
+ scankernelcmdline.parse_cmdline_input()
+
+ expected_params = [KernelCmdlineArg(key=k, value=v) for k, v in [
+ ('BOOT_IMAGE', '(hd0,msdos1)/vmlinuz-xxx'),
+ ('root', 'UUID=some_uid'),
+ ('ro', None),
+ ('console', 'tty0'),
+ ('console', 'ttyS0,115200'),
+ ('rd_NO_PLYMOUTH', None),
+ ('biosdevname', '0'),
+ ('net.ifnames', '0'),
+ ('crashkernel', 'auto')]]
+
+ expected_output_msg = KernelCmdline(parameters=expected_params)
+ assert api.produce.model_instances
+ assert expected_output_msg == api.produce.model_instances[0]
+
+
+def test_cmdline_content(monkeypatch):
+
+ def run_mocked(cmd, **kwargs):
+ assert cmd == ['cat', '/proc/cmdline']
+ output = mock_cmd_output()
+ return {'stdout': output}
+
+ monkeypatch.setattr(scankernelcmdline, 'run', run_mocked)
+ cmd_output = scankernelcmdline.get_cmdline_input()
+ expected_cmd_output = mock_cmd_output()
+
+ assert cmd_output == expected_cmd_output
+
+
+@pytest.mark.parametrize('is_os_error', [True, False])
+def test_cmdline_run_failed(monkeypatch, is_os_error):
+
+ def run_mocked_error(cmd, **kwargs):
+ assert cmd == ['cat', '/proc/cmdline']
+ if is_os_error:
+ raise OSError('OSError raised')
+ raise CalledProcessError("CalledProcessError raised", cmd, "result")
+
+ monkeypatch.setattr(scankernelcmdline, 'run', run_mocked_error)
+ cmd_output = scankernelcmdline.get_cmdline_input()
+ assert cmd_output == ''
--
2.49.0

View File

@ -1,613 +0,0 @@
From 81b24a657037ceffc3959abb4231a19352ca9a82 Mon Sep 17 00:00:00 2001
From: Tomas Fratrik <tfratrik@redhat.com>
Date: Mon, 18 Aug 2025 14:42:15 +0200
Subject: [PATCH 40/55] pylint: enable bad-option-value
This pylint warning triggers when you try to disable a pylint check that is unknown or obsolete. Enabling this rule caused such warnings to appear, so the corresponding disables needed to be removed:
* no-absolute-import -> Only relevant for Python 2. Python 3 uses absolute imports by default.
* no-init -> Obsolete: __init__ method checks have changed, this option no longer exists.
* bad-continuation -> Superseded by modern pylint formatting checks.
* no-self-use -> Checks whether a method could be a function.
* relative-import -> Python 3 discourages relative imports differently.
Jira: RHELMISC-16038
---
.pylintrc | 8 +----
commands/upgrade/breadcrumbs.py | 9 +++--
.../checkmemory/libraries/checkmemory.py | 4 +--
.../tests/test_enablerhsmtargetrepos.py | 3 +-
.../tests/test_mount_unit_generation.py | 3 +-
.../libraries/upgradeinitramfsgenerator.py | 2 +-
.../unit_test_upgradeinitramfsgenerator.py | 2 +-
.../tests/test_kernelcmdlineconfig.py | 4 +--
.../opensshpermitrootlogincheck/actor.py | 6 ++--
.../actors/persistentnetnamesdisable/actor.py | 6 ++--
.../libraries/scankernel.py | 2 +-
.../tests/unit_test_targetuserspacecreator.py | 3 +-
.../tests/test_trustedgpgkeys.py | 2 +-
.../common/files/rhel_upgrade.py | 9 +++--
.../common/libraries/dnfplugin.py | 3 +-
repos/system_upgrade/common/libraries/grub.py | 4 +--
.../common/libraries/mounting.py | 3 +-
.../common/libraries/overlaygen.py | 35 ++++++++++++-------
.../common/libraries/tests/test_distro.py | 3 +-
.../common/libraries/tests/test_grub.py | 2 +-
.../common/libraries/tests/test_rhsm.py | 6 ++--
.../common/libraries/testutils.py | 2 +-
.../checkvdo/tests/unit_test_checkvdo.py | 6 ++--
.../actors/nisscanner/libraries/nisscan.py | 6 ++--
.../libraries/opensslconfigcheck.py | 3 +-
25 files changed, 81 insertions(+), 55 deletions(-)
diff --git a/.pylintrc b/.pylintrc
index 7a373e3d..0cba1129 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -9,23 +9,19 @@ disable=
raising-bad-type,
redundant-keyword-arg, # it's one or the other, this one is not so bad at all
# "W" Warnings for stylistic problems or minor programming issues
- no-absolute-import,
arguments-differ,
cell-var-from-loop,
fixme,
lost-exception,
- no-init,
pointless-string-statement,
protected-access,
redefined-outer-name,
- relative-import,
undefined-loop-variable,
unsubscriptable-object,
unused-argument,
unused-import,
unspecified-encoding,
# "C" Coding convention violations
- bad-continuation,
missing-docstring,
wrong-import-order,
use-maxsplit-arg,
@@ -33,7 +29,6 @@ disable=
consider-using-enumerate,
# "R" Refactor recommendations
duplicate-code,
- no-self-use,
too-few-public-methods,
too-many-branches,
too-many-locals,
@@ -42,10 +37,9 @@ disable=
use-list-literal,
use-dict-literal,
too-many-lines, # we do not want to take care about that one
- too-many-positional-arguments, # we cannot set yet max-possitional-arguments unfortunately
+ too-many-positional-arguments,
# new for python3 version of pylint
unnecessary-pass,
- bad-option-value, # python 2 doesn't have import-outside-toplevel, but in some case we need to import outside toplevel
super-with-arguments, # required in python 2
raise-missing-from, # no 'raise from' in python 2
use-a-generator, # cannot be modified because of Python2 support
diff --git a/commands/upgrade/breadcrumbs.py b/commands/upgrade/breadcrumbs.py
index 1a90c143..95a551c3 100644
--- a/commands/upgrade/breadcrumbs.py
+++ b/commands/upgrade/breadcrumbs.py
@@ -80,7 +80,8 @@ class _BreadCrumbs:
# even though it shouldn't though, just ignore it
pass
- def _commit_rhsm_facts(self):
+ @staticmethod
+ def _commit_rhsm_facts():
if runs_in_container():
return
cmd = ['/usr/sbin/subscription-manager', 'facts', '--update']
@@ -122,7 +123,8 @@ class _BreadCrumbs:
except OSError:
sys.stderr.write('WARNING: Could not write to /etc/migration-results\n')
- def _get_packages(self):
+ @staticmethod
+ def _get_packages():
cmd = ['/bin/bash', '-c', 'rpm -qa --queryformat="%{nevra} %{SIGPGP:pgpsig}\n" | grep -Ee "leapp|snactor"']
res = _call(cmd, lambda x, y: None, lambda x, y: None)
if res.get('exit_code', None) == 0:
@@ -131,7 +133,8 @@ class _BreadCrumbs:
for t in [line.strip().split(' ', 1) for line in res['stdout'].split('\n') if line.strip()]]
return []
- def _verify_leapp_pkgs(self):
+ @staticmethod
+ def _verify_leapp_pkgs():
if not os.environ.get('LEAPP_IPU_IN_PROGRESS'):
return []
upg_path = os.environ.get('LEAPP_IPU_IN_PROGRESS').split('to')
diff --git a/repos/system_upgrade/common/actors/checkmemory/libraries/checkmemory.py b/repos/system_upgrade/common/actors/checkmemory/libraries/checkmemory.py
index 808c9662..040b404b 100644
--- a/repos/system_upgrade/common/actors/checkmemory/libraries/checkmemory.py
+++ b/repos/system_upgrade/common/actors/checkmemory/libraries/checkmemory.py
@@ -34,8 +34,8 @@ def process():
if minimum_req_error:
title = 'Minimum memory requirements for RHEL {} are not met'.format(version.get_target_major_version())
summary = 'Memory detected: {} MiB, required: {} MiB'.format(
- int(minimum_req_error['detected'] / 1024), # noqa: W1619; pylint: disable=old-division
- int(minimum_req_error['minimal_req'] / 1024), # noqa: W1619; pylint: disable=old-division
+ int(minimum_req_error['detected'] / 1024),
+ int(minimum_req_error['minimal_req'] / 1024),
)
reporting.create_report([
reporting.Title(title),
diff --git a/repos/system_upgrade/common/actors/enablerhsmtargetrepos/tests/test_enablerhsmtargetrepos.py b/repos/system_upgrade/common/actors/enablerhsmtargetrepos/tests/test_enablerhsmtargetrepos.py
index f7b3f34a..dba38fff 100644
--- a/repos/system_upgrade/common/actors/enablerhsmtargetrepos/tests/test_enablerhsmtargetrepos.py
+++ b/repos/system_upgrade/common/actors/enablerhsmtargetrepos/tests/test_enablerhsmtargetrepos.py
@@ -17,7 +17,8 @@ def not_isolated_actions(raise_err=False):
def __init__(self, base_dir=None):
pass
- def call(self, cmd, **kwargs):
+ @staticmethod
+ def call(cmd, **kwargs):
commands_called.append((cmd, kwargs))
if raise_err:
raise_call_error()
diff --git a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/tests/test_mount_unit_generation.py b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/tests/test_mount_unit_generation.py
index 9d75a31d..8849ada9 100644
--- a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/tests/test_mount_unit_generation.py
+++ b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/tests/test_mount_unit_generation.py
@@ -249,7 +249,8 @@ def test_copy_units_mixed_content(monkeypatch):
def __init__(self):
self.base_dir = '/container'
- def full_path(self, path):
+ @staticmethod
+ def full_path(path):
return os.path.join('/container', path.lstrip('/'))
mock_container = MockedContainerContext()
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 3ad92167..f7e4a8af 100644
--- a/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/libraries/upgradeinitramfsgenerator.py
+++ b/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/libraries/upgradeinitramfsgenerator.py
@@ -271,7 +271,7 @@ def _get_fspace(path, convert_to_mibs=False, coefficient=1):
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 int(fspace_bytes / 1024 / 1024)
return fspace_bytes
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 185cd4f0..b96bf79f 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
@@ -257,7 +257,7 @@ class MockedGetFspace:
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
+ return int(self.space / 1024 / 1024)
@pytest.mark.parametrize('input_msgs,dracut_modules,kernel_modules', [
diff --git a/repos/system_upgrade/common/actors/kernelcmdlineconfig/tests/test_kernelcmdlineconfig.py b/repos/system_upgrade/common/actors/kernelcmdlineconfig/tests/test_kernelcmdlineconfig.py
index b7e51833..5b35bcd3 100644
--- a/repos/system_upgrade/common/actors/kernelcmdlineconfig/tests/test_kernelcmdlineconfig.py
+++ b/repos/system_upgrade/common/actors/kernelcmdlineconfig/tests/test_kernelcmdlineconfig.py
@@ -15,7 +15,7 @@ from leapp.models import InstalledTargetKernelInfo, KernelCmdlineArg, TargetKern
TARGET_KERNEL_NEVRA = 'kernel-core-1.2.3-4.x86_64.el8.x64_64'
-# pylint: disable=E501
+# pylint: disable=line-too-long
SAMPLE_KERNEL_ARGS = ('ro rootflags=subvol=root'
' resume=/dev/mapper/luks-2c0df999-81ec-4a35-a1f9-b93afee8c6ad'
' rd.luks.uuid=luks-90a6412f-c588-46ca-9118-5aca35943d25'
@@ -31,7 +31,7 @@ title="Fedora Linux (6.5.13-100.fc37.x86_64) 37 (Thirty Seven)"
id="a3018267cdd8451db7c77bb3e5b1403d-6.5.13-100.fc37.x86_64"
""" # noqa: E501
SAMPLE_GRUBBY_INFO_OUTPUT = TEMPLATE_GRUBBY_INFO_OUTPUT.format(SAMPLE_KERNEL_ARGS, SAMPLE_KERNEL_ROOT)
-# pylint: enable=E501
+# pylint: enable=line-too-long
class MockedRun:
diff --git a/repos/system_upgrade/common/actors/opensshpermitrootlogincheck/actor.py b/repos/system_upgrade/common/actors/opensshpermitrootlogincheck/actor.py
index 9c1a421c..98d329ab 100644
--- a/repos/system_upgrade/common/actors/opensshpermitrootlogincheck/actor.py
+++ b/repos/system_upgrade/common/actors/opensshpermitrootlogincheck/actor.py
@@ -55,7 +55,8 @@ class OpenSshPermitRootLoginCheck(Actor):
else:
api.current_logger().warning('Unknown source major version: {}'.format(get_source_major_version()))
- def process7to8(self, config):
+ @staticmethod
+ def process7to8(config):
# when the config was not modified, we can pass this check and let the
# rpm handle the configuration file update
if not config.modified:
@@ -112,7 +113,8 @@ class OpenSshPermitRootLoginCheck(Actor):
reporting.Groups([reporting.Groups.INHIBITOR])
] + COMMON_RESOURCES)
- def process8to9(self, config):
+ @staticmethod
+ def process8to9(config):
# RHEL8 default sshd configuration file is not modified: It will get replaced by rpm and
# root will no longer be able to connect through ssh. This will probably result in many
# false positives so it will have to be waived a lot
diff --git a/repos/system_upgrade/common/actors/persistentnetnamesdisable/actor.py b/repos/system_upgrade/common/actors/persistentnetnamesdisable/actor.py
index 1add3588..b0182982 100644
--- a/repos/system_upgrade/common/actors/persistentnetnamesdisable/actor.py
+++ b/repos/system_upgrade/common/actors/persistentnetnamesdisable/actor.py
@@ -18,7 +18,8 @@ class PersistentNetNamesDisable(Actor):
produces = (KernelCmdlineArg, Report)
tags = (FactsPhaseTag, IPUWorkflowTag)
- def ethX_count(self, interfaces):
+ @staticmethod
+ def ethX_count(interfaces):
ethX = re.compile('eth[0-9]+')
count = 0
@@ -27,7 +28,8 @@ class PersistentNetNamesDisable(Actor):
count = count + 1
return count
- def single_eth0(self, interfaces):
+ @staticmethod
+ def single_eth0(interfaces):
return len(interfaces) == 1 and interfaces[0].name == 'eth0'
def disable_persistent_naming(self):
diff --git a/repos/system_upgrade/common/actors/scaninstalledtargetkernelversion/libraries/scankernel.py b/repos/system_upgrade/common/actors/scaninstalledtargetkernelversion/libraries/scankernel.py
index c1cc69ee..35683cca 100644
--- a/repos/system_upgrade/common/actors/scaninstalledtargetkernelversion/libraries/scankernel.py
+++ b/repos/system_upgrade/common/actors/scaninstalledtargetkernelversion/libraries/scankernel.py
@@ -70,7 +70,7 @@ def get_boot_files_provided_by_kernel_pkg(kernel_nevra):
@suppress_deprecation(InstalledTargetKernelVersion)
def process():
- # pylint: disable=no-else-return - false positive
+ # pylint: disable=no-else-return # false positive
# TODO: should we take care about stuff of kernel-rt and kernel in the same
# time when both are present? or just one? currently, handle only one
# of these during the upgrade. kernel-rt has higher prio when original sys
diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py b/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
index 1e5b87b0..bb17d89a 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
@@ -50,7 +50,8 @@ class MockedMountingBase:
def __call__(self, **dummy_kwarg):
yield self
- def call(self, *args, **kwargs):
+ @staticmethod
+ def call(*args, **kwargs):
return {'stdout': ''}
def nspawn(self):
diff --git a/repos/system_upgrade/common/actors/trustedgpgkeysscanner/tests/test_trustedgpgkeys.py b/repos/system_upgrade/common/actors/trustedgpgkeysscanner/tests/test_trustedgpgkeys.py
index 7497c2a9..b8229d00 100644
--- a/repos/system_upgrade/common/actors/trustedgpgkeysscanner/tests/test_trustedgpgkeys.py
+++ b/repos/system_upgrade/common/actors/trustedgpgkeysscanner/tests/test_trustedgpgkeys.py
@@ -40,7 +40,7 @@ class MockedGetGpgFromFile:
self._data[fname] = fps
def get_files(self):
- return self._data.keys() # noqa: W1655; pylint: disable=dict-keys-not-iterating
+ return self._data.keys()
def __call__(self, fname):
return self._data.get(fname, [])
diff --git a/repos/system_upgrade/common/files/rhel_upgrade.py b/repos/system_upgrade/common/files/rhel_upgrade.py
index 4f76a61d..a5d7045b 100644
--- a/repos/system_upgrade/common/files/rhel_upgrade.py
+++ b/repos/system_upgrade/common/files/rhel_upgrade.py
@@ -49,7 +49,8 @@ class RhelUpgradeCommand(dnf.cli.Command):
metavar="[%s]" % "|".join(CMDS))
parser.add_argument('filename')
- def _process_entities(self, entities, op, entity_name):
+ @staticmethod
+ def _process_entities(entities, op, entity_name):
"""
Adds list of packages for given operation to the transaction
"""
@@ -73,7 +74,8 @@ class RhelUpgradeCommand(dnf.cli.Command):
with open(self.opts.filename, 'w+') as fo:
json.dump(self.plugin_data, fo, sort_keys=True, indent=2)
- def _read_aws_region(self, repo):
+ @staticmethod
+ def _read_aws_region(repo):
region = None
if repo.baseurl:
# baseurl is tuple (changed by Amazon-id plugin)
@@ -86,7 +88,8 @@ class RhelUpgradeCommand(dnf.cli.Command):
sys.exit(1)
return region
- def _fix_rhui_url(self, repo, region):
+ @staticmethod
+ def _fix_rhui_url(repo, region):
if repo.baseurl:
repo.baseurl = tuple(
url.replace('REGION', region, 1) for url in repo.baseurl
diff --git a/repos/system_upgrade/common/libraries/dnfplugin.py b/repos/system_upgrade/common/libraries/dnfplugin.py
index 4f0c3a99..1af52dc5 100644
--- a/repos/system_upgrade/common/libraries/dnfplugin.py
+++ b/repos/system_upgrade/common/libraries/dnfplugin.py
@@ -461,9 +461,10 @@ def perform_transaction_install(target_userspace_info, storage_info, used_repos,
@contextlib.contextmanager
def _prepare_perform(used_repos, target_userspace_info, xfs_info, storage_info, target_iso=None):
- # noqa: W0135; pylint: disable=contextmanager-generator-missing-cleanup
+ # noqa: W0135; pylint: disable=bad-option-value,contextmanager-generator-missing-cleanup
# NOTE(pstodulk): the pylint check is not valid in this case - finally is covered
# implicitly
+ # noqa: W0135
reserve_space = overlaygen.get_recommended_leapp_free_space(target_userspace_info.path)
with _prepare_transaction(used_repos=used_repos,
target_userspace_info=target_userspace_info
diff --git a/repos/system_upgrade/common/libraries/grub.py b/repos/system_upgrade/common/libraries/grub.py
index 71432371..77679d01 100644
--- a/repos/system_upgrade/common/libraries/grub.py
+++ b/repos/system_upgrade/common/libraries/grub.py
@@ -34,7 +34,6 @@ class EFIBootLoaderEntry:
"""
Representation of an UEFI boot loader entry.
"""
- # pylint: disable=eq-without-hash
def __init__(self, boot_number, label, active, efi_bin_source):
self.boot_number = boot_number
@@ -163,7 +162,8 @@ class EFIBootInfo:
# it's not expected that no entry exists
raise StopActorExecution('UEFI: Unable to detect any UEFI bootloader entry.')
- def _parse_key_value(self, bootmgr_output, key):
+ @staticmethod
+ def _parse_key_value(bootmgr_output, key):
# e.g.: <key>: <value>
for line in bootmgr_output.splitlines():
if line.startswith(key + ':'):
diff --git a/repos/system_upgrade/common/libraries/mounting.py b/repos/system_upgrade/common/libraries/mounting.py
index 4e99e31e..ae3885cf 100644
--- a/repos/system_upgrade/common/libraries/mounting.py
+++ b/repos/system_upgrade/common/libraries/mounting.py
@@ -66,7 +66,8 @@ class IsolationType:
""" Release the isolation context """
pass
- def make_command(self, cmd):
+ @staticmethod
+ def make_command(cmd):
""" Transform the given command to the isolated environment """
return cmd
diff --git a/repos/system_upgrade/common/libraries/overlaygen.py b/repos/system_upgrade/common/libraries/overlaygen.py
index a048af2b..83dc33b8 100644
--- a/repos/system_upgrade/common/libraries/overlaygen.py
+++ b/repos/system_upgrade/common/libraries/overlaygen.py
@@ -185,7 +185,7 @@ def _get_fspace(path, convert_to_mibs=False, coefficient=1):
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 int(fspace_bytes / 1024 / 1024)
return fspace_bytes
@@ -325,7 +325,7 @@ def _prepare_required_mounts(scratch_dir, mounts_dir, storage_info, scratch_rese
@contextlib.contextmanager
def _build_overlay_mount(root_mount, mounts):
- # noqa: W0135; pylint: disable=contextmanager-generator-missing-cleanup
+ # noqa: W0135; pylint: disable=bad-option-value,contextmanager-generator-missing-cleanup
# NOTE(pstodulk): the pylint check is not valid in this case - finally is covered
# implicitly
if not root_mount:
@@ -480,8 +480,8 @@ def _create_mount_disk_image(disk_images_directory, path, disk_size):
# NOTE(pstodulk): In case the formatting params are modified,
# the minimal required size could be different
api.current_logger().warning(
- 'The apparent size for the disk image representing {path}'
- ' is too small ({disk_size} MiBs) for a formatting. Setting 130 MiBs instead.'
+ 'The apparent size for the disk image representing {path} '
+ 'is too small ({disk_size} MiBs) for a formatting. Setting 130 MiBs instead.'
.format(path=path, disk_size=disk_size)
)
disk_size = 130
@@ -489,12 +489,11 @@ def _create_mount_disk_image(disk_images_directory, path, disk_size):
cmd = [
'/bin/dd',
'if=/dev/zero', 'of={}'.format(diskimage_path),
- 'bs=1M', 'count=0', 'seek={}'.format(disk_size)
+ 'bs=1M', 'count=0', 'seek={}'.format(disk_size),
]
hint = (
'Please ensure that there is enough diskspace on the partition hosting'
- 'the {} directory.'
- .format(disk_images_directory)
+ 'the {} directory.'.format(disk_images_directory)
)
api.current_logger().debug('Attempting to create disk image at %s', diskimage_path)
@@ -540,7 +539,9 @@ def _create_mounts_dir(scratch_dir, mounts_dir):
utils.makedirs(mounts_dir)
api.current_logger().debug('Done creating mount directories.')
except OSError:
- api.current_logger().error('Failed to create mounting directories %s', mounts_dir, exc_info=True)
+ api.current_logger().error(
+ 'Failed to create mounting directories %s', mounts_dir, exc_info=True
+ )
# This is an attempt for giving the user a chance to resolve it on their own
raise StopActorExecutionError(
@@ -556,17 +557,25 @@ def _mount_dnf_cache(overlay_target):
"""
Convenience context manager to ensure bind mounted /var/cache/dnf and removal of the mount.
"""
- # noqa: W0135; pylint: disable=contextmanager-generator-missing-cleanup
+ # noqa: W0135; pylint: disable=bad-option-value,contextmanager-generator-missing-cleanup
# NOTE(pstodulk): the pylint check is not valid in this case - finally is covered
# implicitly
with mounting.BindMount(
- source='/var/cache/dnf',
- target=os.path.join(overlay_target, 'var', 'cache', 'dnf')) as cache_mount:
+ source='/var/cache/dnf',
+ target=os.path.join(overlay_target, 'var', 'cache', 'dnf'),
+ ) as cache_mount:
yield cache_mount
@contextlib.contextmanager
-def create_source_overlay(mounts_dir, scratch_dir, xfs_info, storage_info, mount_target=None, scratch_reserve=0):
+def create_source_overlay(
+ mounts_dir,
+ scratch_dir,
+ xfs_info,
+ storage_info,
+ mount_target=None,
+ scratch_reserve=0,
+):
"""
Context manager that prepares the source system overlay and yields the mount.
@@ -610,7 +619,7 @@ def create_source_overlay(mounts_dir, scratch_dir, xfs_info, storage_info, mount
:type scratch_reserve: Optional[int]
:rtype: mounting.BindMount or mounting.NullMount
"""
- # noqa: W0135; pylint: disable=contextmanager-generator-missing-cleanup
+ # noqa: W0135; pylint: disable=bad-option-value,contextmanager-generator-missing-cleanup
# NOTE(pstodulk): the pylint check is not valid in this case - finally is covered
# implicitly
api.current_logger().debug('Creating source overlay in {scratch_dir} with mounts in {mounts_dir}'.format(
diff --git a/repos/system_upgrade/common/libraries/tests/test_distro.py b/repos/system_upgrade/common/libraries/tests/test_distro.py
index 8e866455..13e782e6 100644
--- a/repos/system_upgrade/common/libraries/tests/test_distro.py
+++ b/repos/system_upgrade/common/libraries/tests/test_distro.py
@@ -168,7 +168,8 @@ def test_get_distro_repoids(
monkeypatch.setattr(os.path, 'exists', lambda f: f in _CENTOS_REPOFILES)
class MockedContext:
- def full_path(self, path):
+ @staticmethod
+ def full_path(path):
return path
repoids = get_distro_repoids(MockedContext(), distro_id, '9', 'x86_64')
diff --git a/repos/system_upgrade/common/libraries/tests/test_grub.py b/repos/system_upgrade/common/libraries/tests/test_grub.py
index d6f428bb..08dc6895 100644
--- a/repos/system_upgrade/common/libraries/tests/test_grub.py
+++ b/repos/system_upgrade/common/libraries/tests/test_grub.py
@@ -23,7 +23,7 @@ INVALID_DD = b'Nothing to see here!'
CUR_DIR = os.path.dirname(os.path.abspath(__file__))
-# pylint: disable=E501
+# pylint: disable=line-too-long
# flake8: noqa: E501
EFIBOOTMGR_OUTPUT = r"""
BootCurrent: 0006
diff --git a/repos/system_upgrade/common/libraries/tests/test_rhsm.py b/repos/system_upgrade/common/libraries/tests/test_rhsm.py
index 84a1bd5e..b118da29 100644
--- a/repos/system_upgrade/common/libraries/tests/test_rhsm.py
+++ b/repos/system_upgrade/common/libraries/tests/test_rhsm.py
@@ -73,7 +73,8 @@ class IsolatedActionsMocked:
# A map from called commands to their mocked output
self.mocked_command_call_outputs = dict()
- def is_isolated(self):
+ @staticmethod
+ def is_isolated():
return True
def call(self, cmd, *args, **dummy_kwargs):
@@ -93,7 +94,8 @@ class IsolatedActionsMocked:
'exit_code': exit_code
}
- def full_path(self, path):
+ @staticmethod
+ def full_path(path):
return path
def remove(self, path):
diff --git a/repos/system_upgrade/common/libraries/testutils.py b/repos/system_upgrade/common/libraries/testutils.py
index 328a7ede..e84cc03a 100644
--- a/repos/system_upgrade/common/libraries/testutils.py
+++ b/repos/system_upgrade/common/libraries/testutils.py
@@ -120,7 +120,7 @@ class CurrentActorMocked: # pylint:disable=R0904
return os.path.join(self._common_tools_folder, name)
def consume(self, model):
- return iter(filter( # pylint:disable=W0110,W1639
+ return iter(filter(
lambda msg: isinstance(msg, model), self._msgs
))
diff --git a/repos/system_upgrade/el8toel9/actors/checkvdo/tests/unit_test_checkvdo.py b/repos/system_upgrade/el8toel9/actors/checkvdo/tests/unit_test_checkvdo.py
index 865e036f..d7cfb4fb 100644
--- a/repos/system_upgrade/el8toel9/actors/checkvdo/tests/unit_test_checkvdo.py
+++ b/repos/system_upgrade/el8toel9/actors/checkvdo/tests/unit_test_checkvdo.py
@@ -15,13 +15,15 @@ from leapp.utils.report import is_inhibitor
# Mock actor base for CheckVdo tests.
class MockedActorCheckVdo(CurrentActorMocked):
- def get_vdo_answer(self):
+ @staticmethod
+ def get_vdo_answer():
return False
# Mock actor for all_vdo_converted dialog response.
class MockedActorAllVdoConvertedTrue(MockedActorCheckVdo):
- def get_vdo_answer(self):
+ @staticmethod
+ def get_vdo_answer():
return True
diff --git a/repos/system_upgrade/el8toel9/actors/nisscanner/libraries/nisscan.py b/repos/system_upgrade/el8toel9/actors/nisscanner/libraries/nisscan.py
index 9910f748..ae51c69d 100644
--- a/repos/system_upgrade/el8toel9/actors/nisscanner/libraries/nisscan.py
+++ b/repos/system_upgrade/el8toel9/actors/nisscanner/libraries/nisscan.py
@@ -14,7 +14,8 @@ class NISScanLibrary:
Helper library for NISScan actor.
"""
- def client_has_non_default_configuration(self):
+ @staticmethod
+ def client_has_non_default_configuration():
"""
Check for any significant ypbind configuration lines in .conf file.
"""
@@ -31,7 +32,8 @@ class NISScanLibrary:
return True
return False
- def server_has_non_default_configuration(self):
+ @staticmethod
+ def server_has_non_default_configuration():
"""
Check for any additional (not default) files in ypserv DIR.
"""
diff --git a/repos/system_upgrade/el8toel9/actors/opensslconfigcheck/libraries/opensslconfigcheck.py b/repos/system_upgrade/el8toel9/actors/opensslconfigcheck/libraries/opensslconfigcheck.py
index f36a62e1..07c1b22f 100644
--- a/repos/system_upgrade/el8toel9/actors/opensslconfigcheck/libraries/opensslconfigcheck.py
+++ b/repos/system_upgrade/el8toel9/actors/opensslconfigcheck/libraries/opensslconfigcheck.py
@@ -115,7 +115,8 @@ def _openssl_reachable_key(config, key, value=None):
return False
-# pylint: disable=too-many-return-statements -- could not simplify more
+# pylint: disable=too-many-return-statements
+# could not simplify more
def _openssl_reachable_path(config, path, value=None):
"""
Check if the given path is reachable in OpenSSL configuration
--
2.51.1

View File

@ -1,182 +0,0 @@
From 2abc41bb019a0ebef73e48f2a50990d8e5038e51 Mon Sep 17 00:00:00 2001
From: Tomas Fratrik <tfratrik@redhat.com>
Date: Mon, 18 Aug 2025 15:16:36 +0200
Subject: [PATCH 41/55] pylint: enable super-with-arguments
Jira: RHELMISC-16038
---
.pylintrc | 1 -
.../unit_test_applytransactionworkarounds.py | 2 +-
.../common/files/rhel_upgrade.py | 4 +--
.../common/libraries/mounting.py | 28 +++++++++++--------
.../common/libraries/repofileutils.py | 2 +-
5 files changed, 20 insertions(+), 17 deletions(-)
diff --git a/.pylintrc b/.pylintrc
index 0cba1129..4cfc49e0 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -40,7 +40,6 @@ disable=
too-many-positional-arguments,
# new for python3 version of pylint
unnecessary-pass,
- super-with-arguments, # required in python 2
raise-missing-from, # no 'raise from' in python 2
use-a-generator, # cannot be modified because of Python2 support
consider-using-f-string, # sorry, not gonna happen, still have to support py2
diff --git a/repos/system_upgrade/common/actors/applytransactionworkarounds/tests/unit_test_applytransactionworkarounds.py b/repos/system_upgrade/common/actors/applytransactionworkarounds/tests/unit_test_applytransactionworkarounds.py
index 369514fc..96b8094f 100644
--- a/repos/system_upgrade/common/actors/applytransactionworkarounds/tests/unit_test_applytransactionworkarounds.py
+++ b/repos/system_upgrade/common/actors/applytransactionworkarounds/tests/unit_test_applytransactionworkarounds.py
@@ -7,7 +7,7 @@ from leapp.models import DNFWorkaround
class ShowMessageCurrentActorMocked(CurrentActorMocked):
def __init__(self, *args, **kwargs):
- super(ShowMessageCurrentActorMocked, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
self._show_messages = []
@property
diff --git a/repos/system_upgrade/common/files/rhel_upgrade.py b/repos/system_upgrade/common/files/rhel_upgrade.py
index a5d7045b..63910fe0 100644
--- a/repos/system_upgrade/common/files/rhel_upgrade.py
+++ b/repos/system_upgrade/common/files/rhel_upgrade.py
@@ -40,7 +40,7 @@ class RhelUpgradeCommand(dnf.cli.Command):
summary = 'Plugin for upgrading to the next RHEL major release'
def __init__(self, cli):
- super(RhelUpgradeCommand, self).__init__(cli)
+ super().__init__(cli)
self.plugin_data = {}
@staticmethod
@@ -225,6 +225,6 @@ class RhelUpgradePlugin(dnf.Plugin):
name = 'rhel-upgrade'
def __init__(self, base, cli):
- super(RhelUpgradePlugin, self).__init__(base, cli)
+ super().__init__(base, cli)
if cli:
cli.register_command(RhelUpgradeCommand)
diff --git a/repos/system_upgrade/common/libraries/mounting.py b/repos/system_upgrade/common/libraries/mounting.py
index ae3885cf..279d31dc 100644
--- a/repos/system_upgrade/common/libraries/mounting.py
+++ b/repos/system_upgrade/common/libraries/mounting.py
@@ -46,7 +46,7 @@ class MountError(Exception):
""" Exception that is thrown when a mount related operation failed """
def __init__(self, message, details):
- super(MountError, self).__init__(message)
+ super().__init__(message)
self.details = details
@@ -75,7 +75,7 @@ class IsolationType:
""" systemd-nspawn implementation """
def __init__(self, target, binds=(), env_vars=None):
- super(IsolationType.NSPAWN, self).__init__(target=target)
+ super().__init__(target=target)
self.binds = list(binds) + ALWAYS_BIND
self.env_vars = env_vars or get_all_envs()
@@ -98,7 +98,7 @@ class IsolationType:
""" chroot implementation """
def __init__(self, target):
- super(IsolationType.CHROOT, self).__init__(target)
+ super().__init__(target)
self.context = None
def create(self):
@@ -262,14 +262,14 @@ class ChrootActions(IsolatedActions):
""" Isolation with chroot """
def __init__(self, base_dir):
- super(ChrootActions, self).__init__(base_dir=base_dir, implementation=IsolationType.CHROOT)
+ super().__init__(base_dir=base_dir, implementation=IsolationType.CHROOT)
class NspawnActions(IsolatedActions):
""" Isolation with systemd-nspawn """
def __init__(self, base_dir, binds=(), env_vars=None):
- super(NspawnActions, self).__init__(
+ super().__init__(
base_dir=base_dir, implementation=IsolationType.NSPAWN, binds=binds, env_vars=env_vars)
@@ -278,7 +278,7 @@ class NotIsolatedActions(IsolatedActions):
_isolated = False
def __init__(self, base_dir):
- super(NotIsolatedActions, self).__init__(base_dir=base_dir, implementation=IsolationType.NONE)
+ super().__init__(base_dir=base_dir, implementation=IsolationType.NONE)
class MountConfig:
@@ -375,7 +375,7 @@ class NullMount(MountingBase):
""" This is basically a NoOp for compatibility with other mount operations, in case a mount is optional """
def __init__(self, target, config=MountConfig.AttachOnly):
- super(NullMount, self).__init__(source=target, target=target, mode=MountingMode.NONE, config=config)
+ super().__init__(source=target, target=target, mode=MountingMode.NONE, config=config)
def __enter__(self):
return self
@@ -388,21 +388,21 @@ class LoopMount(MountingBase):
""" Performs loop mounts """
def __init__(self, source, target, config=MountConfig.Mount):
- super(LoopMount, self).__init__(source=source, target=target, mode=MountingMode.LOOP, config=config)
+ super().__init__(source=source, target=target, mode=MountingMode.LOOP, config=config)
class BindMount(MountingBase):
""" Performs bind mounts """
def __init__(self, source, target, config=MountConfig.Mount):
- super(BindMount, self).__init__(source=source, target=target, mode=MountingMode.BIND, config=config)
+ super().__init__(source=source, target=target, mode=MountingMode.BIND, config=config)
class TypedMount(MountingBase):
""" Performs a typed mounts """
def __init__(self, fstype, source, target, config=MountConfig.Mount):
- super(TypedMount, self).__init__(source=source, target=target, mode=MountingMode.FSTYPE, config=config)
+ super().__init__(source=source, target=target, mode=MountingMode.FSTYPE, config=config)
self.fstype = fstype
def _mount_options(self):
@@ -416,8 +416,12 @@ class OverlayMount(MountingBase):
""" Performs an overlayfs mount """
def __init__(self, name, source, workdir, config=MountConfig.Mount):
- super(OverlayMount, self).__init__(source=source, target=os.path.join(workdir, name),
- mode=MountingMode.OVERLAY, config=config)
+ super().__init__(
+ source=source,
+ target=os.path.join(workdir, name),
+ mode=MountingMode.OVERLAY,
+ config=config
+ )
self._upper_dir = os.path.join(workdir, 'upper')
self._work_dir = os.path.join(workdir, 'work')
self.additional_directories = (self._upper_dir, self._work_dir)
diff --git a/repos/system_upgrade/common/libraries/repofileutils.py b/repos/system_upgrade/common/libraries/repofileutils.py
index cab3c42b..376473a4 100644
--- a/repos/system_upgrade/common/libraries/repofileutils.py
+++ b/repos/system_upgrade/common/libraries/repofileutils.py
@@ -16,7 +16,7 @@ class InvalidRepoDefinition(Exception):
def __init__(self, msg, repofile, repoid):
message = 'Invalid repository definition: {repoid} in: {repofile}: {msg}'.format(
repoid=repoid, repofile=repofile, msg=msg)
- super(InvalidRepoDefinition, self).__init__(message)
+ super().__init__(message)
self.repofile = repofile
self.repoid = repoid
--
2.51.1

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,203 +0,0 @@
From 215f307eeb1362e420ac08f528f9f11d6c1c974d Mon Sep 17 00:00:00 2001
From: Tomas Fratrik <tfratrik@redhat.com>
Date: Mon, 8 Sep 2025 08:10:13 +0200
Subject: [PATCH 42/55] pylint: enable use-a-generator
Comprehensions inside functions like any(), all(), max(), min(), or sum()
are unnecessary. Enabling this warning enforces using generator expressions
instead of full list/set comprehensions in these cases.
Jira: RHELMISC-16038
---
.pylintrc | 1 -
.../common/actors/checkluks/libraries/checkluks.py | 2 +-
.../actors/checksaphana/tests/test_checksaphana.py | 7 +++++--
.../tests/test_ddddload.py | 2 +-
.../tests/test_persistentnetnamesconfig.py | 2 +-
.../libraries/scandynamiclinkerconfiguration.py | 2 +-
.../tests/test_checksystemdbrokensymlinks.py | 4 ++--
.../tests/test_transitionsystemdservicesstates.py | 6 ++----
.../tests/unit_test_targetuserspacecreator.py | 4 ++--
.../actors/rocecheck/tests/unit_test_rocecheck.py | 10 ++++++++--
10 files changed, 23 insertions(+), 17 deletions(-)
diff --git a/.pylintrc b/.pylintrc
index 4cfc49e0..a82f8818 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -41,7 +41,6 @@ disable=
# new for python3 version of pylint
unnecessary-pass,
raise-missing-from, # no 'raise from' in python 2
- use-a-generator, # cannot be modified because of Python2 support
consider-using-f-string, # sorry, not gonna happen, still have to support py2
logging-format-interpolation
diff --git a/repos/system_upgrade/common/actors/checkluks/libraries/checkluks.py b/repos/system_upgrade/common/actors/checkluks/libraries/checkluks.py
index d52b9e73..84e8e61f 100644
--- a/repos/system_upgrade/common/actors/checkluks/libraries/checkluks.py
+++ b/repos/system_upgrade/common/actors/checkluks/libraries/checkluks.py
@@ -27,7 +27,7 @@ def _formatted_list_output(input_list, sep=FMT_LIST_SEPARATOR):
def _at_least_one_tpm_token(luks_dump):
- return any([token.token_type == "clevis-tpm2" for token in luks_dump.tokens])
+ return any(token.token_type == "clevis-tpm2" for token in luks_dump.tokens)
def _get_ceph_volumes():
diff --git a/repos/system_upgrade/common/actors/checksaphana/tests/test_checksaphana.py b/repos/system_upgrade/common/actors/checksaphana/tests/test_checksaphana.py
index 29e9c930..8ec8d17f 100644
--- a/repos/system_upgrade/common/actors/checksaphana/tests/test_checksaphana.py
+++ b/repos/system_upgrade/common/actors/checksaphana/tests/test_checksaphana.py
@@ -284,7 +284,7 @@ def test_checksaphana_perform_check(monkeypatch):
# Expected 3 reports due to v1names + v2lownames + running
assert len(reports) == 3
# Verifies that all expected title patterns are within the reports and not just coincidentally 3
- assert all([any([pattern(report) for report in reports]) for pattern in EXPECTED_TITLE_PATTERNS.values()])
+ assert all(any(pattern(report) for report in reports) for pattern in EXPECTED_TITLE_PATTERNS.values())
list_clear(reports)
monkeypatch.setattr(checksaphana.api, 'consume', _consume_mock_sap_hana_info(
@@ -294,4 +294,7 @@ def test_checksaphana_perform_check(monkeypatch):
# Expected 2 reports due to v1names + v2lownames
assert len(reports) == 2
# Verifies that all expected title patterns are within the reports and not just coincidentally 2
- assert all([any([EXPECTED_TITLE_PATTERNS[pattern](report) for report in reports]) for pattern in ['v1', 'low']])
+ assert all(
+ any(EXPECTED_TITLE_PATTERNS[pattern](report) for report in reports)
+ for pattern in ['v1', 'low']
+ )
diff --git a/repos/system_upgrade/common/actors/loaddevicedriverdeprecationdata/tests/test_ddddload.py b/repos/system_upgrade/common/actors/loaddevicedriverdeprecationdata/tests/test_ddddload.py
index c3386745..1f3473b6 100644
--- a/repos/system_upgrade/common/actors/loaddevicedriverdeprecationdata/tests/test_ddddload.py
+++ b/repos/system_upgrade/common/actors/loaddevicedriverdeprecationdata/tests/test_ddddload.py
@@ -60,7 +60,7 @@ def test_filtered_load(monkeypatch):
assert produced
assert len(produced[0].entries) == 3
- assert not any([e.device_type == 'unsupported' for e in produced[0].entries])
+ assert not any(e.device_type == 'unsupported' for e in produced[0].entries)
@pytest.mark.parametrize('data', (
diff --git a/repos/system_upgrade/common/actors/persistentnetnamesconfig/tests/test_persistentnetnamesconfig.py b/repos/system_upgrade/common/actors/persistentnetnamesconfig/tests/test_persistentnetnamesconfig.py
index 5ad52c43..ee199ae4 100644
--- a/repos/system_upgrade/common/actors/persistentnetnamesconfig/tests/test_persistentnetnamesconfig.py
+++ b/repos/system_upgrade/common/actors/persistentnetnamesconfig/tests/test_persistentnetnamesconfig.py
@@ -177,7 +177,7 @@ def test_bz_1899455_crash_iface(monkeypatch, adjust_cwd):
for prod_models in [RenamedInterfaces, InitrdIncludes, TargetInitramfsTasks]:
any(isinstance(i, prod_models) for i in persistentnetnamesconfig.api.produce.model_instances)
- assert any(['Some network devices' in x for x in persistentnetnamesconfig.api.current_logger.warnmsg])
+ assert any('Some network devices' in x for x in persistentnetnamesconfig.api.current_logger.warnmsg)
def test_no_network_renaming(monkeypatch):
diff --git a/repos/system_upgrade/common/actors/scandynamiclinkerconfiguration/libraries/scandynamiclinkerconfiguration.py b/repos/system_upgrade/common/actors/scandynamiclinkerconfiguration/libraries/scandynamiclinkerconfiguration.py
index 8d3b473e..73b0c84e 100644
--- a/repos/system_upgrade/common/actors/scandynamiclinkerconfiguration/libraries/scandynamiclinkerconfiguration.py
+++ b/repos/system_upgrade/common/actors/scandynamiclinkerconfiguration/libraries/scandynamiclinkerconfiguration.py
@@ -113,5 +113,5 @@ def scan_dynamic_linker_configuration():
included_configs=included_config_files,
used_variables=used_variables)
- if other_lines or any([config.modified for config in included_config_files]) or used_variables:
+ if other_lines or any(config.modified for config in included_config_files) or used_variables:
api.produce(configuration)
diff --git a/repos/system_upgrade/common/actors/systemd/checksystemdbrokensymlinks/tests/test_checksystemdbrokensymlinks.py b/repos/system_upgrade/common/actors/systemd/checksystemdbrokensymlinks/tests/test_checksystemdbrokensymlinks.py
index bcc33f13..a4c0a657 100644
--- a/repos/system_upgrade/common/actors/systemd/checksystemdbrokensymlinks/tests/test_checksystemdbrokensymlinks.py
+++ b/repos/system_upgrade/common/actors/systemd/checksystemdbrokensymlinks/tests/test_checksystemdbrokensymlinks.py
@@ -20,7 +20,7 @@ def test_report_broken_symlinks(monkeypatch):
checksystemdbrokensymlinks._report_broken_symlinks(symlinks)
assert created_reports.called
- assert all([s in created_reports.report_fields['summary'] for s in symlinks])
+ assert all(s in created_reports.report_fields['summary'] for s in symlinks)
def test_report_enabled_services_broken_symlinks(monkeypatch):
@@ -35,7 +35,7 @@ def test_report_enabled_services_broken_symlinks(monkeypatch):
checksystemdbrokensymlinks._report_enabled_services_broken_symlinks(symlinks)
assert created_reports.called
- assert all([s in created_reports.report_fields['summary'] for s in symlinks])
+ assert all(s in created_reports.report_fields['summary'] for s in symlinks)
class ReportBrokenSymlinks:
diff --git a/repos/system_upgrade/common/actors/systemd/transitionsystemdservicesstates/tests/test_transitionsystemdservicesstates.py b/repos/system_upgrade/common/actors/systemd/transitionsystemdservicesstates/tests/test_transitionsystemdservicesstates.py
index 6964a65b..488b37d4 100644
--- a/repos/system_upgrade/common/actors/systemd/transitionsystemdservicesstates/tests/test_transitionsystemdservicesstates.py
+++ b/repos/system_upgrade/common/actors/systemd/transitionsystemdservicesstates/tests/test_transitionsystemdservicesstates.py
@@ -205,9 +205,7 @@ def test_report_kept_enabled(monkeypatch, tasks, expect_extended_summary):
assert created_reports.called
if expect_extended_summary:
assert extended_summary_str in created_reports.report_fields["summary"]
- assert all(
- [s in created_reports.report_fields["summary"] for s in tasks.to_enable]
- )
+ all(s in created_reports.report_fields['summary'] for s in tasks.to_enable)
else:
assert extended_summary_str not in created_reports.report_fields["summary"]
@@ -238,7 +236,7 @@ def test_report_newly_enabled(monkeypatch):
transitionsystemdservicesstates._report_newly_enabled(newly_enabled)
assert created_reports.called
- assert all([s in created_reports.report_fields["summary"] for s in newly_enabled])
+ assert all(s in created_reports.report_fields["summary"] for s in newly_enabled)
@pytest.mark.parametrize(
diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py b/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
index bb17d89a..0bb64f6f 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
@@ -1068,7 +1068,7 @@ def test_consume_data(monkeypatch, raised, no_rhsm, testdata):
assert raised[1] in err.value.message
else:
assert userspacegen.api.current_logger.warnmsg
- assert any([raised[1] in x for x in userspacegen.api.current_logger.warnmsg])
+ assert any(raised[1] in x for x in userspacegen.api.current_logger.warnmsg)
@pytest.mark.skip(reason="Currently not implemented in the actor. It's TODO.")
@@ -1390,7 +1390,7 @@ def test__get_files_owned_by_rpms_recursive(monkeypatch):
assert sorted(owned[0:4]) == sorted(out)
def has_dbgmsg(substr):
- return any([substr in log for log in logger.dbgmsg])
+ return any(substr in log for log in logger.dbgmsg)
# test a few
assert has_dbgmsg(
diff --git a/repos/system_upgrade/el8toel9/actors/rocecheck/tests/unit_test_rocecheck.py b/repos/system_upgrade/el8toel9/actors/rocecheck/tests/unit_test_rocecheck.py
index a36cc8ed..b5511d17 100644
--- a/repos/system_upgrade/el8toel9/actors/rocecheck/tests/unit_test_rocecheck.py
+++ b/repos/system_upgrade/el8toel9/actors/rocecheck/tests/unit_test_rocecheck.py
@@ -91,7 +91,10 @@ def test_roce_old_rhel(monkeypatch, msgs, version):
monkeypatch.setattr(reporting, "create_report", create_report_mocked())
rocecheck.process()
assert reporting.create_report.called
- assert any(['version of RHEL' in report['title'] for report in reporting.create_report.reports])
+ assert any(
+ 'version of RHEL' in report['title']
+ for report in reporting.create_report.reports
+ )
# NOTE: what about the situation when net.naming-scheme is configured multiple times???
@@ -113,4 +116,7 @@ def test_roce_wrong_configuration(monkeypatch, msgs, version):
monkeypatch.setattr(reporting, "create_report", create_report_mocked())
rocecheck.process()
assert reporting.create_report.called
- assert any(['RoCE configuration' in report['title'] for report in reporting.create_report.reports])
+ assert any(
+ 'RoCE configuration' in report['title']
+ for report in reporting.create_report.reports
+ )
--
2.51.1

View File

@ -1,484 +0,0 @@
From adac307afff48ebbf4255edbd620ed29cbc9429e Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Thu, 21 Aug 2025 13:12:19 +0200
Subject: [PATCH 43/55] Set CurrentActorMocked src/dst version to 8->9 values
Currently, the default upgrade path is 7.8->8.1 which has been dropped
from the repo. Several tests make assumptions about these defaults and in
some cases this means that code path for other general upgrade paths
(8->9, 9->10) are left untested e.g. modify_userspace_for_livemode.
This patch changes the default path to 8.10->9.6.
Updated tests:
- checkrhui: assume 8->9 upgrade path
- setuptargetrepos: Update tests to assume 8->9 upg path.
- repairsystemdsymlinks: use 8->9 upgrade path instead of 7->8:
We need to mock some "installation changed" service as there is
*currently* none.
- checkmemory: assume 8->9 upgrade path
- peseventsscanner: assume 8->9 upgrade path
- lib/config: assume correct upgrade path
- persistentnetnamesconfig: use 8->9 upgrade path instead of 7->8
Jira: RHELMISC-16538
---
.../checkmemory/tests/test_checkmemory.py | 2 +-
.../tests/component_test_checkrhui.py | 20 +++---
.../libraries/persistentnetnamesconfig.py | 24 +++----
.../tests/test_persistentnetnamesconfig.py | 16 ++++-
.../tests/test_pes_event_scanner.py | 14 ++--
.../tests/test_setuptargetrepos.py | 68 +++++++++----------
.../libraries/repairsystemdsymlinks.py | 1 -
.../tests/test_repairsystemdsymlinks.py | 29 +++++---
.../libraries/config/tests/test_version.py | 2 +-
.../common/libraries/testutils.py | 2 +-
10 files changed, 98 insertions(+), 80 deletions(-)
diff --git a/repos/system_upgrade/common/actors/checkmemory/tests/test_checkmemory.py b/repos/system_upgrade/common/actors/checkmemory/tests/test_checkmemory.py
index a0bac0a9..79158dc6 100644
--- a/repos/system_upgrade/common/actors/checkmemory/tests/test_checkmemory.py
+++ b/repos/system_upgrade/common/actors/checkmemory/tests/test_checkmemory.py
@@ -21,7 +21,7 @@ def test_check_memory_high(monkeypatch):
def test_report(monkeypatch):
- title_msg = 'Minimum memory requirements for RHEL 8 are not met'
+ title_msg = 'Minimum memory requirements for RHEL 9 are not met'
monkeypatch.setattr(api, 'current_actor', CurrentActorMocked())
monkeypatch.setattr(api, 'consume', lambda x: iter([MemoryInfo(mem_total=129)]))
monkeypatch.setattr(reporting, "create_report", create_report_mocked())
diff --git a/repos/system_upgrade/common/actors/cloud/checkrhui/tests/component_test_checkrhui.py b/repos/system_upgrade/common/actors/cloud/checkrhui/tests/component_test_checkrhui.py
index 02ca352e..2e6f279e 100644
--- a/repos/system_upgrade/common/actors/cloud/checkrhui/tests/component_test_checkrhui.py
+++ b/repos/system_upgrade/common/actors/cloud/checkrhui/tests/component_test_checkrhui.py
@@ -279,10 +279,14 @@ class ExpectedAction(Enum):
)
def test_process(monkeypatch, extra_installed_pkgs, skip_rhsm, expected_action):
known_setups = {
- RHUIFamily('rhui-variant'): [
- mk_rhui_setup(clients={'src_pkg'}, os_version='7'),
- mk_rhui_setup(clients={'target_pkg'}, os_version='8', leapp_pkg='leapp_pkg',
- mandatory_files=[('file1', '/etc'), ('file2', '/var')]),
+ RHUIFamily("rhui-variant"): [
+ mk_rhui_setup(clients={"src_pkg"}, os_version="8"),
+ mk_rhui_setup(
+ clients={"target_pkg"},
+ os_version="9",
+ leapp_pkg="leapp_pkg",
+ mandatory_files=[("file1", "/etc"), ("file2", "/var")],
+ ),
]
}
@@ -291,7 +295,7 @@ def test_process(monkeypatch, extra_installed_pkgs, skip_rhsm, expected_action):
installed_rpms = InstalledRPM(items=installed_pkgs)
monkeypatch.setattr(api, 'produce', produce_mocked())
- actor = CurrentActorMocked(src_ver='7.9', msgs=[installed_rpms], config=_make_default_config(all_rhui_cfg))
+ actor = CurrentActorMocked(msgs=[installed_rpms], config=_make_default_config(all_rhui_cfg))
monkeypatch.setattr(api, 'current_actor', actor)
monkeypatch.setattr(reporting, 'create_report', create_report_mocked())
monkeypatch.setattr(rhsm, 'skip_rhsm', lambda: skip_rhsm)
@@ -318,12 +322,12 @@ def test_unknown_target_rhui_setup(monkeypatch, is_target_setup_known):
rhui_family = RHUIFamily('rhui-variant')
known_setups = {
rhui_family: [
- mk_rhui_setup(clients={'src_pkg'}, os_version='7'),
+ mk_rhui_setup(clients={'src_pkg'}, os_version='8'),
]
}
if is_target_setup_known:
- target_setup = mk_rhui_setup(clients={'target_pkg'}, os_version='8', leapp_pkg='leapp_pkg')
+ target_setup = mk_rhui_setup(clients={'target_pkg'}, os_version='9', leapp_pkg='leapp_pkg')
known_setups[rhui_family].append(target_setup)
installed_pkgs = {'zip', 'kernel-core', 'python', 'src_pkg', 'leapp_pkg'}
@@ -331,7 +335,7 @@ def test_unknown_target_rhui_setup(monkeypatch, is_target_setup_known):
installed_rpms = InstalledRPM(items=installed_pkgs)
monkeypatch.setattr(api, 'produce', produce_mocked())
- actor = CurrentActorMocked(src_ver='7.9', msgs=[installed_rpms], config=_make_default_config(all_rhui_cfg))
+ actor = CurrentActorMocked(msgs=[installed_rpms], config=_make_default_config(all_rhui_cfg))
monkeypatch.setattr(api, 'current_actor', actor)
monkeypatch.setattr(reporting, 'create_report', create_report_mocked())
monkeypatch.setattr(rhsm, 'skip_rhsm', lambda: True)
diff --git a/repos/system_upgrade/common/actors/persistentnetnamesconfig/libraries/persistentnetnamesconfig.py b/repos/system_upgrade/common/actors/persistentnetnamesconfig/libraries/persistentnetnamesconfig.py
index c90d13f2..189cd4d0 100644
--- a/repos/system_upgrade/common/actors/persistentnetnamesconfig/libraries/persistentnetnamesconfig.py
+++ b/repos/system_upgrade/common/actors/persistentnetnamesconfig/libraries/persistentnetnamesconfig.py
@@ -55,21 +55,21 @@ def process():
)
return
- rhel7_ifaces = next(api.consume(PersistentNetNamesFacts)).interfaces
- rhel8_ifaces = next(api.consume(PersistentNetNamesFactsInitramfs)).interfaces
+ source_ifaces = next(api.consume(PersistentNetNamesFacts)).interfaces
+ target_ifaces = next(api.consume(PersistentNetNamesFactsInitramfs)).interfaces
- rhel7_ifaces_map = {iface.mac: iface for iface in rhel7_ifaces}
- rhel8_ifaces_map = {iface.mac: iface for iface in rhel8_ifaces}
+ source_ifaces_map = {iface.mac: iface for iface in source_ifaces}
+ target_ifaces_map = {iface.mac: iface for iface in target_ifaces}
initrd_files = []
missing_ifaces = []
renamed_interfaces = []
- if rhel7_ifaces != rhel8_ifaces:
- for iface in rhel7_ifaces:
- rhel7_name = rhel7_ifaces_map[iface.mac].name
+ if source_ifaces != target_ifaces:
+ for iface in source_ifaces:
+ source_name = source_ifaces_map[iface.mac].name
try:
- rhel8_name = rhel8_ifaces_map[iface.mac].name
+ target_name = target_ifaces_map[iface.mac].name
except KeyError:
missing_ifaces.append(iface)
api.current_logger().warning(
@@ -80,13 +80,13 @@ def process():
)
continue
- if rhel7_name != rhel8_name and get_env('LEAPP_NO_NETWORK_RENAMING', '0') != '1':
- api.current_logger().warning('Detected interface rename {} -> {}.'.format(rhel7_name, rhel8_name))
+ if source_name != target_name and get_env('LEAPP_NO_NETWORK_RENAMING', '0') != '1':
+ api.current_logger().warning('Detected interface rename {} -> {}.'.format(source_name, target_name))
if re.search('eth[0-9]+', iface.name) is not None:
api.current_logger().warning('Interface named using eth prefix, refusing to generate link file')
- renamed_interfaces.append(RenamedInterface(**{'rhel7_name': rhel7_name,
- 'rhel8_name': rhel8_name}))
+ renamed_interfaces.append(RenamedInterface(**{'rhel7_name': source_name,
+ 'rhel8_name': target_name}))
continue
initrd_files.append(generate_link_file(iface))
diff --git a/repos/system_upgrade/common/actors/persistentnetnamesconfig/tests/test_persistentnetnamesconfig.py b/repos/system_upgrade/common/actors/persistentnetnamesconfig/tests/test_persistentnetnamesconfig.py
index ee199ae4..c584c7ea 100644
--- a/repos/system_upgrade/common/actors/persistentnetnamesconfig/tests/test_persistentnetnamesconfig.py
+++ b/repos/system_upgrade/common/actors/persistentnetnamesconfig/tests/test_persistentnetnamesconfig.py
@@ -12,7 +12,6 @@ from leapp.models import (
PCIAddress,
PersistentNetNamesFacts,
PersistentNetNamesFactsInitramfs,
- RenamedInterface,
RenamedInterfaces,
TargetInitramfsTasks
)
@@ -170,7 +169,12 @@ def test_bz_1899455_crash_iface(monkeypatch, adjust_cwd):
PersistentNetNamesFactsInitramfs.create(json_msgs["PersistentNetNamesFactsInitramfs"]),
]
monkeypatch.setattr(persistentnetnamesconfig, 'generate_link_file', generate_link_file_mocked)
- monkeypatch.setattr(persistentnetnamesconfig.api, 'current_actor', CurrentActorMocked(msgs=msgs))
+ monkeypatch.setattr(
+ persistentnetnamesconfig.api,
+ "current_actor",
+ # without this the actor exits early
+ CurrentActorMocked(msgs=msgs, envars={"LEAPP_DISABLE_NET_NAMING_SCHEMES": "1"}),
+ )
monkeypatch.setattr(persistentnetnamesconfig.api, 'current_logger', logger_mocked())
monkeypatch.setattr(persistentnetnamesconfig.api, 'produce', produce_mocked())
persistentnetnamesconfig.process()
@@ -194,7 +198,13 @@ def test_no_network_renaming(monkeypatch):
msgs = [PersistentNetNamesFacts(interfaces=interfaces)]
interfaces[0].name = 'changedinterfacename0'
msgs.append(PersistentNetNamesFactsInitramfs(interfaces=interfaces))
- mocked_actor = CurrentActorMocked(msgs=msgs, envars={'LEAPP_NO_NETWORK_RENAMING': '1'})
+ mocked_actor = CurrentActorMocked(
+ msgs=msgs,
+ envars={
+ "LEAPP_DISABLE_NET_NAMING_SCHEMES": "1",
+ "LEAPP_NO_NETWORK_RENAMING": "1",
+ },
+ )
monkeypatch.setattr(persistentnetnamesconfig.api, 'current_actor', mocked_actor)
monkeypatch.setattr(persistentnetnamesconfig.api, 'current_logger', logger_mocked())
monkeypatch.setattr(persistentnetnamesconfig.api, 'produce', produce_mocked())
diff --git a/repos/system_upgrade/common/actors/peseventsscanner/tests/test_pes_event_scanner.py b/repos/system_upgrade/common/actors/peseventsscanner/tests/test_pes_event_scanner.py
index 09a1e82d..f67f3840 100644
--- a/repos/system_upgrade/common/actors/peseventsscanner/tests/test_pes_event_scanner.py
+++ b/repos/system_upgrade/common/actors/peseventsscanner/tests/test_pes_event_scanner.py
@@ -325,18 +325,18 @@ def test_blacklisted_repoid_is_not_produced(monkeypatch):
Test that upgrade with a package that would be from a blacklisted repository on the target system does not remove
the package as it was already installed, however, the blacklisted repoid should not be produced.
"""
- installed_pkgs = {Package('pkg-a', 'blacklisted-rhel7', None), Package('pkg-b', 'repoid-rhel7', None)}
+ installed_pkgs = {Package('pkg-a', 'blacklisted-rhel8', None), Package('pkg-b', 'repoid-rhel8', None)}
events = [
- Event(1, Action.MOVED, {Package('pkg-b', 'repoid-rhel7', None)}, {Package('pkg-b', 'repoid-rhel8', None)},
- (8, 0), (8, 1), []),
- Event(2, Action.MOVED, {Package('pkg-a', 'repoid-rhel7', None)}, {Package('pkg-a', 'blacklisted-rhel8', None)},
- (8, 0), (8, 1), []),
+ Event(1, Action.MOVED, {Package('pkg-b', 'repoid-rhel8', None)}, {Package('pkg-b', 'repoid-rhel9', None)},
+ (9, 0), (9, 1), []),
+ Event(2, Action.MOVED, {Package('pkg-a', 'repoid-rhel8', None)}, {Package('pkg-a', 'blacklisted-rhel9', None)},
+ (9, 0), (9, 1), []),
]
monkeypatch.setattr(pes_events_scanner, 'get_installed_pkgs', lambda: installed_pkgs)
monkeypatch.setattr(pes_events_scanner, 'get_pes_events', lambda folder, filename: events)
monkeypatch.setattr(pes_events_scanner, 'apply_transaction_configuration', lambda pkgs, transaction_cfg: pkgs)
- monkeypatch.setattr(pes_events_scanner, 'get_blacklisted_repoids', lambda: {'blacklisted-rhel8'})
+ monkeypatch.setattr(pes_events_scanner, 'get_blacklisted_repoids', lambda: {'blacklisted-rhel9'})
monkeypatch.setattr(pes_events_scanner, 'replace_pesids_with_repoids_in_packages',
lambda pkgs, src_pkgs_repoids: pkgs)
@@ -357,7 +357,7 @@ def test_blacklisted_repoid_is_not_produced(monkeypatch):
repo_setup_tasks = [msg for msg in api.produce.model_instances if isinstance(msg, RepositoriesSetupTasks)]
assert len(repo_setup_tasks) == 1
- assert repo_setup_tasks[0].to_enable == ['repoid-rhel8']
+ assert repo_setup_tasks[0].to_enable == ['repoid-rhel9']
@pytest.mark.parametrize(
diff --git a/repos/system_upgrade/common/actors/setuptargetrepos/tests/test_setuptargetrepos.py b/repos/system_upgrade/common/actors/setuptargetrepos/tests/test_setuptargetrepos.py
index e4a30f7f..ce7f01c0 100644
--- a/repos/system_upgrade/common/actors/setuptargetrepos/tests/test_setuptargetrepos.py
+++ b/repos/system_upgrade/common/actors/setuptargetrepos/tests/test_setuptargetrepos.py
@@ -1,6 +1,5 @@
import pytest
-from leapp.libraries import stdlib
from leapp.libraries.actor import setuptargetrepos
from leapp.libraries.common.testutils import CurrentActorMocked, produce_mocked
from leapp.libraries.stdlib import api
@@ -15,8 +14,7 @@ from leapp.models import (
RepositoriesSetupTasks,
RepositoryData,
RepositoryFile,
- RPM,
- TargetRepositories
+ RPM
)
RH_PACKAGER = 'Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla>'
@@ -108,27 +106,27 @@ def test_repos_mapping_for_distro(monkeypatch, distro_id):
the RepositoriesMapping information for a specific distro.
"""
repos_data = [
- RepositoryData(repoid='{}-7-server-rpms'.format(distro_id), name='{} 7 Server'.format(distro_id)),
- RepositoryData(repoid='{}-7-blacklisted-rpms'.format(distro_id), name='{} 7 Blacklisted'.format(distro_id))]
+ RepositoryData(repoid='{}-8-server-rpms'.format(distro_id), name='{} 8 Server'.format(distro_id)),
+ RepositoryData(repoid='{}-8-blacklisted-rpms'.format(distro_id), name='{} 8 Blacklisted'.format(distro_id))]
repos_files = [RepositoryFile(file='/etc/yum.repos.d/redhat.repo', data=repos_data)]
facts = RepositoriesFacts(repositories=repos_files)
installed_rpms = InstalledRPM(
- items=[mock_package('foreman', '{}-7-for-x86_64-satellite-extras-rpms'.format(distro_id)),
- mock_package('foreman-proxy', 'nosuch-{}-7-for-x86_64-satellite-extras-rpms'.format(distro_id))])
+ items=[mock_package('foreman', '{}-8-for-x86_64-satellite-extras-rpms'.format(distro_id)),
+ mock_package('foreman-proxy', 'nosuch-{}-8-for-x86_64-satellite-extras-rpms'.format(distro_id))])
repomap = RepositoriesMapping(
- mapping=[RepoMapEntry(source='{0}7-base'.format(distro_id),
- target=['{0}8-baseos'.format(distro_id),
- '{0}8-appstream'.format(distro_id),
- '{0}8-blacklist'.format(distro_id)]),
- RepoMapEntry(source='{0}7-satellite-extras'.format(distro_id),
- target=['{0}8-satellite-extras'.format(distro_id)])],
+ mapping=[RepoMapEntry(source='{0}8-base'.format(distro_id),
+ target=['{0}9-baseos'.format(distro_id),
+ '{0}9-appstream'.format(distro_id),
+ '{0}9-blacklist'.format(distro_id)]),
+ RepoMapEntry(source='{0}8-satellite-extras'.format(distro_id),
+ target=['{0}9-satellite-extras'.format(distro_id)])],
repositories=[
PESIDRepositoryEntry(
- pesid='{0}7-base'.format(distro_id),
- repoid='{0}-7-server-rpms'.format(distro_id),
- major_version='7',
+ pesid='{0}8-base'.format(distro_id),
+ repoid='{0}-8-server-rpms'.format(distro_id),
+ major_version='8',
arch='x86_64',
repo_type='rpm',
channel='ga',
@@ -136,9 +134,9 @@ def test_repos_mapping_for_distro(monkeypatch, distro_id):
distro=distro_id,
),
PESIDRepositoryEntry(
- pesid='{0}8-baseos'.format(distro_id),
- repoid='{0}-8-for-x86_64-baseos-htb-rpms'.format(distro_id),
- major_version='8',
+ pesid='{0}9-baseos'.format(distro_id),
+ repoid='{0}-9-for-x86_64-baseos-htb-rpms'.format(distro_id),
+ major_version='9',
arch='x86_64',
repo_type='rpm',
channel='ga',
@@ -146,9 +144,9 @@ def test_repos_mapping_for_distro(monkeypatch, distro_id):
distro=distro_id,
),
PESIDRepositoryEntry(
- pesid='{0}8-appstream'.format(distro_id),
- repoid='{0}-8-for-x86_64-appstream-htb-rpms'.format(distro_id),
- major_version='8',
+ pesid='{0}9-appstream'.format(distro_id),
+ repoid='{0}-9-for-x86_64-appstream-htb-rpms'.format(distro_id),
+ major_version='9',
arch='x86_64',
repo_type='rpm',
channel='ga',
@@ -156,9 +154,9 @@ def test_repos_mapping_for_distro(monkeypatch, distro_id):
distro=distro_id,
),
PESIDRepositoryEntry(
- pesid='{0}8-blacklist'.format(distro_id),
- repoid='{0}-8-blacklisted-rpms'.format(distro_id),
- major_version='8',
+ pesid='{0}9-blacklist'.format(distro_id),
+ repoid='{0}-9-blacklisted-rpms'.format(distro_id),
+ major_version='9',
arch='x86_64',
repo_type='rpm',
channel='ga',
@@ -166,9 +164,9 @@ def test_repos_mapping_for_distro(monkeypatch, distro_id):
distro=distro_id,
),
PESIDRepositoryEntry(
- pesid='{0}7-satellite-extras'.format(distro_id),
- repoid='{0}-7-for-x86_64-satellite-extras-rpms'.format(distro_id),
- major_version='7',
+ pesid='{0}8-satellite-extras'.format(distro_id),
+ repoid='{0}-8-for-x86_64-satellite-extras-rpms'.format(distro_id),
+ major_version='8',
arch='x86_64',
repo_type='rpm',
channel='ga',
@@ -176,9 +174,9 @@ def test_repos_mapping_for_distro(monkeypatch, distro_id):
distro=distro_id,
),
PESIDRepositoryEntry(
- pesid='{0}8-satellite-extras'.format(distro_id),
- repoid='{0}-8-for-x86_64-satellite-extras-rpms'.format(distro_id),
- major_version='8',
+ pesid='{0}9-satellite-extras'.format(distro_id),
+ repoid='{0}-9-for-x86_64-satellite-extras-rpms'.format(distro_id),
+ major_version='9',
arch='x86_64',
repo_type='rpm',
channel='ga',
@@ -188,7 +186,7 @@ def test_repos_mapping_for_distro(monkeypatch, distro_id):
]
)
- repos_blacklisted = RepositoriesBlacklisted(repoids=['{}-8-blacklisted-rpms'.format(distro_id)])
+ repos_blacklisted = RepositoriesBlacklisted(repoids=['{}-9-blacklisted-rpms'.format(distro_id)])
msgs = [facts, repomap, repos_blacklisted, installed_rpms]
@@ -207,9 +205,9 @@ def test_repos_mapping_for_distro(monkeypatch, distro_id):
produced_rhel_repoids = {repo.repoid for repo in rhel_repos}
expected_repoids = {
- "{0}-8-for-x86_64-baseos-htb-rpms".format(distro_id),
- "{0}-8-for-x86_64-appstream-htb-rpms".format(distro_id),
- "{0}-8-for-x86_64-satellite-extras-rpms".format(distro_id),
+ "{0}-9-for-x86_64-baseos-htb-rpms".format(distro_id),
+ "{0}-9-for-x86_64-appstream-htb-rpms".format(distro_id),
+ "{0}-9-for-x86_64-satellite-extras-rpms".format(distro_id),
}
assert produced_distro_repoids == expected_repoids
diff --git a/repos/system_upgrade/common/actors/systemd/repairsystemdsymlinks/libraries/repairsystemdsymlinks.py b/repos/system_upgrade/common/actors/systemd/repairsystemdsymlinks/libraries/repairsystemdsymlinks.py
index 3fcf4aa6..a8e801b9 100644
--- a/repos/system_upgrade/common/actors/systemd/repairsystemdsymlinks/libraries/repairsystemdsymlinks.py
+++ b/repos/system_upgrade/common/actors/systemd/repairsystemdsymlinks/libraries/repairsystemdsymlinks.py
@@ -7,7 +7,6 @@ from leapp.libraries.stdlib import api, CalledProcessError, run
from leapp.models import SystemdBrokenSymlinksSource, SystemdBrokenSymlinksTarget, SystemdServicesInfoSource
_INSTALLATION_CHANGED = {
- '8': ['rngd.service', 'sysstat.service'],
'9': [],
'10': [],
}
diff --git a/repos/system_upgrade/common/actors/systemd/repairsystemdsymlinks/tests/test_repairsystemdsymlinks.py b/repos/system_upgrade/common/actors/systemd/repairsystemdsymlinks/tests/test_repairsystemdsymlinks.py
index 5771fc6c..d52abdfa 100644
--- a/repos/system_upgrade/common/actors/systemd/repairsystemdsymlinks/tests/test_repairsystemdsymlinks.py
+++ b/repos/system_upgrade/common/actors/systemd/repairsystemdsymlinks/tests/test_repairsystemdsymlinks.py
@@ -1,13 +1,8 @@
from leapp.libraries.actor import repairsystemdsymlinks
from leapp.libraries.common import systemd
-from leapp.libraries.common.testutils import CurrentActorMocked, logger_mocked
-from leapp.libraries.stdlib import api, CalledProcessError, run
-from leapp.models import (
- SystemdBrokenSymlinksSource,
- SystemdBrokenSymlinksTarget,
- SystemdServiceFile,
- SystemdServicesInfoSource
-)
+from leapp.libraries.common.testutils import CurrentActorMocked
+from leapp.libraries.stdlib import api
+from leapp.models import SystemdServiceFile, SystemdServicesInfoSource
class MockedSystemdCmd:
@@ -20,8 +15,16 @@ class MockedSystemdCmd:
def test_bad_symslinks(monkeypatch):
+ # there is no _INSTALLATION_CHANGED service on RHEL 8 and RHEL 9, but it's
+ # possible such service will be discovered and added in the future as it
+ # was on RHEL 7, so let's add such case
+ monkeypatch.setitem(
+ repairsystemdsymlinks._INSTALLATION_CHANGED,
+ "9", ["some.service"],
+ )
+
service_files = [
- SystemdServiceFile(name='rngd.service', state='enabled'),
+ SystemdServiceFile(name='some.service', state='enabled'),
SystemdServiceFile(name='sysstat.service', state='disabled'),
SystemdServiceFile(name='hello.service', state='enabled'),
SystemdServiceFile(name='world.service', state='disabled'),
@@ -36,11 +39,15 @@ def test_bad_symslinks(monkeypatch):
monkeypatch.setattr(systemd, 'reenable_unit', reenable_mocked)
service_info = SystemdServicesInfoSource(service_files=service_files)
- monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=[service_info]))
+ monkeypatch.setattr(
+ api,
+ "current_actor",
+ CurrentActorMocked(src_ver="8.10", dst_ver="9.6", msgs=[service_info]),
+ )
repairsystemdsymlinks._handle_bad_symlinks(service_info.service_files)
- assert reenable_mocked.units == ['rngd.service']
+ assert reenable_mocked.units == ['some.service']
def test_handle_newly_broken_symlink(monkeypatch):
diff --git a/repos/system_upgrade/common/libraries/config/tests/test_version.py b/repos/system_upgrade/common/libraries/config/tests/test_version.py
index d51f8098..f36dbc5f 100644
--- a/repos/system_upgrade/common/libraries/config/tests/test_version.py
+++ b/repos/system_upgrade/common/libraries/config/tests/test_version.py
@@ -94,7 +94,7 @@ def test_matches_source_version(monkeypatch, result, version_list):
(False, ['8.2', '8.0']),
])
def test_matches_target_version(monkeypatch, result, version_list):
- monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(src_ver='7.6'))
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(src_ver='7.6', dst_ver='8.1'))
assert version.matches_target_version(*version_list) == result
diff --git a/repos/system_upgrade/common/libraries/testutils.py b/repos/system_upgrade/common/libraries/testutils.py
index e84cc03a..107ad8a7 100644
--- a/repos/system_upgrade/common/libraries/testutils.py
+++ b/repos/system_upgrade/common/libraries/testutils.py
@@ -80,7 +80,7 @@ def _make_default_config(actor_config_schema):
class CurrentActorMocked: # pylint:disable=R0904
def __init__(self, arch=architecture.ARCH_X86_64, envars=None, # pylint:disable=R0913
kernel='3.10.0-957.43.1.el7.x86_64',
- release_id='rhel', src_ver='7.8', dst_ver='8.1', msgs=None, flavour='default', config=None,
+ release_id='rhel', src_ver='8.10', dst_ver='9.6', msgs=None, flavour='default', config=None,
virtual_source_version=None, virtual_target_version=None,
supported_upgrade_paths=None):
"""
--
2.51.1

View File

@ -0,0 +1,28 @@
From 6c205281850c28068edc7fc5ab453c65398b7054 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Fri, 30 May 2025 18:28:25 +0200
Subject: [PATCH 43/43] unit-tests: suppress deprecation warning for
is_rhel_alt()
The deprecation warning is not wanted in unit-tests. Supress it.
Signed-off-by: Petr Stodulka <pstodulk@redhat.com>
---
.../system_upgrade/common/libraries/config/tests/test_version.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/repos/system_upgrade/common/libraries/config/tests/test_version.py b/repos/system_upgrade/common/libraries/config/tests/test_version.py
index 420571c0..d51f8098 100644
--- a/repos/system_upgrade/common/libraries/config/tests/test_version.py
+++ b/repos/system_upgrade/common/libraries/config/tests/test_version.py
@@ -108,6 +108,7 @@ def test_matches_target_version(monkeypatch, result, version_list):
(False, '4.14.0-100.8.2.el8.x86_64', 'rhel', '8.1'),
(False, '4.14.0-100.8.2.el9.x86_64', 'rhel', '9.1'),
])
+@suppress_deprecation(version.is_rhel_alt)
def test_is_rhel_alt(monkeypatch, result, kernel, release_id, src_ver):
monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(src_ver=src_ver, kernel=kernel,
release_id=release_id))
--
2.49.0

View File

@ -0,0 +1,267 @@
From c7ea9fc29989a37071bf6355828328910b6b5e1d Mon Sep 17 00:00:00 2001
From: Daniel Diblik <ddiblik@redhat.com>
Date: Tue, 17 Jun 2025 15:21:15 +0200
Subject: [PATCH 44/66] Remove obsolete workflows
* tmt-tests.yml and reuse-copr-build.yml were replaced by the Packit
workflows ages ago
* removed the obsolete workflows
Signed-off-by: Daniel Diblik <ddiblik@redhat.com>
---
.github/workflows/reuse-copr-build.yml | 163 -------------------------
.github/workflows/tmt-tests.yml | 72 -----------
2 files changed, 235 deletions(-)
delete mode 100644 .github/workflows/reuse-copr-build.yml
delete mode 100644 .github/workflows/tmt-tests.yml
diff --git a/.github/workflows/reuse-copr-build.yml b/.github/workflows/reuse-copr-build.yml
deleted file mode 100644
index a772fb64..00000000
--- a/.github/workflows/reuse-copr-build.yml
+++ /dev/null
@@ -1,163 +0,0 @@
-name: reuse-copr-build@TF
-
-on:
- workflow_call:
- secrets:
- FEDORA_COPR_LOGIN:
- required: true
- FEDORA_COPR_TOKEN:
- required: true
- outputs:
- artifacts:
- description: "A string with test artifacts to install in tft test env"
- value: ${{ jobs.reusable_workflow_copr_build_job.outputs.artifacts }}
-
-jobs:
- reusable_workflow_copr_build_job:
- # This job only runs for '/rerun' pull request comments by owner, member, or collaborator of the repo/organization.
- name: Build copr builds for tft tests
- runs-on: ubuntu-24.04
- outputs:
- artifacts: ${{ steps.gen_artifacts.outputs.artifacts }}
- if: |
- github.event.issue.pull_request
- && startsWith(github.event.comment.body, '/rerun')
- && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
- steps:
- - name: Update repository
- id: repo_update
- run: sudo apt-get update
-
- - name: Install necessary deps
- id: deps_install
- run: sudo apt-get install -y libkrb5-dev
-
- - name: Get pull request number
- id: pr_nr
- run: |
- PR_URL="${{ github.event.comment.issue_url }}"
- echo "::set-output name=pr_nr::${PR_URL##*/}"
-
- - name: Checkout
- # TODO: The correct way to checkout would be to use similar approach as in get_commit_by_timestamp function of
- # the github gluetool module (i.e. do not use HEAD but the last commit before comment).
- id: checkout
- uses: actions/checkout@v4
- with:
- ref: "refs/pull/${{ steps.pr_nr.outputs.pr_nr }}/head"
-
- - name: Get ref and sha
- id: ref_sha
- run: |
- echo "::set-output name=sha::$(git rev-parse --short HEAD)"
- echo "::set-output name=ref::refs/pull/${{ steps.pr_nr.outputs.pr_nr }}/head"
-
- - name: Trigger copr build
- id: copr_build
- env:
- COPR_CONFIG: "copr_fedora.conf"
- COPR_CHROOT: "epel-8-x86_64"
- COPR_REPO: "@oamg/leapp"
- run: |
- cat << EOF > $COPR_CONFIG
- [copr-cli]
- login = ${{ secrets.FEDORA_COPR_LOGIN }}
- username = oamgbot
- token = ${{ secrets.FEDORA_COPR_TOKEN }}
- copr_url = https://copr.fedorainfracloud.org
- # expiration date: 2030-07-04
- EOF
-
- pip install copr-cli
- PR=${{ steps.pr_nr.outputs.pr_nr }} COPR_CONFIG=$COPR_CONFIG COPR_REPO="$COPR_REPO" COPR_CHROOT=$COPR_CHROOT make copr_build | tee copr.log
-
- COPR_URL=$(grep -Po 'https://copr.fedorainfracloud.org/coprs/build/\d+' copr.log)
- echo "::set-output name=copr_url::${COPR_URL}"
- echo "::set-output name=copr_id::${COPR_URL##*/}"
-
- - name: Add comment with copr build url
- # TODO: Create comment when copr build fails.
- id: link_copr
- uses: actions/github-script@v7
- with:
- script: |
- github.issues.createComment({
- issue_number: context.issue.number,
- owner: context.repo.owner,
- repo: context.repo.repo,
- body: 'Copr build succeeded: ${{ steps.copr_build.outputs.copr_url }}'
- })
-
- - name: Get dependent leapp pr number from rerun comment
- uses: actions-ecosystem/action-regex-match@v2
- id: leapp_pr_regex_match
- with:
- text: ${{ github.event.comment.body }}
- regex: '^/(rerun|rerun-sst)\s+([0-9]+)\s*$'
-
- - name: If leapp_pr was specified in the comment - trigger copr build
- # TODO: XXX FIXME This should schedule copr build for leapp but for now it will be just setting an env var
- id: leapp_pr
- if: ${{ steps.leapp_pr_regex_match.outputs.match != '' }}
- run: |
- echo "::set-output name=leapp_pr::${{ steps.leapp_pr_regex_match.outputs.group2 }}"
-
- - name: Checkout leapp
- id: checkout_leapp
- if: ${{ steps.leapp_pr_regex_match.outputs.match != '' }}
- uses: actions/checkout@v4
- with:
- repository: "oamg/leapp"
- ref: "refs/pull/${{ steps.leapp_pr.outputs.leapp_pr }}/head"
-
- - name: Get ref and sha for leapp
- id: ref_sha_leapp
- if: ${{ steps.leapp_pr_regex_match.outputs.match != '' }}
- run: |
- echo "::set-output name=sha::$(git rev-parse --short HEAD)"
- echo "::set-output name=ref::refs/pull/${{ steps.leapp_pr.outputs.leapp_pr }}/head"
-
- - name: Trigger copr build for leapp
- id: copr_build_leapp
- if: ${{ steps.leapp_pr_regex_match.outputs.match != '' }}
- env:
- COPR_CONFIG: "copr_fedora.conf"
- COPR_CHROOT: "epel-8-x86_64"
- COPR_REPO: "@oamg/leapp"
- run: |
- cat << EOF > $COPR_CONFIG
- [copr-cli]
- login = ${{ secrets.FEDORA_COPR_LOGIN }}
- username = oamgbot
- token = ${{ secrets.FEDORA_COPR_TOKEN }}
- copr_url = https://copr.fedorainfracloud.org
- # expiration date: 2030-07-04
- EOF
-
- pip install copr-cli
- PR=${{ steps.leapp_pr.outputs.leapp_pr }} COPR_CONFIG=$COPR_CONFIG COPR_REPO="$COPR_REPO" COPR_CHROOT=$COPR_CHROOT make copr_build | tee copr.log
-
- COPR_URL=$(grep -Po 'https://copr.fedorainfracloud.org/coprs/build/\d+' copr.log)
- echo "::set-output name=copr_url::${COPR_URL}"
- echo "::set-output name=copr_id::${COPR_URL##*/}"
-
- - name: Add comment with copr build url for leapp
- # TODO: Create comment when copr build fails.
- id: link_copr_leapp
- if: ${{ steps.leapp_pr_regex_match.outputs.match != '' }}
- uses: actions/github-script@v7
- with:
- script: |
- github.issues.createComment({
- issue_number: context.issue.number,
- owner: context.repo.owner,
- repo: context.repo.repo,
- body: 'Copr build succeeded: ${{ steps.copr_build_leapp.outputs.copr_url }}'
- })
-
- - name: Generate artifacts output
- id: gen_artifacts
- env:
- ARTIFACTS: ${{ steps.leapp_pr_regex_match.outputs.match != '' && format('{0};{1}', steps.copr_build_leapp.outputs.copr_id, steps.copr_build.outputs.copr_id) || steps.copr_build.outputs.copr_id }}
- run: |
- echo "::set-output name=artifacts::${{ env.ARTIFACTS }}"
diff --git a/.github/workflows/tmt-tests.yml b/.github/workflows/tmt-tests.yml
deleted file mode 100644
index c9f76ef7..00000000
--- a/.github/workflows/tmt-tests.yml
+++ /dev/null
@@ -1,72 +0,0 @@
-name: tmt@TF
-
-on:
- issue_comment:
- types:
- - created
-
-jobs:
- call_workflow_copr_build:
- uses: ./.github/workflows/reuse-copr-build.yml
- secrets: inherit
-
- call_workflow_tests_86to90_integration:
- needs: call_workflow_copr_build
- uses: oamg/leapp/.github/workflows/reuse-tests-8to9.yml@main
- secrets: inherit
- with:
- copr_artifacts: ${{ needs.call_workflow_copr_build.outputs.artifacts }}
- tmt_plan_regex: "^(?!.*max_sst)(.*tier1)"
- variables: 'SOURCE_RELEASE=8.6;TARGET_RELEASE=9.0;TARGET_KERNEL=el9;RHSM_REPOS=rhel-8-for-x86_64-appstream-eus-rpms,rhel-8-for-x86_64-baseos-eus-rpms;LEAPPDATA_BRANCH=upstream'
- pull_request_status_name: "8.6to9.0"
- if: |
- github.event.issue.pull_request
- && ! startsWith(github.event.comment.body, '/rerun-sst')
- && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
-
- call_workflow_tests_88to92_integration:
- needs: call_workflow_copr_build
- uses: oamg/leapp/.github/workflows/reuse-tests-8to9.yml@main
- secrets: inherit
- with:
- copr_artifacts: ${{ needs.call_workflow_copr_build.outputs.artifacts }}
- tmt_plan_regex: "^(?!.*max_sst)(.*tier1)"
- variables: 'SOURCE_RELEASE=8.8;TARGET_RELEASE=9.2;TARGET_KERNEL=el9;RHSM_REPOS=rhel-8-for-x86_64-appstream-rpms,rhel-8-for-x86_64-baseos-rpms;LEAPPDATA_BRANCH=upstream'
- compose: "RHEL-8.8.0-Nightly"
- pull_request_status_name: "8.8to9.2"
- tmt_context: "distro=rhel-8.8"
- if: |
- github.event.issue.pull_request
- && ! startsWith(github.event.comment.body, '/rerun-sst')
- && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
-
- call_workflow_tests_86to90_sst:
- needs: call_workflow_copr_build
- uses: oamg/leapp/.github/workflows/reuse-tests-8to9.yml@main
- secrets: inherit
- with:
- copr_artifacts: ${{ needs.call_workflow_copr_build.outputs.artifacts }}
- tmt_plan_regex: "^(?!.*tier[2-3].*)(.*max_sst.*)"
- variables: 'SOURCE_RELEASE=8.6;TARGET_RELEASE=9.0;TARGET_KERNEL=el9;RHSM_REPOS=rhel-8-for-x86_64-appstream-eus-rpms,rhel-8-for-x86_64-baseos-eus-rpms;LEAPPDATA_BRANCH=upstream'
- pull_request_status_name: "8to9-sst"
- update_pull_request_status: 'false'
- if: |
- github.event.issue.pull_request
- && startsWith(github.event.comment.body, '/rerun-sst')
- && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
-
- call_workflow_tests_86to90_aws:
- needs: call_workflow_copr_build
- uses: oamg/leapp/.github/workflows/reuse-tests-8to9.yml@main
- secrets: inherit
- with:
- copr_artifacts: ${{ needs.call_workflow_copr_build.outputs.artifacts }}
- tmt_plan_regex: "^(?!.*upgrade_plugin)(?!.*tier[2-3].*)(?!.*rhsm)(?!.*c2r)(?!.*sap)(?!.*7to8)(.*e2e)"
- compose: "RHEL-8.6-rhui"
- environment_settings: '{"provisioning": {"post_install_script": "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"}}'
- pull_request_status_name: "8to9-aws-e2e"
- variables: 'SOURCE_RELEASE=8.6;TARGET_RELEASE=9.0;TARGET_KERNEL=el9;RHSM_REPOS=rhel-8-for-x86_64-appstream-eus-rpms,rhel-8-for-x86_64-baseos-eus-rpms;RHUI=aws;LEAPPDATA_BRANCH=upstream'
- if: |
- github.event.issue.pull_request
- && ! startsWith(github.event.comment.body, '/rerun-sst')
- && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
--
2.50.1

View File

@ -1,303 +0,0 @@
From ad9b2ae552b6c36d78a445dbbcfcc179afd1d839 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Thu, 21 Aug 2025 14:23:55 +0200
Subject: [PATCH 44/55] scancpu: Remove non-JSON ("txt") lscpu output support
This was only used on RHEL 7.
- Remove txt test files
- Remove empty_field test - IIRC it's not possible to have and empty
field in JSON lscpu output, there would be null
---
.../actors/scancpu/libraries/scancpu.py | 11 ++---
.../scancpu/tests/files/{json => }/invalid | 0
.../tests/files/{json => }/lscpu_aarch64 | 0
.../tests/files/{json => }/lscpu_ppc64le | 0
.../tests/files/{json => }/lscpu_s390x | 0
.../tests/files/{json => }/lscpu_x86_64 | 0
.../scancpu/tests/files/txt/lscpu_aarch64 | 25 -----------
.../scancpu/tests/files/txt/lscpu_empty_field | 4 --
.../scancpu/tests/files/txt/lscpu_ppc64le | 15 -------
.../scancpu/tests/files/txt/lscpu_s390x | 26 ------------
.../scancpu/tests/files/txt/lscpu_x86_64 | 36 ----------------
.../actors/scancpu/tests/test_scancpu.py | 42 ++-----------------
12 files changed, 7 insertions(+), 152 deletions(-)
rename repos/system_upgrade/common/actors/scancpu/tests/files/{json => }/invalid (100%)
rename repos/system_upgrade/common/actors/scancpu/tests/files/{json => }/lscpu_aarch64 (100%)
rename repos/system_upgrade/common/actors/scancpu/tests/files/{json => }/lscpu_ppc64le (100%)
rename repos/system_upgrade/common/actors/scancpu/tests/files/{json => }/lscpu_s390x (100%)
rename repos/system_upgrade/common/actors/scancpu/tests/files/{json => }/lscpu_x86_64 (100%)
delete mode 100644 repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_aarch64
delete mode 100644 repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_empty_field
delete mode 100644 repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_ppc64le
delete mode 100644 repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_s390x
delete mode 100644 repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_x86_64
diff --git a/repos/system_upgrade/common/actors/scancpu/libraries/scancpu.py b/repos/system_upgrade/common/actors/scancpu/libraries/scancpu.py
index db3f92d4..ecc23349 100644
--- a/repos/system_upgrade/common/actors/scancpu/libraries/scancpu.py
+++ b/repos/system_upgrade/common/actors/scancpu/libraries/scancpu.py
@@ -2,17 +2,15 @@ import json
import re
from leapp.libraries.common.config import architecture
-from leapp.libraries.common.config.version import get_source_major_version
from leapp.libraries.stdlib import api, CalledProcessError, run
from leapp.models import CPUInfo, DetectedDeviceOrDriver, DeviceDriverDeprecationData
-LSCPU_NAME_VALUE = re.compile(r'^(?P<name>[^:]+):[^\S\n]+(?P<value>.+)\n?', flags=re.MULTILINE)
PPC64LE_MODEL = re.compile(r'\d+\.\d+ \(pvr (?P<family>[0-9a-fA-F]+) 0*[0-9a-fA-F]+\)')
-def _get_lscpu_output(output_json=False):
+def _get_lscpu_output():
try:
- result = run(['lscpu'] + (['-J'] if output_json else []))
+ result = run(['lscpu', '-J'])
return result.get('stdout', '')
except (OSError, CalledProcessError):
api.current_logger().debug('Executing `lscpu` failed', exc_info=True)
@@ -20,10 +18,7 @@ def _get_lscpu_output(output_json=False):
def _parse_lscpu_output():
- if get_source_major_version() == '7':
- return dict(LSCPU_NAME_VALUE.findall(_get_lscpu_output()))
-
- lscpu = _get_lscpu_output(output_json=True)
+ lscpu = _get_lscpu_output()
try:
parsed_json = json.loads(lscpu)
# The json contains one entry "lscpu" which is a list of dictionaries
diff --git a/repos/system_upgrade/common/actors/scancpu/tests/files/json/invalid b/repos/system_upgrade/common/actors/scancpu/tests/files/invalid
similarity index 100%
rename from repos/system_upgrade/common/actors/scancpu/tests/files/json/invalid
rename to repos/system_upgrade/common/actors/scancpu/tests/files/invalid
diff --git a/repos/system_upgrade/common/actors/scancpu/tests/files/json/lscpu_aarch64 b/repos/system_upgrade/common/actors/scancpu/tests/files/lscpu_aarch64
similarity index 100%
rename from repos/system_upgrade/common/actors/scancpu/tests/files/json/lscpu_aarch64
rename to repos/system_upgrade/common/actors/scancpu/tests/files/lscpu_aarch64
diff --git a/repos/system_upgrade/common/actors/scancpu/tests/files/json/lscpu_ppc64le b/repos/system_upgrade/common/actors/scancpu/tests/files/lscpu_ppc64le
similarity index 100%
rename from repos/system_upgrade/common/actors/scancpu/tests/files/json/lscpu_ppc64le
rename to repos/system_upgrade/common/actors/scancpu/tests/files/lscpu_ppc64le
diff --git a/repos/system_upgrade/common/actors/scancpu/tests/files/json/lscpu_s390x b/repos/system_upgrade/common/actors/scancpu/tests/files/lscpu_s390x
similarity index 100%
rename from repos/system_upgrade/common/actors/scancpu/tests/files/json/lscpu_s390x
rename to repos/system_upgrade/common/actors/scancpu/tests/files/lscpu_s390x
diff --git a/repos/system_upgrade/common/actors/scancpu/tests/files/json/lscpu_x86_64 b/repos/system_upgrade/common/actors/scancpu/tests/files/lscpu_x86_64
similarity index 100%
rename from repos/system_upgrade/common/actors/scancpu/tests/files/json/lscpu_x86_64
rename to repos/system_upgrade/common/actors/scancpu/tests/files/lscpu_x86_64
diff --git a/repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_aarch64 b/repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_aarch64
deleted file mode 100644
index 3b9619ef..00000000
--- a/repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_aarch64
+++ /dev/null
@@ -1,25 +0,0 @@
-Architecture: aarch64
-Byte Order: Little Endian
-CPU(s): 160
-On-line CPU(s) list: 0-159
-Thread(s) per core: 1
-Core(s) per socket: 80
-Socket(s): 2
-NUMA node(s): 4
-Vendor ID: ARM
-BIOS Vendor ID: Ampere(R)
-Model: 1
-Model name: Neoverse-N1
-BIOS Model name: Ampere(R) Altra(R) Processor
-Stepping: r3p1
-CPU max MHz: 3000.0000
-CPU min MHz: 1000.0000
-BogoMIPS: 50.00
-L1d cache: 64K
-L1i cache: 64K
-L2 cache: 1024K
-NUMA node0 CPU(s): 0-79
-NUMA node1 CPU(s): 80-159
-NUMA node2 CPU(s):
-NUMA node3 CPU(s):
-Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp ssbs
diff --git a/repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_empty_field b/repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_empty_field
deleted file mode 100644
index f830b7fe..00000000
--- a/repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_empty_field
+++ /dev/null
@@ -1,4 +0,0 @@
-Empyt 1:
-Empyt 2:
-Empyt 3:
-Flags: flag
diff --git a/repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_ppc64le b/repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_ppc64le
deleted file mode 100644
index 07d2ed65..00000000
--- a/repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_ppc64le
+++ /dev/null
@@ -1,15 +0,0 @@
-Architecture: ppc64le
-Byte Order: Little Endian
-CPU(s): 8
-On-line CPU(s) list: 0-7
-Thread(s) per core: 1
-Core(s) per socket: 1
-Socket(s): 8
-NUMA node(s): 1
-Model: 2.1 (pvr 004b 0201)
-Model name: POWER8E (raw), altivec supported
-Hypervisor vendor: KVM
-Virtualization type: para
-L1d cache: 64K
-L1i cache: 32K
-NUMA node0 CPU(s): 0-7
diff --git a/repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_s390x b/repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_s390x
deleted file mode 100644
index 2c0de9f9..00000000
--- a/repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_s390x
+++ /dev/null
@@ -1,26 +0,0 @@
-Architecture: s390x
-CPU op-mode(s): 32-bit, 64-bit
-Byte Order: Big Endian
-CPU(s): 4
-On-line CPU(s) list: 0-3
-Thread(s) per core: 1
-Core(s) per socket: 1
-Socket(s) per book: 1
-Book(s) per drawer: 1
-Drawer(s): 4
-NUMA node(s): 1
-Vendor ID: IBM/S390
-Machine type: 3931
-CPU dynamic MHz: 5200
-CPU static MHz: 5200
-BogoMIPS: 3331.00
-Hypervisor: KVM/Linux
-Hypervisor vendor: KVM
-Virtualization type: full
-Dispatching mode: horizontal
-L1d cache: 128K
-L1i cache: 128K
-L2 cache: 32768K
-L3 cache: 262144K
-NUMA node0 CPU(s): 0-3
-Flags: esan3 zarch stfle msa ldisp eimm dfp edat etf3eh highgprs te vx vxd vxe gs vxe2 vxp sort dflt vxp2 nnpa sie
diff --git a/repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_x86_64 b/repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_x86_64
deleted file mode 100644
index a1dc1035..00000000
--- a/repos/system_upgrade/common/actors/scancpu/tests/files/txt/lscpu_x86_64
+++ /dev/null
@@ -1,36 +0,0 @@
-Architecture: x86_64
-CPU op-mode(s): 32-bit, 64-bit
-Address sizes: 46 bits physical, 48 bits virtual
-Byte Order: Little Endian
-CPU(s): 48
-On-line CPU(s) list: 0-47
-Vendor ID: GenuineIntel
-Model name: Intel(R) Xeon(R) CPU E5-2670 v3 @ 2.30GHz
-CPU family: 6
-Model: 63
-Thread(s) per core: 2
-Core(s) per socket: 12
-Socket(s): 2
-Stepping: 2
-CPU(s) scaling MHz: 44%
-CPU max MHz: 3100.0000
-CPU min MHz: 1200.0000
-BogoMIPS: 4599.83
-Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm xsaveopt cqm_llc cqm_occup_llc dtherm ida arat pln pts md_clear flush_l1d
-Virtualization: VT-x
-L1d cache: 768 KiB (24 instances)
-L1i cache: 768 KiB (24 instances)
-L2 cache: 6 MiB (24 instances)
-L3 cache: 60 MiB (2 instances)
-NUMA node(s): 2
-NUMA node0 CPU(s): 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46
-NUMA node1 CPU(s): 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47
-Vulnerability Itlb multihit: KVM: Mitigation: VMX disabled
-Vulnerability L1tf: Mitigation; PTE Inversion; VMX conditional cache flushes, SMT vulnerable
-Vulnerability Mds: Mitigation; Clear CPU buffers; SMT vulnerable
-Vulnerability Meltdown: Mitigation; PTI
-Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl and seccomp
-Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization
-Vulnerability Spectre v2: Mitigation; Full generic retpoline, IBPB conditional, IBRS_FW, STIBP conditional, RSB filling
-Vulnerability Srbds: Not affected
-Vulnerability Tsx async abort: Not affected
diff --git a/repos/system_upgrade/common/actors/scancpu/tests/test_scancpu.py b/repos/system_upgrade/common/actors/scancpu/tests/test_scancpu.py
index be0802ba..3605ebe7 100644
--- a/repos/system_upgrade/common/actors/scancpu/tests/test_scancpu.py
+++ b/repos/system_upgrade/common/actors/scancpu/tests/test_scancpu.py
@@ -61,29 +61,20 @@ class mocked_get_cpuinfo:
def __init__(self, filename):
self.filename = filename
- def __call__(self, output_json=False):
+ def __call__(self):
"""
Return lines of the self.filename test file located in the files directory.
Those files contain /proc/cpuinfo content from several machines.
"""
-
- filename = self.filename
- if output_json:
- filename = os.path.join('json', filename)
- else:
- filename = os.path.join('txt', filename)
- filename = os.path.join(CUR_DIR, 'files', filename)
+ filename = os.path.join(CUR_DIR, 'files', self.filename)
with open(filename, 'r') as fp:
return '\n'.join(fp.read().splitlines())
@pytest.mark.parametrize("arch", ARCH_SUPPORTED)
-@pytest.mark.parametrize("version", ['7', '8'])
-def test_scancpu(monkeypatch, arch, version):
-
- monkeypatch.setattr('leapp.libraries.actor.scancpu.get_source_major_version', lambda: version)
+def test_scancpu(monkeypatch, arch):
mocked_cpuinfo = mocked_get_cpuinfo('lscpu_' + arch)
monkeypatch.setattr(scancpu, '_get_lscpu_output', mocked_cpuinfo)
@@ -106,34 +97,9 @@ def test_scancpu(monkeypatch, arch, version):
assert expected == produced
-def test_lscpu_with_empty_field(monkeypatch):
-
- def mocked_cpuinfo(*args, **kwargs):
- return mocked_get_cpuinfo('lscpu_empty_field')(output_json=False)
-
- monkeypatch.setattr(scancpu, '_get_lscpu_output', mocked_cpuinfo)
- monkeypatch.setattr(api, 'produce', produce_mocked())
- current_actor = CurrentActorMocked()
- monkeypatch.setattr(api, 'current_actor', current_actor)
-
- scancpu.process()
-
- expected = CPUInfo(machine_type=None, flags=['flag'])
- produced = api.produce.model_instances[0]
-
- assert api.produce.called == 1
-
- assert expected.machine_type == produced.machine_type
- assert sorted(expected.flags) == sorted(produced.flags)
-
-
def test_parse_invalid_json(monkeypatch):
- monkeypatch.setattr('leapp.libraries.actor.scancpu.get_source_major_version', lambda: '8')
-
- def mocked_cpuinfo(*args, **kwargs):
- return mocked_get_cpuinfo('invalid')(output_json=True)
-
+ mocked_cpuinfo = mocked_get_cpuinfo('invalid')
monkeypatch.setattr(scancpu, '_get_lscpu_output', mocked_cpuinfo)
monkeypatch.setattr(api, 'produce', produce_mocked())
monkeypatch.setattr(api, 'current_logger', logger_mocked())
--
2.51.1

View File

@ -0,0 +1,24 @@
From 7c6bb64e550ccfefe4001e79fef44b7d69446c36 Mon Sep 17 00:00:00 2001
From: Michal Bocek <mbocek@redhat.com>
Date: Thu, 19 Jun 2025 12:46:50 +0200
Subject: [PATCH 45/66] README: IRC -> GitHub discussions
The Leapp team is not available on IRC anymore. We advise the public to
talk to us on GitHub instead.
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 5ec5f723..6b45b4b7 100644
--- a/README.md
+++ b/README.md
@@ -29,4 +29,4 @@ Then you may attach only the `leapp-logs.tgz` file.
Well gladly answer your questions and lead you to through any troubles with the
actor development.
-You can reach us at IRC: `#leapp` on Libera.Chat.
+You can reach us in the [discussions sections of our GitHub repository](https://github.com/oamg/leapp-repository/discussions).
--
2.50.1

View File

@ -1,51 +0,0 @@
From 44c6b10a1813bfa019fb8ee2ec08a619e325ba08 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Thu, 21 Aug 2025 14:34:37 +0200
Subject: [PATCH 45/55] modify_userspace_for_livemode: Remove RHEL7
crypto-policies workaround
---
.../libraries/prepareliveimage.py | 13 -------------
.../tests/test_livemode_userspace_modifications.py | 2 --
2 files changed, 15 deletions(-)
diff --git a/repos/system_upgrade/common/actors/livemode/modify_userspace_for_livemode/libraries/prepareliveimage.py b/repos/system_upgrade/common/actors/livemode/modify_userspace_for_livemode/libraries/prepareliveimage.py
index 686c4cd6..116c463d 100644
--- a/repos/system_upgrade/common/actors/livemode/modify_userspace_for_livemode/libraries/prepareliveimage.py
+++ b/repos/system_upgrade/common/actors/livemode/modify_userspace_for_livemode/libraries/prepareliveimage.py
@@ -381,19 +381,6 @@ def setup_sshd(context, authorized_keys):
error
)
- # @Todo(mhecko): This is hazardous. I guess we are setting this so that we can use weaker SSH keys from RHEL7,
- # # but this way we change crypto settings system-wise (could be a problem for FIPS). Instead, we
- # # should check whether the keys will be OK on RHEL8, and inform the user otherwise.
- if get_target_major_version() == '8': # set to LEGACY for 7>8 only
- try:
- with context.open('/etc/crypto-policies/config', 'w+') as f:
- f.write('LEGACY\n')
- except OSError as error:
- api.current_logger().warning('Cannot set crypto policy to LEGACY')
- details = {'details': 'Failed to set crypto-policies to LEGACY due to the error: {0}'.format(error)}
- raise StopActorExecutionError('Failed to set up livemode SSHD', details=details)
-
-
# stolen from upgradeinitramfsgenerator.py
def _get_target_kernel_version(context):
"""
diff --git a/repos/system_upgrade/common/actors/livemode/modify_userspace_for_livemode/tests/test_livemode_userspace_modifications.py b/repos/system_upgrade/common/actors/livemode/modify_userspace_for_livemode/tests/test_livemode_userspace_modifications.py
index e890f45a..b046d8c7 100644
--- a/repos/system_upgrade/common/actors/livemode/modify_userspace_for_livemode/tests/test_livemode_userspace_modifications.py
+++ b/repos/system_upgrade/common/actors/livemode/modify_userspace_for_livemode/tests/test_livemode_userspace_modifications.py
@@ -296,8 +296,6 @@ def test_setup_sshd(monkeypatch):
Action(type_=ActionType.SYMLINK,
args=('/usr/lib/systemd/system/sshd.service',
'/USERSPACE/etc/systemd/system/multi-user.target.wants/sshd.service')),
- Action(type_=ActionType.OPEN, args=('/USERSPACE/etc/crypto-policies/config',)),
- Action(type_=ActionType.WRITE, args=('LEGACY\n',)),
]
error = assert_execution_trace_subsumes_other(actual_trace, expected_trace)
--
2.51.1

View File

@ -0,0 +1,538 @@
From 9966eb19daca97c18d798080c62af5638c1e0eab Mon Sep 17 00:00:00 2001
From: David Kubek <dkubek@redhat.com>
Date: Tue, 20 Aug 2024 12:57:42 +0200
Subject: [PATCH 46/66] Resolve boot issues in hybrid azure during upgrades
from RHEL 7 > 8 > 9.
This commit addresses the issue where the `/boot/grub2/grub.cfg` file is
overwritten during the upgrade process by an old RHEL7 configuration
leftover on the system, causing the system to fail to boot.
The problem occurs on hybrid Azure images, which support both UEFI and
Legacy systems and have both `grub-pc` and `grub-efi` packages installed.
It is caused by one of the scriplets in `grub-efi` which overwrites the old
configuration.
If old configuration is detected, this actor regenerates the grub
configuration using `grub2-mkconfig -o /boot/grub2/grub.cfg` after
installing rpms to ensure the correct boot configuration is in place.
The fix is applied specifically to Azure hybrid cloud systems.
JIRA: RHEL-38255
---
.../cloud/ensurevalidgrubcfghybrid/actor.py | 34 +++
.../libraries/ensurevalidgrubcfghybrid.py | 66 ++++++
.../tests/files/invalid_grub.cfg | 51 +++++
.../tests/files/valid_grub.cfg | 195 ++++++++++++++++++
.../tests/test_ensurevalidgrubcfghybrid.py | 124 +++++++++++
5 files changed, 470 insertions(+)
create mode 100644 repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/actor.py
create mode 100644 repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/libraries/ensurevalidgrubcfghybrid.py
create mode 100644 repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/tests/files/invalid_grub.cfg
create mode 100644 repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/tests/files/valid_grub.cfg
create mode 100644 repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/tests/test_ensurevalidgrubcfghybrid.py
diff --git a/repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/actor.py b/repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/actor.py
new file mode 100644
index 00000000..68de0433
--- /dev/null
+++ b/repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/actor.py
@@ -0,0 +1,34 @@
+from leapp.actors import Actor
+from leapp.libraries.actor import ensurevalidgrubcfghybrid
+from leapp.models import HybridImage
+from leapp.tags import ApplicationsPhaseTag, IPUWorkflowTag
+
+
+class EnsureValidGrubcfgHybrid(Actor):
+ """
+ Resolve boot failures in Azure Gen1 VMs during upgrades from RHEL 7 to RHEL 8 to RHEL 9.
+
+ This actor addresses the issue where the `/boot/grub2/grub.cfg` file is
+ overwritten during the upgrade process by an old RHEL7 configuration
+ leftover on the system, causing the system to fail to boot.
+
+ The problem occurs on hybrid Azure images, which support both UEFI and
+ Legacy systems and have both `grub-pc` and `grub-efi` packages installed.
+ It is caused by one of the scriplets in `grub-efi` which overwrites the old
+ configuration.
+
+ If old configuration is detected, this actor regenerates the grub
+ configuration using `grub2-mkconfig -o /boot/grub2/grub.cfg` after
+ installing rpms to ensure the correct boot configuration is in place.
+
+ The fix is applied specifically to Azure hybrid cloud systems.
+
+ """
+
+ name = 'ensure_valid_grubcfg_hybrid'
+ consumes = (HybridImage,)
+ produces = ()
+ tags = (ApplicationsPhaseTag, IPUWorkflowTag)
+
+ def process(self):
+ ensurevalidgrubcfghybrid.process()
diff --git a/repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/libraries/ensurevalidgrubcfghybrid.py b/repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/libraries/ensurevalidgrubcfghybrid.py
new file mode 100644
index 00000000..127eccfc
--- /dev/null
+++ b/repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/libraries/ensurevalidgrubcfghybrid.py
@@ -0,0 +1,66 @@
+import re
+
+from leapp.exceptions import StopActorExecutionError
+from leapp.libraries.common.config.architecture import ARCH_ACCEPTED
+from leapp.libraries.stdlib import api, CalledProcessError, run
+from leapp.models import HybridImage
+
+GRUB_CFG_PATH = '/boot/grub2/grub.cfg'
+
+MATCH_ARCH = r'({})'.format('|'.join(ARCH_ACCEPTED))
+MATCH_RHEL7_KERNEL_VERSION = r"\d+\.\d+\.\d+-\d+(\.\d+)*\.el7\.{}".format(MATCH_ARCH)
+MATCH_RHEL7_KERNEL_DEFINITION = r"vmlinuz-{}".format(MATCH_RHEL7_KERNEL_VERSION)
+
+
+def process():
+ if not _is_hybrid_image():
+ api.current_logger().info('System is not a hybrid image. Skipping.')
+ return
+
+ grubcfg = _read_grubcfg()
+ if _is_grubcfg_invalid(grubcfg):
+ _run_grub2_mkconfig()
+
+
+def _is_hybrid_image():
+ return next(api.consume(HybridImage), None) is not None
+
+
+def _read_grubcfg():
+ api.current_logger().debug('Reading {}:'.format(GRUB_CFG_PATH))
+ with open(GRUB_CFG_PATH, 'r') as fin:
+ grubcfg = fin.read()
+
+ api.current_logger().debug(grubcfg)
+ return grubcfg
+
+
+def _is_grubcfg_invalid(grubcfg):
+ return _contains_rhel7_kernel_definition(grubcfg)
+
+
+def _contains_rhel7_kernel_definition(grubcfg):
+ api.current_logger().debug("Looking for RHEL7 kernel version ...")
+
+ match = re.search(MATCH_RHEL7_KERNEL_DEFINITION, grubcfg)
+
+ api.current_logger().debug(
+ "Matched: {}".format(match.group() if match else "[NO MATCH]")
+ )
+
+ return match is not None
+
+
+def _run_grub2_mkconfig():
+ api.current_logger().info("Regenerating {}".format(GRUB_CFG_PATH))
+
+ try:
+ run([
+ 'grub2-mkconfig',
+ '-o',
+ GRUB_CFG_PATH
+ ])
+ except CalledProcessError as err:
+ msg = 'Could not regenerate {}: {}'.format(GRUB_CFG_PATH, str(err))
+ api.current_logger().error(msg)
+ raise StopActorExecutionError(msg)
diff --git a/repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/tests/files/invalid_grub.cfg b/repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/tests/files/invalid_grub.cfg
new file mode 100644
index 00000000..58f55c53
--- /dev/null
+++ b/repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/tests/files/invalid_grub.cfg
@@ -0,0 +1,51 @@
+
+# Created by osbuild
+
+set timeout=10
+
+# load the grubenv file
+load_env
+
+# selection of the next boot 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
+
+if [ "${prev_saved_entry}" ]; then
+ set saved_entry="${prev_saved_entry}"
+ save_env saved_entry
+ set prev_saved_entry=
+ save_env prev_saved_entry
+ set boot_once=true
+fi
+
+function savedefault {
+ if [ -z "${boot_once}" ]; then
+ saved_entry="${chosen}"
+ save_env saved_entry
+ fi
+}
+
+serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1
+terminal_input serial console
+terminal_output serial console
+
+menuentry 'Red Hat Enterprise Linux Server (3.10.0-1160.119.1.el7.x86_64) 7.9 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted --id 'gnulinux-3.10.0-1160.99.1.el7.x86_64-advanced-76a22bf4-f153-4541-b6c7-0332c0dfaeac' {
+ insmod all_video
+ set gfxpayload=keep
+ search --no-floppy --set=root --fs-uuid 61779359-8d11-49ba-bc9d-8d038ee4b108
+ linuxefi /vmlinuz-3.10.0-1160.119.1.el7.x86_64 root=UUID=d3c9a2bd-7ffb-4113-9b8f-234c13b18274 ro crashkernel=auto console=tty1 console=ttyS0 earlyprintk=ttyS0 rootdelay=300 scsi_mod.use_blk_mq=y LANG=en_US.UTF-8
+ initrdefi /initramfs-3.10.0-1160.119.1.el7.x86_64.img
+}
+menuentry 'Red Hat Enterprise Linux (3.10.0-1160.99.1.el7.x86_64) 7.9 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted --id 'gnulinux-3.10.0-1160.99.1.el7.x86_64-advanced-76a22bf4-f153-4541-b6c7-0332c0dfaeac' {
+ insmod all_video
+ set gfxpayload=keep
+ search --no-floppy --set=root --fs-uuid 61779359-8d11-49ba-bc9d-8d038ee4b108
+ linuxefi /vmlinuz-3.10.0-1160.99.1.el7.x86_64 root=UUID=d3c9a2bd-7ffb-4113-9b8f-234c13b18274 ro crashkernel=auto console=tty1 console=ttyS0 earlyprintk=ttyS0 rootdelay=300 scsi_mod.use_blk_mq=y
+ initrdefi /initramfs-3.10.0-1160.99.1.el7.x86_64.img
+}
diff --git a/repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/tests/files/valid_grub.cfg b/repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/tests/files/valid_grub.cfg
new file mode 100644
index 00000000..8192665e
--- /dev/null
+++ b/repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/tests/files/valid_grub.cfg
@@ -0,0 +1,195 @@
+#
+# DO NOT EDIT THIS FILE
+#
+# It is automatically generated by grub2-mkconfig using templates
+# from /etc/grub.d and settings from /etc/default/grub
+#
+
+### BEGIN /etc/grub.d/00_header ###
+set pager=1
+
+if [ -f ${config_directory}/grubenv ]; then
+ load_env -f ${config_directory}/grubenv
+elif [ -s $prefix/grubenv ]; then
+ load_env
+fi
+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
+
+if [ x"${feature_menuentry_id}" = xy ]; then
+ menuentry_id_option="--id"
+else
+ menuentry_id_option=""
+fi
+
+export menuentry_id_option
+
+if [ "${prev_saved_entry}" ]; then
+ set saved_entry="${prev_saved_entry}"
+ save_env saved_entry
+ set prev_saved_entry=
+ save_env prev_saved_entry
+ set boot_once=true
+fi
+
+function savedefault {
+ if [ -z "${boot_once}" ]; then
+ saved_entry="${chosen}"
+ save_env saved_entry
+ fi
+}
+
+function load_video {
+ if [ x$feature_all_video_module = xy ]; then
+ insmod all_video
+ else
+ insmod efi_gop
+ insmod efi_uga
+ insmod ieee1275_fb
+ insmod vbe
+ insmod vga
+ insmod video_bochs
+ insmod video_cirrus
+ fi
+}
+
+serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1
+terminal_input serial console
+terminal_output serial console
+if [ x$feature_timeout_style = xy ] ; then
+ set timeout_style=countdown
+ set timeout=10
+# Fallback hidden-timeout code in case the timeout_style feature is
+# unavailable.
+elif sleep --interruptible 10 ; then
+ set timeout=0
+fi
+### END /etc/grub.d/00_header ###
+
+### BEGIN /etc/grub.d/00_tuned ###
+set tuned_params=""
+set tuned_initrd=""
+### END /etc/grub.d/00_tuned ###
+
+### BEGIN /etc/grub.d/01_users ###
+if [ -f ${prefix}/user.cfg ]; then
+ source ${prefix}/user.cfg
+ if [ -n "${GRUB2_PASSWORD}" ]; then
+ set superusers="root"
+ export superusers
+ password_pbkdf2 root ${GRUB2_PASSWORD}
+ fi
+fi
+### END /etc/grub.d/01_users ###
+
+### BEGIN /etc/grub.d/08_fallback_counting ###
+insmod increment
+# Check if boot_counter exists and boot_success=0 to activate this behaviour.
+if [ -n "${boot_counter}" -a "${boot_success}" = "0" ]; then
+ # if countdown has ended, choose to boot rollback deployment,
+ # i.e. default=1 on OSTree-based systems.
+ if [ "${boot_counter}" = "0" -o "${boot_counter}" = "-1" ]; then
+ set default=1
+ set boot_counter=-1
+ # otherwise decrement boot_counter
+ else
+ decrement boot_counter
+ fi
+ save_env boot_counter
+fi
+### END /etc/grub.d/08_fallback_counting ###
+
+### BEGIN /etc/grub.d/10_linux ###
+insmod part_gpt
+insmod xfs
+set root='hd0,gpt2'
+if [ x$feature_platform_search_hint = xy ]; then
+ search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2 61779359-8d11-49ba-bc9d-8d038ee4b108
+else
+ search --no-floppy --fs-uuid --set=root 61779359-8d11-49ba-bc9d-8d038ee4b108
+fi
+insmod part_gpt
+insmod xfs
+set boot='hd0,gpt2'
+if [ x$feature_platform_search_hint = xy ]; then
+ search --no-floppy --fs-uuid --set=boot --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2 61779359-8d11-49ba-bc9d-8d038ee4b108
+else
+ search --no-floppy --fs-uuid --set=boot 61779359-8d11-49ba-bc9d-8d038ee4b108
+fi
+
+# This section was generated by a script. Do not modify the generated file - all changes
+# will be lost the next time file is regenerated. Instead edit the BootLoaderSpec files.
+#
+# The blscfg command parses the BootLoaderSpec files stored in /boot/loader/entries and
+# populates the boot menu. Please refer to the Boot Loader Specification documentation
+# for the files format: https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/.
+
+# The kernelopts variable should be defined in the grubenv file. But to ensure that menu
+# entries populated from BootLoaderSpec files that use this variable work correctly even
+# without a grubenv file, define a fallback kernelopts variable if this has not been set.
+#
+# The kernelopts variable in the grubenv file can be modified using the grubby tool or by
+# executing the grub2-mkconfig tool. For the latter, the values of the GRUB_CMDLINE_LINUX
+# and GRUB_CMDLINE_LINUX_DEFAULT options from /etc/default/grub file are used to set both
+# the kernelopts variable in the grubenv file and the fallback kernelopts variable.
+if [ -z "${kernelopts}" ]; then
+ set kernelopts="root=/dev/mapper/rootvg-rootlv ro ro crashkernel=auto console=tty1 console=ttyS0 earlyprintk=ttyS0 rootdelay=300 scsi_mod.use_blk_mq=y "
+fi
+
+insmod blscfg
+blscfg
+### END /etc/grub.d/10_linux ###
+
+### BEGIN /etc/grub.d/10_reset_boot_success ###
+# Hiding the menu is ok if last boot was ok or if this is a first boot attempt to boot the entry
+if [ "${boot_success}" = "1" -o "${boot_indeterminate}" = "1" ]; then
+ set menu_hide_ok=1
+else
+ set menu_hide_ok=0
+fi
+# Reset boot_indeterminate after a successful boot
+if [ "${boot_success}" = "1" ] ; then
+ set boot_indeterminate=0
+# Avoid boot_indeterminate causing the menu to be hidden more then once
+elif [ "${boot_indeterminate}" = "1" ]; then
+ set boot_indeterminate=2
+fi
+# Reset boot_success for current boot
+set boot_success=0
+save_env boot_success boot_indeterminate
+### END /etc/grub.d/10_reset_boot_success ###
+
+### BEGIN /etc/grub.d/12_menu_auto_hide ###
+### END /etc/grub.d/12_menu_auto_hide ###
+
+### BEGIN /etc/grub.d/20_linux_xen ###
+### END /etc/grub.d/20_linux_xen ###
+
+### BEGIN /etc/grub.d/20_ppc_terminfo ###
+### END /etc/grub.d/20_ppc_terminfo ###
+
+### BEGIN /etc/grub.d/30_os-prober ###
+### END /etc/grub.d/30_os-prober ###
+
+### BEGIN /etc/grub.d/30_uefi-firmware ###
+### END /etc/grub.d/30_uefi-firmware ###
+
+### BEGIN /etc/grub.d/40_custom ###
+# This file provides an easy way to add custom menu entries. Simply type the
+# menu entries you want to add after this comment. Be careful not to change
+# the 'exec tail' line above.
+### END /etc/grub.d/40_custom ###
+
+### BEGIN /etc/grub.d/41_custom ###
+if [ -f ${config_directory}/custom.cfg ]; then
+ source ${config_directory}/custom.cfg
+elif [ -z "${config_directory}" -a -f $prefix/custom.cfg ]; then
+ source $prefix/custom.cfg;
+fi
+### END /etc/grub.d/41_custom ###
diff --git a/repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/tests/test_ensurevalidgrubcfghybrid.py b/repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/tests/test_ensurevalidgrubcfghybrid.py
new file mode 100644
index 00000000..c0fb0a0d
--- /dev/null
+++ b/repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/tests/test_ensurevalidgrubcfghybrid.py
@@ -0,0 +1,124 @@
+import os
+
+import pytest
+
+from leapp.exceptions import StopActorExecutionError
+from leapp.libraries.actor import ensurevalidgrubcfghybrid
+from leapp.libraries.common.testutils import CurrentActorMocked, logger_mocked
+from leapp.libraries.stdlib import api, CalledProcessError
+from leapp.models import HybridImage
+
+CUR_DIR = os.path.dirname(os.path.abspath(__file__))
+
+
+def raise_call_error(args=None):
+ raise CalledProcessError(
+ message='A Leapp Command Error occurred.',
+ command=args,
+ result={'signal': None, 'exit_code': 1, 'pid': 0, 'stdout': 'fake', 'stderr': 'fake'}
+ )
+
+
+class run_mocked(object):
+ def __init__(self, raise_err=False):
+ self.called = 0
+ self.args = []
+ self.raise_err = raise_err
+
+ def __call__(self, *args):
+ self.called += 1
+ self.args.append(args)
+ if self.raise_err:
+ raise_call_error(args)
+
+
+def test_not_hybrid_image(monkeypatch):
+ """
+ Skip when system is not a hybrid.
+ """
+
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=[]))
+ monkeypatch.setattr(api, 'current_logger', logger_mocked())
+ monkeypatch.setattr(ensurevalidgrubcfghybrid, 'run', run_mocked(raise_err=False))
+
+ ensurevalidgrubcfghybrid.process()
+
+ assert api.current_logger.infomsg[0].startswith('System is not a hybrid image')
+ assert ensurevalidgrubcfghybrid.run.called == 0
+
+
+@pytest.mark.parametrize("is_invalid", [True, False])
+def test_is_grubcfg_valid(monkeypatch, is_invalid):
+
+ grubcfg_filename = ('invalid' if is_invalid else 'valid') + '_grub.cfg'
+ grubcfg_filepath = os.path.join(CUR_DIR, 'files', grubcfg_filename)
+ with open(grubcfg_filepath, 'r') as fin:
+ grubcfg = fin.read()
+
+ assert ensurevalidgrubcfghybrid._is_grubcfg_invalid(grubcfg) == is_invalid
+
+
+def test_valid_grubcfg(monkeypatch):
+ """
+ Test valid configuration does not trigger grub2-mkconfig
+ """
+
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=[HybridImage()]))
+ monkeypatch.setattr(api, 'current_logger', logger_mocked())
+ monkeypatch.setattr(ensurevalidgrubcfghybrid, 'run', run_mocked(raise_err=False))
+
+ grubcfg_filepath = os.path.join(CUR_DIR, 'files', 'valid_grub.cfg')
+ with open(grubcfg_filepath, 'r') as fin:
+ grubcfg = fin.read()
+
+ monkeypatch.setattr(ensurevalidgrubcfghybrid, '_read_grubcfg', lambda: grubcfg)
+
+ ensurevalidgrubcfghybrid.process()
+
+ assert ensurevalidgrubcfghybrid.run.called == 0
+
+
+def test_invalid_grubcfg(monkeypatch):
+ """
+ Test invalid configuration triggers grub2-mkconfig
+ """
+
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=[HybridImage()]))
+ monkeypatch.setattr(api, 'current_logger', logger_mocked())
+ monkeypatch.setattr(ensurevalidgrubcfghybrid, 'run', run_mocked(raise_err=False))
+
+ grubcfg_filepath = os.path.join(CUR_DIR, 'files', 'invalid_grub.cfg')
+ with open(grubcfg_filepath, 'r') as fin:
+ grubcfg = fin.read()
+
+ monkeypatch.setattr(ensurevalidgrubcfghybrid, '_read_grubcfg', lambda: grubcfg)
+
+ ensurevalidgrubcfghybrid.process()
+
+ assert ensurevalidgrubcfghybrid.run.called == 1
+ assert any(msg.startswith('Regenerating') for msg in api.current_logger.infomsg)
+
+
+def test_run_error(monkeypatch):
+ """
+ Test invalid configuration triggers grub2-mkconfig
+ """
+
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=[HybridImage()]))
+ monkeypatch.setattr(api, 'current_logger', logger_mocked())
+ monkeypatch.setattr(ensurevalidgrubcfghybrid, 'run', run_mocked(raise_err=True))
+
+ grubcfg_filepath = os.path.join(CUR_DIR, 'files', 'invalid_grub.cfg')
+ with open(grubcfg_filepath, 'r') as fin:
+ grubcfg = fin.read()
+
+ monkeypatch.setattr(ensurevalidgrubcfghybrid, '_read_grubcfg', lambda: grubcfg)
+
+ with pytest.raises(StopActorExecutionError):
+ ensurevalidgrubcfghybrid.process()
+
+ assert ensurevalidgrubcfghybrid.run.called == 1
+ assert any(
+ msg.startswith('Could not regenerate')
+ for msg in api.current_logger.err
+ )
--
2.50.1

View File

@ -1,61 +0,0 @@
From 4bede4b415f3e561399bf5c4ebed659c1aa4948d Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Thu, 21 Aug 2025 14:37:41 +0200
Subject: [PATCH 46/55] modify_userspace_for_livemode: Remove unused code in
modify_userspace_for_livemode
---
.../libraries/prepareliveimage.py | 30 +------------------
1 file changed, 1 insertion(+), 29 deletions(-)
diff --git a/repos/system_upgrade/common/actors/livemode/modify_userspace_for_livemode/libraries/prepareliveimage.py b/repos/system_upgrade/common/actors/livemode/modify_userspace_for_livemode/libraries/prepareliveimage.py
index 116c463d..2587bf89 100644
--- a/repos/system_upgrade/common/actors/livemode/modify_userspace_for_livemode/libraries/prepareliveimage.py
+++ b/repos/system_upgrade/common/actors/livemode/modify_userspace_for_livemode/libraries/prepareliveimage.py
@@ -6,7 +6,7 @@ import os.path
from leapp.exceptions import StopActorExecutionError
from leapp.libraries.common import mounting
from leapp.libraries.common.config.version import get_target_major_version
-from leapp.libraries.stdlib import api, CalledProcessError
+from leapp.libraries.stdlib import api
from leapp.models import LiveImagePreparationInfo
LEAPP_UPGRADE_SERVICE_FILE = 'upgrade.service'
@@ -381,34 +381,6 @@ def setup_sshd(context, authorized_keys):
error
)
-# stolen from upgradeinitramfsgenerator.py
-def _get_target_kernel_version(context):
- """
- Get the version of the most recent kernel version within the container.
- """
- try:
- results = context.call(['rpm', '-qa', 'kernel-core'], split=True)['stdout']
-
- except CalledProcessError as error:
- problem = 'Could not query the target userspace kernel version through rpm. Full error: {0}'.format(error)
- raise StopActorExecutionError(
- 'Cannot get the version of the installed kernel.',
- details={'Problem': problem})
-
- if len(results) > 1:
- raise StopActorExecutionError(
- 'Cannot detect the version of the target userspace kernel.',
- details={'Problem': 'Detected unexpectedly multiple kernels inside target userspace container.'})
- if not results:
- raise StopActorExecutionError(
- 'Cannot detect the version of the target userspace kernel.',
- details={'Problem': 'An rpm query for the available kernels did not produce any results.'})
-
- kernel_version = '-'.join(results[0].rsplit("-", 2)[-2:])
- api.current_logger().debug('Detected kernel version inside container: {}.'.format(kernel_version))
-
- return kernel_version
-
def fakerootfs():
"""
--
2.51.1

File diff suppressed because it is too large Load Diff

View File

@ -1,170 +0,0 @@
From 000c5f6558e788842fbf95d2fdb0014d18285c15 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Thu, 21 Aug 2025 15:10:58 +0200
Subject: [PATCH 47/55] repositoriesblacklist: Remove the rhel7-optional
unsupported PESID
Update tests to assume 8->9 upgrade path.
---
.../libraries/repositoriesblacklist.py | 4 +-
.../tests/test_repositoriesblacklist.py | 48 ++++++++++---------
2 files changed, 27 insertions(+), 25 deletions(-)
diff --git a/repos/system_upgrade/common/actors/repositoriesblacklist/libraries/repositoriesblacklist.py b/repos/system_upgrade/common/actors/repositoriesblacklist/libraries/repositoriesblacklist.py
index e22fbee0..5059f619 100644
--- a/repos/system_upgrade/common/actors/repositoriesblacklist/libraries/repositoriesblacklist.py
+++ b/repos/system_upgrade/common/actors/repositoriesblacklist/libraries/repositoriesblacklist.py
@@ -6,7 +6,6 @@ from leapp.models import CustomTargetRepository, RepositoriesBlacklisted, Reposi
# {OS_MAJOR_VERSION: PESID}
UNSUPPORTED_PESIDS = {
- "7": "rhel7-optional",
"8": "rhel8-CRB",
"9": "rhel9-CRB",
"10": "rhel10-CRB"
@@ -28,9 +27,8 @@ def _report_using_unsupported_repos(repos):
def _report_excluded_repos(repos):
- optional_repository_name = 'optional' if get_source_major_version() == '7' else 'CRB'
api.current_logger().info(
- "The {0} repository is not enabled. Excluding {1} from the upgrade".format(optional_repository_name, repos)
+ "The CRB repository is not enabled. Excluding {} from the upgrade".format(repos)
)
report = [
diff --git a/repos/system_upgrade/common/actors/repositoriesblacklist/tests/test_repositoriesblacklist.py b/repos/system_upgrade/common/actors/repositoriesblacklist/tests/test_repositoriesblacklist.py
index c4f9a36e..945007c6 100644
--- a/repos/system_upgrade/common/actors/repositoriesblacklist/tests/test_repositoriesblacklist.py
+++ b/repos/system_upgrade/common/actors/repositoriesblacklist/tests/test_repositoriesblacklist.py
@@ -20,8 +20,8 @@ from leapp.models import (
def repofacts_opts_disabled():
repos_data = [
RepositoryData(
- repoid="rhel-7-server-optional-rpms",
- name="RHEL 7 Server",
+ repoid="codeready-builder-for-rhel-8-x86_64-rpms",
+ name="RHEL 8 CRB",
enabled=False,
)
]
@@ -32,11 +32,11 @@ def repofacts_opts_disabled():
@pytest.fixture
-def rhel7_optional_pesidrepo():
+def rhel8_crb_pesidrepo():
return PESIDRepositoryEntry(
- pesid='rhel7-optional',
- major_version='7',
- repoid='rhel-7-server-optional-rpms',
+ pesid='rhel8-CRB',
+ major_version='8',
+ repoid='codeready-builder-for-rhel-8-x86_64-rpms',
rhui='',
arch='x86_64',
channel='ga',
@@ -46,11 +46,11 @@ def rhel7_optional_pesidrepo():
@pytest.fixture
-def rhel8_crb_pesidrepo():
+def rhel9_crb_pesidrepo():
return PESIDRepositoryEntry(
- pesid='rhel8-CRB',
- major_version='8',
- repoid='codeready-builder-for-rhel-8-x86_64-rpms',
+ pesid='rhel9-CRB',
+ major_version='9',
+ repoid='codeready-builder-for-rhel-9-x86_64-rpms',
rhui='',
arch='x86_64',
channel='ga',
@@ -60,10 +60,10 @@ def rhel8_crb_pesidrepo():
@pytest.fixture
-def repomap_opts_only(rhel7_optional_pesidrepo, rhel8_crb_pesidrepo):
+def repomap_opts_only(rhel8_crb_pesidrepo, rhel9_crb_pesidrepo):
return RepositoriesMapping(
- mapping=[RepoMapEntry(source='rhel7-optional', target=['rhel8-CRB'])],
- repositories=[rhel7_optional_pesidrepo, rhel8_crb_pesidrepo]
+ mapping=[RepoMapEntry(source='rhel8-CRB', target=['rhel9-CRB'])],
+ repositories=[rhel8_crb_pesidrepo, rhel9_crb_pesidrepo]
)
@@ -75,8 +75,8 @@ def test_all_target_optionals_blacklisted_when_no_optional_on_source(monkeypatch
repos_data = [
RepositoryData(
- repoid="rhel-7-server-rpms",
- name="RHEL 7 Server",
+ repoid="rhel-8-server-rpms",
+ name="RHEL 8 Server",
enabled=True,
)
]
@@ -92,7 +92,7 @@ def test_all_target_optionals_blacklisted_when_no_optional_on_source(monkeypatch
repositoriesblacklist.process()
assert api.produce.called
- assert 'codeready-builder-for-rhel-8-x86_64-rpms' in api.produce.model_instances[0].repoids
+ assert 'codeready-builder-for-rhel-9-x86_64-rpms' in api.produce.model_instances[0].repoids
def test_with_no_mapping_for_optional_repos(monkeypatch, repomap_opts_only, repofacts_opts_disabled):
@@ -115,7 +115,11 @@ def test_blacklist_produced_when_optional_repo_disabled(monkeypatch, repofacts_o
Tests whether a correct blacklist is generated when there is disabled optional repo on the system.
"""
- monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=[repofacts_opts_disabled, repomap_opts_only]))
+ monkeypatch.setattr(
+ api,
+ "current_actor",
+ CurrentActorMocked(msgs=[repofacts_opts_disabled, repomap_opts_only]),
+ )
monkeypatch.setattr(api, "produce", produce_mocked())
monkeypatch.setattr(reporting, "create_report", produce_mocked())
@@ -123,7 +127,7 @@ def test_blacklist_produced_when_optional_repo_disabled(monkeypatch, repofacts_o
assert api.produce.model_instances, 'A blacklist should get generated.'
- expected_blacklisted_repoid = 'codeready-builder-for-rhel-8-x86_64-rpms'
+ expected_blacklisted_repoid = 'codeready-builder-for-rhel-9-x86_64-rpms'
err_msg = 'Blacklist does not contain expected repoid.'
assert expected_blacklisted_repoid in api.produce.model_instances[0].repoids, err_msg
@@ -166,8 +170,8 @@ def test_repositoriesblacklist_not_empty(monkeypatch, repofacts_opts_disabled, r
def test_repositoriesblacklist_empty(monkeypatch, repofacts_opts_disabled, repomap_opts_only):
"""
- Tests whether nothing is produced if there are some disabled optional repos, but an empty blacklist is determined
- from the repo mapping data.
+ Tests whether nothing is produced if there are some disabled optional
+ repos, but an empty blacklist is determined from the repo mapping data.
"""
msgs_to_feed = [repofacts_opts_disabled, repomap_opts_only]
@@ -177,7 +181,7 @@ def test_repositoriesblacklist_empty(monkeypatch, repofacts_opts_disabled, repom
repositoriesblacklist,
"_get_repoids_to_exclude",
lambda dummy_mapping: set()
- ) # pylint:disable=W0108
+ )
monkeypatch.setattr(api, "produce", produce_mocked())
repositoriesblacklist.process()
@@ -187,7 +191,7 @@ def test_repositoriesblacklist_empty(monkeypatch, repofacts_opts_disabled, repom
@pytest.mark.parametrize(
("enabled_repo", "exp_report_title", "message_produced"),
[
- ("codeready-builder-for-rhel-8-x86_64-rpms", "Using repository not supported by Red Hat", False),
+ ("codeready-builder-for-rhel-9-x86_64-rpms", "Using repository not supported by Red Hat", False),
("some_other_enabled_repo", "Excluded target system repositories", True),
(None, "Excluded target system repositories", True),
],
--
2.51.1

View File

@ -0,0 +1,61 @@
From ba074a40e4297c90cbb8e5e522ec2a154fa2b9b0 Mon Sep 17 00:00:00 2001
From: Michal Bocek <mbocek@redhat.com>
Date: Tue, 1 Jul 2025 20:38:20 +0200
Subject: [PATCH 48/66] Point to leapp-repository contribution guidelines
Instead of the leapp framework contribution guidelines.
Also update the leapp-repository contribution guidelines to point to the
new place of the leapp framework Python coding guidelines (moved under
https://github.com/oamg/leapp/commit/123f2700dc0a354d4357ce325ff61fcb2f53e33b).
---
CONTRIBUTING.md | 2 +-
README.md | 6 +++---
docs/source/contrib-and-devel-guidelines.md | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d4cb2046..7315b693 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1 +1 @@
-See the [Contribution guidelines](https://leapp.readthedocs.io/en/latest/contributing.html)
+See the [contribution guidelines](https://leapp-repository.readthedocs.io/latest/contrib-and-devel-guidelines.html).
diff --git a/README.md b/README.md
index 6b45b4b7..43da589e 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-**Before doing anything, please read the upstream [documentation](https://leapp-repository.readthedocs.io/).**
+**Before doing anything, please read the [leapp-repository documentation](https://leapp-repository.readthedocs.io/).**
-Also, you could find useufl to read [Leapp framework documentation](https://leapp.readthedocs.io/).
+Also, you could find the [Leapp framework documentation](https://leapp.readthedocs.io/) useful to read.
---
@@ -17,7 +17,7 @@ Also, you could find useufl to read [Leapp framework documentation](https://leap
- *All files in /var/log/leapp*
- */var/lib/leapp/leapp.db*
- *journalctl*
- - If you want, you can optionally send anything else would you like to provide (e.g. storage info)
+ - If you want, you can optionally send any other relevant information (e.g. storage, network)
**For your convenience you can pack all logs with this command:**
diff --git a/docs/source/contrib-and-devel-guidelines.md b/docs/source/contrib-and-devel-guidelines.md
index 66bef9b1..f2edf8b7 100644
--- a/docs/source/contrib-and-devel-guidelines.md
+++ b/docs/source/contrib-and-devel-guidelines.md
@@ -1,7 +1,7 @@
# Contribution and development guidelines
## Code guidelines
-Your code should follow the [Python Coding Guidelines](https://leapp.readthedocs.io/en/latest/python-coding-guidelines.html) used for the leapp project. On top of these rules follow instructions
+Your code should follow the [Python Coding Guidelines](https://leapp.readthedocs.io/en/latest/contributing.html#follow-python-coding-guidelines) used for the leapp project. On top of these rules follow instructions
below.
### Retrieving information about the source system should be separated from its use
--
2.50.1

View File

@ -1,209 +0,0 @@
From 0a203330cee4fba6a28c65f1c6e0e450cc45771e Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Thu, 30 Oct 2025 11:52:39 +0100
Subject: [PATCH 48/55] mount_unit_gen: bind mount /sysroot/boot to /boot
Our changes towards using systemd-fstab-generator in the upgrade
initramfs caused that we are mounting almost all partitions, including
/boot (the actual mount target is /sysroot/boot) early in the boot
process. When upgrading with FIPS, the dracut fips module tries to mount
the device where the boot partition resides to check the integrity of
the kernel, however, it fails as the boot block device is already
mounted by us. This patch therefore introduces a static unit that
bind-mounts What=/sysroot/boot to Where=/boot, making the contents of
/boot available to the fips module. The bind-mounting service is
introduced only if the source system has /boot on a separate partition.
This is determined by checking whether anything shuld be mounted at
/boot according to fstab.
Jira-ref: RHEL-123886
---
.../initramfs/mount_units_generator/actor.py | 3 +-
.../files/bundled_units/boot.mount | 11 ++++
.../libraries/mount_unit_generator.py | 38 ++++++++++-
.../tests/test_mount_unit_generation.py | 63 ++++++++++++++++++-
4 files changed, 111 insertions(+), 4 deletions(-)
create mode 100644 repos/system_upgrade/common/actors/initramfs/mount_units_generator/files/bundled_units/boot.mount
diff --git a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/actor.py b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/actor.py
index dd667513..23c618b6 100644
--- a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/actor.py
+++ b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/actor.py
@@ -1,6 +1,6 @@
from leapp.actors import Actor
from leapp.libraries.actor import mount_unit_generator as mount_unit_generator_lib
-from leapp.models import LiveModeConfig, TargetUserSpaceInfo, UpgradeInitramfsTasks
+from leapp.models import LiveModeConfig, StorageInfo, TargetUserSpaceInfo, UpgradeInitramfsTasks
from leapp.tags import InterimPreparationPhaseTag, IPUWorkflowTag
@@ -15,6 +15,7 @@ class MountUnitGenerator(Actor):
consumes = (
LiveModeConfig,
TargetUserSpaceInfo,
+ StorageInfo,
)
produces = (
UpgradeInitramfsTasks,
diff --git a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/files/bundled_units/boot.mount b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/files/bundled_units/boot.mount
new file mode 100644
index 00000000..869c5e4c
--- /dev/null
+++ b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/files/bundled_units/boot.mount
@@ -0,0 +1,11 @@
+[Unit]
+DefaultDependencies=no
+Before=local-fs.target
+After=sysroot-boot.target
+Requires=sysroot-boot.target
+
+[Mount]
+What=/sysroot/boot
+Where=/boot
+Type=none
+Options=bind
diff --git a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/libraries/mount_unit_generator.py b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/libraries/mount_unit_generator.py
index 943bddd4..e3070986 100644
--- a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/libraries/mount_unit_generator.py
+++ b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/libraries/mount_unit_generator.py
@@ -5,7 +5,9 @@ import tempfile
from leapp.exceptions import StopActorExecutionError
from leapp.libraries.common import mounting
from leapp.libraries.stdlib import api, CalledProcessError, run
-from leapp.models import LiveModeConfig, TargetUserSpaceInfo, UpgradeInitramfsTasks
+from leapp.models import LiveModeConfig, StorageInfo, TargetUserSpaceInfo, UpgradeInitramfsTasks
+
+BIND_MOUNT_SYSROOT_BOOT_UNIT = 'boot.mount'
def run_systemd_fstab_generator(output_directory):
@@ -294,6 +296,39 @@ def request_units_inclusion_in_initramfs(files_to_include):
api.produce(tasks)
+def does_system_have_separate_boot_partition():
+ storage_info = next(api.consume(StorageInfo), None)
+ if not storage_info:
+ err_msg = 'Actor did not receive required information about system storage (StorageInfo)'
+ raise StopActorExecutionError(err_msg)
+
+ for fstab_entry in storage_info.fstab:
+ if fstab_entry.fs_file == '/boot':
+ return True
+
+ return False
+
+
+def inject_bundled_units(workspace):
+ """
+ Copy static units that are bundled within this actor into the workspace.
+ """
+ bundled_units_dir = api.get_actor_folder_path('bundled_units')
+ for unit in os.listdir(bundled_units_dir):
+ if unit == BIND_MOUNT_SYSROOT_BOOT_UNIT:
+ has_separate_boot = does_system_have_separate_boot_partition()
+ if not has_separate_boot:
+ # We perform bind-mounting because of dracut's fips module.
+ # When /boot is not a separate partition, we don't need to bind mount it --
+ # the fips module itself will create a symlink.
+ continue
+
+ unit_path = os.path.join(bundled_units_dir, unit)
+ unit_dst = os.path.join(workspace, unit)
+ api.current_logger().debug('Copying static unit bundled within leapp {} to {}'.format(unit, unit_dst))
+ shutil.copyfile(unit_path, unit_dst)
+
+
def setup_storage_initialization():
livemode_config = next(api.consume(LiveModeConfig), None)
if livemode_config and livemode_config.is_enabled:
@@ -306,6 +341,7 @@ def setup_storage_initialization():
run_systemd_fstab_generator(workspace_path)
remove_units_for_targets_that_are_already_mounted_by_dracut(workspace_path)
prefix_all_mount_units_with_sysroot(workspace_path)
+ inject_bundled_units(workspace_path)
fix_symlinks_in_targets(workspace_path)
mount_unit_files = copy_units_into_system_location(upgrade_container_ctx, workspace_path)
request_units_inclusion_in_initramfs(mount_unit_files)
diff --git a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/tests/test_mount_unit_generation.py b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/tests/test_mount_unit_generation.py
index 8849ada9..eb90a75d 100644
--- a/repos/system_upgrade/common/actors/initramfs/mount_units_generator/tests/test_mount_unit_generation.py
+++ b/repos/system_upgrade/common/actors/initramfs/mount_units_generator/tests/test_mount_unit_generation.py
@@ -5,9 +5,9 @@ import pytest
from leapp.exceptions import StopActorExecutionError
from leapp.libraries.actor import mount_unit_generator
-from leapp.libraries.common.testutils import logger_mocked
+from leapp.libraries.common.testutils import CurrentActorMocked, logger_mocked
from leapp.libraries.stdlib import api, CalledProcessError
-from leapp.models import TargetUserSpaceInfo, UpgradeInitramfsTasks
+from leapp.models import FstabEntry, StorageInfo, TargetUserSpaceInfo, UpgradeInitramfsTasks
def test_run_systemd_fstab_generator_successful_generation(monkeypatch):
@@ -267,3 +267,62 @@ def test_copy_units_mixed_content(monkeypatch):
]
assert sorted(files) == sorted(expected_files)
assert mount_unit_generator._delete_file.removal_called
+
+
+class CurrentActorMockedWithActorFolder(CurrentActorMocked):
+ def __init__(self, actor_folder_path, *args, **kwargs):
+ self.actor_folder_path = actor_folder_path
+ super().__init__(*args, **kwargs)
+
+ def get_actor_folder_path(self, subfolder):
+ return os.path.join(self.actor_folder_path, subfolder)
+
+
+@pytest.mark.parametrize('has_separate_boot', (True, False))
+def test_injection_of_sysroot_boot_bindmount_unit(monkeypatch, has_separate_boot):
+ fstab_entries = [
+ FstabEntry(fs_spec='UUID=123', fs_file='/root', fs_vfstype='xfs',
+ fs_mntops='defaults', fs_freq='0', fs_passno='0')
+ ]
+
+ if has_separate_boot:
+ boot_fstab_entry = FstabEntry(fs_spec='UUID=123', fs_file='/root', fs_vfstype='xfs',
+ fs_mntops='defaults', fs_freq='0', fs_passno='0')
+ fstab_entries.append(boot_fstab_entry)
+
+ storage_info = StorageInfo(fstab=fstab_entries)
+
+ actor_mock = CurrentActorMockedWithActorFolder(actor_folder_path='/actor', msgs=[storage_info])
+ monkeypatch.setattr(api, 'current_actor', actor_mock)
+
+ workspace_path = '/workspace'
+ was_copyfile_for_sysroot_boot_called = False
+
+ def copyfile_mocked(source, dest, *args, **kwargs):
+ if not os.path.basename(source) == mount_unit_generator.BIND_MOUNT_SYSROOT_BOOT_UNIT:
+ return
+
+ assert has_separate_boot
+ assert dest == os.path.join(workspace_path, mount_unit_generator.BIND_MOUNT_SYSROOT_BOOT_UNIT)
+
+ nonlocal was_copyfile_for_sysroot_boot_called
+ was_copyfile_for_sysroot_boot_called = True
+
+ monkeypatch.setattr(shutil, 'copyfile', copyfile_mocked)
+
+ def listdir_mocked(path):
+ assert path == actor_mock.get_actor_folder_path('bundled_units')
+ return [
+ mount_unit_generator.BIND_MOUNT_SYSROOT_BOOT_UNIT,
+ 'other.mount'
+ ]
+
+ monkeypatch.setattr(os, 'listdir', listdir_mocked)
+ monkeypatch.setattr(mount_unit_generator,
+ 'does_system_have_separate_boot_partition',
+ lambda: has_separate_boot)
+
+ mount_unit_generator.inject_bundled_units(workspace_path)
+
+ if has_separate_boot:
+ assert was_copyfile_for_sysroot_boot_called
--
2.51.1

View File

@ -0,0 +1,46 @@
From be6d23241e6fbe0c42a4f6a2df48efd6f999ed71 Mon Sep 17 00:00:00 2001
From: karolinku <kkula@redhat.com>
Date: Thu, 3 Jul 2025 13:12:32 +0200
Subject: [PATCH 49/66] Read the DNF config by module.py library
The DNF configuration has not been loaded when trying to get
information about available module streams (library module.py).
This causes a traceback e.g. on systems which must access DNF
repositories via a proxy.
This patch introduces loading the DNF configuration before trying
to access remote resources.
Jira: RHEL-39095
---
.../common/actors/rpmscanner/libraries/rpmscanner.py | 2 ++
repos/system_upgrade/common/libraries/module.py | 1 +
2 files changed, 3 insertions(+)
diff --git a/repos/system_upgrade/common/actors/rpmscanner/libraries/rpmscanner.py b/repos/system_upgrade/common/actors/rpmscanner/libraries/rpmscanner.py
index dbe56191..74c4b101 100644
--- a/repos/system_upgrade/common/actors/rpmscanner/libraries/rpmscanner.py
+++ b/repos/system_upgrade/common/actors/rpmscanner/libraries/rpmscanner.py
@@ -25,6 +25,8 @@ except ImportError:
def _get_package_repository_data_yum():
yum_base = yum.YumBase()
+ # DNF configuration is not loaded here, since no impact for operations
+ # done by the actor is observed here
pkg_repos = {}
try:
diff --git a/repos/system_upgrade/common/libraries/module.py b/repos/system_upgrade/common/libraries/module.py
index 7d4e8aa4..db725e71 100644
--- a/repos/system_upgrade/common/libraries/module.py
+++ b/repos/system_upgrade/common/libraries/module.py
@@ -38,6 +38,7 @@ def _create_or_get_dnf_base(base=None):
conf.substitutions.update_from_etc('/')
base = dnf.Base(conf=conf)
+ base.conf.read()
base.init_plugins()
base.read_all_repos()
# configure plugins after the repositories are loaded
--
2.50.1

View File

@ -1,40 +0,0 @@
From 9b06998b2077d0007da818059d5c6e244ac55948 Mon Sep 17 00:00:00 2001
From: Peter Mocary <pmocary@redhat.com>
Date: Mon, 10 Nov 2025 19:31:25 +0100
Subject: [PATCH 49/55] fix parsing of dnf config dump
This patch fixes handling of empty lines during parsing of output from
`dnf config-manager --dump` command.
Jira: RHEL-120328
---
repos/system_upgrade/common/libraries/dnfconfig.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/repos/system_upgrade/common/libraries/dnfconfig.py b/repos/system_upgrade/common/libraries/dnfconfig.py
index 4b5afeb5..9f1902b6 100644
--- a/repos/system_upgrade/common/libraries/dnfconfig.py
+++ b/repos/system_upgrade/common/libraries/dnfconfig.py
@@ -43,8 +43,11 @@ def _get_main_dump(context, disable_plugins):
output_data = {}
for line in data[main_start:]:
+ if not line.strip():
+ continue
try:
key, val = _strip_split(line, '=', 1)
+ output_data[key] = val
except ValueError:
# This is not expected to happen, but call it a seatbelt in case
# the dnf dump implementation will change and we will miss it
@@ -54,7 +57,6 @@ def _get_main_dump(context, disable_plugins):
api.current_logger().warning(
'Cannot parse the dnf dump correctly, line: {}'.format(line))
pass
- output_data[key] = val
return output_data
--
2.51.1

Some files were not shown because too many files have changed in this diff Show More