Import from CS git

This commit is contained in:
eabdullin 2025-07-21 11:47:55 +00:00
parent b71dc1da3a
commit 51f8cea591
23 changed files with 3728 additions and 1 deletions

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

@ -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

@ -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

File diff suppressed because it is too large Load Diff

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

@ -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

@ -0,0 +1,34 @@
From a4d10adb2f432ef09898228c0e2d00288bbcc412 Mon Sep 17 00:00:00 2001
From: karolinku <kkula@redhat.com>
Date: Mon, 7 Jul 2025 14:52:34 +0200
Subject: [PATCH 50/66] Disable localpkg_gpgcheck parameter from plugin data
This commit is setting the localpkg_gpgcheck DNF option within the
rhel-upgrade plugin to 0 (disabled).
The upgrade process has been blocked with "Error: GPG check FAILED"
when dnf has been configured to apply gpg check also on local packages
(localpkg_gpgcheck=1). That's because the bundled leapp*-deps meta
packages, which are managing Leapp and leapp-repository dependencies
during the transition to the new system, are not signed by the Red
Hat key. Therefore, this option needs to be disabled.
Jira: RHEL-47472
---
repos/system_upgrade/common/files/rhel_upgrade.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/repos/system_upgrade/common/files/rhel_upgrade.py b/repos/system_upgrade/common/files/rhel_upgrade.py
index 34f7b8f9..4f76a61d 100644
--- a/repos/system_upgrade/common/files/rhel_upgrade.py
+++ b/repos/system_upgrade/common/files/rhel_upgrade.py
@@ -116,6 +116,7 @@ class RhelUpgradeCommand(dnf.cli.Command):
self.base.conf.best = self.plugin_data['dnf_conf']['best']
self.base.conf.assumeyes = True
self.base.conf.gpgcheck = self.plugin_data['dnf_conf']['gpgcheck']
+ self.base.conf.localpkg_gpgcheck = False
self.base.conf.debug_solver = self.plugin_data['dnf_conf']['debugsolver']
self.base.conf.module_platform_id = self.plugin_data['dnf_conf']['platform_id']
installroot = self.plugin_data['dnf_conf'].get('installroot')
--
2.50.1

View File

@ -0,0 +1,37 @@
From c3bef4d9e89d109aee226f64e54e2eed088e591b Mon Sep 17 00:00:00 2001
From: Michal Bocek <mbocek@redhat.com>
Date: Tue, 8 Jul 2025 14:09:30 +0200
Subject: [PATCH 51/66] PR welcome msg: update link to contrib guidelines
(#1399)
Following the https://github.com/oamg/leapp-repository/pull/1394 where
the README was updated to point to the leapp-repository guidelines, this
change updates the link to the guidelines in the PR welcome message.
---
.github/workflows/pr-welcome-msg.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/pr-welcome-msg.yml b/.github/workflows/pr-welcome-msg.yml
index 0102c41f..f056fb79 100644
--- a/.github/workflows/pr-welcome-msg.yml
+++ b/.github/workflows/pr-welcome-msg.yml
@@ -19,7 +19,7 @@ jobs:
issue-number: ${{ github.event.pull_request.number }}
body: |
## **Thank you for contributing to the Leapp project!**
- Please note that every PR needs to comply with the [Leapp Guidelines](https://leapp.readthedocs.io/en/latest/contributing.html#) and must pass all tests in order to be mergeable.
+ Please note that every PR needs to comply with the [leapp-repository contribution and development guidelines](https://leapp-repository.readthedocs.io/latest/contrib-and-devel-guidelines.html) and must pass all tests in order to be mergeable.
If you want to request a review or rebuild a package in copr, you can use following commands as a comment:
- **`review please @oamg/developers`** to notify leapp developers of the review request
- **`/packit copr-build`** to submit a public copr build using packit
@@ -39,6 +39,6 @@ jobs:
See other labels for particular jobs defined in the `.packit.yaml` file.
- Please [open ticket](https://url.corp.redhat.com/oamg-ci-issue) in case you experience technical problem with the CI. (RH internal only)
+ Please [open ticket](https://red.ht/rhel-upgrades-ci-issue) in case you experience technical problem with the CI. (RH internal only)
**Note:** In case there are problems with tests not being triggered automatically on new PR/commit or pending for a long time, please contact leapp-infra.
--
2.50.1

View File

@ -0,0 +1,30 @@
From 55c885ce7fbf5fd237047d4f1d8e66a043e3a1b3 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Fri, 11 Jul 2025 14:32:57 +0200
Subject: [PATCH 52/66] Fix: skip checking ownership of files in
.../directory-hash/ dir
This check has been reintroduced in 87013d25b5aa3, however the "root"
directory during traversal is:
/var/lib/leapp/el10userspace/etc/pki/ca-trust/extracted/pem/directory-hash.
The skip condition looks for '/directory-hash/' which is false.
---
.../actors/targetuserspacecreator/libraries/userspacegen.py | 2 +-
1 file changed, 1 insertion(+), 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 9fc96a52..cbad91fe 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
@@ -311,7 +311,7 @@ def _get_files_owned_by_rpms(context, dirpath, pkgs=None, recursive=False):
searchdir = context.full_path(dirpath)
if recursive:
for root, _, files in os.walk(searchdir):
- if '/directory-hash/' in root:
+ if '/directory-hash' in root:
# tl;dr; for the performance improvement
# The directory has been relatively recently added to ca-certificates
# rpm on EL 9+ systems and the content does not seem to be important
--
2.50.1

View File

@ -0,0 +1,35 @@
From acaed7edcea66f2cef9aabc148a431825f91479e Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Fri, 11 Jul 2025 18:17:51 +0200
Subject: [PATCH 53/66] fixup! Fix: skip checking ownership of files in
.../directory-hash/ dir
---
.../actors/targetuserspacecreator/libraries/userspacegen.py | 4 +++-
1 file changed, 3 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 cbad91fe..699f1517 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
@@ -294,6 +294,8 @@ def _get_files_owned_by_rpms(context, dirpath, pkgs=None, recursive=False):
"""
Return the list of file names inside dirpath owned by RPMs.
+ The returned paths are relative to the dirpath.
+
This is important e.g. in case of RHUI which installs specific repo files
in the yum.repos.d directory.
@@ -334,7 +336,7 @@ def _get_files_owned_by_rpms(context, dirpath, pkgs=None, recursive=False):
api.current_logger().debug('SKIP the {} file: not owned by any rpm'.format(fname))
continue
if pkgs and not [pkg for pkg in pkgs if pkg in result['stdout']]:
- api.current_logger().debug('SKIP the {} file: not owned by any searched rpm:'.format(fname))
+ api.current_logger().debug('SKIP the {} file: not owned by any searched rpm'.format(fname))
continue
api.current_logger().debug('Found the file owned by an rpm: {}.'.format(fname))
files_owned_by_rpms.append(fname)
--
2.50.1

100
SOURCES/0054-Add-test.patch Normal file
View File

@ -0,0 +1,100 @@
From 6df858daa7c678d3e951bef3fdf077a0a5b49d36 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Fri, 11 Jul 2025 18:18:07 +0200
Subject: [PATCH 54/66] Add test
---
.../tests/unit_test_targetuserspacecreator.py | 73 +++++++++++++++++++
1 file changed, 73 insertions(+)
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 69ed7040..219cb7c3 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
@@ -13,6 +13,7 @@ from leapp.libraries.actor import userspacegen
from leapp.libraries.common import overlaygen, repofileutils, rhsm
from leapp.libraries.common.config import architecture
from leapp.libraries.common.testutils import CurrentActorMocked, logger_mocked, produce_mocked
+from leapp.libraries.stdlib import api, CalledProcessError
from leapp.utils.deprecation import suppress_deprecation
if sys.version_info < (2, 8):
@@ -1225,3 +1226,75 @@ def test_perform_ok(monkeypatch):
assert userspacegen.api.produce.model_instances[1] == msg_target_repos
# this one is full of constants, so it's safe to check just the instance
assert isinstance(userspacegen.api.produce.model_instances[2], models.TargetUserSpaceInfo)
+
+
+def test__get_files_owned_by_rpms(monkeypatch):
+ # this is not necessarily accurate, but close enoguh
+ fake_walk = [
+ ("/base/dir/etc/pki", ["ca-trust", "tls", "rpm-gpg"], []),
+ ("/base/dir/etc/pki/ca-trust", ["extracted", "source"], []),
+ ("/base/dir/etc/pki/ca-trust/extracted", ["openssl", "java"], []),
+ ("/base/dir/etc/pki/ca-trust/extracted/openssl", [], ["ca-bundle.trust.crt"]),
+ ("/base/dir/etc/pki/ca-trust/extracted/java", [], ["cacerts"]),
+
+ ("/base/dir/etc/pki/ca-trust/source", ["anchors", "directory-hash"], []),
+ ("/base/dir/etc/pki/ca-trust/source/anchors", [], ["my-ca.crt"]),
+ ("/base/dir/etc/pki/ca-trust/extracted/pem/directory-hash", [], [
+ "5931b5bc.0", "a94d09e5.0"
+ ]),
+ ("/base/dir/etc/pki/tls", ["certs", "private"], []),
+ ("/base/dir/etc/pki/tls/certs", [], ["server.crt", "ca-bundle.crt"]),
+ ("/base/dir/etc/pki/tls/private", [], ["server.key"]),
+ ("/base/dir/etc/pki/rpm-gpg", [], [
+ "RPM-GPG-KEY-1",
+ "RPM-GPG-KEY-2",
+ ]),
+ ]
+ monkeypatch.setattr(os, 'walk', lambda _: fake_walk)
+ logger = logger_mocked()
+ monkeypatch.setattr(api, 'current_logger', logger)
+
+ class _MockContext():
+
+ def __init__(self, owned):
+ self.base_dir = '/base/dir'
+ # list of files owned, no base_dir prefixed
+ self.owned = owned
+
+ def full_path(self, path):
+ return os.path.join(self.base_dir, os.path.abspath(path).lstrip('/'))
+
+ def call(self, cmd):
+ assert len(cmd) == 3 and cmd[0] == 'rpm' and cmd[1] == '-qf'
+ if cmd[2] in self.owned:
+ return {'exit_code': 0}
+ raise CalledProcessError("Command failed with exit code 1", cmd, 1)
+
+ search_dir = '/etc/pki'
+ owned = [
+ 'tls/certs/ca-bundle.crt',
+ 'ca-trust/extracted/openssl/ca-bundle.trust.crt',
+ 'rpm-gpg/RPM-GPG-KEY-1',
+ 'rpm-gpg/RPM-GPG-KEY-2',
+ 'ca-trust/extracted/pem/directory-hash/a94d09e5.0',
+ 'ca-trust/extracted/pem/directory-hash/a94d09e5.0',
+ ]
+ # the rpm -qf call happens with the full path
+ owned_fullpath = [os.path.join(search_dir, f) for f in owned]
+ context = _MockContext(owned_fullpath)
+
+ out = userspacegen._get_files_owned_by_rpms(context, '/etc/pki', recursive=True)
+
+ # any directory-hash directory should be skipped
+ assert sorted(owned[0:4]) == sorted(out)
+
+ def has_dbgmsg(substr):
+ return any([substr in log for log in logger.dbgmsg])
+
+ # test a few
+ assert has_dbgmsg(
+ "SKIP files in the /base/dir/etc/pki/ca-trust/extracted/pem/directory-hash directory:"
+ " Not important for the IPU.",
+ )
+ assert has_dbgmsg('SKIP the tls/certs/server.crt file: not owned by any rpm')
+ assert has_dbgmsg('Found the file owned by an rpm: rpm-gpg/RPM-GPG-KEY-2.')
--
2.50.1

View File

@ -0,0 +1,25 @@
From b9d7e965ee1e45f93e8250c0eda1e5b4968ecc34 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Fri, 11 Jul 2025 18:25:50 +0200
Subject: [PATCH 55/66] fixup! Add test
---
.../tests/unit_test_targetuserspacecreator.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 219cb7c3..15db2570 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
@@ -1229,7 +1229,7 @@ def test_perform_ok(monkeypatch):
def test__get_files_owned_by_rpms(monkeypatch):
- # this is not necessarily accurate, but close enoguh
+ # this is not necessarily accurate, but close enough
fake_walk = [
("/base/dir/etc/pki", ["ca-trust", "tls", "rpm-gpg"], []),
("/base/dir/etc/pki/ca-trust", ["extracted", "source"], []),
--
2.50.1

View File

@ -0,0 +1,110 @@
From 803aebd0edffb088181f99d0a4024231a7be942c Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Mon, 14 Jul 2025 11:15:15 +0200
Subject: [PATCH 56/66] Add test for non-recursive
---
.../tests/unit_test_targetuserspacecreator.py | 67 +++++++++++++------
1 file changed, 47 insertions(+), 20 deletions(-)
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 15db2570..267c064e 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
@@ -1228,7 +1228,45 @@ def test_perform_ok(monkeypatch):
assert isinstance(userspacegen.api.produce.model_instances[2], models.TargetUserSpaceInfo)
+class _MockContext():
+
+ def __init__(self, base_dir, owned_by_rpms):
+ self.base_dir = base_dir
+ # list of files owned, no base_dir prefixed
+ self.owned_by_rpms = owned_by_rpms
+
+ def full_path(self, path):
+ return os.path.join(self.base_dir, os.path.abspath(path).lstrip('/'))
+
+ def call(self, cmd):
+ assert len(cmd) == 3 and cmd[0] == 'rpm' and cmd[1] == '-qf'
+ if cmd[2] in self.owned_by_rpms:
+ return {'exit_code': 0}
+ raise CalledProcessError("Command failed with exit code 1", cmd, 1)
+
+
def test__get_files_owned_by_rpms(monkeypatch):
+
+ def listdir_mocked(path):
+ assert path == '/base/dir/some/path'
+ return ['fileA', 'fileB.txt', 'test.log', 'script.sh']
+
+ monkeypatch.setattr(os, 'listdir', listdir_mocked)
+ logger = logger_mocked()
+ monkeypatch.setattr(api, 'current_logger', logger)
+
+ search_dir = '/some/path'
+ # output doesn't include full paths
+ owned = ['fileA', 'script.sh']
+ # but the rpm -qf call happens with the full path
+ owned_fullpath = [os.path.join(search_dir, f) for f in owned]
+ context = _MockContext('/base/dir', owned_fullpath)
+
+ out = userspacegen._get_files_owned_by_rpms(context, '/some/path', recursive=False)
+ assert sorted(owned) == sorted(out)
+
+
+def test__get_files_owned_by_rpms_recursive(monkeypatch):
# this is not necessarily accurate, but close enough
fake_walk = [
("/base/dir/etc/pki", ["ca-trust", "tls", "rpm-gpg"], []),
@@ -1250,27 +1288,17 @@ def test__get_files_owned_by_rpms(monkeypatch):
"RPM-GPG-KEY-2",
]),
]
- monkeypatch.setattr(os, 'walk', lambda _: fake_walk)
- logger = logger_mocked()
- monkeypatch.setattr(api, 'current_logger', logger)
- class _MockContext():
+ def walk_mocked(path):
+ assert path == '/base/dir/etc/pki'
+ return fake_walk
- def __init__(self, owned):
- self.base_dir = '/base/dir'
- # list of files owned, no base_dir prefixed
- self.owned = owned
-
- def full_path(self, path):
- return os.path.join(self.base_dir, os.path.abspath(path).lstrip('/'))
-
- def call(self, cmd):
- assert len(cmd) == 3 and cmd[0] == 'rpm' and cmd[1] == '-qf'
- if cmd[2] in self.owned:
- return {'exit_code': 0}
- raise CalledProcessError("Command failed with exit code 1", cmd, 1)
+ monkeypatch.setattr(os, 'walk', walk_mocked)
+ logger = logger_mocked()
+ monkeypatch.setattr(api, 'current_logger', logger)
search_dir = '/etc/pki'
+ # output doesn't include full paths
owned = [
'tls/certs/ca-bundle.crt',
'ca-trust/extracted/openssl/ca-bundle.trust.crt',
@@ -1281,10 +1309,9 @@ def test__get_files_owned_by_rpms(monkeypatch):
]
# the rpm -qf call happens with the full path
owned_fullpath = [os.path.join(search_dir, f) for f in owned]
- context = _MockContext(owned_fullpath)
-
- out = userspacegen._get_files_owned_by_rpms(context, '/etc/pki', recursive=True)
+ context = _MockContext('/base/dir', owned_fullpath)
+ out = userspacegen._get_files_owned_by_rpms(context, search_dir, recursive=True)
# any directory-hash directory should be skipped
assert sorted(owned[0:4]) == sorted(out)
--
2.50.1

View File

@ -0,0 +1,176 @@
From 7c5d7f711d92fffac5567fd4b31bd6df4d24f1f9 Mon Sep 17 00:00:00 2001
From: Ales Nezbeda <anezbeda@redhat.com>
Date: Wed, 16 Jul 2025 11:58:47 +0200
Subject: [PATCH 57/66] el8to9: actors: mysql: Add MySQL actor with
recommendations (#1335)
Introduce a new mysql_check actor which checks for presence of the
mysql_server package and reports related recommendations for upgrade.
Jira: RHEL-5459
---
.../el8toel9/actors/mysqlcheck/actor.py | 20 ++++++
.../actors/mysqlcheck/libraries/mysqlcheck.py | 51 +++++++++++++++
.../mysqlcheck/tests/test_mysqlcheck.py | 65 +++++++++++++++++++
3 files changed, 136 insertions(+)
create mode 100644 repos/system_upgrade/el8toel9/actors/mysqlcheck/actor.py
create mode 100644 repos/system_upgrade/el8toel9/actors/mysqlcheck/libraries/mysqlcheck.py
create mode 100644 repos/system_upgrade/el8toel9/actors/mysqlcheck/tests/test_mysqlcheck.py
diff --git a/repos/system_upgrade/el8toel9/actors/mysqlcheck/actor.py b/repos/system_upgrade/el8toel9/actors/mysqlcheck/actor.py
new file mode 100644
index 00000000..d675d75c
--- /dev/null
+++ b/repos/system_upgrade/el8toel9/actors/mysqlcheck/actor.py
@@ -0,0 +1,20 @@
+from leapp.actors import Actor
+from leapp.libraries.actor.mysqlcheck import process
+from leapp.models import DistributionSignedRPM, Report
+from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
+
+
+class MySQLCheck(Actor):
+ """
+ Actor checking for presence of MySQL installation.
+
+ Provides user with information related to upgrading systems
+ with MySQL installed.
+ """
+ name = 'mysql_check'
+ consumes = (DistributionSignedRPM,)
+ produces = (Report,)
+ tags = (ChecksPhaseTag, IPUWorkflowTag)
+
+ def process(self):
+ process()
diff --git a/repos/system_upgrade/el8toel9/actors/mysqlcheck/libraries/mysqlcheck.py b/repos/system_upgrade/el8toel9/actors/mysqlcheck/libraries/mysqlcheck.py
new file mode 100644
index 00000000..b446d9c4
--- /dev/null
+++ b/repos/system_upgrade/el8toel9/actors/mysqlcheck/libraries/mysqlcheck.py
@@ -0,0 +1,51 @@
+from leapp import reporting
+from leapp.libraries.common.rpms import has_package
+from leapp.models import DistributionSignedRPM
+
+
+def _report_server_installed():
+ """
+ Create report on mysql-server package installation detection.
+
+ Should remind user about present MySQL server package
+ installation, warn them about necessary additional steps, and
+ redirect them to online documentation for the upgrade process.
+ """
+ reporting.create_report([
+ reporting.Title('Further action to upgrade MySQL might be needed'),
+ reporting.Summary(
+ 'The MySQL server component will be reinstalled during the upgrade with a RHEL 9'
+ ' version. Since RHEL 9 includes the same MySQL version 8.0 by default, no action'
+ ' should be required and there should not be any compatibility issues. However,'
+ ' it is still advisable to follow the documentation on this topic for up to date'
+ ' recommendations.'
+ ' Keep in mind that MySQL 8.0, which is the default in RHEL 9, will reach the end'
+ ' of \'Extended Support\' in April 2026. As such it is advisable to upgrade to'
+ ' MySQL version 8.4, which is provided via a module. MySQL 8.4 is also the'
+ ' default version for RHEL 10, therefore having MySQL 8.4 on the RHEL 9 system'
+ ' will make a future upgrade process to RHEL 10 smoother.'
+ ),
+ reporting.Severity(reporting.Severity.MEDIUM),
+ reporting.Groups([reporting.Groups.SERVICES]),
+ reporting.ExternalLink(title='Migrating MySQL databases from RHEL 8 to RHEL 9',
+ url='https://access.redhat.com/articles/7099753'),
+ reporting.RelatedResource('package', 'mysql-server'),
+ reporting.Remediation(hint=(
+ 'Dump or backup your data before proceeding with the upgrade '
+ 'and consult attached article '
+ '\'Migrating MySQL databases from RHEL 8 to RHEL 9\' '
+ 'with up to date recommended steps before and after the upgrade.'
+ )),
+ ])
+
+
+def process():
+ """
+ Create reports according to detected MySQL packages.
+
+ Create the report if the mysql-server rpm (RH signed) is installed.
+ """
+ has_server = has_package(DistributionSignedRPM, 'mysql-server')
+
+ if has_server:
+ _report_server_installed()
diff --git a/repos/system_upgrade/el8toel9/actors/mysqlcheck/tests/test_mysqlcheck.py b/repos/system_upgrade/el8toel9/actors/mysqlcheck/tests/test_mysqlcheck.py
new file mode 100644
index 00000000..385f4dfd
--- /dev/null
+++ b/repos/system_upgrade/el8toel9/actors/mysqlcheck/tests/test_mysqlcheck.py
@@ -0,0 +1,65 @@
+import pytest
+
+from leapp import reporting
+from leapp.libraries.actor.mysqlcheck import process
+from leapp.libraries.common.testutils import create_report_mocked, CurrentActorMocked
+from leapp.libraries.stdlib import api
+from leapp.models import DistributionSignedRPM, RPM
+
+
+def _generate_rpm_with_name(name):
+ """
+ Generate new RPM model item with given name.
+
+ Parameters:
+ name (str): rpm name
+
+ Returns:
+ rpm (RPM): new RPM object with name parameter set
+ """
+ return RPM(name=name,
+ version='0.1',
+ release='1.sm01',
+ epoch='1',
+ pgpsig='RSA/SHA256, Mon 01 Jan 1970 00:00:00 AM -03, Key ID 199e2f91fd431d51',
+ packager='Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla>',
+ arch='noarch')
+
+
+@pytest.mark.parametrize('has_server', [
+ (True), # with server
+ (False), # without server
+])
+def test_actor_execution(monkeypatch, has_server):
+ """
+ Parametrized helper function for test_actor_* functions.
+
+ First generate list of RPM models based on set arguments. Then, run
+ the actor fed with our RPM list. Finally, assert Reports
+ according to set arguments.
+
+ Parameters:
+ has_server (bool): mysql-server installed
+ """
+
+ # Couple of random packages
+ rpms = [_generate_rpm_with_name('sed'),
+ _generate_rpm_with_name('htop')]
+
+ if has_server:
+ # Add mysql-server
+ rpms += [_generate_rpm_with_name('mysql-server')]
+
+ curr_actor_mocked = CurrentActorMocked(msgs=[DistributionSignedRPM(items=rpms)])
+ monkeypatch.setattr(api, 'current_actor', curr_actor_mocked)
+ monkeypatch.setattr(reporting, "create_report", create_report_mocked())
+
+ # Executed actor fed with fake RPMs
+ process()
+
+ if has_server:
+ # Assert for mysql-server package installed
+ assert reporting.create_report.called == 1
+ else:
+ # Assert for no mysql packages installed
+ assert not reporting.create_report.called
--
2.50.1

View File

@ -0,0 +1,176 @@
From ce71a44ffd1965330813c15056b5e58e50217108 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Wed, 2 Jul 2025 16:36:55 +0200
Subject: [PATCH 58/66] Fix target version format checks
Currently only the format of a version specified by
LEAPP_DEVEL_TARGET_RELEASE is checked, when specified via --target
cmdline argument it isn't, which is a bug.
This patch fixes the bug, by enabling the check for --target too.
NOTE: these are only format checks, the state of support is already
checked later in the upgrade process by the checktargetversion actor.
Jira: RHEL-96238
---
commands/command_utils.py | 28 +++++++++------
commands/tests/test_upgrade_paths.py | 54 +++++++++++++++++++---------
commands/upgrade/util.py | 4 +--
3 files changed, 57 insertions(+), 29 deletions(-)
diff --git a/commands/command_utils.py b/commands/command_utils.py
index 155bacad..e6ba6ba4 100644
--- a/commands/command_utils.py
+++ b/commands/command_utils.py
@@ -59,7 +59,9 @@ def assert_version_format(version_str, desired_format, version_kind):
:raises: CommandError
"""
if not re.match(desired_format.regex, version_str):
- error_str = 'Unexpected format of target version: {0}. The required format is \'{1}\'.'
+ error_str = (
+ 'Unexpected format of target version: {0}. The required format is \'{1}\'.'
+ )
raise CommandError(error_str.format(version_str, desired_format.human_readable))
@@ -182,26 +184,32 @@ def get_target_version(flavour):
return target_versions[-1] if target_versions else None
-def vet_upgrade_path(args):
+def get_target_release(args):
"""
- Make sure the user requested upgrade_path is a supported one.
- If LEAPP_DEVEL_TARGET_RELEASE is set then it's value is not vetted against upgrade_paths_map but used as is.
+ Return the user selected target release or choose one from config.
+
+ A target release can be specified, ordered by priority, by the
+ LEAPP_DEVEL_TARGET_RELEASE or args.target (--target cmdline arg) or in the
+ config file.
+
+ NOTE: when specified via the env var or cmdline arg, the version isn't
+ checked against supported versions, this is done later by an actor in the
+ upgrade process.
:return: `tuple` (target_release, flavor)
"""
flavor = get_upgrade_flavour()
env_version_override = os.getenv('LEAPP_DEVEL_TARGET_RELEASE')
- if env_version_override:
+ target_ver = env_version_override or args.target
+ if target_ver:
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)
+ assert_version_format(target_ver, expected_version_format, _VersionKind.TARGET)
+ return (target_ver, flavor)
- target_release = args.target or get_target_version(flavor)
- return (target_release, flavor)
+ return (get_target_version(flavor), flavor)
def set_resource_limits():
diff --git a/commands/tests/test_upgrade_paths.py b/commands/tests/test_upgrade_paths.py
index c2cb09aa..89b5eb71 100644
--- a/commands/tests/test_upgrade_paths.py
+++ b/commands/tests/test_upgrade_paths.py
@@ -1,3 +1,4 @@
+import os
import resource
import mock
@@ -29,34 +30,53 @@ def test_get_target_version(mock_open, monkeypatch):
assert command_utils.get_target_version('default') == '9.0'
-@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"]}})
-def test_vet_upgrade_path(mock_open, monkeypatch):
+@mock.patch(
+ "leapp.cli.commands.command_utils.get_upgrade_paths_config",
+ return_value={
+ "default": {
+ "7.9": ["8.4"],
+ "8.6": ["9.0", "9.2"],
+ "7": ["8.4"],
+ "8": ["9.0", "9.2"],
+ }
+ },
+)
+def test_get_target_release(mock_open, monkeypatch): # do not remove mock_open
monkeypatch.setattr(command_utils, 'get_os_release_version_id', lambda x: '8.6')
# make sure env var LEAPP_DEVEL_TARGET_RELEASE takes precedence
- # when env var set to a bad version - abort the upgrade
- args = mock.Mock(target='9.0')
- monkeypatch.setenv('LEAPP_DEVEL_TARGET_RELEASE', '1.2badsemver')
- with pytest.raises(CommandError) as err:
- command_utils.vet_upgrade_path(args)
- assert 'Unexpected format of target version' in err
- # MAJOR.MINOR.PATCH is considered as bad version, only MAJOR.MINOR is accepted
args = mock.Mock(target='9.0')
+ monkeypatch.setenv('LEAPP_DEVEL_TARGET_RELEASE', '9.2')
+ print(os.getenv('LEAPP_DEVEL_TARGET_RELEASE'))
+ assert command_utils.get_target_release(args) == ('9.2', 'default')
+
+ # when env var set to a bad version, expect an error
monkeypatch.setenv('LEAPP_DEVEL_TARGET_RELEASE', '9.0.0')
with pytest.raises(CommandError) as err:
- command_utils.vet_upgrade_path(args)
+ command_utils.get_target_release(args)
assert 'Unexpected format of target version' in err
+
# when env var set to a version not in upgrade_paths map - go on and use it
+ # this is checked by an actor in the IPU
monkeypatch.setenv('LEAPP_DEVEL_TARGET_RELEASE', '1.2')
- assert command_utils.vet_upgrade_path(args) == ('1.2', 'default')
- # no env var set, --target is set to proper version
+ assert command_utils.get_target_release(args) == ('1.2', 'default')
+
+ # no env var set, --target is set to proper version - use it
+ args = mock.Mock(target='9.0')
monkeypatch.delenv('LEAPP_DEVEL_TARGET_RELEASE', raising=False)
- assert command_utils.vet_upgrade_path(args) == ('9.0', 'default')
- # env var is set to proper version, --target is set to a bad one - use env var and go on with the upgrade
+ assert command_utils.get_target_release(args) == ('9.0', 'default')
+
+ # --target set with incorrectly formatted version, env var not set, fail
+ args = mock.Mock(target='9.0a')
+ with pytest.raises(CommandError) as err:
+ command_utils.get_target_release(args)
+ assert 'Unexpected format of target version' in err
+
+ # env var is set to proper version, --target set to a bad one:
+ # env var has priority, use it and go on with the upgrade
monkeypatch.setenv('LEAPP_DEVEL_TARGET_RELEASE', '9.0')
- args = mock.Mock(target='1.2')
- assert command_utils.vet_upgrade_path(args) == ('9.0', 'default')
+ args = mock.Mock(target='9.0.0')
+ assert command_utils.get_target_release(args) == ('9.0', 'default')
def _mock_getrlimit_factory(nofile_limits=(1024, 4096), fsize_limits=(1024, 4096)):
diff --git a/commands/upgrade/util.py b/commands/upgrade/util.py
index b54b0b34..7d5b563e 100644
--- a/commands/upgrade/util.py
+++ b/commands/upgrade/util.py
@@ -253,8 +253,8 @@ def prepare_configuration(args):
if args.nogpgcheck:
os.environ['LEAPP_NOGPGCHECK'] = '1'
- # Check upgrade path and fail early if it's unsupported
- target_version, flavor = command_utils.vet_upgrade_path(args)
+ # Check upgrade path and fail early if it's invalid
+ target_version, flavor = command_utils.get_target_release(args)
os.environ['LEAPP_UPGRADE_PATH_TARGET_RELEASE'] = target_version
os.environ['LEAPP_UPGRADE_PATH_FLAVOUR'] = flavor
--
2.50.1

View File

@ -0,0 +1,67 @@
From b8d942afba061255b69fa5c41259d418fb000ad8 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Sun, 15 Jun 2025 17:11:28 +0200
Subject: [PATCH 60/66] libs(rhui): add rhel10 targets for upgrades
---
repos/system_upgrade/common/libraries/rhui.py | 30 +++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/repos/system_upgrade/common/libraries/rhui.py b/repos/system_upgrade/common/libraries/rhui.py
index 30de0275..e1ab7c67 100644
--- a/repos/system_upgrade/common/libraries/rhui.py
+++ b/repos/system_upgrade/common/libraries/rhui.py
@@ -158,6 +158,17 @@ RHUI_SETUPS = {
('cdn.redhat.com-chain.crt', RHUI_PKI_DIR),
('content-rhel9.crt', RHUI_PKI_PRODUCT_DIR)
], os_version='9'),
+ mk_rhui_setup(clients={'rh-amazon-rhui-client'}, leapp_pkg='leapp-rhui-aws',
+ mandatory_files=[
+ ('rhui-client-config-server-10.crt', RHUI_PKI_PRODUCT_DIR),
+ ('rhui-client-config-server-10.key', RHUI_PKI_DIR),
+ ('leapp-aws.repo', YUM_REPOS_PATH)
+ ],
+ optional_files=[
+ ('content-rhel10.key', RHUI_PKI_DIR),
+ ('cdn.redhat.com-chain.crt', RHUI_PKI_DIR),
+ ('content-rhel10.crt', RHUI_PKI_PRODUCT_DIR)
+ ], os_version='10'),
],
RHUIFamily(RHUIProvider.AWS, arch=arch.ARCH_ARM64, client_files_folder='aws'): [
mk_rhui_setup(clients={'rh-amazon-rhui-client-arm'}, optional_files=[], os_version='7', arch=arch.ARCH_ARM64),
@@ -185,6 +196,17 @@ RHUI_SETUPS = {
('cdn.redhat.com-chain.crt', RHUI_PKI_DIR),
('content-rhel9.crt', RHUI_PKI_PRODUCT_DIR)
], os_version='9', arch=arch.ARCH_ARM64),
+ mk_rhui_setup(clients={'rh-amazon-rhui-client'}, leapp_pkg='leapp-rhui-aws',
+ mandatory_files=[
+ ('rhui-client-config-server-10.crt', RHUI_PKI_PRODUCT_DIR),
+ ('rhui-client-config-server-10.key', RHUI_PKI_DIR),
+ ('leapp-aws.repo', YUM_REPOS_PATH)
+ ],
+ optional_files=[
+ ('content-rhel10.key', RHUI_PKI_DIR),
+ ('cdn.redhat.com-chain.crt', RHUI_PKI_DIR),
+ ('content-rhel10.crt', RHUI_PKI_PRODUCT_DIR)
+ ], os_version='10'),
],
RHUIFamily(RHUIProvider.AWS, variant=RHUIVariant.SAP, client_files_folder='aws-sap-e4s'): [
mk_rhui_setup(clients={'rh-amazon-rhui-client-sap-bundle'}, optional_files=[], os_version='7',
@@ -250,6 +272,14 @@ RHUI_SETUPS = {
],
extra_info={'agent_pkg': 'WALinuxAgent'},
os_version='9'),
+ mk_rhui_setup(clients={'rhui-azure-rhel10'}, leapp_pkg='leapp-rhui-azure',
+ mandatory_files=[('leapp-azure.repo', YUM_REPOS_PATH)],
+ optional_files=[
+ ('key.pem', RHUI_PKI_DIR),
+ ('content.crt', RHUI_PKI_PRODUCT_DIR)
+ ],
+ extra_info={'agent_pkg': 'WALinuxAgent'},
+ os_version='10'),
],
RHUIFamily(RHUIProvider.AZURE, variant=RHUIVariant.SAP_APPS, client_files_folder='azure-sap-apps'): [
mk_rhui_setup(clients={'rhui-azure-rhel7-base-sap-apps'}, os_version='7', content_channel=ContentChannel.EUS),
--
2.50.1

View File

@ -0,0 +1,35 @@
From 7f9df48b0040499c5de3441f56d1f1ed77667526 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Sun, 15 Jun 2025 23:39:17 +0200
Subject: [PATCH 61/66] userspacegen: do not repolist source & debug repos
Ignore source/debug repositories when running dnf repolist to check what
repositories are available for the upgrade. Should prevent needless
crashes when the source/debug repositories are malformed, e.g., when the
maintainer forgot to sync their content.
---
.../targetuserspacecreator/libraries/userspacegen.py | 8 +++++++-
1 file changed, 7 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 699f1517..9ec4ecac 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
@@ -929,7 +929,13 @@ def _get_rh_available_repoids(context, indata):
os.rename(foreign_repofile, '{0}.back'.format(foreign_repofile))
try:
- dnf_cmd = ['dnf', 'repolist', '--releasever', target_ver, '-v', '--enablerepo', '*']
+ 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}
--
2.50.1

View File

@ -0,0 +1,46 @@
From 24714605538d2e197b0d7a5012528129439b4764 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Tue, 17 Jun 2025 11:18:33 +0200
Subject: [PATCH 62/66] actor(checkrhui): do not boostrap client on AWS 9>10
The current implementation of the checkrhui actor and its modification
of rhui-associated target userspace preparation instructions contains
too coarse conditions on what should happen on specific upgrade paths.
In other words, changes originally intended only for 8>9 are applied
also during 9>10. This patch fixes this issue -- when performing 9>10 on
AWS, we do not bootstrap the RHUI client, as it has too many
dependencies. Instead, the leapp-rhui-aws package contains all
repositories, certs and keys that grant repository access.
Jira-ref: RHEL-64910
---
.../actors/cloud/checkrhui/libraries/checkrhui.py | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
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 64e36e08..ea154173 100644
--- a/repos/system_upgrade/common/actors/cloud/checkrhui/libraries/checkrhui.py
+++ b/repos/system_upgrade/common/actors/cloud/checkrhui/libraries/checkrhui.py
@@ -254,10 +254,16 @@ def customize_rhui_setup_for_aws(rhui_family, setup_info):
# The leapp-rhui-aws will provide all necessary files to access entire RHEL8 content
setup_info.bootstrap_target_client = False
return
+ if target_version == '9':
+ amazon_plugin_copy_task = CopyFile(src='/usr/lib/python3.9/site-packages/dnf-plugins/amazon-id.py',
+ dst='/usr/lib/python3.6/site-packages/dnf-plugins/')
+ setup_info.postinstall_tasks.files_to_copy.append(amazon_plugin_copy_task)
+ return
- amazon_plugin_copy_task = CopyFile(src='/usr/lib/python3.9/site-packages/dnf-plugins/amazon-id.py',
- dst='/usr/lib/python3.6/site-packages/dnf-plugins/')
- setup_info.postinstall_tasks.files_to_copy.append(amazon_plugin_copy_task)
+ # For 9>10 and higher we give up trying to do client swapping since the client has too many dependencies
+ # from target system's repositories. Our leapp-rhui-aws package will carry all of the repos provided
+ # by the client.
+ setup_info.bootstrap_target_client = False
def produce_rhui_info_to_setup_target(rhui_family, source_setup_desc, target_setup_desc):
--
2.50.1

View File

@ -0,0 +1,456 @@
From d0f6c44acfdd8938c7062deae6a16613af2bb4d1 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Wed, 2 Jul 2025 22:26:23 +0200
Subject: [PATCH 63/66] add azure, aws, alibaba client repositories to
repomapping
Co-Authored-By: jinkangkang.jkk <1547182170@qq.com>
---
etc/leapp/files/repomap.json | 293 ++++++++++++++++++++++++++++++++++-
1 file changed, 292 insertions(+), 1 deletion(-)
diff --git a/etc/leapp/files/repomap.json b/etc/leapp/files/repomap.json
index fc0c42f1..0cd5601a 100644
--- a/etc/leapp/files/repomap.json
+++ b/etc/leapp/files/repomap.json
@@ -1,5 +1,5 @@
{
- "datetime": "202505201636Z",
+ "datetime": "202507171303Z",
"version_format": "1.3.0",
"provided_data_streams": [
"4.0"
@@ -294,6 +294,24 @@
"target": [
"rhel10-HighAvailability"
]
+ },
+ {
+ "source": "rhel9-rhui-client-config-server-9",
+ "target": [
+ "rhel10-rhui-client-config-server-10"
+ ]
+ },
+ {
+ "source": "rhel9-rhui-microsoft-azure-rhel9",
+ "target": [
+ "rhel10-rhui-microsoft-azure-rhel10"
+ ]
+ },
+ {
+ "source": "rhel9-rhui-custom-client-at-alibaba",
+ "target": [
+ "rhel10-rhui-custom-client-at-alibaba"
+ ]
}
]
}
@@ -343,6 +361,15 @@
"distro": "rhel",
"rhui": "aws"
},
+ {
+ "major_version": "10",
+ "repoid": "rhel-10-baseos-rhui-rpms",
+ "arch": "aarch64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "azure"
+ },
{
"major_version": "10",
"repoid": "rhel-10-baseos-rhui-rpms",
@@ -352,6 +379,15 @@
"distro": "rhel",
"rhui": "aws"
},
+ {
+ "major_version": "10",
+ "repoid": "rhel-10-baseos-rhui-rpms",
+ "arch": "x86_64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "azure"
+ },
{
"major_version": "10",
"repoid": "rhel-10-for-aarch64-baseos-beta-rpms",
@@ -456,6 +492,15 @@
"repo_type": "rpm",
"distro": "rhel"
},
+ {
+ "major_version": "10",
+ "repoid": "rhel-10-for-x86_64-baseos-e4s-rhui-rpms",
+ "arch": "x86_64",
+ "channel": "e4s",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "aws"
+ },
{
"major_version": "10",
"repoid": "rhel-10-for-x86_64-baseos-e4s-rpms",
@@ -479,6 +524,24 @@
"channel": "ga",
"repo_type": "rpm",
"distro": "rhel"
+ },
+ {
+ "major_version": "10",
+ "repoid": "rhui-rhel-10-for-aarch64-baseos-rhui-rpms",
+ "arch": "aarch64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "alibaba"
+ },
+ {
+ "major_version": "10",
+ "repoid": "rhui-rhel-10-for-x86_64-baseos-rhui-rpms",
+ "arch": "x86_64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "alibaba"
}
]
},
@@ -526,6 +589,15 @@
"distro": "rhel",
"rhui": "aws"
},
+ {
+ "major_version": "10",
+ "repoid": "rhel-10-appstream-rhui-rpms",
+ "arch": "aarch64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "azure"
+ },
{
"major_version": "10",
"repoid": "rhel-10-appstream-rhui-rpms",
@@ -535,6 +607,15 @@
"distro": "rhel",
"rhui": "aws"
},
+ {
+ "major_version": "10",
+ "repoid": "rhel-10-appstream-rhui-rpms",
+ "arch": "x86_64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "azure"
+ },
{
"major_version": "10",
"repoid": "rhel-10-for-aarch64-appstream-beta-rpms",
@@ -639,6 +720,15 @@
"repo_type": "rpm",
"distro": "rhel"
},
+ {
+ "major_version": "10",
+ "repoid": "rhel-10-for-x86_64-appstream-e4s-rhui-rpms",
+ "arch": "x86_64",
+ "channel": "e4s",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "aws"
+ },
{
"major_version": "10",
"repoid": "rhel-10-for-x86_64-appstream-e4s-rpms",
@@ -662,6 +752,24 @@
"channel": "ga",
"repo_type": "rpm",
"distro": "rhel"
+ },
+ {
+ "major_version": "10",
+ "repoid": "rhui-rhel-10-for-aarch64-appstream-rhui-rpms",
+ "arch": "aarch64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "alibaba"
+ },
+ {
+ "major_version": "10",
+ "repoid": "rhui-rhel-10-for-x86_64-appstream-rhui-rpms",
+ "arch": "x86_64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "alibaba"
}
]
},
@@ -741,6 +849,15 @@
"distro": "rhel",
"rhui": "aws"
},
+ {
+ "major_version": "10",
+ "repoid": "codeready-builder-for-rhel-10-rhui-rpms",
+ "arch": "aarch64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "azure"
+ },
{
"major_version": "10",
"repoid": "codeready-builder-for-rhel-10-rhui-rpms",
@@ -750,6 +867,15 @@
"distro": "rhel",
"rhui": "aws"
},
+ {
+ "major_version": "10",
+ "repoid": "codeready-builder-for-rhel-10-rhui-rpms",
+ "arch": "x86_64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "azure"
+ },
{
"major_version": "10",
"repoid": "codeready-builder-for-rhel-10-s390x-eus-rpms",
@@ -813,6 +939,24 @@
"channel": "ga",
"repo_type": "rpm",
"distro": "centos"
+ },
+ {
+ "major_version": "10",
+ "repoid": "rhui-codeready-builder-for-rhel-10-aarch64-rhui-rpms",
+ "arch": "aarch64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "alibaba"
+ },
+ {
+ "major_version": "10",
+ "repoid": "rhui-codeready-builder-for-rhel-10-x86_64-rhui-rpms",
+ "arch": "x86_64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "alibaba"
}
]
},
@@ -923,6 +1067,33 @@
"repo_type": "rpm",
"distro": "rhel",
"rhui": "aws"
+ },
+ {
+ "major_version": "10",
+ "repoid": "rhel-10-supplementary-rhui-rpms",
+ "arch": "x86_64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "azure"
+ },
+ {
+ "major_version": "10",
+ "repoid": "rhui-rhel-10-for-aarch64-supplementary-rhui-rpms",
+ "arch": "aarch64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "alibaba"
+ },
+ {
+ "major_version": "10",
+ "repoid": "rhui-rhel-10-for-x86_64-supplementary-rhui-rpms",
+ "arch": "x86_64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "alibaba"
}
]
},
@@ -1006,6 +1177,14 @@
"repo_type": "rpm",
"distro": "rhel"
},
+ {
+ "major_version": "10",
+ "repoid": "rhel-10-for-aarch64-nfv-e4s-rpms",
+ "arch": "aarch64",
+ "channel": "e4s",
+ "repo_type": "rpm",
+ "distro": "rhel"
+ },
{
"major_version": "10",
"repoid": "rhel-10-for-aarch64-nfv-rpms",
@@ -1115,6 +1294,15 @@
"repo_type": "rpm",
"distro": "rhel"
},
+ {
+ "major_version": "10",
+ "repoid": "rhel-10-for-x86_64-sap-netweaver-e4s-rhui-rpms",
+ "arch": "x86_64",
+ "channel": "e4s",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "aws"
+ },
{
"major_version": "10",
"repoid": "rhel-10-for-x86_64-sap-netweaver-e4s-rpms",
@@ -1160,6 +1348,15 @@
"repo_type": "rpm",
"distro": "rhel"
},
+ {
+ "major_version": "10",
+ "repoid": "rhel-10-for-x86_64-sap-solutions-e4s-rhui-rpms",
+ "arch": "x86_64",
+ "channel": "e4s",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "aws"
+ },
{
"major_version": "10",
"repoid": "rhel-10-for-x86_64-sap-solutions-e4s-rpms",
@@ -1317,6 +1514,15 @@
"repo_type": "rpm",
"distro": "rhel"
},
+ {
+ "major_version": "10",
+ "repoid": "rhel-10-for-x86_64-highavailability-e4s-rhui-rpms",
+ "arch": "x86_64",
+ "channel": "e4s",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "aws"
+ },
{
"major_version": "10",
"repoid": "rhel-10-for-x86_64-highavailability-e4s-rpms",
@@ -1340,6 +1546,75 @@
"channel": "ga",
"repo_type": "rpm",
"distro": "rhel"
+ },
+ {
+ "major_version": "10",
+ "repoid": "rhui-rhel-10-for-x86_64-highavailability-rhui-rpms",
+ "arch": "x86_64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "alibaba"
+ }
+ ]
+ },
+ {
+ "pesid": "rhel10-rhui-microsoft-azure-rhel10",
+ "entries": [
+ {
+ "major_version": "10",
+ "repoid": "rhui-microsoft-azure-rhel10",
+ "arch": "x86_64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "azure"
+ }
+ ]
+ },
+ {
+ "pesid": "rhel10-rhui-client-config-server-10",
+ "entries": [
+ {
+ "major_version": "10",
+ "repoid": "rhui-client-config-server-10",
+ "arch": "aarch64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "aws"
+ },
+ {
+ "major_version": "10",
+ "repoid": "rhui-client-config-server-10",
+ "arch": "x86_64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "aws"
+ }
+ ]
+ },
+ {
+ "pesid": "rhel10-rhui-custom-client-at-alibaba",
+ "entries": [
+ {
+ "major_version": "10",
+ "repoid": "rhui-custom-rhui_client_at_alibaba-rhel-10",
+ "arch": "aarch64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "alibaba"
+ },
+ {
+ "major_version": "10",
+ "repoid": "rhui-custom-rhui_client_at_alibaba-rhel-10",
+ "arch": "x86_64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "distro": "rhel",
+ "rhui": "alibaba"
}
]
},
@@ -5228,6 +5503,14 @@
"repo_type": "rpm",
"distro": "rhel"
},
+ {
+ "major_version": "9",
+ "repoid": "rhel-9-for-aarch64-nfv-e4s-rpms",
+ "arch": "aarch64",
+ "channel": "e4s",
+ "repo_type": "rpm",
+ "distro": "rhel"
+ },
{
"major_version": "9",
"repoid": "rhel-9-for-aarch64-nfv-rpms",
@@ -5594,6 +5877,14 @@
"repo_type": "rpm",
"distro": "rhel"
},
+ {
+ "major_version": "9",
+ "repoid": "rhel-9-for-x86_64-highavailability-aus-rpms",
+ "arch": "x86_64",
+ "channel": "aus",
+ "repo_type": "rpm",
+ "distro": "rhel"
+ },
{
"major_version": "9",
"repoid": "rhel-9-for-x86_64-highavailability-beta-rpms",
--
2.50.1

View File

@ -0,0 +1,36 @@
From 08196d4533c51b9f9d7d45d90ca0bad8b0ef697d Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Fri, 4 Jul 2025 14:05:48 +0200
Subject: [PATCH 64/66] rhui(azure): add target client's GPG key to mandatory
files
The RHEL10's Azure RHUI client is signed using a different GPG
key than RHEL9 client. Therefore, we need to have the key available
when we try to bootstrap the RHEL10 client during the upgrade.
Jira-ref: RHEL-64911
---
repos/system_upgrade/common/libraries/rhui.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/repos/system_upgrade/common/libraries/rhui.py b/repos/system_upgrade/common/libraries/rhui.py
index e1ab7c67..1e3b5359 100644
--- a/repos/system_upgrade/common/libraries/rhui.py
+++ b/repos/system_upgrade/common/libraries/rhui.py
@@ -273,7 +273,12 @@ RHUI_SETUPS = {
extra_info={'agent_pkg': 'WALinuxAgent'},
os_version='9'),
mk_rhui_setup(clients={'rhui-azure-rhel10'}, leapp_pkg='leapp-rhui-azure',
- mandatory_files=[('leapp-azure.repo', YUM_REPOS_PATH)],
+ mandatory_files=[
+ ('leapp-azure.repo', YUM_REPOS_PATH),
+ # We need to have the new GPG key ready when we will be bootstrapping
+ # target rhui client.
+ ('RPM-GPG-KEY-microsoft-azure-release-new', '/etc/pki/rpm-gpg/')
+ ],
optional_files=[
('key.pem', RHUI_PKI_DIR),
('content.crt', RHUI_PKI_PRODUCT_DIR)
--
2.50.1

View File

@ -0,0 +1,77 @@
From 7468b10c32367d11a098c4f10390c18ec55720e1 Mon Sep 17 00:00:00 2001
From: "jinkangkang.jkk" <jinkangkang.jkk@alibaba-inc.com>
Date: Mon, 16 Jun 2025 20:26:45 +0800
Subject: [PATCH 65/66] feat(alibaba): support rhel9 upgrade to rhel10 using
rhui on alibaba cloud
---
repos/system_upgrade/common/libraries/rhui.py | 32 +++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)
diff --git a/repos/system_upgrade/common/libraries/rhui.py b/repos/system_upgrade/common/libraries/rhui.py
index 1e3b5359..b3225d5f 100644
--- a/repos/system_upgrade/common/libraries/rhui.py
+++ b/repos/system_upgrade/common/libraries/rhui.py
@@ -383,6 +383,13 @@ RHUI_SETUPS = {
('content.crt', RHUI_PKI_PRODUCT_DIR)
],
os_version='9'),
+ mk_rhui_setup(clients={'aliyun_rhui_rhel10'}, leapp_pkg='leapp-rhui-alibaba',
+ mandatory_files=[('leapp-alibaba.repo', YUM_REPOS_PATH)],
+ optional_files=[
+ ('key.pem', RHUI_PKI_DIR),
+ ('content.crt', RHUI_PKI_PRODUCT_DIR)
+ ],
+ os_version='10'),
],
RHUIFamily(RHUIProvider.ALIBABA, arch=arch.ARCH_ARM64, client_files_folder='alibaba'): [
mk_rhui_setup(clients={'aliyun_rhui_rhel8'}, leapp_pkg='leapp-rhui-alibaba',
@@ -399,6 +406,13 @@ RHUI_SETUPS = {
('content.crt', RHUI_PKI_PRODUCT_DIR)
],
os_version='9'),
+ mk_rhui_setup(clients={'aliyun_rhui_rhel10'}, leapp_pkg='leapp-rhui-alibaba',
+ mandatory_files=[('leapp-alibaba.repo', YUM_REPOS_PATH)],
+ optional_files=[
+ ('key.pem', RHUI_PKI_DIR),
+ ('content.crt', RHUI_PKI_PRODUCT_DIR)
+ ],
+ os_version='10'),
]
}
@@ -601,15 +615,29 @@ RHUI_CLOUD_MAP = {
],
},
},
+ '9to10': {
+ 'alibaba': {
+ 'src_pkg': 'aliyun_rhui_rhel9',
+ 'target_pkg': 'aliyun_rhui_rhel10',
+ 'leapp_pkg': 'leapp-rhui-alibaba',
+ 'leapp_pkg_repo': 'leapp-alibaba.repo',
+ 'files_map': [
+ ('content.crt', RHUI_PKI_PRODUCT_DIR),
+ ('key.pem', RHUI_PKI_DIR),
+ ('leapp-alibaba.repo', YUM_REPOS_PATH)
+ ],
+ },
+ }
}
-# TODO(mmatuska) deprecate or adjust for 9to10?
def get_upg_path():
"""
Get upgrade path in specific string format
"""
- return '7to8' if get_target_major_version() == '8' else '8to9'
+ source_major_version = get_source_major_version()
+ target_major_version = get_target_major_version()
+ return '{0}to{1}'.format(source_major_version, target_major_version)
@deprecated(since='2023-07-27', message='This functionality has been replaced with the RHUIInfo message.')
--
2.50.1

View File

@ -0,0 +1,203 @@
From 3356c045fe2982f3a26b26b46258398b490a6d67 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matej=20Matu=C5=A1ka?= <mmatuska@redhat.com>
Date: Thu, 17 Jul 2025 14:33:55 +0200
Subject: [PATCH 66/66] Inhibit upgrade on systems with cgroupsv1 on 9to10
(#1392)
* Inhibit upgrade on systems with cgroupsv1 on 9to10
cgroups-v1 were deprecated in RHEL 9 and are unsupported in RHEL 10. The
option to switch to cgroups-v1 is ignored. Users have to migrate to
cgroups-v2 in order to upgrade.
Both legacy and hybrid modes are unsupported. Only unified hierarchy
(cgroups-v2) is supported. More info on how the modes are switched is
at:
https://www.freedesktop.org/software/systemd/man/247/systemd.html#systemd.unified_cgroup_hierarchy
and
https://www.freedesktop.org/software/systemd/man/247/systemd.html#systemd.legacy_systemd_cgroup_controller.
Jira: RHEL-81212
---
.../actors/inhibitcgroupsv1/actor.py | 23 ++++++
.../libraries/inhibitcgroupsv1.py | 56 ++++++++++++++
.../tests/test_inhibitcgroupsv1.py | 74 +++++++++++++++++++
3 files changed, 153 insertions(+)
create mode 100644 repos/system_upgrade/el9toel10/actors/inhibitcgroupsv1/actor.py
create mode 100644 repos/system_upgrade/el9toel10/actors/inhibitcgroupsv1/libraries/inhibitcgroupsv1.py
create mode 100644 repos/system_upgrade/el9toel10/actors/inhibitcgroupsv1/tests/test_inhibitcgroupsv1.py
diff --git a/repos/system_upgrade/el9toel10/actors/inhibitcgroupsv1/actor.py b/repos/system_upgrade/el9toel10/actors/inhibitcgroupsv1/actor.py
new file mode 100644
index 00000000..7a3e4be4
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/inhibitcgroupsv1/actor.py
@@ -0,0 +1,23 @@
+from leapp.actors import Actor
+from leapp.libraries.actor import inhibitcgroupsv1
+from leapp.models import KernelCmdline
+from leapp.reporting import Report
+from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
+
+
+class InhibitCgroupsv1(Actor):
+ """
+ Inhibit upgrade if cgroups-v1 are enabled
+
+ Support for cgroups-v1 was deprecated in RHEL 9 and removed in RHEL 10.
+ Both legacy and hybrid modes are unsupported, only the unified cgroup
+ hierarchy (cgroups-v2) is supported.
+ """
+
+ name = "inhibit_cgroupsv1"
+ consumes = (KernelCmdline,)
+ produces = (Report,)
+ tags = (ChecksPhaseTag, IPUWorkflowTag)
+
+ def process(self):
+ inhibitcgroupsv1.process()
diff --git a/repos/system_upgrade/el9toel10/actors/inhibitcgroupsv1/libraries/inhibitcgroupsv1.py b/repos/system_upgrade/el9toel10/actors/inhibitcgroupsv1/libraries/inhibitcgroupsv1.py
new file mode 100644
index 00000000..6c891f22
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/inhibitcgroupsv1/libraries/inhibitcgroupsv1.py
@@ -0,0 +1,56 @@
+from leapp import reporting
+from leapp.exceptions import StopActorExecutionError
+from leapp.libraries.stdlib import api
+from leapp.models import KernelCmdline
+
+
+def process():
+ kernel_cmdline = next(api.consume(KernelCmdline), None)
+ if not kernel_cmdline:
+ # really unlikely
+ raise StopActorExecutionError("Did not receive any KernelCmdline messages.")
+
+ unified_hierarchy = True # default since RHEL 9
+ legacy_controller_present = False
+ for param in kernel_cmdline.parameters:
+ if param.key == "systemd.unified_cgroup_hierarchy":
+ if param.value is not None and param.value.lower() in ("0", "false", "no"):
+ unified_hierarchy = False
+ if param.key == "systemd.legacy_systemd_cgroup_controller":
+ # no matter the value, it should be removed
+ # it has no effect when unified hierarchy is enabled
+ legacy_controller_present = True
+
+ if unified_hierarchy:
+ api.current_logger().debug("cgroups-v2 already in use, nothing to do, skipping.")
+ return
+
+ remediation_cmd_args = ["systemd.unified_cgroup_hierarchy"]
+ if legacy_controller_present:
+ remediation_cmd_args.append('systemd.legacy_systemd_cgroup_controller')
+
+ summary = (
+ "Leapp detected cgroups-v1 is enabled on the system."
+ " The support of cgroups-v1 was deprecated in RHEL 9 and is removed in RHEL 10."
+ " Software requiring cgroups-v1 might not work correctly or at all on RHEL 10."
+ )
+ reporting.create_report(
+ [
+ reporting.Title("cgroups-v1 enabled on the system"),
+ reporting.Summary(summary),
+ reporting.Severity(reporting.Severity.HIGH),
+ reporting.Groups([reporting.Groups.INHIBITOR, reporting.Groups.KERNEL]),
+ reporting.RelatedResource("package", "systemd"),
+ reporting.Remediation(
+ hint="Make sure no third party software requires cgroups-v1 and switch to cgroups-v2.",
+ # remove the args from commandline, the defaults are the desired values
+ commands=[
+ [
+ "grubby",
+ "--update-kernel=ALL",
+ '--remove-args="{}"'.format(",".join(remediation_cmd_args)),
+ ],
+ ],
+ ),
+ ]
+ )
diff --git a/repos/system_upgrade/el9toel10/actors/inhibitcgroupsv1/tests/test_inhibitcgroupsv1.py b/repos/system_upgrade/el9toel10/actors/inhibitcgroupsv1/tests/test_inhibitcgroupsv1.py
new file mode 100644
index 00000000..9b3ec96f
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/inhibitcgroupsv1/tests/test_inhibitcgroupsv1.py
@@ -0,0 +1,74 @@
+import pytest
+
+from leapp import reporting
+from leapp.libraries.actor import inhibitcgroupsv1
+from leapp.libraries.common.testutils import create_report_mocked, CurrentActorMocked
+from leapp.libraries.stdlib import api
+from leapp.models import KernelCmdline, KernelCmdlineArg
+
+
+@pytest.mark.parametrize(
+ "cmdline_params", (
+ ([KernelCmdlineArg(key="systemd.unified_cgroup_hierarchy", value="0")]),
+ ([KernelCmdlineArg(key="systemd.unified_cgroup_hierarchy", value="false")]),
+ ([KernelCmdlineArg(key="systemd.unified_cgroup_hierarchy", value="False")]),
+ ([KernelCmdlineArg(key="systemd.unified_cgroup_hierarchy", value="no")]),
+ (
+ [
+ KernelCmdlineArg(key="systemd.unified_cgroup_hierarchy", value="0"),
+ KernelCmdlineArg(key="systemd.legacy_systemd_cgroup_controller", value="0"),
+ ]
+ ), (
+ [
+ KernelCmdlineArg(key="systemd.unified_cgroup_hierarchy", value="0"),
+ KernelCmdlineArg(key="systemd.legacy_systemd_cgroup_controller", value="1"),
+ ]
+ )
+ )
+)
+def test_inhibit_should_inhibit(monkeypatch, cmdline_params):
+ curr_actor_mocked = CurrentActorMocked(msgs=[KernelCmdline(parameters=cmdline_params)])
+ monkeypatch.setattr(api, "current_actor", curr_actor_mocked)
+ monkeypatch.setattr(reporting, "create_report", create_report_mocked())
+
+ inhibitcgroupsv1.process()
+
+ assert reporting.create_report.called == 1
+ report = reporting.create_report.reports[0]
+ assert "cgroups-v1" in report["title"]
+ assert reporting.Groups.INHIBITOR in report["groups"]
+
+ command = [r for r in report["detail"]["remediations"] if r["type"] == "command"][0]
+ assert "systemd.unified_cgroup_hierarchy" in command['context'][2]
+ if len(cmdline_params) == 2:
+ assert "systemd.legacy_systemd_cgroup_controller" in command['context'][2]
+
+
+@pytest.mark.parametrize(
+ "cmdline_params", (
+ ([KernelCmdlineArg(key="systemd.unified_cgroup_hierarchy", value="1")]),
+ ([KernelCmdlineArg(key="systemd.unified_cgroup_hierarchy", value="true")]),
+ ([KernelCmdlineArg(key="systemd.unified_cgroup_hierarchy", value="True")]),
+ ([KernelCmdlineArg(key="systemd.unified_cgroup_hierarchy", value="yes")]),
+ ([KernelCmdlineArg(key="systemd.unified_cgroup_hierarchy", value=None)]),
+ (
+ [
+ KernelCmdlineArg(key="systemd.unified_cgroup_hierarchy", value="1"),
+ KernelCmdlineArg(key="systemd.legacy_systemd_cgroup_controller", value="1"),
+ ]
+ ), (
+ [
+ KernelCmdlineArg(key="systemd.unified_cgroup_hierarchy", value="1"),
+ KernelCmdlineArg(key="systemd.legacy_systemd_cgroup_controller", value="0"),
+ ]
+ ),
+ )
+)
+def test_inhibit_should_not_inhibit(monkeypatch, cmdline_params):
+ curr_actor_mocked = CurrentActorMocked(msgs=[KernelCmdline(parameters=cmdline_params)])
+ monkeypatch.setattr(api, "current_actor", curr_actor_mocked)
+ monkeypatch.setattr(reporting, "create_report", create_report_mocked())
+
+ inhibitcgroupsv1.process()
+
+ assert not reporting.create_report.called
--
2.50.1

View File

@ -52,7 +52,7 @@ py2_byte_compile "%1" "%2"}
Name: leapp-repository
Version: 0.22.0
Release: 4%{?dist}
Release: 5%{?dist}
Summary: Repositories for leapp
License: ASL 2.0
@ -112,6 +112,33 @@ Patch0041: 0041-repomap-Process-repositories-based-on-distro.patch
Patch0042: 0042-Update-the-upgrade-data-files-stream-4.0.patch
Patch0043: 0043-unit-tests-suppress-deprecation-warning-for-is_rhel_.patch
# CTC2 Candidate1
Patch0044: 0044-Remove-obsolete-workflows.patch
Patch0045: 0045-README-IRC-GitHub-discussions.patch
Patch0046: 0046-Resolve-boot-issues-in-hybrid-azure-during-upgrades-.patch
Patch0047: 0047-Restructure-hybrid-image-detection.patch
Patch0048: 0048-Point-to-leapp-repository-contribution-guidelines.patch
Patch0049: 0049-Read-the-DNF-config-by-module.py-library.patch
Patch0050: 0050-Disable-localpkg_gpgcheck-parameter-from-plugin-data.patch
Patch0051: 0051-PR-welcome-msg-update-link-to-contrib-guidelines-139.patch
Patch0052: 0052-Fix-skip-checking-ownership-of-files-in-.-directory-.patch
Patch0053: 0053-fixup-Fix-skip-checking-ownership-of-files-in-.-dire.patch
Patch0054: 0054-Add-test.patch
Patch0055: 0055-fixup-Add-test.patch
Patch0056: 0056-Add-test-for-non-recursive.patch
Patch0057: 0057-el8to9-actors-mysql-Add-MySQL-actor-with-recommendat.patch
Patch0058: 0058-Fix-target-version-format-checks.patch
# do not apply this patch, due to error in centpkg tool
# it doesn't contain any functional change
#Patch0059: 0059-Drop-el7toel8-leapp-repository.patch
Patch0060: 0060-libs-rhui-add-rhel10-targets-for-upgrades.patch
Patch0061: 0061-userspacegen-do-not-repolist-source-debug-repos.patch
Patch0062: 0062-actor-checkrhui-do-not-boostrap-client-on-AWS-9-10.patch
Patch0063: 0063-add-azure-aws-alibaba-client-repositories-to-repomap.patch
Patch0064: 0064-rhui-azure-add-target-client-s-GPG-key-to-mandatory-.patch
Patch0065: 0065-feat-alibaba-support-rhel9-upgrade-to-rhel10-using-r.patch
Patch0066: 0066-Inhibit-upgrade-on-systems-with-cgroupsv1-on-9to10-1.patch
%description
%{summary}
@ -321,6 +348,28 @@ Requires: libdb-utils
%patch -P 0041 -p1
%patch -P 0042 -p1
%patch -P 0043 -p1
%patch -P 0044 -p1
%patch -P 0045 -p1
%patch -P 0046 -p1
%patch -P 0047 -p1
%patch -P 0048 -p1
%patch -P 0049 -p1
%patch -P 0050 -p1
%patch -P 0051 -p1
%patch -P 0052 -p1
%patch -P 0053 -p1
%patch -P 0054 -p1
%patch -P 0055 -p1
%patch -P 0056 -p1
%patch -P 0057 -p1
%patch -P 0058 -p1
%patch -P 0060 -p1
%patch -P 0061 -p1
%patch -P 0062 -p1
%patch -P 0063 -p1
%patch -P 0064 -p1
%patch -P 0065 -p1
%patch -P 0066 -p1
%build
@ -402,6 +451,15 @@ done;
# no files here
%changelog
* Fri Jul 18 2025 Karolina Kula <kkula@redhat.com> - 0.22.0-5
- Fix broken bootloader on Azure hybrid images for systems previously upgraded from RHEL 7
- Load DNF configuration correctly when using DNF libraries
- Disable localpkg_gpgcheck during the upgrade if set to allow installation of bundled leapp and leapp-repository deps packages
- Add actor with recommendations for upgrade of MySQL
- The HybridImage model has been replaced by ConvertGrubenvTask
- Check the input format of the target version properly
- Resolves: RHEL-5459, RHEL-38255, RHEL-39095, RHEL-47472, RHEL-96238
* Thu Jun 05 2025 Karolina Kula <kkula@redhat.com> - 0.22.0-4
- Fix parsing of the kernel cmdline
- Require leapp data with provided_data_streams 4.0+