Rebase to v0.19.0

- Requires leapp-framework 5.0
- Handle correctly the installed certificates to allow upgrades with custom repositories using HTTPs with enabled SSL verification
- Fix failing upgrades with devtmpfs file systems specified in FSTAB
- Do not try to update GRUB core on IBM Z systems
- Minor improvements and fixes of various reports and error messages
- Redesign handling of information about kernel (booted and target) to reflect changes in RHEL 9.3
- Use new leapp CLI API which provides better report summary output
- Resolves: rhbz#2215997, rhbz#2222861, rhbz#2232618
This commit is contained in:
Petr Stodulka 2023-08-23 19:13:13 +02:00
parent 8a0ca1aafa
commit 1cf1046f79
45 changed files with 16 additions and 523765 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@ SOURCES/deps-pkgs-9.tar.gz
SOURCES/leapp-repository-0.18.0.tar.gz
/deps-pkgs-9.tar.gz
/leapp-repository-0.18.0.tar.gz
/leapp-repository-0.19.0.tar.gz

View File

@ -1,49 +0,0 @@
From 096c3a9545c2f98167d38b89d1115d9ae1031c87 Mon Sep 17 00:00:00 2001
From: Michal Reznik <mreznik@redhat.com>
Date: Fri, 25 Mar 2022 18:17:50 +0100
Subject: [PATCH 01/30] Add leapp pkgs rpm verification into the breadcrumbs
---
commands/upgrade/breadcrumbs.py | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/commands/upgrade/breadcrumbs.py b/commands/upgrade/breadcrumbs.py
index 9138965c..bfb91148 100644
--- a/commands/upgrade/breadcrumbs.py
+++ b/commands/upgrade/breadcrumbs.py
@@ -41,6 +41,7 @@ class _BreadCrumbs(object):
self._crumbs = {
'activity': activity,
'packages': self._get_packages(),
+ 'leapp_file_changes': [],
'executed': ' '.join([v if ' ' not in v else '"{}"'.format(v) for v in sys.argv]),
'success': True,
'activity_started': datetime.datetime.utcnow().isoformat() + 'Z',
@@ -86,6 +87,7 @@ class _BreadCrumbs(object):
def save(self):
self._crumbs['run_id'] = os.environ.get('LEAPP_EXECUTION_ID', 'N/A')
+ self._crumbs['leapp_file_changes'].extend(self._verify_leapp_pkgs())
messages = get_messages(('IPUConfig',), self._crumbs['run_id'])
versions = json.loads((messages or [{}])[0].get('message', {}).get(
'data', '{}')).get('version', {'target': 'N/A', 'source': 'N/A'})
@@ -124,6 +126,16 @@ class _BreadCrumbs(object):
for t in [line.strip().split(' ', 1) for line in res['stdout'].split('\n') if line.strip()]]
return []
+ def _verify_leapp_pkgs(self):
+ upg_path = os.environ.get('LEAPP_IPU_IN_PROGRESS').split('to')
+ cmd = ['/bin/bash', '-c', 'rpm -V leapp leapp-upgrade-el{}toel{}'.format(upg_path[0], upg_path[1])]
+ res = _call(cmd, lambda x, y: None, lambda x, y: None)
+ if res.get('exit_code', None) == 1:
+ if res.get('stdout', None):
+ return [{'result': t[0], 'file_name': t[1]}
+ for t in [line.strip().split(' ', 1) for line in res['stdout'].split('\n') if line.strip()]]
+ return []
+
def produces_breadcrumbs(f):
"""
--
2.40.1

View File

@ -1,42 +0,0 @@
From 6aee6d7f3b6628f5161d5bf9795ab53d52fa1819 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Fri, 10 Mar 2023 13:34:41 +0100
Subject: [PATCH 02/30] Update codespell ignorelist: couldn,repositor
The new version of codespell contains additional "typos" for the
detection in the dictionary, which produces FP fails in tests
as typos are detected also in cases like:
couldn\'t
repositor{suffix}
etc. For now, we will just update the ignorelist, but in future
it would be ideal to not generate such cases. Doing differences
between singular/plural is not providing big benefit in report.
Escaping is not so problematic I would say, but in case of issues,
we could just switch to longer form - like "could not".
But there is no beenfit to update the existing code now, so let's
focus in future on better texts and keep the existing strings as
they are until they are reworded due to additional wanted changes
(I mean, if there is any additional reason in future to change them).
FYI:
https://github.com/codespell-project/codespell/issues/2786
---
.github/workflows/codespell.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml
index e7532d98..681669ab 100644
--- a/.github/workflows/codespell.yml
+++ b/.github/workflows/codespell.yml
@@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v3
- uses: codespell-project/actions-codespell@master
with:
- ignore_words_list: ro,fo
+ ignore_words_list: ro,fo,couldn,repositor
skip: "./repos/system_upgrade/common/actors/storagescanner/tests/files/mounts,\
./repos/system_upgrade/el7toel8/actors/networkmanagerreadconfig/tests/files/nm_cfg_file_error,\
./repos/system_upgrade/common/actors/scancpu/tests/files/lscpu_s390x"
--
2.40.1

View File

@ -1,29 +0,0 @@
From bf3da8ef5007606bcd73b677a4524e30ab4a8dff Mon Sep 17 00:00:00 2001
From: Andrea Waltlova <awaltlov@redhat.com>
Date: Mon, 20 Mar 2023 18:35:49 +0100
Subject: [PATCH 03/30] Fix dead link in checkipaserver actor
---
.../actors/checkipaserver/libraries/checkipaserver.py | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/repos/system_upgrade/common/actors/checkipaserver/libraries/checkipaserver.py b/repos/system_upgrade/common/actors/checkipaserver/libraries/checkipaserver.py
index 41daff15..5ec36d06 100644
--- a/repos/system_upgrade/common/actors/checkipaserver/libraries/checkipaserver.py
+++ b/repos/system_upgrade/common/actors/checkipaserver/libraries/checkipaserver.py
@@ -1,10 +1,8 @@
from leapp import reporting
from leapp.libraries.common.config.version import get_source_major_version
-MIGRATION_GUIDE_7 = (
- "https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux"
- "/8/html/installing_identity_management/migrate-7-to-8_migrating"
- )
+MIGRATION_GUIDE_7 = "https://red.ht/IdM-upgrading-RHEL-7-to-RHEL-8"
+
# TBD: update the doc url when migration guide 8->9 becomes available
MIGRATION_GUIDE_8 = "https://red.ht/IdM-upgrading-RHEL-8-to-RHEL-9"
MIGRATION_GUIDES = {
--
2.40.1

View File

@ -1,38 +0,0 @@
From acf3346dd0c0b952194cf0c3ff6803e857165d1f Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Fri, 24 Mar 2023 13:56:07 +0100
Subject: [PATCH 04/30] checkhybridimage: Fix the produce of the report
The actor can produce the report, however the report is never
stored / accepted by the leapp framework as the Report has not been
set in the `produces` tuple. Fixing the actor.
Signed-off-by: Petr Stodulka <pstodulk@redhat.com>
---
.../common/actors/cloud/checkhybridimage/actor.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/repos/system_upgrade/common/actors/cloud/checkhybridimage/actor.py b/repos/system_upgrade/common/actors/cloud/checkhybridimage/actor.py
index 47f5fdd8..3cd2d864 100644
--- a/repos/system_upgrade/common/actors/cloud/checkhybridimage/actor.py
+++ b/repos/system_upgrade/common/actors/cloud/checkhybridimage/actor.py
@@ -1,6 +1,7 @@
from leapp.actors import Actor
from leapp.libraries.actor.checkhybridimage import check_hybrid_image
from leapp.models import FirmwareFacts, HybridImage, InstalledRPM
+from leapp.reporting import Report
from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
@@ -16,7 +17,7 @@ class CheckHybridImage(Actor):
name = 'checkhybridimage'
consumes = (InstalledRPM, FirmwareFacts)
- produces = (HybridImage,)
+ produces = (HybridImage, Report)
tags = (ChecksPhaseTag, IPUWorkflowTag)
def process(self):
--
2.40.1

View File

@ -1,194 +0,0 @@
From d0b26dc60f11a59566564540395e11838a53e1b4 Mon Sep 17 00:00:00 2001
From: Rodolfo Olivieri <rolivier@redhat.com>
Date: Tue, 21 Mar 2023 14:07:39 -0300
Subject: [PATCH 05/30] Upgrade packit.yaml config to have integration tests
This commit introduces the execution of leapp-repository integration tests as
a packit job.
Signed-off-by: Rodolfo Olivieri <rolivier@redhat.com>
---
.packit.yaml | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 170 insertions(+)
diff --git a/.packit.yaml b/.packit.yaml
index f1d59ce1..96ed8901 100644
--- a/.packit.yaml
+++ b/.packit.yaml
@@ -84,3 +84,173 @@ jobs:
post-upstream-clone:
# builds from master branch should start with 100 release, to have high priority
- bash -c "sed -i \"s/1%{?dist}/100%{?dist}/g\" packaging/leapp-repository.spec"
+
+- job: tests
+ fmf_url: "https://gitlab.cee.redhat.com/oamg/tmt-plans"
+ fmf_ref: "master"
+ use_internal_tf: True
+ trigger: pull_request
+ targets:
+ epel-7-x86_64:
+ distros: [RHEL-7.9-ZStream]
+ identifier: tests-7.9to8.6
+ tmt_plan: "^(?!.*c2r)(?!.*sap)(?!.*8to9)"
+ tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
+ tf_extra_params:
+ environments:
+ - tmt:
+ context:
+ distro: "rhel-7.9"
+ env:
+ SOURCE_RELEASE: "7.9"
+ TARGET_RELEASE: "8.6"
+
+- job: tests
+ fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
+ fmf_ref: "master"
+ use_internal_tf: True
+ trigger: pull_request
+ targets:
+ epel-7-x86_64:
+ distros: [RHEL-7.9-ZStream]
+ identifier: tests-7.9to8.8
+ tmt_plan: "^(?!.*upgrade_plugin)(?!.*tier[2-3].*)(?!.*rhsm)(?!.*c2r)(?!.*sap)(?!.*8to9)(?!.*max_sst)"
+ tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
+ tf_extra_params:
+ environments:
+ - tmt:
+ context:
+ distro: "rhel-7.9"
+ env:
+ SOURCE_RELEASE: "7.9"
+ TARGET_RELEASE: "8.8"
+
+- job: tests
+ fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
+ fmf_ref: "master"
+ use_internal_tf: True
+ trigger: pull_request
+ targets:
+ epel-7-x86_64:
+ distros: [RHEL-7.9-ZStream]
+ identifier: tests-7.9to8.8-sst
+ tmt_plan: "^(?!.*tier[2-3].*)(.*max_sst.*)"
+ tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
+ tf_extra_params:
+ environments:
+ - tmt:
+ context:
+ distro: "rhel-7.9"
+ env:
+ SOURCE_RELEASE: "7.9"
+ TARGET_RELEASE: "8.8"
+
+- job: tests
+ fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
+ fmf_ref: "master"
+ use_internal_tf: True
+ trigger: pull_request
+ targets:
+ epel-7-x86_64:
+ distros: [RHEL-7.9-rhui]
+ identifier: tests-7to8-aws-e2e
+ tmt_plan: "^(?!.*upgrade_plugin)(?!.*tier[2-3].*)(?!.*rhsm)(?!.*c2r)(?!.*sap)(?!.*8to9)(.*e2e)"
+ tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys; echo 42; yum-config-manager --enable rhel-7-server-rhui-optional-rpms"
+ tf_extra_params:
+ environments:
+ - tmt:
+ context:
+ distro: "rhel-7.9"
+ env:
+ SOURCE_RELEASE: "7.9"
+ TARGET_RELEASE: "8.6"
+ RHUI: "aws"
+
+- job: tests
+ fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
+ fmf_ref: "master"
+ use_internal_tf: True
+ trigger: pull_request
+ targets:
+ epel-8-x86_64:
+ distros: [RHEL-8.6.0-Nightly]
+ identifier: tests-8.6to9.0
+ tmt_plan: "^(?!.*upgrade_plugin)(?!.*tier[2-3].*)(?!.*rhsm)(?!.*c2r)(?!.*sap)(?!.*7to8)(?!.*max_sst)"
+ tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
+ tf_extra_params:
+ environments:
+ - tmt:
+ context:
+ distro: "rhel-8.6"
+ env:
+ 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"
+
+- job: tests
+ fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
+ fmf_ref: "master"
+ use_internal_tf: True
+ trigger: pull_request
+ targets:
+ epel-8-x86_64:
+ distros: [RHEL-8.7.0-Nightly]
+ identifier: tests-8.7to9.0
+ tmt_plan: "^(?!.*upgrade_plugin)(?!.*tier[2-3].*)(?!.*rhsm)(?!.*c2r)(?!.*sap)(?!.*7to8)(?!.*max_sst)"
+ tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
+ tf_extra_params:
+ environments:
+ - tmt:
+ context:
+ distro: "rhel-8.7"
+ env:
+ SOURCE_RELEASE: "8.7"
+ TARGET_RELEASE: "9.0"
+ TARGET_KERNEL: "el9"
+ RHSM_REPOS: "rhel-8-for-x86_64-appstream-rpms,rhel-8-for-x86_64-baseos-rpms"
+
+- job: tests
+ fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
+ fmf_ref: "master"
+ use_internal_tf: True
+ trigger: pull_request
+ targets:
+ epel-8-x86_64:
+ distros: [RHEL-8.6.0-Nightly]
+ identifier: tests-8.6to9.0-sst
+ tmt_plan: "^(?!.*tier[2-3].*)(.*max_sst.*)"
+ tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
+ tf_extra_params:
+ environments:
+ - tmt:
+ context:
+ distro: "rhel-8.6"
+ env:
+ 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"
+
+- job: tests
+ fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
+ fmf_ref: "master"
+ use_internal_tf: True
+ trigger: pull_request
+ targets:
+ epel-8-x86_64:
+ distros: [RHEL-8.6-rhui]
+ identifier: tests-8to9-aws-e2e
+ tmt_plan: "^(?!.*upgrade_plugin)(?!.*tier[2-3].*)(?!.*rhsm)(?!.*c2r)(?!.*sap)(?!.*7to8)(.*e2e)"
+ tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
+ tf_extra_params:
+ environments:
+ - tmt:
+ context:
+ distro: "rhel-8.6"
+ env:
+ 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"
--
2.40.1

View File

@ -1,178 +0,0 @@
From d0f7e7c5ec10ba5a7baa90e881f050074e3da86c Mon Sep 17 00:00:00 2001
From: Rodolfo Olivieri <rolivier@redhat.com>
Date: Wed, 22 Mar 2023 09:31:18 -0300
Subject: [PATCH 06/30] Update packit config to match the leapp-repositoyr
tests
Signed-off-by: Rodolfo Olivieri <rolivier@redhat.com>
---
.packit.yaml | 101 ++++++++++++++++++++++++++-------------------------
1 file changed, 52 insertions(+), 49 deletions(-)
diff --git a/.packit.yaml b/.packit.yaml
index 96ed8901..0ece84da 100644
--- a/.packit.yaml
+++ b/.packit.yaml
@@ -94,7 +94,7 @@ jobs:
epel-7-x86_64:
distros: [RHEL-7.9-ZStream]
identifier: tests-7.9to8.6
- tmt_plan: "^(?!.*c2r)(?!.*sap)(?!.*8to9)"
+ tmt_plan: "^(?!.*upgrade_plugin)(?!.*tier[2-3].*)(?!.*rhsm)(?!.*c2r)(?!.*sap)(?!.*8to9)(?!.*max_sst)"
tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
tf_extra_params:
environments:
@@ -104,6 +104,7 @@ jobs:
env:
SOURCE_RELEASE: "7.9"
TARGET_RELEASE: "8.6"
+ LEAPPDATA_BRANCH: "upstream"
- job: tests
fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
@@ -124,26 +125,27 @@ jobs:
env:
SOURCE_RELEASE: "7.9"
TARGET_RELEASE: "8.8"
+ LEAPPDATA_BRANCH: "upstream"
-- job: tests
- fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
- fmf_ref: "master"
- use_internal_tf: True
- trigger: pull_request
- targets:
- epel-7-x86_64:
- distros: [RHEL-7.9-ZStream]
- identifier: tests-7.9to8.8-sst
- tmt_plan: "^(?!.*tier[2-3].*)(.*max_sst.*)"
- tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
- tf_extra_params:
- environments:
- - tmt:
- context:
- distro: "rhel-7.9"
- env:
- SOURCE_RELEASE: "7.9"
- TARGET_RELEASE: "8.8"
+# - job: tests
+# fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
+# fmf_ref: "master"
+# use_internal_tf: True
+# trigger: pull_request
+# targets:
+# epel-7-x86_64:
+# distros: [RHEL-7.9-ZStream]
+# identifier: tests-7.9to8.8-sst
+# tmt_plan: "^(?!.*tier[2-3].*)(.*max_sst.*)"
+# tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
+# tf_extra_params:
+# environments:
+# - tmt:
+# context:
+# distro: "rhel-7.9"
+# env:
+# SOURCE_RELEASE: "7.9"
+# TARGET_RELEASE: "8.8"
- job: tests
fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
@@ -165,6 +167,7 @@ jobs:
SOURCE_RELEASE: "7.9"
TARGET_RELEASE: "8.6"
RHUI: "aws"
+ LEAPPDATA_BRANCH: "upstream"
- job: tests
fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
@@ -185,8 +188,8 @@ jobs:
env:
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"
- job: tests
fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
@@ -195,42 +198,42 @@ jobs:
trigger: pull_request
targets:
epel-8-x86_64:
- distros: [RHEL-8.7.0-Nightly]
- identifier: tests-8.7to9.0
+ distros: [RHEL-8.8.0-Nightly]
+ identifier: tests-8.8to9.2
tmt_plan: "^(?!.*upgrade_plugin)(?!.*tier[2-3].*)(?!.*rhsm)(?!.*c2r)(?!.*sap)(?!.*7to8)(?!.*max_sst)"
tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
tf_extra_params:
environments:
- tmt:
context:
- distro: "rhel-8.7"
+ distro: "rhel-8.8"
env:
- SOURCE_RELEASE: "8.7"
- TARGET_RELEASE: "9.0"
- TARGET_KERNEL: "el9"
+ SOURCE_RELEASE: "8.8"
+ TARGET_RELEASE: "9.2"
RHSM_REPOS: "rhel-8-for-x86_64-appstream-rpms,rhel-8-for-x86_64-baseos-rpms"
+ LEAPPDATA_BRANCH: "upstream"
-- job: tests
- fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
- fmf_ref: "master"
- use_internal_tf: True
- trigger: pull_request
- targets:
- epel-8-x86_64:
- distros: [RHEL-8.6.0-Nightly]
- identifier: tests-8.6to9.0-sst
- tmt_plan: "^(?!.*tier[2-3].*)(.*max_sst.*)"
- tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
- tf_extra_params:
- environments:
- - tmt:
- context:
- distro: "rhel-8.6"
- env:
- 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"
+# - job: tests
+# fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
+# fmf_ref: "master"
+# use_internal_tf: True
+# trigger: pull_request
+# targets:
+# epel-8-x86_64:
+# distros: [RHEL-8.6.0-Nightly]
+# identifier: tests-8.6to9.0-sst
+# tmt_plan: "^(?!.*tier[2-3].*)(.*max_sst.*)"
+# tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
+# tf_extra_params:
+# environments:
+# - tmt:
+# context:
+# distro: "rhel-8.6"
+# env:
+# SOURCE_RELEASE: "8.6"
+# TARGET_RELEASE: "9.0"
+# RHSM_REPOS: "rhel-8-for-x86_64-appstream-eus-rpms,rhel-8-for-x86_64-baseos-eus-rpms"
+# LEAPPDATA_BRANCH: "upstream"
- job: tests
fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
@@ -251,6 +254,6 @@ jobs:
env:
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"
--
2.40.1

View File

@ -1,28 +0,0 @@
From 9d0eab76ca2ac4d27a5dd014ae1f986338b6c421 Mon Sep 17 00:00:00 2001
From: Rodolfo Olivieri <rolivier@redhat.com>
Date: Thu, 23 Mar 2023 11:56:51 -0300
Subject: [PATCH 07/30] Add new environment variable to 8.8to9.2
Signed-off-by: Rodolfo Olivieri <rolivier@redhat.com>
---
.packit.yaml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.packit.yaml b/.packit.yaml
index 0ece84da..3c0f7d55 100644
--- a/.packit.yaml
+++ b/.packit.yaml
@@ -210,8 +210,9 @@ jobs:
env:
SOURCE_RELEASE: "8.8"
TARGET_RELEASE: "9.2"
- RHSM_REPOS: "rhel-8-for-x86_64-appstream-rpms,rhel-8-for-x86_64-baseos-rpms"
+ RHSM_REPOS: "rhel-8-for-x86_64-appstream-beta-rpms,rhel-8-for-x86_64-baseos-beta-rpms"
LEAPPDATA_BRANCH: "upstream"
+ LEAPP_DEVEL_TARGET_RELEASE: "9.2"
# - job: tests
# fmf_url: "https://gitlab.cee.redhat.com/oamg/leapp-tests"
--
2.40.1

View File

@ -1,30 +0,0 @@
From 5326d06042006f585be4de720dcd9316dda0772e Mon Sep 17 00:00:00 2001
From: mreznik <mreznik@redhat.com>
Date: Tue, 11 Apr 2023 14:52:42 +0200
Subject: [PATCH 08/30] Stop mentioning the "releasever" file removal
Do not mention the "releasever" file removal in order to not confuse
users.
---
.../checketcreleasever/libraries/checketcreleasever.py | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/repos/system_upgrade/common/actors/checketcreleasever/libraries/checketcreleasever.py b/repos/system_upgrade/common/actors/checketcreleasever/libraries/checketcreleasever.py
index c92d7dad..b0eb7918 100644
--- a/repos/system_upgrade/common/actors/checketcreleasever/libraries/checketcreleasever.py
+++ b/repos/system_upgrade/common/actors/checketcreleasever/libraries/checketcreleasever.py
@@ -15,10 +15,7 @@ def handle_etc_releasever():
'file and/or the system is using RHUI infrastructure. In order to avoid issues with repofile URLs '
'(when --release option is not provided) in cases where there is the previous major.minor version value '
'in the configuration, release version will be set to the target release version ({}). This will also '
- 'ensure the system stays on the target version after the upgrade. In order to enable latest minor version '
- 'updates, you can remove "/etc/dnf/vars/releasever" file.'.format(
- target_version
- )
+ 'ensure the system stays on the expected target version after the upgrade'.format(target_version)
),
reporting.Severity(reporting.Severity.INFO),
reporting.Groups([reporting.Groups.UPGRADE_PROCESS]),
--
2.40.1

View File

@ -1,32 +0,0 @@
From dd501739e40837d721dbe2a43a412402555ef46c Mon Sep 17 00:00:00 2001
From: Inessa Vasilevskaya <ivasilev@redhat.com>
Date: Tue, 14 Mar 2023 12:03:35 +0100
Subject: [PATCH 09/30] Fix trace with impossible LEAPP_DEVEL_TARGET_RELEASE
With this change the (pre)upgrade will correctly handle
impossible target release version, no more ugly trace will
be shown.
OAMG-8651
---
commands/upgrade/breadcrumbs.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/commands/upgrade/breadcrumbs.py b/commands/upgrade/breadcrumbs.py
index bfb91148..61660fb1 100644
--- a/commands/upgrade/breadcrumbs.py
+++ b/commands/upgrade/breadcrumbs.py
@@ -127,6 +127,10 @@ class _BreadCrumbs(object):
return []
def _verify_leapp_pkgs(self):
+ if not os.environ.get('LEAPP_IPU_IN_PROGRESS'):
+ # NOTE(ivasilev) this can happen if LEAPP_DEVEL_TARGET_RELEASE is specified and pointing to an impossible
+ # version
+ return []
upg_path = os.environ.get('LEAPP_IPU_IN_PROGRESS').split('to')
cmd = ['/bin/bash', '-c', 'rpm -V leapp leapp-upgrade-el{}toel{}'.format(upg_path[0], upg_path[1])]
res = _call(cmd, lambda x, y: None, lambda x, y: None)
--
2.40.1

View File

@ -1,65 +0,0 @@
From 035f5a9cfdc74e760cc39a32769296466cb04ff5 Mon Sep 17 00:00:00 2001
From: Inessa Vasilevskaya <ivasilev@redhat.com>
Date: Thu, 13 Apr 2023 19:50:55 +0200
Subject: [PATCH 10/30] Make copr-build functioning again
After some unknown changes around COPR, the building
command and the used COPR configuration file needs to be
updated.
OAMG-8876
---
.github/workflows/reuse-copr-build.yml | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/reuse-copr-build.yml b/.github/workflows/reuse-copr-build.yml
index eb700df4..093e0c1a 100644
--- a/.github/workflows/reuse-copr-build.yml
+++ b/.github/workflows/reuse-copr-build.yml
@@ -57,18 +57,19 @@ jobs:
env:
COPR_CONFIG: "copr_fedora.conf"
COPR_CHROOT: "epel-7-x86_64,epel-8-x86_64"
+ COPR_REPO: "@oamg/leapp"
run: |
cat << EOF > $COPR_CONFIG
[copr-cli]
login = ${{ secrets.FEDORA_COPR_LOGIN }}
- username = @oamg
+ 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_CHROOT=$COPR_CHROOT make copr_build | tee copr.log
+ 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}"
@@ -122,18 +123,19 @@ jobs:
env:
COPR_CONFIG: "copr_fedora.conf"
COPR_CHROOT: "epel-7-x86_64,epel-8-x86_64"
+ COPR_REPO: "@oamg/leapp"
run: |
cat << EOF > $COPR_CONFIG
[copr-cli]
login = ${{ secrets.FEDORA_COPR_LOGIN }}
- username = @oamg
+ 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_CHROOT=$COPR_CHROOT make copr_build | tee copr.log
+ 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}"
--
2.40.1

View File

@ -1,93 +0,0 @@
From eb438f8be15b99fb4fae2346386e60283903ca20 Mon Sep 17 00:00:00 2001
From: Inessa Vasilevskaya <ivasilev@redhat.com>
Date: Mon, 17 Apr 2023 12:36:24 +0200
Subject: [PATCH 11/30] Add tag in packit.yaml to enable cost metrics
collection
Now all tft tests run by packit should be marked accordingly
with a sst-upgrades tag.
OAMG-8892
---
.packit.yaml | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/.packit.yaml b/.packit.yaml
index 3c0f7d55..595e94be 100644
--- a/.packit.yaml
+++ b/.packit.yaml
@@ -101,6 +101,11 @@ jobs:
- tmt:
context:
distro: "rhel-7.9"
+ # tag resources as sst_upgrades to enable cost metrics collection
+ - settings:
+ provisioning:
+ tags:
+ BusinessUnit: sst_upgrades
env:
SOURCE_RELEASE: "7.9"
TARGET_RELEASE: "8.6"
@@ -122,6 +127,11 @@ jobs:
- tmt:
context:
distro: "rhel-7.9"
+ # tag resources as sst_upgrades to enable cost metrics collection
+ - settings:
+ provisioning:
+ tags:
+ BusinessUnit: sst_upgrades
env:
SOURCE_RELEASE: "7.9"
TARGET_RELEASE: "8.8"
@@ -163,6 +173,11 @@ jobs:
- tmt:
context:
distro: "rhel-7.9"
+ # tag resources as sst_upgrades to enable cost metrics collection
+ - settings:
+ provisioning:
+ tags:
+ BusinessUnit: sst_upgrades
env:
SOURCE_RELEASE: "7.9"
TARGET_RELEASE: "8.6"
@@ -185,6 +200,11 @@ jobs:
- tmt:
context:
distro: "rhel-8.6"
+ # tag resources as sst_upgrades to enable cost metrics collection
+ - settings:
+ provisioning:
+ tags:
+ BusinessUnit: sst_upgrades
env:
SOURCE_RELEASE: "8.6"
TARGET_RELEASE: "9.0"
@@ -207,6 +227,11 @@ jobs:
- tmt:
context:
distro: "rhel-8.8"
+ # tag resources as sst_upgrades to enable cost metrics collection
+ - settings:
+ provisioning:
+ tags:
+ BusinessUnit: sst_upgrades
env:
SOURCE_RELEASE: "8.8"
TARGET_RELEASE: "9.2"
@@ -252,6 +277,11 @@ jobs:
- tmt:
context:
distro: "rhel-8.6"
+ # tag resources as sst_upgrades to enable cost metrics collection
+ - settings:
+ provisioning:
+ tags:
+ BusinessUnit: sst_upgrades
env:
SOURCE_RELEASE: "8.6"
TARGET_RELEASE: "9.0"
--
2.40.1

View File

@ -1,134 +0,0 @@
From f4edd16317ee188dd0958a293ea51d0afa2f606e Mon Sep 17 00:00:00 2001
From: Inessa Vasilevskaya <ivasilev@redhat.com>
Date: Mon, 17 Apr 2023 13:33:12 +0200
Subject: [PATCH 12/30] Workaround packit#2010 issue
Looks like tf_post_install_script and environment override does
not play nice together yet, so let's workaround it for now.
OAMG-8892
---
.packit.yaml | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/.packit.yaml b/.packit.yaml
index 595e94be..fd0af7ec 100644
--- a/.packit.yaml
+++ b/.packit.yaml
@@ -95,15 +95,15 @@ jobs:
distros: [RHEL-7.9-ZStream]
identifier: tests-7.9to8.6
tmt_plan: "^(?!.*upgrade_plugin)(?!.*tier[2-3].*)(?!.*rhsm)(?!.*c2r)(?!.*sap)(?!.*8to9)(?!.*max_sst)"
- tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
tf_extra_params:
environments:
- tmt:
context:
distro: "rhel-7.9"
- # tag resources as sst_upgrades to enable cost metrics collection
- - settings:
+ # tag resources as sst_upgrades to enable cost metrics collection
+ settings:
provisioning:
+ post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
tags:
BusinessUnit: sst_upgrades
env:
@@ -121,15 +121,15 @@ jobs:
distros: [RHEL-7.9-ZStream]
identifier: tests-7.9to8.8
tmt_plan: "^(?!.*upgrade_plugin)(?!.*tier[2-3].*)(?!.*rhsm)(?!.*c2r)(?!.*sap)(?!.*8to9)(?!.*max_sst)"
- tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
tf_extra_params:
environments:
- tmt:
context:
distro: "rhel-7.9"
- # tag resources as sst_upgrades to enable cost metrics collection
- - settings:
+ # tag resources as sst_upgrades to enable cost metrics collection
+ settings:
provisioning:
+ post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
tags:
BusinessUnit: sst_upgrades
env:
@@ -167,15 +167,15 @@ jobs:
distros: [RHEL-7.9-rhui]
identifier: tests-7to8-aws-e2e
tmt_plan: "^(?!.*upgrade_plugin)(?!.*tier[2-3].*)(?!.*rhsm)(?!.*c2r)(?!.*sap)(?!.*8to9)(.*e2e)"
- tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys; echo 42; yum-config-manager --enable rhel-7-server-rhui-optional-rpms"
tf_extra_params:
environments:
- tmt:
context:
distro: "rhel-7.9"
- # tag resources as sst_upgrades to enable cost metrics collection
- - settings:
+ # tag resources as sst_upgrades to enable cost metrics collection
+ settings:
provisioning:
+ post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys; yum-config-manager --enable rhel-7-server-rhui-optional-rpms"
tags:
BusinessUnit: sst_upgrades
env:
@@ -194,15 +194,15 @@ jobs:
distros: [RHEL-8.6.0-Nightly]
identifier: tests-8.6to9.0
tmt_plan: "^(?!.*upgrade_plugin)(?!.*tier[2-3].*)(?!.*rhsm)(?!.*c2r)(?!.*sap)(?!.*7to8)(?!.*max_sst)"
- tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
tf_extra_params:
environments:
- tmt:
context:
distro: "rhel-8.6"
- # tag resources as sst_upgrades to enable cost metrics collection
- - settings:
+ # tag resources as sst_upgrades to enable cost metrics collection
+ settings:
provisioning:
+ post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
tags:
BusinessUnit: sst_upgrades
env:
@@ -221,15 +221,15 @@ jobs:
distros: [RHEL-8.8.0-Nightly]
identifier: tests-8.8to9.2
tmt_plan: "^(?!.*upgrade_plugin)(?!.*tier[2-3].*)(?!.*rhsm)(?!.*c2r)(?!.*sap)(?!.*7to8)(?!.*max_sst)"
- tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
tf_extra_params:
environments:
- tmt:
context:
distro: "rhel-8.8"
- # tag resources as sst_upgrades to enable cost metrics collection
- - settings:
+ # tag resources as sst_upgrades to enable cost metrics collection
+ settings:
provisioning:
+ post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
tags:
BusinessUnit: sst_upgrades
env:
@@ -271,15 +271,15 @@ jobs:
distros: [RHEL-8.6-rhui]
identifier: tests-8to9-aws-e2e
tmt_plan: "^(?!.*upgrade_plugin)(?!.*tier[2-3].*)(?!.*rhsm)(?!.*c2r)(?!.*sap)(?!.*7to8)(.*e2e)"
- tf_post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
tf_extra_params:
environments:
- tmt:
context:
distro: "rhel-8.6"
- # tag resources as sst_upgrades to enable cost metrics collection
- - settings:
+ # tag resources as sst_upgrades to enable cost metrics collection
+ settings:
provisioning:
+ post_install_script: "#!/bin/sh\nsudo sed -i s/.*ssh-rsa/ssh-rsa/ /root/.ssh/authorized_keys"
tags:
BusinessUnit: sst_upgrades
env:
--
2.40.1

View File

@ -1,71 +0,0 @@
From 0404072439f9c528d569cd23e60b83fb3823b3b5 Mon Sep 17 00:00:00 2001
From: mreznik <mreznik@redhat.com>
Date: Sun, 9 Apr 2023 10:37:31 +0200
Subject: [PATCH 13/30] Improve the "checkgrubcore" report message
No action is needed in case Leapp is able to detect the GRUB2 device
---
.../common/actors/checkgrubcore/actor.py | 16 +++++++++-------
.../checkgrubcore/tests/test_checkgrubcore.py | 2 +-
2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/repos/system_upgrade/common/actors/checkgrubcore/actor.py b/repos/system_upgrade/common/actors/checkgrubcore/actor.py
index 37eeeca8..6aa99797 100644
--- a/repos/system_upgrade/common/actors/checkgrubcore/actor.py
+++ b/repos/system_upgrade/common/actors/checkgrubcore/actor.py
@@ -6,8 +6,10 @@ from leapp.models import FirmwareFacts, GrubInfo
from leapp.reporting import create_report, Report
from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
-GRUB_SUMMARY = ('On legacy (BIOS) systems, GRUB core (located in the gap between the MBR and the '
- 'first partition) does not get automatically updated when GRUB is upgraded.')
+GRUB_SUMMARY = ('On legacy (BIOS) systems, GRUB2 core (located in the gap between the MBR and the '
+ 'first partition) cannot be updated during the rpm transaction and Leapp has to initiate '
+ 'the update running "grub2-install" after the transaction. No action is needed before the '
+ 'upgrade. After the upgrade, it is recommended to check the GRUB configuration.')
class CheckGrubCore(Actor):
@@ -33,7 +35,7 @@ class CheckGrubCore(Actor):
if grub_info.orig_device_name:
create_report([
reporting.Title(
- 'GRUB core will be updated during upgrade'
+ 'GRUB2 core will be automatically updated during the upgrade'
),
reporting.Summary(GRUB_SUMMARY),
reporting.Severity(reporting.Severity.HIGH),
@@ -41,13 +43,13 @@ class CheckGrubCore(Actor):
])
else:
create_report([
- reporting.Title('Leapp could not identify where GRUB core is located'),
+ reporting.Title('Leapp could not identify where GRUB2 core is located'),
reporting.Summary(
- 'We assume GRUB core is located on the same device as /boot. Leapp needs to '
- 'update GRUB core as it is not done automatically on legacy (BIOS) systems. '
+ 'We assumed GRUB2 core is located on the same device as /boot, however Leapp could not '
+ 'detect GRUB2 on the device. GRUB2 core needs to be updated maually on legacy (BIOS) systems. '
),
reporting.Severity(reporting.Severity.HIGH),
reporting.Groups([reporting.Groups.BOOT]),
reporting.Remediation(
- hint='Please run "grub2-install <GRUB_DEVICE> command manually after upgrade'),
+ hint='Please run "grub2-install <GRUB_DEVICE> command manually after the upgrade'),
])
diff --git a/repos/system_upgrade/common/actors/checkgrubcore/tests/test_checkgrubcore.py b/repos/system_upgrade/common/actors/checkgrubcore/tests/test_checkgrubcore.py
index 0816963b..fe15b65b 100644
--- a/repos/system_upgrade/common/actors/checkgrubcore/tests/test_checkgrubcore.py
+++ b/repos/system_upgrade/common/actors/checkgrubcore/tests/test_checkgrubcore.py
@@ -5,7 +5,7 @@ from leapp.libraries.common.config import mock_configs
from leapp.models import FirmwareFacts, GrubInfo
from leapp.reporting import Report
-NO_GRUB = 'Leapp could not identify where GRUB core is located'
+NO_GRUB = 'Leapp could not identify where GRUB2 core is located'
def test_actor_update_grub(current_actor_context):
--
2.40.1

View File

@ -1,27 +0,0 @@
From 8ed665ca45c90ddd305ff6a3be341d2eef351a9e Mon Sep 17 00:00:00 2001
From: Inessa Vasilevskaya <ivasilev@redhat.com>
Date: Tue, 25 Apr 2023 12:18:52 +0200
Subject: [PATCH 14/30] Update pr-welcome-msg with packit tests info
Let's mention the big leap for leapp officially together with
a command to (re-)trigger tests.
---
.github/workflows/pr-welcome-msg.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/pr-welcome-msg.yml b/.github/workflows/pr-welcome-msg.yml
index 5fbf9558..adeed97c 100644
--- a/.github/workflows/pr-welcome-msg.yml
+++ b/.github/workflows/pr-welcome-msg.yml
@@ -24,6 +24,8 @@ jobs:
- **review please** to notify leapp developers of review request
- **/packit copr-build** to submit a public copr build using packit
+ Packit will automatically schedule regression tests for this PR's build and leapp\*master\*. If you need a different version of leapp from PR#42, use `/packit test oamg/leapp#42`
+
To launch regression testing public members of oamg organization can leave the following comment:
- **/rerun** to schedule basic regression tests using this pr build and leapp\*master\* as artifacts
- **/rerun 42** to schedule basic regression tests using this pr build and leapp\*PR42\* as artifacts
--
2.40.1

View File

@ -1,38 +0,0 @@
From e43346659072d2b86df8272949951e12675ee2e3 Mon Sep 17 00:00:00 2001
From: Inessa Vasilevskaya <ivasilev@redhat.com>
Date: Tue, 25 Apr 2023 12:37:36 +0200
Subject: [PATCH 15/30] Further tune welcome-bot message
- Do not use master, use latest upstream
- Add precise command to request review from oamg-developers
---
.github/workflows/pr-welcome-msg.yml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/pr-welcome-msg.yml b/.github/workflows/pr-welcome-msg.yml
index adeed97c..7e7ba831 100644
--- a/.github/workflows/pr-welcome-msg.yml
+++ b/.github/workflows/pr-welcome-msg.yml
@@ -21,15 +21,15 @@ jobs:
## **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.
If you want to request a review or rebuild a package in copr, you can use following commands as a comment:
- - **review please** to notify leapp developers of review request
+ - **review please @oamg/developers** to notify leapp developers of the review request
- **/packit copr-build** to submit a public copr build using packit
- Packit will automatically schedule regression tests for this PR's build and leapp\*master\*. If you need a different version of leapp from PR#42, use `/packit test oamg/leapp#42`
+ Packit will automatically schedule regression tests for this PR's build and latest upstream leapp build. If you need a different version of leapp from PR#42, use `/packit test oamg/leapp#42`
To launch regression testing public members of oamg organization can leave the following comment:
- - **/rerun** to schedule basic regression tests using this pr build and leapp\*master\* as artifacts
+ - **/rerun** to schedule basic regression tests using this pr build and latest upstream leapp build as artifacts
- **/rerun 42** to schedule basic regression tests using this pr build and leapp\*PR42\* as artifacts
- - **/rerun-sst** to schedule sst tests using this pr build and leapp\*master\* as artifacts
+ - **/rerun-sst** to schedule sst tests using this pr build and latest upstream leapp build as artifacts
- **/rerun-sst 42** to schedule sst tests using this pr build and leapp\*PR42\* as artifacts
Please [open ticket](https://url.corp.redhat.com/oamg-ci-issue) in case you experience technical problem with the CI. (RH internal only)
--
2.40.1

View File

@ -1,24 +0,0 @@
From ac8b6a1bad62ce5a823b61677788e4a9a6c16e33 Mon Sep 17 00:00:00 2001
From: Inessa Vasilevskaya <ivasilev@redhat.com>
Date: Tue, 25 Apr 2023 14:37:26 +0200
Subject: [PATCH 16/30] Remove note about leapp-ci build
As leapp packages are built by packit now, this is not used
anymore.
---
.github/workflows/pr-welcome-msg.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/pr-welcome-msg.yml b/.github/workflows/pr-welcome-msg.yml
index 7e7ba831..cec7c778 100644
--- a/.github/workflows/pr-welcome-msg.yml
+++ b/.github/workflows/pr-welcome-msg.yml
@@ -34,4 +34,4 @@ jobs:
Please [open ticket](https://url.corp.redhat.com/oamg-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 consider rerunning the CI by commenting **leapp-ci build** (might require several comments). If the problem persists, contact leapp-infra.
+ **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.40.1

View File

@ -1,38 +0,0 @@
From a600097a8f5ab9f0083a9abb906e0a0b5394176c Mon Sep 17 00:00:00 2001
From: Inessa Vasilevskaya <ivasilev@redhat.com>
Date: Wed, 8 Mar 2023 12:12:51 +0100
Subject: [PATCH 17/30] Fix false positive non-utf symlinks reported
Because of botched up check for python2 valid utf symlinks were reported
as non-utf ones.
OAMG-8629
---
.../system_upgrade/common/actors/rootscanner/actor.py | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/repos/system_upgrade/common/actors/rootscanner/actor.py b/repos/system_upgrade/common/actors/rootscanner/actor.py
index 515fd7d7..dc02c7a2 100644
--- a/repos/system_upgrade/common/actors/rootscanner/actor.py
+++ b/repos/system_upgrade/common/actors/rootscanner/actor.py
@@ -28,8 +28,16 @@ class RootScanner(Actor):
return subdir_cls(name=name)
for subdir in os.listdir('/'):
- # Note(ivasilev) non-utf encoded string will appear as byte strings
+ # Note(ivasilev) in py3 env non-utf encoded string will appear as byte strings
+ # However in py2 env subdir will be always of str type, so verification if this is a valid utf-8 string
+ # should be done differently than formerly suggested plain six.binary_type check
+ decoded = True
if isinstance(subdir, six.binary_type):
+ try:
+ subdir.decode('utf-8')
+ except (AttributeError, UnicodeDecodeError):
+ decoded = False
+ if not decoded:
invalid_subdirs.append(_create_a_subdir(InvalidRootSubdirectory, subdir, os.path.join(b'/', subdir)))
else:
subdirs.append(_create_a_subdir(RootSubdirectory, subdir, os.path.join('/', subdir)))
--
2.40.1

View File

@ -1,153 +0,0 @@
From 56b468355e460b9389a97982bd9a04097ce8f96b Mon Sep 17 00:00:00 2001
From: Inessa Vasilevskaya <ivasilev@redhat.com>
Date: Thu, 23 Mar 2023 15:35:08 +0100
Subject: [PATCH 18/30] Refactor rootscanner to use library
Also introduce tests for the nonutf symlinks
---
commands/upgrade/breadcrumbs.py | 2 --
.../common/actors/rootscanner/actor.py | 32 ++---------------
.../rootscanner/libraries/rootscanner.py | 34 +++++++++++++++++++
.../rootscanner/tests/test_rootscanner.py | 31 +++++++++++++++++
4 files changed, 68 insertions(+), 31 deletions(-)
create mode 100644 repos/system_upgrade/common/actors/rootscanner/libraries/rootscanner.py
create mode 100644 repos/system_upgrade/common/actors/rootscanner/tests/test_rootscanner.py
diff --git a/commands/upgrade/breadcrumbs.py b/commands/upgrade/breadcrumbs.py
index 61660fb1..16903ee0 100644
--- a/commands/upgrade/breadcrumbs.py
+++ b/commands/upgrade/breadcrumbs.py
@@ -128,8 +128,6 @@ class _BreadCrumbs(object):
def _verify_leapp_pkgs(self):
if not os.environ.get('LEAPP_IPU_IN_PROGRESS'):
- # NOTE(ivasilev) this can happen if LEAPP_DEVEL_TARGET_RELEASE is specified and pointing to an impossible
- # version
return []
upg_path = os.environ.get('LEAPP_IPU_IN_PROGRESS').split('to')
cmd = ['/bin/bash', '-c', 'rpm -V leapp leapp-upgrade-el{}toel{}'.format(upg_path[0], upg_path[1])]
diff --git a/repos/system_upgrade/common/actors/rootscanner/actor.py b/repos/system_upgrade/common/actors/rootscanner/actor.py
index dc02c7a2..a3fbb55d 100644
--- a/repos/system_upgrade/common/actors/rootscanner/actor.py
+++ b/repos/system_upgrade/common/actors/rootscanner/actor.py
@@ -1,9 +1,6 @@
-import os
-
-import six
-
from leapp.actors import Actor
-from leapp.models import InvalidRootSubdirectory, RootDirectory, RootSubdirectory
+from leapp.libraries.actor.rootscanner import scan_dir
+from leapp.models import RootDirectory
from leapp.tags import FactsPhaseTag, IPUWorkflowTag
@@ -19,27 +16,4 @@ class RootScanner(Actor):
tags = (IPUWorkflowTag, FactsPhaseTag)
def process(self):
- subdirs = []
- invalid_subdirs = []
-
- def _create_a_subdir(subdir_cls, name, path):
- if os.path.islink(path):
- return subdir_cls(name=name, target=os.readlink(path))
- return subdir_cls(name=name)
-
- for subdir in os.listdir('/'):
- # Note(ivasilev) in py3 env non-utf encoded string will appear as byte strings
- # However in py2 env subdir will be always of str type, so verification if this is a valid utf-8 string
- # should be done differently than formerly suggested plain six.binary_type check
- decoded = True
- if isinstance(subdir, six.binary_type):
- try:
- subdir.decode('utf-8')
- except (AttributeError, UnicodeDecodeError):
- decoded = False
- if not decoded:
- invalid_subdirs.append(_create_a_subdir(InvalidRootSubdirectory, subdir, os.path.join(b'/', subdir)))
- else:
- subdirs.append(_create_a_subdir(RootSubdirectory, subdir, os.path.join('/', subdir)))
-
- self.produce(RootDirectory(items=subdirs, invalid_items=invalid_subdirs))
+ self.produce(scan_dir(b'/'))
diff --git a/repos/system_upgrade/common/actors/rootscanner/libraries/rootscanner.py b/repos/system_upgrade/common/actors/rootscanner/libraries/rootscanner.py
new file mode 100644
index 00000000..3f29c065
--- /dev/null
+++ b/repos/system_upgrade/common/actors/rootscanner/libraries/rootscanner.py
@@ -0,0 +1,34 @@
+import os
+
+import six
+
+from leapp.models import InvalidRootSubdirectory, RootDirectory, RootSubdirectory
+
+
+def scan_dir(root_dir=b'/'):
+ """
+ Scan root directory and return a RootDirectory(subdirs, invalid_subdirs) model object
+ """
+ subdirs = []
+ invalid_subdirs = []
+
+ def _create_a_subdir(subdir_cls, name, path):
+ if os.path.islink(path):
+ return subdir_cls(name=name, target=os.readlink(path))
+ return subdir_cls(name=name)
+
+ for subdir in os.listdir(root_dir):
+ # Note(ivasilev) in py3 env non-utf encoded string will appear as byte strings
+ # However in py2 env subdir will be always of str type, so verification if this is a valid utf-8 string
+ # should be done differently than formerly suggested plain six.binary_type check
+ decoded = True
+ if isinstance(subdir, six.binary_type):
+ try:
+ subdir = subdir.decode('utf-8')
+ except (AttributeError, UnicodeDecodeError):
+ decoded = False
+ if not decoded:
+ invalid_subdirs.append(_create_a_subdir(InvalidRootSubdirectory, subdir, os.path.join(b'/', subdir)))
+ else:
+ subdirs.append(_create_a_subdir(RootSubdirectory, subdir, os.path.join('/', subdir)))
+ return RootDirectory(items=subdirs, invalid_items=invalid_subdirs)
diff --git a/repos/system_upgrade/common/actors/rootscanner/tests/test_rootscanner.py b/repos/system_upgrade/common/actors/rootscanner/tests/test_rootscanner.py
new file mode 100644
index 00000000..d0e5626a
--- /dev/null
+++ b/repos/system_upgrade/common/actors/rootscanner/tests/test_rootscanner.py
@@ -0,0 +1,31 @@
+import os
+import shutil
+import tempfile
+
+import pytest
+
+from leapp.libraries.actor.rootscanner import scan_dir
+
+
+@pytest.mark.parametrize("filename,symlink,count_invalid",
+ [(u'a_utf_file'.encode('utf-8'), u"utf8_symlink".encode('utf-8'), 0),
+ (u'простофайл'.encode('koi8-r'), u"этонеутф8".encode('koi8-r'), 2),
+ (u'a_utf_file'.encode('utf-8'), u"этонеутф8".encode('koi8-r'), 1)])
+def test_invalid_symlinks(filename, symlink, count_invalid):
+ # Let's create a directory with both valid utf-8 and non-utf symlinks
+ # NOTE(ivasilev) As this has to run for python2 as well can't use the nice tempfile.TemporaryDirectory way
+ tmpdirname = tempfile.mkdtemp()
+ # create the file in the temp directory
+ path_to_file = os.path.join(tmpdirname.encode('utf-8'), filename)
+ path_to_symlink = os.path.join(tmpdirname.encode('utf-8'), symlink)
+ with open(path_to_file, 'w') as f:
+ f.write('Some data here')
+ # create a symlink
+ os.symlink(path_to_file, path_to_symlink)
+ # run scan_dir
+ model = scan_dir(tmpdirname.encode('utf-8'))
+ # verify the results
+ assert len(model.items) == 2 - count_invalid
+ assert len(model.invalid_items) == count_invalid
+ # cleanup
+ shutil.rmtree(tmpdirname)
--
2.40.1

View File

@ -1,26 +0,0 @@
From aa21fa14e6f8a4644ee1190943127c3c0f2bc206 Mon Sep 17 00:00:00 2001
From: Inessa Vasilevskaya <ivasilev@redhat.com>
Date: Thu, 23 Mar 2023 15:39:22 +0100
Subject: [PATCH 19/30] update .pylintrc
---
.pylintrc | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.pylintrc b/.pylintrc
index f5da1f1f..7ddb58d6 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -52,7 +52,8 @@ disable=
consider-using-with, # on bunch spaces we cannot change that...
duplicate-string-formatting-argument, # TMP: will be fixed in close future
consider-using-f-string, # sorry, not gonna happen, still have to support py2
- use-dict-literal
+ use-dict-literal,
+ redundant-u-string-prefix # still have py2 to support
[FORMAT]
# Maximum number of characters on a single line.
--
2.40.1

View File

@ -1,21 +0,0 @@
From d1a7170b5076f03673b17ffd56dd4eb121f4ae2c Mon Sep 17 00:00:00 2001
From: Inessa Vasilevskaya <ivasilev@redhat.com>
Date: Thu, 23 Mar 2023 17:11:33 +0100
Subject: [PATCH 20/30] Set encoding for tests
---
.../common/actors/rootscanner/tests/test_rootscanner.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/repos/system_upgrade/common/actors/rootscanner/tests/test_rootscanner.py b/repos/system_upgrade/common/actors/rootscanner/tests/test_rootscanner.py
index d0e5626a..659a3017 100644
--- a/repos/system_upgrade/common/actors/rootscanner/tests/test_rootscanner.py
+++ b/repos/system_upgrade/common/actors/rootscanner/tests/test_rootscanner.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
import os
import shutil
import tempfile
--
2.40.1

File diff suppressed because it is too large Load Diff

View File

@ -1,98 +0,0 @@
From 619982896c07aa453a1b48b2bf399e4fe4f723b2 Mon Sep 17 00:00:00 2001
From: Jarek Prokop <jprokop@redhat.com>
Date: Fri, 21 Apr 2023 17:25:15 +0200
Subject: [PATCH 22/30] Add el8toel9 actor to handle directory -> symlink with
ruby IRB.
The `/usr/share/ruby/irb/` directory is a symlink in RHEL 9.
Simply remove the directory to then let the RPM mechanism create the
correct symlink on update.
Users should not expect to ever retain anything in this directory.
---
.../actors/registerrubyirbadjustment/actor.py | 22 ++++++++++++++++++
.../test_register_ruby_irb_adjustments.py | 11 +++++++++
.../el8toel9/tools/handlerubyirbsymlink | 23 +++++++++++++++++++
3 files changed, 56 insertions(+)
create mode 100644 repos/system_upgrade/el8toel9/actors/registerrubyirbadjustment/actor.py
create mode 100644 repos/system_upgrade/el8toel9/actors/registerrubyirbadjustment/tests/test_register_ruby_irb_adjustments.py
create mode 100755 repos/system_upgrade/el8toel9/tools/handlerubyirbsymlink
diff --git a/repos/system_upgrade/el8toel9/actors/registerrubyirbadjustment/actor.py b/repos/system_upgrade/el8toel9/actors/registerrubyirbadjustment/actor.py
new file mode 100644
index 00000000..ac4d1e6f
--- /dev/null
+++ b/repos/system_upgrade/el8toel9/actors/registerrubyirbadjustment/actor.py
@@ -0,0 +1,22 @@
+from leapp.actors import Actor
+from leapp.models import DNFWorkaround
+from leapp.tags import FactsPhaseTag, IPUWorkflowTag
+
+
+class RegisterRubyIRBAdjustment(Actor):
+ """
+ Registers a workaround which will adjust the Ruby IRB directories during the upgrade.
+ """
+
+ name = 'register_ruby_irb_adjustment'
+ consumes = ()
+ produces = (DNFWorkaround,)
+ tags = (IPUWorkflowTag, FactsPhaseTag)
+
+ def process(self):
+ self.produce(
+ DNFWorkaround(
+ display_name='IRB directory fix',
+ script_path=self.get_tool_path('handlerubyirbsymlink'),
+ )
+ )
diff --git a/repos/system_upgrade/el8toel9/actors/registerrubyirbadjustment/tests/test_register_ruby_irb_adjustments.py b/repos/system_upgrade/el8toel9/actors/registerrubyirbadjustment/tests/test_register_ruby_irb_adjustments.py
new file mode 100644
index 00000000..fc341646
--- /dev/null
+++ b/repos/system_upgrade/el8toel9/actors/registerrubyirbadjustment/tests/test_register_ruby_irb_adjustments.py
@@ -0,0 +1,11 @@
+import os.path
+
+from leapp.models import DNFWorkaround
+
+
+def test_register_ruby_irb_adjustments(current_actor_context):
+ current_actor_context.run()
+ assert len(current_actor_context.consume(DNFWorkaround)) == 1
+ assert current_actor_context.consume(DNFWorkaround)[0].display_name == 'IRB directory fix'
+ assert os.path.basename(current_actor_context.consume(DNFWorkaround)[0].script_path) == 'handlerubyirbsymlink'
+ assert os.path.exists(current_actor_context.consume(DNFWorkaround)[0].script_path)
diff --git a/repos/system_upgrade/el8toel9/tools/handlerubyirbsymlink b/repos/system_upgrade/el8toel9/tools/handlerubyirbsymlink
new file mode 100755
index 00000000..9558dd48
--- /dev/null
+++ b/repos/system_upgrade/el8toel9/tools/handlerubyirbsymlink
@@ -0,0 +1,23 @@
+#!/usr/bin/bash -e
+
+# just in case of hidden files.. not sure why would someone do that, it's more
+# like forgotten cache file possibility, but rather do that..
+shopt -s dotglob
+
+handle_dir() {
+ # Check that $1 is not already a symlink
+ # then remove the directory so that RPM can freely create the
+ # symlink.
+ if [ "$(readlink "$1")" == "/usr/share/gems/gems/irb-1.3.5" ]; then
+ return
+ fi
+
+ # There is no configuration or anything that the user should ever customize
+ # and expect to retain.
+ rm -rf "$1"
+
+ return 0
+}
+
+
+handle_dir /usr/share/ruby/irb
--
2.40.1

View File

@ -1,558 +0,0 @@
From 0c03180b274e9245611a7379a997ac81c726a9e9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michal=20He=C4=8Dko?= <michal.sk.com@gmail.com>
Date: Wed, 10 May 2023 16:51:49 +0200
Subject: [PATCH 23/30] Enable 8>9 upgrades with FIPS enabled (#1053)
Short story long:
==============
FIPS refers to a set of security standards governing many aspects of how information should be handled by computers and by people. FIPS in context of RHEL typically means FIPS 140, a single document defining rules for the use of encryption and cryptographic services. In essence, it defines requirements for cryptographic modules (e.g. what algorithms can be used, thus preventing the use of insecure ones) manipulating sensitive information.
From the point of view of upgrades there are 5 components that are certified under FIPS: kernel, OpenSSL, GnuTLS, NSS, and libgcrypt. As for the kernel, fips=1 needs to be present on the cmdline in order to enable FIPS in the kernel. Kernel offers a /proc/sys/crypto/fips_enabled virtual file containing the information about whether the kernel has booted with FIPS enabled.
According to FIPS, the userspace components need to verify that they were not tampered with, and thus they have to have some sort of checksum either in a special section of a binary, or in a separate file. The components read /proc/sys/crypto/fips_enabled to know when to switch into the FIPS enabled mode. OpenSSL does things a bit differently, by not including support for FIPS directly but via a special fips.so module. Furthermore, for OpenSSL to check whether FIPS is enabled a configuration file must be present at /etc/pki/tls/openssl.cnf, because the code checking for FIPS is a part of configuration parsing.
As every userspace component has different implementation of FIPS-mode, and a different way for the user to check whether the component believes that the system it is running on has FIPS enabled, there is no straightforward way for us to make really sure that all of the components run in FIPS enabled inside the target userspace container.
Brief summary of changes in the code:
* scanfips: split scanning for fips into a separate actor
* checkfips: inhibit the IPU only on 7>8
* in case of FIPS for IPU 8 -> 9, copy related files into the target container to be able to generate FIPS compliant initramfs
* checkfipsenabled: check for fips in upgrade initramfs (LastTestsPhase); interrupt the upgrade if FIPS is not enabled in the upgrade environment
* upgradeinitramfsgenerator: refactor library and tests due to FIPS
* create upgrade kernel hmac unconditionallly
---------
Co-authored-by: Michal Hecko <mhecko@redhat.com>
---
.../libraries/addupgradebootentry.py | 1 +
.../tests/unit_test_addupgradebootentry.py | 2 +-
.../common/actors/checkfips/actor.py | 50 +++++++++++++------
.../actors/checkfips/tests/test_checkfips.py | 23 +++++++++
.../initramfs/checkfipsenabled/actor.py | 21 ++++++++
.../checkfipsenabled/libraries/check_fips.py | 23 +++++++++
.../tests/test_checkfipsenabled.py | 31 ++++++++++++
.../upgradeinitramfsgenerator/actor.py | 2 +
.../files/generate-initram.sh | 3 ++
.../libraries/upgradeinitramfsgenerator.py | 28 ++++++++++-
.../unit_test_upgradeinitramfsgenerator.py | 16 +++++-
.../libraries/removebootfiles.py | 2 +-
.../tests/unit_test_removebootfiles.py | 4 +-
.../tests/unit_test_removeupgradebootentry.py | 2 +-
.../common/actors/scanfips/actor.py | 28 +++++++++++
.../tests/test_scanfips.py} | 13 +++--
.../common/models/bootcontent.py | 1 +
repos/system_upgrade/common/models/fips.py | 12 +++++
18 files changed, 233 insertions(+), 29 deletions(-)
create mode 100644 repos/system_upgrade/common/actors/checkfips/tests/test_checkfips.py
create mode 100644 repos/system_upgrade/common/actors/initramfs/checkfipsenabled/actor.py
create mode 100644 repos/system_upgrade/common/actors/initramfs/checkfipsenabled/libraries/check_fips.py
create mode 100644 repos/system_upgrade/common/actors/initramfs/checkfipsenabled/tests/test_checkfipsenabled.py
create mode 100644 repos/system_upgrade/common/actors/scanfips/actor.py
rename repos/system_upgrade/common/actors/{checkfips/tests/unit_test_checkfips.py => scanfips/tests/test_scanfips.py} (74%)
create mode 100644 repos/system_upgrade/common/models/fips.py
diff --git a/repos/system_upgrade/common/actors/addupgradebootentry/libraries/addupgradebootentry.py b/repos/system_upgrade/common/actors/addupgradebootentry/libraries/addupgradebootentry.py
index beddafec..4e1c4204 100644
--- a/repos/system_upgrade/common/actors/addupgradebootentry/libraries/addupgradebootentry.py
+++ b/repos/system_upgrade/common/actors/addupgradebootentry/libraries/addupgradebootentry.py
@@ -88,6 +88,7 @@ def get_boot_file_paths():
raise StopActorExecutionError('Could not create a GRUB boot entry for the upgrade initramfs',
details={'details': 'Did not receive a message about the leapp-provided'
'kernel and initramfs'})
+ # Returning information about kernel hmac file path is needless as it is not used when adding boot entry
return boot_content.kernel_path, boot_content.initram_path
diff --git a/repos/system_upgrade/common/actors/addupgradebootentry/tests/unit_test_addupgradebootentry.py b/repos/system_upgrade/common/actors/addupgradebootentry/tests/unit_test_addupgradebootentry.py
index cc442f8d..ddc37e52 100644
--- a/repos/system_upgrade/common/actors/addupgradebootentry/tests/unit_test_addupgradebootentry.py
+++ b/repos/system_upgrade/common/actors/addupgradebootentry/tests/unit_test_addupgradebootentry.py
@@ -135,7 +135,7 @@ def test_add_boot_entry_configs(monkeypatch):
def test_get_boot_file_paths(monkeypatch):
# BootContent message available
def consume_message_mocked(*models):
- yield BootContent(kernel_path='/ghi', initram_path='/jkl')
+ yield BootContent(kernel_path='/ghi', initram_path='/jkl', kernel_hmac_path='/path')
monkeypatch.setattr('leapp.libraries.stdlib.api.consume', consume_message_mocked)
diff --git a/repos/system_upgrade/common/actors/checkfips/actor.py b/repos/system_upgrade/common/actors/checkfips/actor.py
index e76af950..bd09b1b9 100644
--- a/repos/system_upgrade/common/actors/checkfips/actor.py
+++ b/repos/system_upgrade/common/actors/checkfips/actor.py
@@ -1,7 +1,8 @@
from leapp import reporting
from leapp.actors import Actor
from leapp.exceptions import StopActorExecutionError
-from leapp.models import KernelCmdline, Report
+from leapp.libraries.common.config import version
+from leapp.models import DracutModule, FIPSInfo, Report, UpgradeInitramfsTasks
from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
@@ -11,25 +12,44 @@ class CheckFips(Actor):
"""
name = 'check_fips'
- consumes = (KernelCmdline,)
- produces = (Report,)
+ consumes = (FIPSInfo,)
+ produces = (Report, UpgradeInitramfsTasks)
tags = (IPUWorkflowTag, ChecksPhaseTag)
def process(self):
- cmdline = next(self.consume(KernelCmdline), None)
- if not cmdline:
- raise StopActorExecutionError('Cannot check FIPS state due to missing command line parameters',
- details={'Problem': 'Did not receive a message with kernel command '
- 'line parameters (KernelCmdline)'})
- for parameter in cmdline.parameters:
- if parameter.key == 'fips' and parameter.value == '1':
- title = 'Cannot upgrade a system with FIPS mode enabled'
- summary = 'Leapp has detected that FIPS is enabled on this system. ' \
- 'In-place upgrade of systems in FIPS mode is currently unsupported.'
+ fips_info = next(self.consume(FIPSInfo), None)
+
+ if not fips_info:
+ raise StopActorExecutionError('Cannot check FIPS state due to not receiving necessary FIPSInfo message',
+ details={'Problem': 'Did not receive a message with information about FIPS '
+ 'usage'})
+
+ if version.get_target_major_version() == '8':
+ if fips_info.is_enabled:
+ title = 'Automated upgrades from RHEL 7 to RHEL 8 in FIPS mode are not supported'
+ summary = ('Leapp has detected that FIPS is enabled on this system. '
+ 'Automated in-place upgrade of RHEL 7 systems in FIPS mode is currently unsupported '
+ 'and manual intervention is required.')
+
+ fips_7to8_steps_docs_url = 'https://red.ht/planning-upgrade-to-rhel8'
+
reporting.create_report([
reporting.Title(title),
reporting.Summary(summary),
reporting.Severity(reporting.Severity.HIGH),
- reporting.Groups([reporting.Groups.SECURITY]),
- reporting.Groups([reporting.Groups.INHIBITOR])
+ reporting.Groups([reporting.Groups.SECURITY, reporting.Groups.INHIBITOR]),
+ reporting.ExternalLink(url=fips_7to8_steps_docs_url,
+ title='Planning an upgrade from RHEL 7 to RHEL 8')
])
+ else:
+ # FIXME(mhecko): We include these files manually as they are not included automatically when the fips
+ # module is used due to a bug in dracut. This code should be removed, once the dracut bug is resolved.
+ # See https://bugzilla.redhat.com/show_bug.cgi?id=2176560
+ if fips_info.is_enabled:
+ fips_required_initramfs_files = [
+ '/etc/crypto-policies/back-ends/opensslcnf.config',
+ '/etc/pki/tls/openssl.cnf',
+ '/usr/lib64/ossl-modules/fips.so',
+ ]
+ self.produce(UpgradeInitramfsTasks(include_files=fips_required_initramfs_files,
+ include_dracut_modules=[DracutModule(name='fips')]))
diff --git a/repos/system_upgrade/common/actors/checkfips/tests/test_checkfips.py b/repos/system_upgrade/common/actors/checkfips/tests/test_checkfips.py
new file mode 100644
index 00000000..5498bf23
--- /dev/null
+++ b/repos/system_upgrade/common/actors/checkfips/tests/test_checkfips.py
@@ -0,0 +1,23 @@
+import pytest
+
+from leapp.libraries.common.config import version
+from leapp.models import FIPSInfo, Report
+from leapp.utils.report import is_inhibitor
+
+
+@pytest.mark.parametrize(('fips_info', 'target_major_version', 'should_inhibit'), [
+ (FIPSInfo(is_enabled=True), '8', True),
+ (FIPSInfo(is_enabled=True), '9', False),
+ (FIPSInfo(is_enabled=False), '8', False),
+ (FIPSInfo(is_enabled=False), '9', False),
+])
+def test_check_fips(monkeypatch, current_actor_context, fips_info, target_major_version, should_inhibit):
+ monkeypatch.setattr(version, 'get_target_major_version', lambda: target_major_version)
+ current_actor_context.feed(fips_info)
+ current_actor_context.run()
+ if should_inhibit:
+ output = current_actor_context.consume(Report)
+ assert len(output) == 1
+ assert is_inhibitor(output[0].report)
+ else:
+ assert not any(is_inhibitor(msg.report) for msg in current_actor_context.consume(Report))
diff --git a/repos/system_upgrade/common/actors/initramfs/checkfipsenabled/actor.py b/repos/system_upgrade/common/actors/initramfs/checkfipsenabled/actor.py
new file mode 100644
index 00000000..ef1930da
--- /dev/null
+++ b/repos/system_upgrade/common/actors/initramfs/checkfipsenabled/actor.py
@@ -0,0 +1,21 @@
+from leapp.actors import Actor
+from leapp.libraries.actor import check_fips as check_fips_lib
+from leapp.models import FIPSInfo
+from leapp.tags import IPUWorkflowTag, LateTestsPhaseTag
+
+
+class CheckFIPSCorrectlyEnabled(Actor):
+ """
+ Sanity check to stop the IPU if the system did not boot into the upgrade initramfs with FIPS settings preserved.
+
+ The performed check should be unlikely to fail, as it would mean that the upgrade boot entry was created without
+ fips=1 on the kernel cmdline.
+ """
+
+ name = 'check_fips_correctly_enabled'
+ consumes = (FIPSInfo,)
+ produces = ()
+ tags = (LateTestsPhaseTag, IPUWorkflowTag)
+
+ def process(self):
+ check_fips_lib.check_fips_state_perserved()
diff --git a/repos/system_upgrade/common/actors/initramfs/checkfipsenabled/libraries/check_fips.py b/repos/system_upgrade/common/actors/initramfs/checkfipsenabled/libraries/check_fips.py
new file mode 100644
index 00000000..ba236619
--- /dev/null
+++ b/repos/system_upgrade/common/actors/initramfs/checkfipsenabled/libraries/check_fips.py
@@ -0,0 +1,23 @@
+from leapp.exceptions import StopActorExecutionError
+from leapp.libraries.stdlib import api
+from leapp.models import FIPSInfo
+
+
+def read_sys_fips_state():
+ with open('/proc/sys/crypto/fips_enabled') as fips_status_handle:
+ return fips_status_handle.read().strip()
+
+
+def check_fips_state_perserved():
+ fips_info = next(api.consume(FIPSInfo), None)
+ if not fips_info:
+ # Unexpected, FIPSInfo is produced unconditionally
+ raise StopActorExecutionError('Cannot check for the correct FIPS state in the upgrade initramfs',
+ details={'Problem': 'Did not receive any FIPSInfo message'})
+
+ if fips_info.is_enabled:
+ fips_status = read_sys_fips_state()
+ if fips_status != '1':
+ details = {'details': ('The system is reporting FIPS as disabled, although it should be enabled'
+ ' since it was enabled on the source system.')}
+ raise StopActorExecutionError('Failed to enable FIPS in the upgrade initramfs', details=details)
diff --git a/repos/system_upgrade/common/actors/initramfs/checkfipsenabled/tests/test_checkfipsenabled.py b/repos/system_upgrade/common/actors/initramfs/checkfipsenabled/tests/test_checkfipsenabled.py
new file mode 100644
index 00000000..9a396e8a
--- /dev/null
+++ b/repos/system_upgrade/common/actors/initramfs/checkfipsenabled/tests/test_checkfipsenabled.py
@@ -0,0 +1,31 @@
+import pytest
+
+from leapp.exceptions import StopActorExecutionError
+from leapp.libraries.actor import check_fips
+from leapp.libraries.common.testutils import CurrentActorMocked
+from leapp.libraries.stdlib import api
+from leapp.models import FIPSInfo
+
+
+@pytest.mark.parametrize(
+ ('fips_info', 'sys_fips_enabled_contents', 'should_prevent_ipu'),
+ (
+ (FIPSInfo(is_enabled=False), '0', False),
+ (FIPSInfo(is_enabled=True), '0', True),
+ (FIPSInfo(is_enabled=True), '1', False),
+ )
+)
+def test_ipu_prevention_if_fips_not_perserved(monkeypatch,
+ fips_info,
+ sys_fips_enabled_contents,
+ should_prevent_ipu):
+
+ mocked_actor = CurrentActorMocked(msgs=[fips_info])
+ monkeypatch.setattr(check_fips, 'read_sys_fips_state', lambda: sys_fips_enabled_contents)
+ monkeypatch.setattr(api, 'current_actor', mocked_actor)
+
+ if should_prevent_ipu:
+ with pytest.raises(StopActorExecutionError):
+ check_fips.check_fips_state_perserved()
+ else:
+ check_fips.check_fips_state_perserved() # unhandled exception with crash the test
diff --git a/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/actor.py b/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/actor.py
index dc97172a..2c52e817 100644
--- a/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/actor.py
+++ b/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/actor.py
@@ -4,6 +4,7 @@ from leapp.models import RequiredUpgradeInitramPackages # deprecated
from leapp.models import UpgradeDracutModule # deprecated
from leapp.models import (
BootContent,
+ FIPSInfo,
TargetOSInstallationImage,
TargetUserSpaceInfo,
TargetUserSpaceUpgradeTasks,
@@ -27,6 +28,7 @@ class UpgradeInitramfsGenerator(Actor):
name = 'upgrade_initramfs_generator'
consumes = (
+ FIPSInfo,
RequiredUpgradeInitramPackages, # deprecated
TargetOSInstallationImage,
TargetUserSpaceInfo,
diff --git a/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/files/generate-initram.sh b/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/files/generate-initram.sh
index 104af586..d6934147 100755
--- a/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/files/generate-initram.sh
+++ b/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/files/generate-initram.sh
@@ -78,6 +78,9 @@ build() {
}
\cp "/lib/modules/${KERNEL_VERSION}/vmlinuz" "vmlinuz-upgrade.$KERNEL_ARCH"
+ # Copy out kernel HMAC so that integrity checks can be performed (performed only in FIPS mode)
+ \cp "/lib/modules/${KERNEL_VERSION}/.vmlinuz.hmac" ".vmlinuz-upgrade.$KERNEL_ARCH.hmac"
+
stage "Building initram disk for kernel: $KERNEL_VERSION"
\dracut \
-vvvv \
diff --git a/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/libraries/upgradeinitramfsgenerator.py b/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/libraries/upgradeinitramfsgenerator.py
index f6539b25..2f145217 100644
--- a/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/libraries/upgradeinitramfsgenerator.py
+++ b/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/libraries/upgradeinitramfsgenerator.py
@@ -180,6 +180,24 @@ def generate_initram_disk(context):
copy_boot_files(context)
+def create_upgrade_hmac_from_target_hmac(original_hmac_path, upgrade_hmac_path, upgrade_kernel):
+ # Rename the kernel name stored in the HMAC file as the upgrade kernel is named differently and the HMAC file
+ # refers to the real target kernel
+ with open(original_hmac_path) as original_hmac_file:
+ hmac_file_lines = [line for line in original_hmac_file.read().split('\n') if line]
+ if len(hmac_file_lines) > 1:
+ details = ('Expected the target kernel HMAC file to containing only one HMAC line, '
+ 'found {0}'.format(len(hmac_file_lines)))
+ raise StopActorExecutionError('Failed to prepare HMAC file for upgrade kernel.',
+ details={'details': details})
+
+ # Keep only non-empty strings after splitting on space
+ hmac, dummy_target_kernel_name = [fragment for fragment in hmac_file_lines[0].split(' ') if fragment]
+
+ with open(upgrade_hmac_path, 'w') as upgrade_kernel_hmac_file:
+ upgrade_kernel_hmac_file.write('{hmac} {kernel}\n'.format(hmac=hmac, kernel=upgrade_kernel))
+
+
def copy_boot_files(context):
"""
Function to copy the generated initram and corresponding kernel to /boot - Additionally produces a BootContent
@@ -188,14 +206,22 @@ def copy_boot_files(context):
curr_arch = api.current_actor().configuration.architecture
kernel = 'vmlinuz-upgrade.{}'.format(curr_arch)
initram = 'initramfs-upgrade.{}.img'.format(curr_arch)
+
+ kernel_hmac = '.{0}.hmac'.format(kernel)
+ kernel_hmac_path = os.path.join('/boot', kernel_hmac)
+
content = BootContent(
kernel_path=os.path.join('/boot', kernel),
- initram_path=os.path.join('/boot', initram)
+ initram_path=os.path.join('/boot', initram),
+ kernel_hmac_path=kernel_hmac_path
)
context.copy_from(os.path.join('/artifacts', kernel), content.kernel_path)
context.copy_from(os.path.join('/artifacts', initram), content.initram_path)
+ kernel_hmac_path = context.full_path(os.path.join('/artifacts', kernel_hmac))
+ create_upgrade_hmac_from_target_hmac(kernel_hmac_path, content.kernel_hmac_path, kernel)
+
api.produce(content)
diff --git a/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/tests/unit_test_upgradeinitramfsgenerator.py b/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/tests/unit_test_upgradeinitramfsgenerator.py
index 13939df1..cd9d0546 100644
--- a/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/tests/unit_test_upgradeinitramfsgenerator.py
+++ b/repos/system_upgrade/common/actors/initramfs/upgradeinitramfsgenerator/tests/unit_test_upgradeinitramfsgenerator.py
@@ -10,6 +10,7 @@ from leapp.libraries.common.testutils import CurrentActorMocked, logger_mocked,
from leapp.utils.deprecation import suppress_deprecation
from leapp.models import ( # isort:skip
+ FIPSInfo,
RequiredUpgradeInitramPackages, # deprecated
UpgradeDracutModule, # deprecated
BootContent,
@@ -133,19 +134,32 @@ class MockedLogger(logger_mocked):
@pytest.mark.parametrize('arch', architecture.ARCH_SUPPORTED)
def test_copy_boot_files(monkeypatch, arch):
kernel = 'vmlinuz-upgrade.{}'.format(arch)
+ kernel_hmac = '.vmlinuz-upgrade.{}.hmac'.format(arch)
initram = 'initramfs-upgrade.{}.img'.format(arch)
bootc = BootContent(
kernel_path=os.path.join('/boot', kernel),
+ kernel_hmac_path=os.path.join('/boot', kernel_hmac),
initram_path=os.path.join('/boot', initram)
)
+ context = MockedContext()
monkeypatch.setattr(upgradeinitramfsgenerator.api, 'current_actor', CurrentActorMocked(arch=arch))
monkeypatch.setattr(upgradeinitramfsgenerator.api, 'produce', produce_mocked())
- context = MockedContext()
+
+ def create_upgrade_hmac_from_target_hmac_mock(original_hmac_path, upgrade_hmac_path, upgrade_kernel):
+ hmac_file = '.{}.hmac'.format(upgrade_kernel)
+ assert original_hmac_path == os.path.join(context.full_path('/artifacts'), hmac_file)
+ assert upgrade_hmac_path == bootc.kernel_hmac_path
+
+ monkeypatch.setattr(upgradeinitramfsgenerator,
+ 'create_upgrade_hmac_from_target_hmac',
+ create_upgrade_hmac_from_target_hmac_mock)
+
upgradeinitramfsgenerator.copy_boot_files(context)
assert len(context.called_copy_from) == 2
assert (os.path.join('/artifacts', kernel), bootc.kernel_path) in context.called_copy_from
assert (os.path.join('/artifacts', initram), bootc.initram_path) in context.called_copy_from
+
assert upgradeinitramfsgenerator.api.produce.called == 1
assert upgradeinitramfsgenerator.api.produce.model_instances[0] == bootc
diff --git a/repos/system_upgrade/common/actors/removebootfiles/libraries/removebootfiles.py b/repos/system_upgrade/common/actors/removebootfiles/libraries/removebootfiles.py
index a0eccbb8..d31af906 100644
--- a/repos/system_upgrade/common/actors/removebootfiles/libraries/removebootfiles.py
+++ b/repos/system_upgrade/common/actors/removebootfiles/libraries/removebootfiles.py
@@ -14,7 +14,7 @@ def remove_boot_files():
api.current_logger().warning('Did not receive a message about the leapp-provided kernel and initramfs ->'
' Skipping removal of these files.')
raise StopActorExecution
- for filepath in boot_content.kernel_path, boot_content.initram_path:
+ for filepath in boot_content.kernel_path, boot_content.initram_path, boot_content.kernel_hmac_path:
remove_file(filepath)
diff --git a/repos/system_upgrade/common/actors/removebootfiles/tests/unit_test_removebootfiles.py b/repos/system_upgrade/common/actors/removebootfiles/tests/unit_test_removebootfiles.py
index dab94e89..7e5fbbf0 100644
--- a/repos/system_upgrade/common/actors/removebootfiles/tests/unit_test_removebootfiles.py
+++ b/repos/system_upgrade/common/actors/removebootfiles/tests/unit_test_removebootfiles.py
@@ -20,14 +20,14 @@ class remove_file_mocked(object):
def test_remove_boot_files(monkeypatch):
# BootContent message available
def consume_message_mocked(*models):
- yield BootContent(kernel_path='/abc', initram_path='/def')
+ yield BootContent(kernel_path='/abc', initram_path='/def', kernel_hmac_path='/ghi')
monkeypatch.setattr('leapp.libraries.stdlib.api.consume', consume_message_mocked)
monkeypatch.setattr(removebootfiles, 'remove_file', remove_file_mocked())
removebootfiles.remove_boot_files()
- assert removebootfiles.remove_file.files_to_remove == ['/abc', '/def']
+ assert removebootfiles.remove_file.files_to_remove == ['/abc', '/def', '/ghi']
# No BootContent message available
def consume_no_message_mocked(*models):
diff --git a/repos/system_upgrade/common/actors/removeupgradebootentry/tests/unit_test_removeupgradebootentry.py b/repos/system_upgrade/common/actors/removeupgradebootentry/tests/unit_test_removeupgradebootentry.py
index 1bf48c15..54eec552 100644
--- a/repos/system_upgrade/common/actors/removeupgradebootentry/tests/unit_test_removeupgradebootentry.py
+++ b/repos/system_upgrade/common/actors/removeupgradebootentry/tests/unit_test_removeupgradebootentry.py
@@ -50,7 +50,7 @@ def test_remove_boot_entry(firmware, arch, monkeypatch):
def test_get_upgrade_kernel_filepath(monkeypatch):
# BootContent message available
def consume_message_mocked(*models):
- yield BootContent(kernel_path='/abc', initram_path='/def')
+ yield BootContent(kernel_path='/abc', initram_path='/def', kernel_hmac_path='/ghi')
monkeypatch.setattr(api, 'consume', consume_message_mocked)
diff --git a/repos/system_upgrade/common/actors/scanfips/actor.py b/repos/system_upgrade/common/actors/scanfips/actor.py
new file mode 100644
index 00000000..f369b796
--- /dev/null
+++ b/repos/system_upgrade/common/actors/scanfips/actor.py
@@ -0,0 +1,28 @@
+from leapp.actors import Actor
+from leapp.exceptions import StopActorExecutionError
+from leapp.models import FIPSInfo, KernelCmdline
+from leapp.tags import FactsPhaseTag, IPUWorkflowTag
+
+
+class ScanFIPS(Actor):
+ """
+ Determine whether the source system has FIPS enabled.
+ """
+
+ name = 'scan_fips'
+ consumes = (KernelCmdline,)
+ produces = (FIPSInfo,)
+ tags = (IPUWorkflowTag, FactsPhaseTag)
+
+ def process(self):
+ cmdline = next(self.consume(KernelCmdline), None)
+ if not cmdline:
+ raise StopActorExecutionError('Cannot check FIPS state due to missing command line parameters',
+ details={'Problem': 'Did not receive a message with kernel command '
+ 'line parameters (KernelCmdline)'})
+
+ for parameter in cmdline.parameters:
+ if parameter.key == 'fips' and parameter.value == '1':
+ self.produce(FIPSInfo(is_enabled=True))
+ return
+ self.produce(FIPSInfo(is_enabled=False))
diff --git a/repos/system_upgrade/common/actors/checkfips/tests/unit_test_checkfips.py b/repos/system_upgrade/common/actors/scanfips/tests/test_scanfips.py
similarity index 74%
rename from repos/system_upgrade/common/actors/checkfips/tests/unit_test_checkfips.py
rename to repos/system_upgrade/common/actors/scanfips/tests/test_scanfips.py
index 7774352e..c5f6ac66 100644
--- a/repos/system_upgrade/common/actors/checkfips/tests/unit_test_checkfips.py
+++ b/repos/system_upgrade/common/actors/scanfips/tests/test_scanfips.py
@@ -1,6 +1,6 @@
import pytest
-from leapp.models import KernelCmdline, KernelCmdlineArg, Report
+from leapp.models import FIPSInfo, KernelCmdline, KernelCmdlineArg
from leapp.snactor.fixture import current_actor_context
ballast1 = [KernelCmdlineArg(key=k, value=v) for k, v in [
@@ -19,7 +19,7 @@ ballast2 = [KernelCmdlineArg(key=k, value=v) for k, v in [
('LANG', 'en_US.UTF-8')]]
-@pytest.mark.parametrize('parameters,expected_report', [
+@pytest.mark.parametrize(('parameters', 'should_detect_enabled_fips'), [
([], False),
([KernelCmdlineArg(key='fips', value='')], False),
([KernelCmdlineArg(key='fips', value='0')], False),
@@ -27,11 +27,10 @@ ballast2 = [KernelCmdlineArg(key=k, value=v) for k, v in [
([KernelCmdlineArg(key='fips', value='11')], False),
([KernelCmdlineArg(key='fips', value='yes')], False)
])
-def test_check_fips(current_actor_context, parameters, expected_report):
+def test_check_fips(current_actor_context, parameters, should_detect_enabled_fips):
cmdline = KernelCmdline(parameters=ballast1+parameters+ballast2)
current_actor_context.feed(cmdline)
current_actor_context.run()
- if expected_report:
- assert current_actor_context.consume(Report)
- else:
- assert not current_actor_context.consume(Report)
+ produced_msgs = current_actor_context.consume(FIPSInfo)
+
+ assert (FIPSInfo(is_enabled=should_detect_enabled_fips),) == produced_msgs
diff --git a/repos/system_upgrade/common/models/bootcontent.py b/repos/system_upgrade/common/models/bootcontent.py
index 03efa8f6..edada01e 100644
--- a/repos/system_upgrade/common/models/bootcontent.py
+++ b/repos/system_upgrade/common/models/bootcontent.py
@@ -11,3 +11,4 @@ class BootContent(Model):
kernel_path = fields.String(help='Filepath of the kernel copied to /boot/ by Leapp.')
initram_path = fields.String(help='Filepath of the initramfs copied to /boot/ by Leapp.')
+ kernel_hmac_path = fields.String(help='Filepath of the kernel hmac copied to /boot/ by Leapp.')
diff --git a/repos/system_upgrade/common/models/fips.py b/repos/system_upgrade/common/models/fips.py
new file mode 100644
index 00000000..aa9930db
--- /dev/null
+++ b/repos/system_upgrade/common/models/fips.py
@@ -0,0 +1,12 @@
+from leapp.models import fields, Model
+from leapp.topics import SystemInfoTopic
+
+
+class FIPSInfo(Model):
+ """
+ Information about whether the source system has FIPS enabled.
+ """
+ topic = SystemInfoTopic
+
+ is_enabled = fields.Boolean(default=False)
+ """ Is fips enabled on the source system """
--
2.40.1

View File

@ -1,259 +0,0 @@
From 24bfcccc59047c43237ce1b0202245314eca7158 Mon Sep 17 00:00:00 2001
From: Irina Gulina <igulina@redhat.com>
Date: Fri, 5 May 2023 08:43:19 +0200
Subject: [PATCH 24/30] Change the upgrade paths for SAP HANA
- Drop 7.9 to 8.2
- Add 7.9 to 8.8, but keep 7.9 to 8.6 as default
- Add 8.8 to 9.2
- Drop SAP HANA version check for the target releases >=8.8 and >=9.2
- Correct actor.py docstring to support ppc64le for 8to9 upgrade (see PR1042)
---
.../common/actors/checksaphana/actor.py | 11 +++-
.../checksaphana/libraries/checksaphana.py | 57 ++++++++++++-------
.../checksaphana/tests/test_checksaphana.py | 31 +---------
.../common/files/upgrade_paths.json | 7 ++-
.../common/libraries/config/version.py | 2 +-
5 files changed, 50 insertions(+), 58 deletions(-)
diff --git a/repos/system_upgrade/common/actors/checksaphana/actor.py b/repos/system_upgrade/common/actors/checksaphana/actor.py
index 70e78147..97d00455 100644
--- a/repos/system_upgrade/common/actors/checksaphana/actor.py
+++ b/repos/system_upgrade/common/actors/checksaphana/actor.py
@@ -12,10 +12,15 @@ class CheckSapHana(Actor):
If the upgrade flavour is 'default' no checks are being executed.
The following checks are executed:
- - If this system is _NOT_ running on x86_64, the upgrade is inhibited.
- - If SAP HANA 1 has been detected on the system the upgrade is inhibited since it is not supported on RHEL8.
+ - If the major target release is 8, and this system is _NOT_ running on x86_64, the upgrade is inhibited.
+ - If the major target release is 9, and this system is _NOT_ running on x86_64 or ppc64le,
+ the upgrade is inhibited.
+ - If SAP HANA 1 has been detected on the system the upgrade is inhibited since there is no supported upgrade path
+ with installed SAP HANA 1.
- If SAP HANA 2 has been detected, the upgrade will be inhibited if an unsupported version for the target release
- has been detected.
+ has been detected (<8.8, <9.2).
+ - If the target release >=8.8 or >=9.2, the upgrade will be inhibited unless a user confirms to proceed
+ for the currently installed SAP HANA 2.0 version and the chosen target release.
- If SAP HANA is running the upgrade is inhibited.
"""
diff --git a/repos/system_upgrade/common/actors/checksaphana/libraries/checksaphana.py b/repos/system_upgrade/common/actors/checksaphana/libraries/checksaphana.py
index 92109997..1b08f3d2 100644
--- a/repos/system_upgrade/common/actors/checksaphana/libraries/checksaphana.py
+++ b/repos/system_upgrade/common/actors/checksaphana/libraries/checksaphana.py
@@ -10,20 +10,36 @@ SAP_HANA_SUPPORTER_ARCHS = {
'9': [architecture.ARCH_X86_64, architecture.ARCH_PPC64LE]
}
-# SAP HANA 2.00 rev 54 is the minimal supported revision for both RHEL 7.9 and RHEL 8.2
-
SAP_HANA_MINIMAL_MAJOR_VERSION = 2
-# RHEL 8.2 target requirements
-SAP_HANA_RHEL82_REQUIRED_PATCH_LEVELS = ((5, 54, 0),)
-SAP_HANA_RHEL82_MINIMAL_VERSION_STRING = 'HANA 2.0 SPS05 rev 54 or later'
# RHEL 8.6 target requirements
SAP_HANA_RHEL86_REQUIRED_PATCH_LEVELS = ((5, 59, 2),)
SAP_HANA_RHEL86_MINIMAL_VERSION_STRING = 'HANA 2.0 SPS05 rev 59.02 or later'
-# RHEL 9 target requirements
-SAP_HANA_RHEL9_REQUIRED_PATCH_LEVELS = ((5, 59, 4), (6, 63, 0))
-SAP_HANA_RHEL9_MINIMAL_VERSION_STRING = 'HANA 2.0 SPS05 rev 59.04 or later, or SPS06 rev 63 or later'
+# RHEL 9.0 target requirements
+SAP_HANA_RHEL90_REQUIRED_PATCH_LEVELS = ((5, 59, 4), (6, 63, 0))
+SAP_HANA_RHEL90_MINIMAL_VERSION_STRING = 'HANA 2.0 SPS05 rev 59.04 or later, or SPS06 rev 63 or later'
+
+
+def _report_skip_check():
+ summary = (
+ 'For the target RHEL releases >=8.8 and >=9.2 '
+ 'the leapp utility does not check RHEL and SAP HANA 2.0 '
+ 'versions compatibility. Please ensure your SAP HANA 2.0 '
+ 'is supported on the target RHEL release and '
+ 'proceed on your discretion. '
+ 'SAP HANA: Supported Operating Systems '
+ 'https://launchpad.support.sap.com/#/notes/2235581')
+ remedy_hint = 'Ensure your SAP HANA 2.0 is supported on the target release.'
+ reporting.create_report([
+ reporting.Title('SAP HANA 2.0 version should be checked prior the upgrade'),
+ reporting.Summary(summary),
+ reporting.Severity(reporting.Severity.MEDIUM),
+ reporting.Groups([reporting.Groups.SANITY]),
+ reporting.Remediation(hint=remedy_hint),
+ reporting.ExternalLink(url='https://launchpad.support.sap.com/#/notes/2235581',
+ title='SAP HANA: Supported Operating Systems'),
+ ])
def _manifest_get(manifest, key, default_value=None):
@@ -45,7 +61,6 @@ def running_check(info):
reporting.Severity(reporting.Severity.HIGH),
reporting.Groups([reporting.Groups.SANITY]),
reporting.Groups([reporting.Groups.INHIBITOR]),
- reporting.Audience('sysadmin')
])
@@ -72,12 +87,10 @@ def _create_detected_instances_list(details):
def _min_ver_string():
- if version.get_target_major_version() == '8':
+ if version.matches_target_version('8.6'):
ver_str = SAP_HANA_RHEL86_MINIMAL_VERSION_STRING
- if version.matches_target_version('8.2'):
- ver_str = SAP_HANA_RHEL82_MINIMAL_VERSION_STRING
else:
- ver_str = SAP_HANA_RHEL9_MINIMAL_VERSION_STRING
+ ver_str = SAP_HANA_RHEL90_MINIMAL_VERSION_STRING
return ver_str
@@ -89,10 +102,9 @@ def version1_check(info):
_add_hana_details(found, instance)
if found:
- min_ver_string = _min_ver_string()
detected = _create_detected_instances_list(found)
reporting.create_report([
- reporting.Title('Found SAP HANA 1 which is not supported with the target version of RHEL'),
+ reporting.Title('Found SAP HANA 1.0 which is not supported with the target version of RHEL'),
reporting.Summary(
('SAP HANA 1.00 is not supported with the version of RHEL you are upgrading to.\n\n'
'The following instances have been detected to be version 1.00:\n'
@@ -101,12 +113,11 @@ def version1_check(info):
reporting.Severity(reporting.Severity.HIGH),
reporting.RemediationHint((
'In order to upgrade RHEL, you will have to upgrade your SAP HANA 1.0 software to '
- '{supported}.'.format(supported=min_ver_string))),
+ 'SAP HANA 2.0 supported on the target RHEL release first.')),
reporting.ExternalLink(url='https://launchpad.support.sap.com/#/notes/2235581',
title='SAP HANA: Supported Operating Systems'),
reporting.Groups([reporting.Groups.SANITY]),
reporting.Groups([reporting.Groups.INHIBITOR]),
- reporting.Audience('sysadmin')
])
@@ -160,12 +171,10 @@ def _sp_rev_patchlevel_check(instance, patchlevels):
def _fullfills_hana_min_version(instance):
""" Performs a check whether the version of SAP HANA fulfills the minimal requirements for the target RHEL """
- if version.get_target_major_version() == '8':
+ if version.matches_target_version('8.6'):
patchlevels = SAP_HANA_RHEL86_REQUIRED_PATCH_LEVELS
- if version.matches_target_version('8.2'):
- patchlevels = SAP_HANA_RHEL82_REQUIRED_PATCH_LEVELS
else:
- patchlevels = SAP_HANA_RHEL9_REQUIRED_PATCH_LEVELS
+ patchlevels = SAP_HANA_RHEL90_REQUIRED_PATCH_LEVELS
return _major_version_check(instance) and _sp_rev_patchlevel_check(instance, patchlevels)
@@ -175,6 +184,11 @@ def version2_check(info):
for instance in info.instances:
if _manifest_get(instance.manifest, 'release', None) == '1.00':
continue
+ if version.matches_target_version('> 8.6', '< 9.0') or version.matches_target_version('> 9.0'):
+ # if a target release is >=8.8 or >=9.2, the SAP HANA and RHEL versions compatibility is not checked
+ _report_skip_check()
+ return
+ # if a starget release is 8.6 or 9.0 we still check SAP HANA and RHEL versions compatibility
if not _fullfills_hana_min_version(instance):
_add_hana_details(found, instance)
@@ -196,7 +210,6 @@ def version2_check(info):
reporting.Severity(reporting.Severity.HIGH),
reporting.Groups([reporting.Groups.SANITY]),
reporting.Groups([reporting.Groups.INHIBITOR]),
- reporting.Audience('sysadmin')
])
diff --git a/repos/system_upgrade/common/actors/checksaphana/tests/test_checksaphana.py b/repos/system_upgrade/common/actors/checksaphana/tests/test_checksaphana.py
index 3dc2c192..1417b00a 100644
--- a/repos/system_upgrade/common/actors/checksaphana/tests/test_checksaphana.py
+++ b/repos/system_upgrade/common/actors/checksaphana/tests/test_checksaphana.py
@@ -166,33 +166,6 @@ class MockSAPHanaVersionInstance(object):
]
-@pytest.mark.parametrize(
- 'major,rev,patchlevel,result', (
- (2, 52, 0, True),
- (2, 52, 1, True),
- (2, 52, 2, True),
- (2, 53, 0, True),
- (2, 60, 0, True),
- (2, 48, 2, True),
- (2, 48, 1, False),
- (2, 48, 0, False),
- (2, 38, 2, False),
- (2, 49, 0, True),
- )
-)
-def test_checksaphana__fullfills_rhel82_hana_min_version(monkeypatch, major, rev, patchlevel, result):
- monkeypatch.setattr(version, 'get_target_major_version', lambda: '8')
- monkeypatch.setattr(version, 'get_target_version', lambda: '8.2')
- monkeypatch.setattr(checksaphana, 'SAP_HANA_RHEL82_REQUIRED_PATCH_LEVELS', ((4, 48, 2), (5, 52, 0)))
- assert checksaphana._fullfills_hana_min_version(
- MockSAPHanaVersionInstance(
- major=major,
- rev=rev,
- patchlevel=patchlevel,
- )
- ) == result
-
-
@pytest.mark.parametrize(
'major,rev,patchlevel,result', (
(2, 52, 0, True),
@@ -239,10 +212,10 @@ def test_checksaphana__fullfills_rhel86_hana_min_version(monkeypatch, major, rev
(2, 64, 0, True),
)
)
-def test_checksaphana__fullfills_hana_rhel9_min_version(monkeypatch, major, rev, patchlevel, result):
+def test_checksaphana__fullfills_hana_rhel90_min_version(monkeypatch, major, rev, patchlevel, result):
monkeypatch.setattr(version, 'get_target_major_version', lambda: '9')
monkeypatch.setattr(version, 'get_target_version', lambda: '9.0')
- monkeypatch.setattr(checksaphana, 'SAP_HANA_RHEL9_REQUIRED_PATCH_LEVELS', ((5, 59, 4), (6, 63, 0)))
+ monkeypatch.setattr(checksaphana, 'SAP_HANA_RHEL90_REQUIRED_PATCH_LEVELS', ((5, 59, 4), (6, 63, 0)))
assert checksaphana._fullfills_hana_min_version(
MockSAPHanaVersionInstance(
major=major,
diff --git a/repos/system_upgrade/common/files/upgrade_paths.json b/repos/system_upgrade/common/files/upgrade_paths.json
index 5e3c5d32..5d8b44e9 100644
--- a/repos/system_upgrade/common/files/upgrade_paths.json
+++ b/repos/system_upgrade/common/files/upgrade_paths.json
@@ -7,9 +7,10 @@
"8": ["9.2"]
},
"saphana": {
- "7.9": ["8.2", "8.6"],
- "7": ["8.2", "8.6"],
+ "7.9": ["8.8", "8.6"],
+ "7": ["8.8", "8.6"],
"8.6": ["9.0"],
- "8": ["9.0"]
+ "8.8": ["9.2"],
+ "8": ["9.2", "9.0"]
}
}
diff --git a/repos/system_upgrade/common/libraries/config/version.py b/repos/system_upgrade/common/libraries/config/version.py
index cc5bfca5..6bf6b4da 100644
--- a/repos/system_upgrade/common/libraries/config/version.py
+++ b/repos/system_upgrade/common/libraries/config/version.py
@@ -14,7 +14,7 @@ OP_MAP = {
_SUPPORTED_VERSIONS = {
# Note: 'rhel-alt' is detected when on 'rhel' with kernel 4.x
'7': {'rhel': ['7.9'], 'rhel-alt': [], 'rhel-saphana': ['7.9']},
- '8': {'rhel': ['8.6', '8.8'], 'rhel-saphana': ['8.6']},
+ '8': {'rhel': ['8.6', '8.8'], 'rhel-saphana': ['8.6', '8.8']},
}
--
2.40.1

View File

@ -1,377 +0,0 @@
From 777e0a641739add1fca50af774d6d924af5550d7 Mon Sep 17 00:00:00 2001
From: David Kubek <dkubek@redhat.com>
Date: Tue, 14 Mar 2023 11:54:18 +0100
Subject: [PATCH 25/30] Inhibit unsupported x86-64 microarchitecture RHEL9
As per [x86-64-ABI][1] In addition to the AMD64 baseline architecture,
several micro-architecture levels implemented by later CPU modules have
been defined, starting at level ``x86-64-v2``.
RHEL9 has a higher CPU requirement than older versions, it now requires
a CPU compatible with ``x86-64-v2`` instruction set or higher. Until
now, there was no check for this and the upgrade crashed unexpectedly.
This commit handles this issue and provides the user with a report
explaining the problem.
The CPU Features are gathered using the ``lscpu`` command by way of
using the ``ScanCPU`` actor. The ``ScanCPU`` actor had to be also
modified to provide the required flags. The mapping of CPU Features to
flags provided by ``lscpu`` has been determined by using the
``/arch/x86/include/asm/cpufeatures.h`` file from the linux kernel.
[1]: https://gitlab.com/x86-psABIs/x86-64-ABI.git
---
.../actors/scancpu/libraries/scancpu.py | 13 +++-
.../actors/scancpu/tests/test_scancpu.py | 74 +++++++++++++++----
repos/system_upgrade/common/models/cpuinfo.py | 4 +-
.../actors/checkmicroarchitecture/actor.py | 63 ++++++++++++++++
.../libraries/checkmicroarchitecture.py | 47 ++++++++++++
.../tests/test_checkmicroarchitecture.py | 65 ++++++++++++++++
6 files changed, 249 insertions(+), 17 deletions(-)
create mode 100644 repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/actor.py
create mode 100644 repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/libraries/checkmicroarchitecture.py
create mode 100644 repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/tests/test_checkmicroarchitecture.py
diff --git a/repos/system_upgrade/common/actors/scancpu/libraries/scancpu.py b/repos/system_upgrade/common/actors/scancpu/libraries/scancpu.py
index 68f5623b..e5555f99 100644
--- a/repos/system_upgrade/common/actors/scancpu/libraries/scancpu.py
+++ b/repos/system_upgrade/common/actors/scancpu/libraries/scancpu.py
@@ -17,6 +17,11 @@ def _get_lscpu_output():
return ''
+def _get_cpu_flags(lscpu):
+ flags = lscpu.get('Flags', '')
+ return flags.split()
+
+
def _get_cpu_entries_for(arch_prefix):
result = []
for message in api.consume(DeviceDriverDeprecationData):
@@ -137,4 +142,10 @@ def process():
api.produce(*_find_deprecation_data_entries(lscpu))
# Backwards compatibility
machine_type = lscpu.get('Machine type')
- api.produce(CPUInfo(machine_type=int(machine_type) if machine_type else None))
+ flags = _get_cpu_flags(lscpu)
+ api.produce(
+ CPUInfo(
+ machine_type=int(machine_type) if machine_type else None,
+ flags=flags
+ )
+ )
diff --git a/repos/system_upgrade/common/actors/scancpu/tests/test_scancpu.py b/repos/system_upgrade/common/actors/scancpu/tests/test_scancpu.py
index 44d4de87..894fae08 100644
--- a/repos/system_upgrade/common/actors/scancpu/tests/test_scancpu.py
+++ b/repos/system_upgrade/common/actors/scancpu/tests/test_scancpu.py
@@ -1,14 +1,59 @@
import os
+import pytest
+
from leapp.libraries.actor import scancpu
from leapp.libraries.common import testutils
+from leapp.libraries.common.config.architecture import (
+ ARCH_ARM64,
+ ARCH_PPC64LE,
+ ARCH_S390X,
+ ARCH_SUPPORTED,
+ ARCH_X86_64
+)
from leapp.libraries.stdlib import api
from leapp.models import CPUInfo
CUR_DIR = os.path.dirname(os.path.abspath(__file__))
+LSCPU = {
+ ARCH_ARM64: {
+ "machine_type": None,
+ "flags": ['fp', 'asimd', 'evtstrm', 'aes', 'pmull', 'sha1', 'sha2', 'crc32', 'cpuid'],
+ },
+ ARCH_PPC64LE: {
+ "machine_type": None,
+ "flags": []
+ },
+ ARCH_S390X: {
+ "machine_type":
+ 2827,
+ "flags": [
+ 'esan3', 'zarch', 'stfle', 'msa', 'ldisp', 'eimm', 'dfp', 'edat', 'etf3eh', 'highgprs', 'te', 'vx', 'vxd',
+ 'vxe', 'gs', 'vxe2', 'vxp', 'sort', 'dflt', 'sie'
+ ]
+ },
+ ARCH_X86_64: {
+ "machine_type":
+ None,
+ "flags": [
+ 'fpu', 'vme', 'de', 'pse', 'tsc', 'msr', 'pae', 'mce', 'cx8', 'apic', 'sep', 'mtrr', 'pge', 'mca', 'cmov',
+ 'pat', 'pse36', 'clflush', 'dts', 'acpi', 'mmx', 'fxsr', 'sse', 'sse2', 'ss', 'ht', 'tm', 'pbe', 'syscall',
+ 'nx', 'pdpe1gb', 'rdtscp', 'lm', 'constant_tsc', 'arch_perfmon', 'pebs', 'bts', 'rep_good', 'nopl',
+ 'xtopology', 'nonstop_tsc', 'cpuid', 'aperfmperf', 'pni', 'pclmulqdq', 'dtes64', 'monitor', 'ds_cpl',
+ 'vmx', 'smx', 'est', 'tm2', 'ssse3', 'sdbg', 'fma', 'cx16', 'xtpr', 'pdcm', 'pcid', 'dca', 'sse4_1',
+ 'sse4_2', 'x2apic', 'movbe', 'popcnt', 'tsc_deadline_timer', 'aes', 'xsave', 'avx', 'f16c', 'rdrand',
+ 'lahf_lm', 'abm', 'cpuid_fault', 'epb', 'invpcid_single', 'pti', 'ssbd', 'ibrs', 'ibpb', 'stibp',
+ 'tpr_shadow', 'vnmi', 'flexpriority', 'ept', 'vpid', 'ept_ad', 'fsgsbase', 'tsc_adjust', 'bmi1', 'avx2',
+ 'smep', 'bmi2', 'erms', 'invpcid', 'cqm', 'xsaveopt', 'cqm_llc', 'cqm_occup_llc', 'dtherm', 'ida', 'arat',
+ 'pln', 'pts', 'md_clear', 'flush_l1d'
+ ]
+ },
+}
+
class mocked_get_cpuinfo(object):
+
def __init__(self, filename):
self.filename = filename
@@ -22,24 +67,25 @@ class mocked_get_cpuinfo(object):
return '\n'.join(fp.read().splitlines())
-def test_machine_type(monkeypatch):
+@pytest.mark.parametrize("arch", ARCH_SUPPORTED)
+def test_scancpu(monkeypatch, arch):
- # cpuinfo doesn't contain a machine field
- mocked_cpuinfo = mocked_get_cpuinfo('lscpu_x86_64')
+ mocked_cpuinfo = mocked_get_cpuinfo('lscpu_' + arch)
monkeypatch.setattr(scancpu, '_get_lscpu_output', mocked_cpuinfo)
monkeypatch.setattr(api, 'produce', testutils.produce_mocked())
- current_actor = testutils.CurrentActorMocked(arch=testutils.architecture.ARCH_X86_64)
+ current_actor = testutils.CurrentActorMocked(arch=arch)
monkeypatch.setattr(api, 'current_actor', current_actor)
- scancpu.process()
- assert api.produce.called == 1
- assert CPUInfo() == api.produce.model_instances[0]
- # cpuinfo contains a machine field
- api.produce.called = 0
- api.produce.model_instances = []
- current_actor = testutils.CurrentActorMocked(arch=testutils.architecture.ARCH_S390X)
- monkeypatch.setattr(api, 'current_actor', current_actor)
- mocked_cpuinfo.filename = 'lscpu_s390x'
scancpu.process()
+
+ expected = CPUInfo(machine_type=LSCPU[arch]["machine_type"], flags=LSCPU[arch]["flags"])
+ produced = api.produce.model_instances[0]
+
assert api.produce.called == 1
- assert CPUInfo(machine_type=2827) == api.produce.model_instances[0]
+
+ # Produced what was expected
+ assert expected.machine_type == produced.machine_type
+ assert sorted(expected.flags) == sorted(produced.flags)
+
+ # Did not produce anything extra
+ assert expected == produced
diff --git a/repos/system_upgrade/common/models/cpuinfo.py b/repos/system_upgrade/common/models/cpuinfo.py
index e3e52838..ee245563 100644
--- a/repos/system_upgrade/common/models/cpuinfo.py
+++ b/repos/system_upgrade/common/models/cpuinfo.py
@@ -32,8 +32,8 @@ class CPUInfo(Model):
# byte_order = fields.StringEnum(['Little Endian', 'Big Endian'])
# """ Byte order of the CPU: 'Little Endian' or 'Big Endian' """
- # flags = fields.List(fields.String(), default=[])
- # """ Specifies flags/features of the CPU. """
+ flags = fields.List(fields.String(), default=[])
+ """ Specifies flags/features of the CPU. """
# hypervisor = fields.Nullable(fields.String())
# hypervisor_vendor = fields.Nullable(fields.String())
diff --git a/repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/actor.py b/repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/actor.py
new file mode 100644
index 00000000..98ffea80
--- /dev/null
+++ b/repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/actor.py
@@ -0,0 +1,63 @@
+import leapp.libraries.actor.checkmicroarchitecture as checkmicroarchitecture
+from leapp.actors import Actor
+from leapp.models import CPUInfo
+from leapp.reporting import Report
+from leapp.tags import ChecksPhaseTag, IPUWorkflowTag
+
+
+class CheckMicroarchitecture(Actor):
+ """
+ Inhibit if RHEL9 microarchitecture requirements are not satisfied
+
+
+ As per `x86-64-ABI`_ In addition to the AMD64 baseline architecture, several
+ micro-architecture levels implemented by later CPU modules have been
+ defined, starting at level ``x86-64-v2``. The levels are cumulative in the
+ sense that features from previous levels are implicitly included in later
+ levels.
+
+ RHEL9 has a higher CPU requirement than older versions, it now requires a
+ CPU compatible with ``x86-64-v2`` instruction set or higher.
+
+ .. table:: Required CPU features by microarchitecure level with a
+ corresponding flag as shown by ``lscpu``.
+
+ +------------+-------------+--------------------+
+ | Version | CPU Feature | flag (lscpu) |
+ +============+=============+====================+
+ | (baseline) | CMOV | cmov |
+ | | CX8 | cx8 |
+ | | FPU | fpu |
+ | | FXSR | fxsr |
+ | | MMX | mmx |
+ | | OSFXSR | (common with FXSR) |
+ | | SCE | syscall |
+ | | SSE | sse |
+ | | SSE2 | sse2 |
+ +------------+-------------+--------------------+
+ | x86-64-v2 | CMPXCHG16B | cx16 |
+ | | LAHF-SAHF | lahf_lm |
+ | | POPCNT | popcnt |
+ | | SSE3 | pni |
+ | | SSE4_1 | sse4_1 |
+ | | SSE4_2 | sse4_2 |
+ | | SSSE3 | ssse3 |
+ +------------+-------------+--------------------+
+ | ... | | |
+ +------------+-------------+--------------------+
+
+ Note: To get the corresponding flag for the CPU feature consult the file
+ ``/arch/x86/include/asm/cpufeatures.h`` in the linux kernel.
+
+
+ .. _x86-64-ABI: https://gitlab.com/x86-psABIs/x86-64-ABI.git
+
+ """
+
+ name = 'check_microarchitecture'
+ consumes = (CPUInfo,)
+ produces = (Report,)
+ tags = (ChecksPhaseTag, IPUWorkflowTag,)
+
+ def process(self):
+ checkmicroarchitecture.process()
diff --git a/repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/libraries/checkmicroarchitecture.py b/repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/libraries/checkmicroarchitecture.py
new file mode 100644
index 00000000..0f1f1fca
--- /dev/null
+++ b/repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/libraries/checkmicroarchitecture.py
@@ -0,0 +1,47 @@
+from leapp import reporting
+from leapp.libraries.common.config.architecture import ARCH_X86_64, matches_architecture
+from leapp.libraries.stdlib import api
+from leapp.models import CPUInfo
+
+X86_64_BASELINE_FLAGS = ['cmov', 'cx8', 'fpu', 'fxsr', 'mmx', 'syscall', 'sse', 'sse2']
+X86_64_V2_FLAGS = ['cx16', 'lahf_lm', 'popcnt', 'pni', 'sse4_1', 'sse4_2', 'ssse3']
+
+
+def _inhibit_upgrade(missing_flags):
+ title = 'Current x86-64 microarchitecture is unsupported in RHEL9'
+ summary = ('RHEL9 has a higher CPU requirement than older versions, it now requires a CPU '
+ 'compatible with x86-64-v2 instruction set or higher.\n\n'
+ 'Missings flags detected are: {}\n'.format(', '.join(missing_flags)))
+
+ reporting.create_report([
+ reporting.Title(title),
+ reporting.Summary(summary),
+ reporting.ExternalLink(title='Building Red Hat Enterprise Linux 9 for the x86-64-v2 microarchitecture level',
+ url=('https://developers.redhat.com/blog/2021/01/05/'
+ 'building-red-hat-enterprise-linux-9-for-the-x86-64-v2-microarchitecture-level')),
+ reporting.Severity(reporting.Severity.HIGH),
+ reporting.Groups([reporting.Groups.INHIBITOR]),
+ reporting.Groups([reporting.Groups.SANITY]),
+ reporting.Remediation(hint=('If case of using virtualization, virtualization platforms often allow '
+ 'configuring a minimum denominator CPU model for compatibility when migrating '
+ 'between different CPU models. Ensure that minimum requirements are not below '
+ 'that of RHEL9\n')),
+ ])
+
+
+def process():
+ """
+ Check whether the processor matches the required microarchitecture.
+ """
+
+ if not matches_architecture(ARCH_X86_64):
+ api.current_logger().info('Architecture not x86-64. Skipping microarchitecture test.')
+ return
+
+ cpuinfo = next(api.consume(CPUInfo))
+
+ required_flags = X86_64_BASELINE_FLAGS + X86_64_V2_FLAGS
+ missing_flags = [flag for flag in required_flags if flag not in cpuinfo.flags]
+ api.current_logger().debug('Required flags missing: %s', missing_flags)
+ if missing_flags:
+ _inhibit_upgrade(missing_flags)
diff --git a/repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/tests/test_checkmicroarchitecture.py b/repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/tests/test_checkmicroarchitecture.py
new file mode 100644
index 00000000..b7c850d9
--- /dev/null
+++ b/repos/system_upgrade/el8toel9/actors/checkmicroarchitecture/tests/test_checkmicroarchitecture.py
@@ -0,0 +1,65 @@
+import pytest
+
+from leapp import reporting
+from leapp.libraries.actor import checkmicroarchitecture
+from leapp.libraries.common.config.architecture import ARCH_SUPPORTED, ARCH_X86_64
+from leapp.libraries.common.testutils import create_report_mocked, CurrentActorMocked, logger_mocked
+from leapp.libraries.stdlib import api
+from leapp.models import CPUInfo
+from leapp.utils.report import is_inhibitor
+
+
+@pytest.mark.parametrize("arch", [arch for arch in ARCH_SUPPORTED if not arch == ARCH_X86_64])
+def test_not_x86_64_passes(monkeypatch, arch):
+ """
+ Test no report is generated on an architecture different from x86-64
+ """
+
+ monkeypatch.setattr(reporting, "create_report", create_report_mocked())
+ monkeypatch.setattr(api, 'current_logger', logger_mocked())
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(arch=arch))
+
+ checkmicroarchitecture.process()
+
+ assert 'Architecture not x86-64. Skipping microarchitecture test.' in api.current_logger.infomsg
+ assert not reporting.create_report.called
+
+
+def test_valid_microarchitecture(monkeypatch):
+ """
+ Test no report is generated on a valid microarchitecture
+ """
+
+ monkeypatch.setattr(reporting, "create_report", create_report_mocked())
+ monkeypatch.setattr(api, 'current_logger', logger_mocked())
+
+ required_flags = checkmicroarchitecture.X86_64_BASELINE_FLAGS + checkmicroarchitecture.X86_64_V2_FLAGS
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(arch=ARCH_X86_64,
+ msgs=[CPUInfo(flags=required_flags)]))
+
+ checkmicroarchitecture.process()
+
+ assert 'Architecture not x86-64. Skipping microarchitecture test.' not in api.current_logger.infomsg
+ assert not reporting.create_report.called
+
+
+def test_invalid_microarchitecture(monkeypatch):
+ """
+ Test report is generated on x86-64 architecture with invalid microarchitecture and the upgrade is inhibited
+ """
+
+ monkeypatch.setattr(reporting, "create_report", create_report_mocked())
+ monkeypatch.setattr(api, 'current_logger', logger_mocked())
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(arch=ARCH_X86_64, msgs=[CPUInfo()]))
+
+ checkmicroarchitecture.process()
+
+ produced_title = reporting.create_report.report_fields.get('title')
+ produced_summary = reporting.create_report.report_fields.get('summary')
+
+ assert 'Architecture not x86-64. Skipping microarchitecture test.' not in api.current_logger().infomsg
+ assert reporting.create_report.called == 1
+ assert 'microarchitecture is unsupported' in produced_title
+ assert 'RHEL9 has a higher CPU requirement' in produced_summary
+ assert reporting.create_report.report_fields['severity'] == reporting.Severity.HIGH
+ assert is_inhibitor(reporting.create_report.report_fields)
--
2.40.1

View File

@ -1,25 +0,0 @@
From 7043c7e0c5e674f4337ea0d141e19e5cefbbe79d Mon Sep 17 00:00:00 2001
From: Marek Filip <wecros@gmail.com>
Date: Wed, 31 May 2023 13:39:39 +0200
Subject: [PATCH 26/30] Fix doc link in checktargetrepos.py
---
.../actors/checktargetrepos/libraries/checktargetrepos.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/repos/system_upgrade/common/actors/checktargetrepos/libraries/checktargetrepos.py b/repos/system_upgrade/common/actors/checktargetrepos/libraries/checktargetrepos.py
index 77d53feb..5a53bf21 100644
--- a/repos/system_upgrade/common/actors/checktargetrepos/libraries/checktargetrepos.py
+++ b/repos/system_upgrade/common/actors/checktargetrepos/libraries/checktargetrepos.py
@@ -32,7 +32,7 @@ def process():
if target_major_version == '8':
ipu_doc_url = (
'https://access.redhat.com/documentation/en-us/'
- 'red_hat_enterprise_linux/8/html-single/upgrading_to_rhel_8/index'
+ 'red_hat_enterprise_linux/8/html-single/upgrading_from_rhel_7_to_rhel_8/index'
)
elif target_major_version == '9':
ipu_doc_url = 'TBA'
--
2.40.1

View File

@ -1,119 +0,0 @@
From 548a3b77e7dcf214bc1319f2cf47a0612dc78573 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Mon, 5 Jun 2023 18:37:07 +0200
Subject: [PATCH 27/30] Update the repomap.json file to address changes in RHUI
Azure
Diff:
Upg paths are unchanged.
Mappings are unchanged.
The following repos have been removed:
- Repo(pesid='rhel8-BaseOS', major_version='8', repoid='rhui-rhel-8-for-x86_64-baseos-rhui-rpms', repo_type='rpm', channel='ga', arch='x86_64', rhui='azure')
- Repo(pesid='rhel8-CRB', major_version='8', repoid='rhui-codeready-builder-for-rhel-8-x86_64-rhui-rpms', repo_type='rpm', channel='ga', arch='x86_64', rhui='azure')
- Repo(pesid='rhel8-AppStream', major_version='8', repoid='rhui-rhel-8-for-x86_64-appstream-rhui-rpms', repo_type='rpm', channel='ga', arch='x86_64', rhui='azure')
The following repos have been added:
- Repo(pesid='rhel8-AppStream', major_version='8', repoid='rhel-8-for-x86_64-appstream-rhui-rpms', repo_type='rpm', channel='ga', arch='x86_64', rhui='azure')
- Repo(pesid='rhel8-CRB', major_version='8', repoid='codeready-builder-for-rhel-8-x86_64-rhui-rpms', repo_type='rpm', channel='ga', arch='x86_64', rhui='azure')
- Repo(pesid='rhel8-BaseOS', major_version='8', repoid='rhel-8-for-x86_64-baseos-rhui-rpms', repo_type='rpm', channel='ga', arch='x86_64', rhui='azure')
---
etc/leapp/files/repomap.json | 44 ++++++++++++++++++------------------
1 file changed, 22 insertions(+), 22 deletions(-)
diff --git a/etc/leapp/files/repomap.json b/etc/leapp/files/repomap.json
index 88116e2d..14b6f0d7 100644
--- a/etc/leapp/files/repomap.json
+++ b/etc/leapp/files/repomap.json
@@ -1,5 +1,5 @@
{
- "datetime": "202303072246Z",
+ "datetime": "202306051542Z",
"version_format": "1.0.0",
"mapping": [
{
@@ -1409,6 +1409,14 @@
"channel": "eus",
"repo_type": "rpm"
},
+ {
+ "major_version": "8",
+ "repoid": "rhel-8-for-x86_64-baseos-rhui-rpms",
+ "arch": "x86_64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "rhui": "azure"
+ },
{
"major_version": "8",
"repoid": "rhel-8-for-x86_64-baseos-rpms",
@@ -1432,14 +1440,6 @@
"repo_type": "rpm",
"rhui": "aws"
},
- {
- "major_version": "8",
- "repoid": "rhui-rhel-8-for-x86_64-baseos-rhui-rpms",
- "arch": "x86_64",
- "channel": "ga",
- "repo_type": "rpm",
- "rhui": "azure"
- },
{
"major_version": "8",
"repoid": "rhui-rhel-8-for-x86_64-baseos-rhui-rpms",
@@ -1615,6 +1615,14 @@
"channel": "eus",
"repo_type": "rpm"
},
+ {
+ "major_version": "8",
+ "repoid": "rhel-8-for-x86_64-appstream-rhui-rpms",
+ "arch": "x86_64",
+ "channel": "ga",
+ "repo_type": "rpm",
+ "rhui": "azure"
+ },
{
"major_version": "8",
"repoid": "rhel-8-for-x86_64-appstream-rpms",
@@ -1638,14 +1646,6 @@
"repo_type": "rpm",
"rhui": "aws"
},
- {
- "major_version": "8",
- "repoid": "rhui-rhel-8-for-x86_64-appstream-rhui-rpms",
- "arch": "x86_64",
- "channel": "ga",
- "repo_type": "rpm",
- "rhui": "azure"
- },
{
"major_version": "8",
"repoid": "rhui-rhel-8-for-x86_64-appstream-rhui-rpms",
@@ -1762,18 +1762,18 @@
},
{
"major_version": "8",
- "repoid": "codeready-builder-for-rhel-8-x86_64-rpms",
+ "repoid": "codeready-builder-for-rhel-8-x86_64-rhui-rpms",
"arch": "x86_64",
"channel": "ga",
- "repo_type": "rpm"
+ "repo_type": "rpm",
+ "rhui": "azure"
},
{
"major_version": "8",
- "repoid": "rhui-codeready-builder-for-rhel-8-x86_64-rhui-rpms",
+ "repoid": "codeready-builder-for-rhel-8-x86_64-rpms",
"arch": "x86_64",
"channel": "ga",
- "repo_type": "rpm",
- "rhui": "azure"
+ "repo_type": "rpm"
},
{
"major_version": "8",
--
2.40.1

View File

@ -1,748 +0,0 @@
From 855c025f455f3c5f4949f016d39b573666789ab9 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Mon, 19 Jun 2023 12:26:17 +0200
Subject: [PATCH 28/30] Add prod certs and upgrade paths for 8.9 & 9.3
---
.github/workflows/codespell.yml | 4 +--
.../common/files/prod-certs/8.9/279.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/8.9/362.pem | 36 +++++++++++++++++++
.../common/files/prod-certs/8.9/363.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/8.9/419.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/8.9/433.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/8.9/479.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/8.9/486.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/8.9/72.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/9.3/279.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/9.3/362.pem | 36 +++++++++++++++++++
.../common/files/prod-certs/9.3/363.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/9.3/419.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/9.3/433.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/9.3/479.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/9.3/486.pem | 35 ++++++++++++++++++
.../common/files/prod-certs/9.3/72.pem | 35 ++++++++++++++++++
.../common/files/upgrade_paths.json | 7 ++--
.../common/libraries/config/version.py | 2 +-
19 files changed, 569 insertions(+), 6 deletions(-)
create mode 100644 repos/system_upgrade/common/files/prod-certs/8.9/279.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/8.9/362.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/8.9/363.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/8.9/419.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/8.9/433.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/8.9/479.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/8.9/486.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/8.9/72.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.3/279.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.3/362.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.3/363.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.3/419.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.3/433.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.3/479.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.3/486.pem
create mode 100644 repos/system_upgrade/common/files/prod-certs/9.3/72.pem
diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml
index 50115826..1348c7fe 100644
--- a/.github/workflows/codespell.yml
+++ b/.github/workflows/codespell.yml
@@ -23,5 +23,5 @@ jobs:
./repos/system_upgrade/common/actors/scancpu/tests/files/lscpu_s390x,\
./etc/leapp/files/device_driver_deprecation_data.json,\
./etc/leapp/files/pes-events.json,\
- ./etc/leapp/files/repomap.json"
-
+ ./etc/leapp/files/repomap.json,\
+ ./repos/system_upgrade/common/files/prod-certs"
diff --git a/repos/system_upgrade/common/files/prod-certs/8.9/279.pem b/repos/system_upgrade/common/files/prod-certs/8.9/279.pem
new file mode 100644
index 00000000..db37263c
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/8.9/279.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGJTCCBA2gAwIBAgIJALDxRLt/tU+JMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTIzMDExMTE0MTgyN1oXDTQzMDEx
+MTE0MTgyN1owRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFtjNWViY2Fi
+ZS0yMjgwLTQ1MTAtOWIxNy02OTg5ZDljNGE5OGJdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBrjCBqzAJBgNVHRMEAjAAMEMGDCsGAQQBkggJAYIXAQQzDDFSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIFBvd2VyLCBsaXR0bGUgZW5kaWFuMBUGDCsG
+AQQBkggJAYIXAgQFDAM4LjkwGQYMKwYBBAGSCAkBghcDBAkMB3BwYzY0bGUwJwYM
+KwYBBAGSCAkBghcEBBcMFXJoZWwtOCxyaGVsLTgtcHBjNjRsZTANBgkqhkiG9w0B
+AQsFAAOCAgEAZ5VTVzFyEs0H5dkrav/ynp2WADNCzAVBk7byHzIniDA+9blCDyFi
+w6Yb8KcDEpk4LRxj5wFWSdyCBGX4QpmHZkzxISk49O4MiOhpcfNKwNPzl7p8zdvO
+nm7H+ZIwPWHd5jKvxORsqB8Y7Tk6xM3usXcwSsv93jijIY7nifKIA1kUovi8h7pw
+ZxAys/ABvkegVXp2783GSc9H2ItWVExBEb3rgCkzW5b+ltRnncDYB4lRH5GlND8Q
+OBrth+253HImkA1mSvWewOwOcdtPB79IKkgF2P3vfrakFQva6F4vA7KKcIBdPf/I
+D1wuniZyBxwvKSdN62jy2LWgkSM2SoXpDyUVE0fE8qkoXEcuAImVWeaL4o0uoFn2
+tZ141z7pG8uMzPweS+x6LwmezftSuUtVh2rESuszfvR8dckPvA2a39BU4qpxt4Nr
+nyosCDBxT3p5CZyvVzFalanZd2J8aWnertrn1K+KMi5pEmqPCUccGwHZe6wvaEAu
+yKUOXdcjs627TIce2OGNAu92cNXeZAsG3xAzzFxo/mBx8TxaMNL579sf7YYsfdY5
+L47yhN5LD1efLfP1yQjrdcwR3LKVg8NU0JFc2xBf9tnZ1vzlT350nNkgZfkNhoLi
+mTSquBuT+oOdcmNrJIpv65hyRG08YGhS0AAMYsheE2TGcjo6VPpQCDU=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/8.9/362.pem b/repos/system_upgrade/common/files/prod-certs/8.9/362.pem
new file mode 100644
index 00000000..6fd40e9e
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/8.9/362.pem
@@ -0,0 +1,36 @@
+-----BEGIN CERTIFICATE-----
+MIIGNDCCBBygAwIBAgIJALDxRLt/tU9zMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTIzMDExMTE0MTY1NloXDTQzMDEx
+MTE0MTY1NlowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs2YmYzNWFh
+NS0yOTFlLTQ3MzktODBlOS01ZDZlODJlODM0YjJdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBvTCBujAJBgNVHRMEAjAAMEgGDCsGAQQBkggJAYJqAQQ4DDZSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIFBvd2VyLCBsaXR0bGUgZW5kaWFuIEJldGEw
+GgYMKwYBBAGSCAkBgmoCBAoMCDguOSBCZXRhMBkGDCsGAQQBkggJAYJqAwQJDAdw
+cGM2NGxlMCwGDCsGAQQBkggJAYJqBAQcDBpyaGVsLTgscmhlbC04LWJldGEtcHBj
+NjRsZTANBgkqhkiG9w0BAQsFAAOCAgEARkOuDEfPta9hzL9cW/KcxeJMKSCIDnYN
+s9+ROCossSvxA7aLedpTcQ3S+rKbw4gDHjwG2ej1xrt3GWc7Kbhmdofk1fKPn4M/
+70Iy6bWcwagHLgUNMziQEzftogYbmOtxMZKX7E1bk1DqvROs2kg/2+a1b/5Z51gT
+a5B9SjFPF02FmlqIaFt2mVKr2RjfZo9c5J16lbZdNKLTXxMZbcxJF6DH0xyyft57
+MyMsl7fcIH81Lz7kFJ56EfnJvy2H+VCxKYIJZFetAaQKqyPGqbid9QH/ZMHB3tYv
+sjWd9Dn0jeuQ6K4Cb0wqEx84a9REh0Ige8r9AY+wwWwuivpmCtFtGccEwmMvL657
+kBMffttaCCyL83GupdTg05+1AokLIFNm0UE/+ma69JOS2hvjM+pC/eMJGZlRAOWM
+oZtsKoKU42oAA9sLSbHAKAN54hnRKOIGABdOGmHOCwPm7tZJ99ZkQo8vli/hCuBE
+pVZiFGYbo34mlsOcJxjBI/4RUIXmWijbgHQemJUgWecbEHlEYu7yR1aVWDraTAKm
+vxxf41D4xDis+g9dspHQWwqxHJ2QsOPp1AtXThgO5vJ6Mu0sd50SDXiD0qrMq/5l
+95Gaa5Ih6JjFttlftftJ6l3rsycLLwoPBcHKMptgyin1ysg/TsRZ9OvznrMhTT9w
+nEMeBZgLxXU=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/8.9/363.pem b/repos/system_upgrade/common/files/prod-certs/8.9/363.pem
new file mode 100644
index 00000000..803aafc2
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/8.9/363.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGJjCCBA6gAwIBAgIJALDxRLt/tU9yMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTIzMDExMTE0MTY1NVoXDTQzMDEx
+MTE0MTY1NVowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFtlYmNjOWQw
+Yy0yYjU1LTQ4MTAtOGY0ZC1mZTczYzViYzYyNDJdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBrzCBrDAJBgNVHRMEAjAAMDoGDCsGAQQBkggJAYJrAQQqDChSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIEFSTSA2NCBCZXRhMBoGDCsGAQQBkggJAYJr
+AgQKDAg4LjkgQmV0YTAZBgwrBgEEAZIICQGCawMECQwHYWFyY2g2NDAsBgwrBgEE
+AZIICQGCawQEHAwacmhlbC04LHJoZWwtOC1iZXRhLWFhcmNoNjQwDQYJKoZIhvcN
+AQELBQADggIBAEKQU4JdkRynFZJqFN6waBVJsSWfdMPvCDZ7C+aJiXjeJEzccziE
+QK1rN2TiZzMcJdGu4eimXIPdjz5gZnupy6ZbNZLjGBfCEuIGQZLOF1aBwdM/chPq
+bZniU+Iu3VmJZ5nBdYBMwWee8I9E4T1Ia5m8sh93pL9F8M4a/SRBG26tSTRPHf3I
+zpEIR7nsbussbApcSiq/sGOr80DDycpS2hc5qPiICnwPIfGQNEgMRA8G//3JJZ1q
+4nwG5WHxLK68K9i9bUKOBVizEiAnqGCdDcTez1Qanags95Uvebnpx6QvST6b4bjG
+8pvbu8GTw/CGnYSw9pg2Is8nkDIQN66j/JGcbysFad4vldiLjUYkjVpdxYUT6fVE
+jmWFE0Px6jf7u0NqD3sjKVxy5RwcBorrYC2TM4tQfJbrTfVhJXxRUFVKkcq8q10a
+zhTISai2re7qPE08SQ1pzQ98KV44ZY0atnGOhb95EKhE1+Nvdzjf0aNDzcWGHTlO
+TwaoGeZXgh0xRUj+6+MXsk6c5PLNnEUOdsW4pkYt1ew0FhzkyED0hr2rVAUXSBCH
+5nJ7N6DStcVZwgc7j5c57c8+a22L6R6ncuoZh7qmujVN7zgvP/6c7ZcGUixe+I7s
+h/14X8CuC12Hwod3A9Qod/7LorjbKAO45xIWYaMjvnYVgwA26Jk5Uapb
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/8.9/419.pem b/repos/system_upgrade/common/files/prod-certs/8.9/419.pem
new file mode 100644
index 00000000..c41dc91d
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/8.9/419.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGFzCCA/+gAwIBAgIJALDxRLt/tU+IMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTIzMDExMTE0MTgyN1oXDTQzMDEx
+MTE0MTgyN1owRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFthODQ5MGNk
+YS04M2IwLTQ2ZDYtOGRhMy1mOGU0YTY4NzQyZjFdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBoDCBnTAJBgNVHRMEAjAAMDUGDCsGAQQBkggJAYMjAQQlDCNSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIEFSTSA2NDAVBgwrBgEEAZIICQGDIwIEBQwD
+OC45MBkGDCsGAQQBkggJAYMjAwQJDAdhYXJjaDY0MCcGDCsGAQQBkggJAYMjBAQX
+DBVyaGVsLTgscmhlbC04LWFhcmNoNjQwDQYJKoZIhvcNAQELBQADggIBABZR2AuL
+G1qvNs6+3mXN3QncJaKV5BenG8lglARP2V0+R26F4vbJJ2bxSc5Xyr1tp+qji2fL
+POJSwCwR06RDMhUEs8N5cLfpzDpXhq9KPF+L3GEDemMeWzt4JeVI3ekJLPWqm4L/
+5qxFsqL1GFYvDK/Qd9Rf5NEsum3Phv6y9aYhmLPEnDcKxhl0+ju3nth68p3pnk7b
+pJlUQ+xsVuQixG8OBAugPcbW624Nf6g9R5ZtwAFv9t709zUjqI4HCJJAbgfAI18Z
+uPiHs7S42xY3XVTTucx2DAkKlMi4bS9Pk/EK7r5xiiDZkN1zqyYVN9kKUqJGhtFq
+w1W+SPuryexcZ6lXzZUzaxQXc2u1N1ATGdgubyS94O2lY6XM7JAN+nSe51xrbtcM
+XOwibUGCmELek8wmJTSIj1kFo/7vBVgyqoffDOgmRXpogFCJZk2v69WVCWmo2BYS
+5LnucG8iZMQ1Ix+6llsNgCTp32zApk26DA8WYzGRsXv88TWhNpI0iQjO9HMhJlBN
+PqwrQpyprOFwKsKJxWSC1kcEPJ3gYJVawUq5hbYxpUplxt1q670xfKqN0egXcUrL
+rnNWYsq+pJpQo601pgP2eQJQRWzWFwioYkbbliPMgFQVuKQATGq4l2VZn/PQ/SSF
+/CDtUf1/ucR7cRcl/AT1MVlkC1DrCHb2yDgh
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/8.9/433.pem b/repos/system_upgrade/common/files/prod-certs/8.9/433.pem
new file mode 100644
index 00000000..5ce693ee
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/8.9/433.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGKTCCBBGgAwIBAgIJALDxRLt/tU90MA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTIzMDExMTE0MTY1NloXDTQzMDEx
+MTE0MTY1NlowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs4YjkzMzU0
+Zi1lMDdmLTQxYzUtOTRkOC05MWQ0MGY0Y2NhNWRdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBsjCBrzAJBgNVHRMEAjAAMEEGDCsGAQQBkggJAYMxAQQxDC9SZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIElCTSB6IFN5c3RlbXMgQmV0YTAaBgwrBgEE
+AZIICQGDMQIECgwIOC45IEJldGEwFwYMKwYBBAGSCAkBgzEDBAcMBXMzOTB4MCoG
+DCsGAQQBkggJAYMxBAQaDBhyaGVsLTgscmhlbC04LWJldGEtczM5MHgwDQYJKoZI
+hvcNAQELBQADggIBAKH1KhOE0yRAcJ2aqMvGlfrhqEPhtzBNp73vt0QNyNDlU3Ud
+ijwKlTIsmLFbAXGQj4WdR4TbCm0BZP4+6pMPjwhFXHdU5fHpOD/BiIV7csZKNWZy
+HpuBv0Kp4Xv7yJoHy6YhPoaIPIwDX4VPPjoSccn2jHUDGg/o9mTyUZfCnIe5GrwM
+MDck15uvG5kRhIkCcW6AkJuaNpPNLLHLjX7VNDYwAYllmWbozu0YQ7KhHHslT0z3
+HFlDVFbrt3X/0Zv0DOrkN/50f0i6KlPevFBBdvPuGTkPIRANSmNGu0DRn8fF1G+3
+8TrAi1tIBaQ6E4/RZJ3y0YGnV2fO/bDuv8qscQGWoSkmFEAsrvCih5swoBhJ8aPn
+6FusamiIKH/okwX59eAA+yhFfohmsrn3kxXNbDOfozchHYuP3trk6jfDLsS6519f
+cHGaJtmzVNfsF2QoHp9aWbkgE0kzBPUOvXOa6T3AXYcTzhkpWDR+MxcUl9y/eNh1
+s/hbiQH7BBMHq+/sMPD7n3Dus51am1xamDy1B+v8b5p8kNTbrUR0uzEzCQNsrZtM
+jSa3SziP+DJwGu5Ag2qFAfI5rXFHCPrk+fgeg/4uSz+Smtm1W1mqK0AQMmYBqgCq
+q8WPWP8kQt79RbtprUgNTCvSg+mY18uiyO6B0VqcT9gRIE6/oTXR7RfFCH6h
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/8.9/479.pem b/repos/system_upgrade/common/files/prod-certs/8.9/479.pem
new file mode 100644
index 00000000..c8952280
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/8.9/479.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGFTCCA/2gAwIBAgIJALDxRLt/tU+LMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTIzMDExMTE0MTgyOFoXDTQzMDEx
+MTE0MTgyOFowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFtiOThjZDg0
+ZC0yMDk5LTRmNGQtOWM0My1mYWFjMjI1OGExOTBdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBnjCBmzAJBgNVHRMEAjAAMDUGDCsGAQQBkggJAYNfAQQlDCNSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIHg4Nl82NDAVBgwrBgEEAZIICQGDXwIEBQwD
+OC45MBgGDCsGAQQBkggJAYNfAwQIDAZ4ODZfNjQwJgYMKwYBBAGSCAkBg18EBBYM
+FHJoZWwtOCxyaGVsLTgteDg2XzY0MA0GCSqGSIb3DQEBCwUAA4ICAQB0AKa00fqK
+1LSDclHITX5fN2fBiT9mU0yen8ku+tOFZQ2zkkspGSEE+//d6jXn7xbYByf4YMmN
+M4wzIVET6uJ8uvi8Z/D3Pktm4ErPQMjZ3N3J6oKkrgZSaaqvMS+YCbaGKL17iOxz
+QwXub6oSpfW0KguSeCPtJ2wODQs45ggIPPdnuJsiyn/nXRwg+qlM0KPpn0y4TWHM
+tmAf4Vu4Bz9wdqQylZ1n8oIX5vm0R4m7ihM0zLyt4tTucMr1dh9H8V6Cw/RGg1b/
+J2Z8HvtIWfOa0dmLDkYxbmZRfoBXKjG8KTE0PrvaRuaa1wb7P9ZhVw8yfHqSG4QS
+DqHEMaYpodqjYKcmRpAd7yR16OpEMv+j5oOHiXwyR51pKjconspuSdD9Oso6o/H4
+JFloBTzAYWV5FMeDMzDwJ89D3T8okZwv/jftIlCMHcQFwKvd+pPQGrdJkLc06WsB
+RtKb89s7pwaqpItHScFypX0DzluJ/uIy6cT8xGjbbohyvRhCuUxEcNmlTUmMlQT9
+ll+5nCh6g+qUFFRclCAYstnU+7akEEa+L8sLcq7Bs576ZYlbuoFgBbXhYA2YU95m
+OI/q7kF/hm5p8pHNw/JnRzeX7Fo+n4AyeOBT9Az+bTis4gyCo3v9sAuLyscrCPtv
+0Vkuk+SRppk0hoUZzNtyeMAAzLFK+juhpA==
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/8.9/486.pem b/repos/system_upgrade/common/files/prod-certs/8.9/486.pem
new file mode 100644
index 00000000..9ac3b351
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/8.9/486.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGJDCCBAygAwIBAgIJALDxRLt/tU91MA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTIzMDExMTE0MTY1NloXDTQzMDEx
+MTE0MTY1NlowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs5MDhjYjA5
+ZC1mOTlmLTQ1OTEtOWViOS02Y2E2ZTg2OTQ1ODRdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBrTCBqjAJBgNVHRMEAjAAMDoGDCsGAQQBkggJAYNmAQQqDChSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIHg4Nl82NCBCZXRhMBoGDCsGAQQBkggJAYNm
+AgQKDAg4LjkgQmV0YTAYBgwrBgEEAZIICQGDZgMECAwGeDg2XzY0MCsGDCsGAQQB
+kggJAYNmBAQbDBlyaGVsLTgscmhlbC04LWJldGEteDg2XzY0MA0GCSqGSIb3DQEB
+CwUAA4ICAQAFLcBknEcS9WQCE5QzsjzEKMW2FzObxTJk69Al1/gYVfYmWszd8F5V
+jUyd077DiWkqaHGYR64/E7acdSRd1npms52Jj07YGQTshIbaNQLoseQeJ8b/Bcma
++Htrr73JWK+rcUdOiLjv+7gykFevxptgYUACLnjfJxxJmVWBVt5305yOgvFj6Sip
+RTALMY0uQty9/T4HybURCjK+hHinnDPypGKEg/7KRpjpQ8kRGjD5IZQ4sQzHkrIE
+fvVHs4t5IIYJ5iaR6ropcBUrBrz+loTOfcCAoUhAVjYDIOJnuQm2XVNgbM/uDBZG
+fwI7XKauUVvNa/h2tbSQ/f3cyEVbfSwfv8nlLoWe4XYvipTQpPcIDvm8GgOuiyax
+kXy5a2ToyiAfepEeJhSBX4IM38TjWiEn2+jcapaQSuAtH6Wy+3HWO6qpnRQ8sRF4
+WrK+WqW2DnTop9K1fLdUnwjFimZDdBxwnnJ0JLop7ZJWchKFFT3oxsykBMnH+6gm
+O1nHZpgtBAcOj+qLi6z+PvptqBxeTSnSQbdEWpsC+RsWXIOvvTllHRduKU62PdSg
++87Mp4opiStjhgRVDq1Ba8XWxo/rlf6HDuPI/uut4XhZ8tpsJ+aj6t0lQLU6dm81
+1Vjw3yHlJy4ire6E9jzz9q1JNYLWWLJCbPEPlF4hd8zw6nAfDzSNmw==
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/8.9/72.pem b/repos/system_upgrade/common/files/prod-certs/8.9/72.pem
new file mode 100644
index 00000000..9d896b59
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/8.9/72.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGFjCCA/6gAwIBAgIJALDxRLt/tU+KMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTIzMDExMTE0MTgyN1oXDTQzMDEx
+MTE0MTgyN1owRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFthNDU4Nzll
+OS0zYWE4LTQ3MTEtOTIwNi03M2Y1Yzk3ZTAwYjVdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBnzCBnDAJBgNVHRMEAjAAMDsGCysGAQQBkggJAUgBBCwMKlJlZCBIYXQg
+RW50ZXJwcmlzZSBMaW51eCBmb3IgSUJNIHogU3lzdGVtczAUBgsrBgEEAZIICQFI
+AgQFDAM4LjkwFgYLKwYBBAGSCAkBSAMEBwwFczM5MHgwJAYLKwYBBAGSCAkBSAQE
+FQwTcmhlbC04LHJoZWwtOC1zMzkweDANBgkqhkiG9w0BAQsFAAOCAgEASZ0dxU60
+Wrrh5ApGxwe53AbbIiDdMc4641p2IbVM6J3/09Er4orl6xch0s/ReVbWgYfO4DDT
+q+L0f5csn8HggdFHmEvjFwJ1IBWj4gWpBQuZy4MSowntNla2MnVeFPKBK46qrDNO
+SQKwEkIRB5hYKMDAwZFY6ewuuVpEnhfBoSfr/Xg7e414pWhRaVlTk/x6L78KZk9j
+7gw4QpptMq9r2qp+TaAew76g5bVDLDnCYTX3c+MGqVZcj5dw3TUctvLYRc+gY6gO
+5bpmLCbtsD19IKqB4Wi7IF/NqdN4YLBaNfedyugzUDWkJWt1mIZfunpsoQm0Yys7
+upkEMwgfMBclq9QDnO4jbOC3cnp7qKgkim94wxPdGf19xijSfBnIwIwuFxzJPFpe
+spp8DUz6alwyBmM9UjIzpybfMVOKDHR8LCiB53EMJW2nxWgW8nItYSMbfsNukAJv
+Md4UKRJ5zHB+xcyAI1NF7KgfrmScC0HwZ5BiDDK1iZHAeTOH6GtNkii4HSGvuZAW
+m7ujIHohHCfIKiZiR2YfMnWhYQiH0Y9CX9k4wDWRwdyMRQQftX5RUWLzxFbferTG
+gSVVQjLpeCaWZv3jqekrGzNK0jcaUTTPi//FyeCE8aNXET6M+aK65AmsgnPL+a/K
+7SvOvOa0GfDBoH++jO1u2fAK4DqLd5iFv/o=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.3/279.pem b/repos/system_upgrade/common/files/prod-certs/9.3/279.pem
new file mode 100644
index 00000000..dc6d933a
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.3/279.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGJTCCBA2gAwIBAgIJALDxRLt/tVOwMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTIzMDExODE3MjYxNloXDTQzMDEx
+ODE3MjYxNlowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs4MzNlZjBl
+ZS1hM2U2LTQ3NmQtOTczZi1lM2I1MTczMGJlMGRdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBrjCBqzAJBgNVHRMEAjAAMEMGDCsGAQQBkggJAYIXAQQzDDFSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIFBvd2VyLCBsaXR0bGUgZW5kaWFuMBUGDCsG
+AQQBkggJAYIXAgQFDAM5LjMwGQYMKwYBBAGSCAkBghcDBAkMB3BwYzY0bGUwJwYM
+KwYBBAGSCAkBghcEBBcMFXJoZWwtOSxyaGVsLTktcHBjNjRsZTANBgkqhkiG9w0B
+AQsFAAOCAgEASI4aXuhlVXPj5zmgb3YBTJzQ0QA/+e8jfSmm5NEOagwYvSg5ISp8
+urRpmGMnOJboeXylvSmqPIjVQoJeTk1yE7OqB7F3NDEiPY0QCOHpvHdHd4qjwpp5
+yw2NVk9+8b/3vD3M49bGlOwG2pHSaeybPlrJLBPF2ARHO0HxtqSx2spB0k6XBBG/
+rB6PUtUKbudtCvVNuG70YPAXpvGANgwHNWP6o2EsnZPvATrmvA/PtElNCF39syqJ
+Y1yYe+FYkr9y/ToUTDUFN4aRljrFCHZrGCwz8xI72JqKAB5EaLWdiETWaeWL3VCi
+6CVRDSQ/BvSl+C3bJ7n98Rlt+hEawxGK1zs4VAvpOVq2A1jas9Ia4S+1xvmWVAdi
+it/vH//5I2qIwjE2CGY5Ov5vywW0JT9+kxL1zGiOG8kwxmOdllqqFqQW8eKK9mUe
+HMLZKKX/ASfpg23B8ZaEFiaOCHLqirGc2hokPFWELv6lNclqFajMdWPNwDglP+OK
+ljg+4XC3gqYgt0Cjv/skg6GnWMh4F/xRWDIQAx1TwWPbdF9f2tEmoRspNj+0FLCI
+0rTZ5JRKA7w8tD0TBKZooH7iMxdcJ+mtccp7F3SWpbZMNwR/HxoEbXCtgIhX4mPf
+eJxFT+hA2DbrMI/hPQj7UlSt+suyTzPYphXHy25XGvwxSo/ejudOrq0=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.3/362.pem b/repos/system_upgrade/common/files/prod-certs/9.3/362.pem
new file mode 100644
index 00000000..80a0beb7
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.3/362.pem
@@ -0,0 +1,36 @@
+-----BEGIN CERTIFICATE-----
+MIIGNDCCBBygAwIBAgIJALDxRLt/tVOaMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTIzMDExODE3MjYwNFoXDTQzMDEx
+ODE3MjYwNFowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFszY2M4Mzk2
+My01YmI2LTQ2NTMtYWM3MC03NTc5OTFjZmU1MDddMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBvTCBujAJBgNVHRMEAjAAMEgGDCsGAQQBkggJAYJqAQQ4DDZSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIFBvd2VyLCBsaXR0bGUgZW5kaWFuIEJldGEw
+GgYMKwYBBAGSCAkBgmoCBAoMCDkuMyBCZXRhMBkGDCsGAQQBkggJAYJqAwQJDAdw
+cGM2NGxlMCwGDCsGAQQBkggJAYJqBAQcDBpyaGVsLTkscmhlbC05LWJldGEtcHBj
+NjRsZTANBgkqhkiG9w0BAQsFAAOCAgEAAZCh34sM762ZlnRF4Gi0hfmRr+z9pDmn
+IKw7M3wonyVmvPOCixNMjJGY5K052ZA8TDctC5FfJoKdr3cbEqIxBhHAVS8UYmhu
+qK4egMqUNI3Ui4DaYCDw9Ic7UDZ6KEf2FbK8OHGSZgCG6KCcECGJ/mBzryvP3Ctc
+KYdRHZLJ9h/HmjjD1fhQ0mZySNzKu3XlqT8fqi8g9XLS00defVKrc5G6TdpQJoaQ
+koWLPmSsWQTjQlo6GuTpe/lcsYWzEqjwOpX7eltkAXGYZTf47Ao02XfVuVoRvIEJ
+uESGh18LskQLacrrIBoztjZK7BQcCDfaL26qW5cPSPbZcBbMbc2Y/mL6zCfnaf2t
+VQ0hs2+n/U6f5enymfig9jYdhqq4NvnhhTNC5VZERXuR92bnkyBozogtRQ27RHFT
+cKRF6v6tG8/KWZqmHj4v+yLh0s3ECFH48wO1dzyFhQQWhwxmXQDb5XA8OjpxEGt/
+F9HrNoJhyhXLEc4Sphea5XsDFUYZbGR/MO7f7Pa5SeVqmz35BOLpZVwzU2Dq65Ww
+RPl+litDq4YrrPmdbagB0P0P4uU53i0k8oWF57eqEGgtgJEMlXFkAhwgQ1Pdh37p
+KoczLfGsv79MDbtjbwXZZ1AwDpRlkjEGOkb7zDkYiVhr/UE+Mwv6qNXgdhuKA674
+GXHtOldbC38=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.3/363.pem b/repos/system_upgrade/common/files/prod-certs/9.3/363.pem
new file mode 100644
index 00000000..63ccf162
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.3/363.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGJjCCBA6gAwIBAgIJALDxRLt/tVOZMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTIzMDExODE3MjYwNFoXDTQzMDEx
+ODE3MjYwNFowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFtmNWYyNjUw
+Zi0xODVmLTRkYTItYmFkYy0zOGU2OTBhYjY1Y2FdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBrzCBrDAJBgNVHRMEAjAAMDoGDCsGAQQBkggJAYJrAQQqDChSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIEFSTSA2NCBCZXRhMBoGDCsGAQQBkggJAYJr
+AgQKDAg5LjMgQmV0YTAZBgwrBgEEAZIICQGCawMECQwHYWFyY2g2NDAsBgwrBgEE
+AZIICQGCawQEHAwacmhlbC05LHJoZWwtOS1iZXRhLWFhcmNoNjQwDQYJKoZIhvcN
+AQELBQADggIBAALbefHcK3VySf323O/ORY07zjxqGZAccrIT5BhvyCmr4DNtElMO
+5JdcTuabdx8srv+fHbne8DPKunXwxXoiCE3OuROwb8TvxEkdhNt9X+MvyIIaqAJE
+yftfq2fzh01rtSwu5PpWQzYX7NqFaJnZAOT0aVMZfufGuBflP4wWUBfhVdLt0/uJ
+NSe59gFuq9U8XPfDk7rcL1gmHT+n+4rxaNUtrRul0o8KR/kCytTYmS/HrrAfmzQW
+w/oJOqMIfjmgCTNkE4j/ZGR5hqGcxLvqHBV5cD5Og7bPLhM/FCEc1QdBD6Gkoocu
+R4k+oZuT2St12cD56yB4gVSeFX4XYt3ehX+zmHP1el/m6ZFM1SPqIsHbs549cG9D
+s8mNxlMIOY47n3welSYWvGOVEReB1ihX74tDmfC3keg2t5qVCyQHKAddQ1z+GM0Q
+ngiJuYEf9rUFuFe23bEy3NkCLWSfQYDsHC1FjaOhxUCNSkN6YW8IUXQWz5Rb5Som
+NucA3B+F7e43hi5ZOgHQ6BY+OiUnyt2XUWbJqBuapiq3XWuDMT5hkVC7yEqS0X2u
+jHluXbxExHjkQydVWQvVDSffOcimcHTddAGMI3UFmDAzzdRXlbm/By5uGZQbUcag
+MG0E415u4myf7Sry8X1Fc/Dgmxj+aU6jsE+0Ur2J08iUC8FMoqRaVNs/
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.3/419.pem b/repos/system_upgrade/common/files/prod-certs/9.3/419.pem
new file mode 100644
index 00000000..a64cb936
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.3/419.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGFzCCA/+gAwIBAgIJALDxRLt/tVOvMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTIzMDExODE3MjYxNVoXDTQzMDEx
+ODE3MjYxNVowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFsxMDY3YTc5
+Mi01OTk2LTQ3MTEtODgwMC0xOTUwOTU0NzU4NTBdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBoDCBnTAJBgNVHRMEAjAAMDUGDCsGAQQBkggJAYMjAQQlDCNSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIEFSTSA2NDAVBgwrBgEEAZIICQGDIwIEBQwD
+OS4zMBkGDCsGAQQBkggJAYMjAwQJDAdhYXJjaDY0MCcGDCsGAQQBkggJAYMjBAQX
+DBVyaGVsLTkscmhlbC05LWFhcmNoNjQwDQYJKoZIhvcNAQELBQADggIBACN+Q+sC
+Czu4DtARf+f1yOJbM6fZGI0j8O4uJ6fm6pTCG5VLMhaOmz19MF3tjd/3ZpyZirq7
+dUoYiTA1IN9k/f3pm8uunCmpG3tJyM7x2wL72B+7d37UbiaZ042h0oCjy0jb9CBg
+cfb9g+MNCCWBoAExpFavwG8x0FQCoxWIOal/yYN8GGGTZYZ7oj3dwpdJ9XYhSI2J
+YhHaaiQJAQihl+m9yVRw6DKm98tfgMPh2C7W5Wp/krFQbE5vcJZbkX7IN298grd5
+uacOMYUK7szcGCW957rCto+she4Ig6Z/eQznWzAtQz99rVzDX0D6rV8OgYfmofXB
+E/QebHOlLe8M17rZPslGD4UHXqZ0aqeKFLUzpM45jA6jJ5b78r7KpiPcYFE5OpFR
+6NakTavJ8ilUBIgSXQicVZH5LNvELgO5dzCjlrfJqj5tGvPwEHUP/uSpKg0Z71DH
+2yW9U4WoYz3s1FEc5vcXrU+vz7Pxl7sELiJ753fH71kUyG2QjwxgfbdH0YwZ/a/t
+sTrjyTrFpOajacPSdBp/SMOul40eRkJPmDNRp6kIzU+wRKO+x2Dsm9ZNklTk1Tk5
+FX8y1eyYUyO3IPRFzO9tmQYvNrCbnxtnVHvsiK2bQFkKEy8SUOYKbjOJ9p4koAjm
+zNT9mgMCVTfmKugrpVbptkDlWlbmRMGakOs1
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.3/433.pem b/repos/system_upgrade/common/files/prod-certs/9.3/433.pem
new file mode 100644
index 00000000..9c9fecfd
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.3/433.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGKTCCBBGgAwIBAgIJALDxRLt/tVObMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTIzMDExODE3MjYwNFoXDTQzMDEx
+ODE3MjYwNFowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFsxODFiNGNm
+Ny1mZTJiLTRhMjQtYWJiYy0xYzJlYmUwZTRhOGVdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBsjCBrzAJBgNVHRMEAjAAMEEGDCsGAQQBkggJAYMxAQQxDC9SZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIElCTSB6IFN5c3RlbXMgQmV0YTAaBgwrBgEE
+AZIICQGDMQIECgwIOS4zIEJldGEwFwYMKwYBBAGSCAkBgzEDBAcMBXMzOTB4MCoG
+DCsGAQQBkggJAYMxBAQaDBhyaGVsLTkscmhlbC05LWJldGEtczM5MHgwDQYJKoZI
+hvcNAQELBQADggIBANaD1YdjSAn6VNTSFKuX/sIc0VhrtbcXLXj6U3AdDvoJN4Yi
+Qm3fFn2Y4N7W8U8gREaIxRaEUG3G1Lru6S9uYIoZu6w+faHOehbKyTU07xJ3YwIU
+lWdIciAwnOsUxnoMN7NDW1caFGPUTgPrDArzkHSyn88Hh+dmtuocvZ3s7WSZqXTC
+opZjxbP/O5+Td7NKBNmAEdi7lIQVWcljyrv+2HxlYiIfZ6o0iRBpbabhxoKCDXG1
+p1e5Pz92nXXPHG0lWvw6XNCebnEwU91ndEebbRI4lIe7FNYdIIhylWW8wAmPT7eP
+rEX6Q4Vd3LDbGwcGQXyxVgpqCyW62VN9BlBIRHowGI9qKPBctTANUmmyNhswiiO5
+j3UtRHCv3iJcpEv7iW6volH4HwF+uv/PtGJCHeDWnt6qUleBbtjvmapzCRhUOzID
+To7n5blIFCptEfcBUnT8SlUZWKQ2lhf5KZ0k9vPHWtFib0pJ1WETwTiho6BeoY8F
+2HfD/6xFuOHshsjkl3druUpX3xjLOqqCaSDKwGwJTMt+TT//GwasL7OvheZG4dIa
+OrZXnzl+pw5cNSofOC1FWKi7xD0x8fAmQbMwLf/eKrpynVnFvcDsWbEAtZfU6jy0
+i2oFGDjHYX9VwnB9pjRk6gm7Y1eCQSkheP4gM/w7+FVuW4azbJ3R4vQm/kSO
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.3/479.pem b/repos/system_upgrade/common/files/prod-certs/9.3/479.pem
new file mode 100644
index 00000000..8217fc3b
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.3/479.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGFTCCA/2gAwIBAgIJALDxRLt/tVOyMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTIzMDExODE3MjYxNloXDTQzMDEx
+ODE3MjYxNlowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs4MzdlYzZi
+OC1mZWQyLTRhODUtOWJlMC1jMjJkZDM3NmE2YjBdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBnjCBmzAJBgNVHRMEAjAAMDUGDCsGAQQBkggJAYNfAQQlDCNSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIHg4Nl82NDAVBgwrBgEEAZIICQGDXwIEBQwD
+OS4zMBgGDCsGAQQBkggJAYNfAwQIDAZ4ODZfNjQwJgYMKwYBBAGSCAkBg18EBBYM
+FHJoZWwtOSxyaGVsLTkteDg2XzY0MA0GCSqGSIb3DQEBCwUAA4ICAQDDwbB0lRuo
+eheuRxVPx5mOpwMk72D4/940FBBIfgpJ0tyelkSOEBnL4GmN5HzN6vXwyj03N/M7
+Q2d9lAMKjsobWJZ4Wd12eJhB1FYUd/LNv62T9QL1Xac7ve/LWUNIXygcazh2nwVw
+jJo1gzJ9BLIExZiNLpBESeMcJn+Vgi9tQGcqD+QjWH5E14xwHD1j0Ni8GuQpr/S5
+KS1sF1rVl+m5BZP93NfNlijL9OXIzUyX78wq3vh+YcfrtyMi4Ric3s+6sXz/1l1E
+EfUyzxJy4AGuzAYA1zGmQhNv0GrqWnXoqjyNPCqZz3c5K1o6BaQGZoyojA6sSm0D
+2QW0j4haVimS0x8FboEOHIxpxNl91iTQ5OwzwmGxzNssW/w+guPzGjo9fPg0gptY
+witpiGTsAeqbqQ8uyNhXVkZA1vcYwP44MtZdQTGt1VIRyVnPzFEoGmfGG5a6vk7v
+4GBWjM/uSyJHXFe3GZFZcnmwchYEbKf78tAaWrbhfWSf5ahj68VJNc/waNfjQ8TW
+HPlV1x1RVTuGRDocWGUYabq4d3deU6vw3/EYowfphwK6ID5Sh/jfsVtO8BasVvK4
+d1s51rINFw7chj8leszo3zKgdaGhJG5DNE+/lh/zq4+3SSVmMz60ymbSyJ58am1m
+maoFBh+goPx/hrRTXxtfp+qNp4C7xY8o3Q==
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.3/486.pem b/repos/system_upgrade/common/files/prod-certs/9.3/486.pem
new file mode 100644
index 00000000..591f473b
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.3/486.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGJDCCBAygAwIBAgIJALDxRLt/tVOcMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTIzMDExODE3MjYwNFoXDTQzMDEx
+ODE3MjYwNFowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFthNWYyMDk4
+NC04NGYxLTQ0ZTUtOTNkNC0wMzJiMDI1MDQyYWRdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBrTCBqjAJBgNVHRMEAjAAMDoGDCsGAQQBkggJAYNmAQQqDChSZWQgSGF0
+IEVudGVycHJpc2UgTGludXggZm9yIHg4Nl82NCBCZXRhMBoGDCsGAQQBkggJAYNm
+AgQKDAg5LjMgQmV0YTAYBgwrBgEEAZIICQGDZgMECAwGeDg2XzY0MCsGDCsGAQQB
+kggJAYNmBAQbDBlyaGVsLTkscmhlbC05LWJldGEteDg2XzY0MA0GCSqGSIb3DQEB
+CwUAA4ICAQC+1Krw6yHDMaqNxAN1dlGAJA58Sm5RUimBgyHDG/IGo5uTJWuqJF2J
+rbfcoo1pswElQiMRUrChbT3vUXgXaORlVQHdnBepH228qTTA33CiP2UoQKYwR1rj
+FtZGnyUdqwITn9Sm8ZbX0fa74UUZ4bS1IkZQKJdKHkBQHUjhtEUvA76baJjWLG2Y
+f282IVG1t5Z8zRDhR6akabtIjEd8AQZ4EFufFLCyZMxKhvKd4RYOvBOD06AFl3KM
++kiMjFQlLjUF3ldB7JnSpMwN829ocX3rrGYQMzYz6yg5ByxWmYqHMymBgRhC/gDX
+Sxi0Znej559QBTXidLy5exASrc/t8iwwlr94WLRDfAyV2Ven9OQu5/fbdnCY2Wb0
+2MOkglx6tVgl+Y1H2pfF7qOcS3iYDSkCxPlgWXYIoxsxvwW0W0nGA2WsIntnP9UK
+5cFX5lFMgsNGxqFmrHVR1Q9DVg9tCV3uG9lQPvwX3bHHtvaxZD5NJ6HgvEaNcvyN
+ZW6QYTnaam6XqavL0sBw9/N01SEW7NBM1DO3VGMrWzWF3nTADUbea9wCVqXkkydd
+spjFWAlxMMVWXz0CWCNdBiylKHhpmencrkA0wxjaDntJcm8qtmJol1obz8/5GNxX
+BzszVd7VwwGY6G7h929bctv9NsyfmA+NlXYWFp5Hwdqp+jmBnxlr3Q==
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/prod-certs/9.3/72.pem b/repos/system_upgrade/common/files/prod-certs/9.3/72.pem
new file mode 100644
index 00000000..25dbb8ab
--- /dev/null
+++ b/repos/system_upgrade/common/files/prod-certs/9.3/72.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGFjCCA/6gAwIBAgIJALDxRLt/tVOxMA0GCSqGSIb3DQEBCwUAMIGuMQswCQYD
+VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExFjAUBgNVBAoMDVJlZCBI
+YXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0d29yazEuMCwGA1UEAwwlUmVk
+IEhhdCBFbnRpdGxlbWVudCBQcm9kdWN0IEF1dGhvcml0eTEkMCIGCSqGSIb3DQEJ
+ARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMB4XDTIzMDExODE3MjYxNloXDTQzMDEx
+ODE3MjYxNlowRDFCMEAGA1UEAww5UmVkIEhhdCBQcm9kdWN0IElEIFs2MGExNTA1
+Yy1jNDJkLTQyNzktOGM4My0yNGQyYjFmMDM3YmRdMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAxj9J04z+Ezdyx1U33kFftLv0ntNS1BSeuhoZLDhs18yk
+sepG7hXXtHh2CMFfLZmTjAyL9i1XsxykQpVQdXTGpUF33C2qBQHB5glYs9+d781x
+8p8m8zFxbPcW82TIJXbgW3ErVh8vk5qCbG1cCAAHb+DWMq0EAyy1bl/JgAghYNGB
+RvKJObTdCrdpYh02KUqBLkSPZHvo6DUJFN37MXDpVeQq9VtqRjpKLLwuEfXb0Y7I
+5xEOrR3kYbOaBAWVt3mYZ1t0L/KfY2jVOdU5WFyyB9PhbMdLi1xE801j+GJrwcLa
+xmqvj4UaICRzcPATP86zVM1BBQa+lilkRQes5HyjZzZDiGYudnXhbqmLo/n0cuXo
+QBVVjhzRTMx71Eiiahmiw+U1vGqkHhQNxb13HtN1lcAhUCDrxxeMvrAjYdWpYlpI
+yW3NssPWt1YUHidMBSAJ4KctIf91dyE93aStlxwC/QnyFsZOmcEsBzVCnz9GmWMl
+1/6XzBS1yDUqByklx0TLH+z/sK9A+O2rZAy1mByCYwVxvbOZhnqGxAuToIS+A81v
+5hCjsCiOScVB+cil30YBu0cH85RZ0ILNkHdKdrLLWW4wjphK2nBn2g2i3+ztf+nQ
+ED2pQqZ/rhuW79jcyCZl9kXqe1wOdF0Cwah4N6/3LzIXEEKyEJxNqQwtNc2IVE8C
+AwEAAaOBnzCBnDAJBgNVHRMEAjAAMDsGCysGAQQBkggJAUgBBCwMKlJlZCBIYXQg
+RW50ZXJwcmlzZSBMaW51eCBmb3IgSUJNIHogU3lzdGVtczAUBgsrBgEEAZIICQFI
+AgQFDAM5LjMwFgYLKwYBBAGSCAkBSAMEBwwFczM5MHgwJAYLKwYBBAGSCAkBSAQE
+FQwTcmhlbC05LHJoZWwtOS1zMzkweDANBgkqhkiG9w0BAQsFAAOCAgEARLQjlxaO
+jQEdcV7ycIcjgwpeeB4TDFrg+3NCnBTqHWw4zoKv0r19CRuMNW7uyKlpRRk+0Eyt
+zblQD9cxsNywibOMliSV6aKZb7jVfx/0wbx+w+7A+n2YpkHedWQpcbSYsrQ+GZLg
+ORTfbpqt+qXUyx2PqyGqwjpO0mvW1cpV4Nqm0vs8veAPMuJd9wnbb8n3Ib/XcmHA
+hlnTCoO5kYZk9xAFYNmdWQSSfmD3hH7bdWMV17ppWrkNY14RF8BjYcmHOaUOAGdf
+caKDx9I4QeQfKDfBhvxj9KdAecQEAjhxuD3qjwkQfbrGkRdKsMAu85xagvHAXwaY
+tobmyUZg/uXozr8Vss3wwWxllDxtGpQG8mAUTlly6vvlbDXGns2Ga4RbEA++vRUM
+rOK2r7lCg8bexbHRa+F4WtUhrcZ3gIiGGDJt93aOcfgZul+FW/fXQSYKYP/C4cEn
+1VhUakpp+j+Iffu7Y5TPGE9fOGxbkmcUBbLxDOlt1M58F6tt9rOLCcLUDBU20ZLD
+GJVE7BqyQQ4FEkzPZ6zb1fbVWP1VPZT00Mgb6FFyrfo4FeLSoqMIU7y/1LRocwi2
+BW7E9IfcO3OPdIu3hsGs7vXd+juMj8pGres6bp8EFS5wF7QgcSBMTGO4/bPAg0Wv
+pUuiDsjVPVq0wfhTOOj2Tp6mPKcg62IRpT0=
+-----END CERTIFICATE-----
diff --git a/repos/system_upgrade/common/files/upgrade_paths.json b/repos/system_upgrade/common/files/upgrade_paths.json
index 5d8b44e9..2069e26d 100644
--- a/repos/system_upgrade/common/files/upgrade_paths.json
+++ b/repos/system_upgrade/common/files/upgrade_paths.json
@@ -1,10 +1,11 @@
{
"default": {
- "7.9": ["8.6", "8.8"],
+ "7.9": ["8.6", "8.8", "8.9"],
"8.6": ["9.0"],
"8.8": ["9.2"],
- "7": ["8.6", "8.8"],
- "8": ["9.2"]
+ "8.9": ["9.3"],
+ "7": ["8.6", "8.8", "8.9"],
+ "8": ["9.3"]
},
"saphana": {
"7.9": ["8.8", "8.6"],
diff --git a/repos/system_upgrade/common/libraries/config/version.py b/repos/system_upgrade/common/libraries/config/version.py
index 6bf6b4da..e146bd9b 100644
--- a/repos/system_upgrade/common/libraries/config/version.py
+++ b/repos/system_upgrade/common/libraries/config/version.py
@@ -14,7 +14,7 @@ OP_MAP = {
_SUPPORTED_VERSIONS = {
# Note: 'rhel-alt' is detected when on 'rhel' with kernel 4.x
'7': {'rhel': ['7.9'], 'rhel-alt': [], 'rhel-saphana': ['7.9']},
- '8': {'rhel': ['8.6', '8.8'], 'rhel-saphana': ['8.6', '8.8']},
+ '8': {'rhel': ['8.6', '8.8', '8.9'], 'rhel-saphana': ['8.6', '8.8']},
}
--
2.40.1

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,33 +0,0 @@
From f9eef56f9555120117d5d9df0ed46e5517562fd3 Mon Sep 17 00:00:00 2001
From: Christoph Dwertmann <cdwertmann@gmail.com>
Date: Tue, 18 Jul 2023 03:36:42 +1000
Subject: [PATCH 32/42] Use correct flag and ENV var to disable insights
registration (#1089)
Doc: Fix doc for disabling registration to RH Insights
The original document speaks about `LEAPP_NO_INSIGHTS_AUTOREGISTER` and
the `--no-insights-autoregister` option. However the correct envar is
`LEAPP_NO_INSIGHTS_REGISTER` and the option is `--no-insights-register`
---
.../libraries/checkinsightsautoregister.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/repos/system_upgrade/common/actors/checkinsightsautoregister/libraries/checkinsightsautoregister.py b/repos/system_upgrade/common/actors/checkinsightsautoregister/libraries/checkinsightsautoregister.py
index 98cf8e2e..762f3c08 100644
--- a/repos/system_upgrade/common/actors/checkinsightsautoregister/libraries/checkinsightsautoregister.py
+++ b/repos/system_upgrade/common/actors/checkinsightsautoregister/libraries/checkinsightsautoregister.py
@@ -28,8 +28,8 @@ def _report_registration_info(installing_client):
summary = (
"After the upgrade, this system will be automatically registered into Red Hat Insights."
"{}"
- " To skip the automatic registration, use the '--no-insights-autoregister' command line option or"
- " set the NO_INSIGHTS_AUTOREGISTER environment variable."
+ " To skip the automatic registration, use the '--no-insights-register' command line option or"
+ " set the LEAPP_NO_INSIGHTS_REGISTER environment variable."
).format(pkg_msg.format(INSIGHTS_CLIENT_PKG) if installing_client else "")
reporting.create_report(
--
2.41.0

View File

@ -1,75 +0,0 @@
From f1df66449ce3ca3062ff74a1d93d6a9e478d57f7 Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Thu, 16 Mar 2023 12:23:33 +0100
Subject: [PATCH 33/42] CLI: Use new Leapp output APIs - reports summary better
The new Leapp output APIs now display better summary about the
report. See https://github.com/oamg/leapp/pull/818 for more info.
* Require leapp-framework versio 4.0
* Suppress redundant-keyword-arg for pylint
pstodulk: we have one error or another and this one is not actually
so important from my POV - I would even argue that it's
not a bad habit
---
.pylintrc | 1 +
commands/preupgrade/__init__.py | 3 ++-
commands/upgrade/__init__.py | 2 +-
packaging/leapp-repository.spec | 2 +-
4 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/.pylintrc b/.pylintrc
index 7ddb58d6..2ef31167 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -7,6 +7,7 @@ disable=
no-member,
no-name-in-module,
raising-bad-type,
+ redundant-keyword-arg, # it's one or the other, this one is not so bad at all
# "W" Warnings for stylistic problems or minor programming issues
no-absolute-import,
arguments-differ,
diff --git a/commands/preupgrade/__init__.py b/commands/preupgrade/__init__.py
index 614944cc..15a93110 100644
--- a/commands/preupgrade/__init__.py
+++ b/commands/preupgrade/__init__.py
@@ -80,7 +80,8 @@ def preupgrade(args, breadcrumbs):
report_inhibitors(context)
report_files = util.get_cfg_files('report', cfg)
log_files = util.get_cfg_files('logs', cfg)
- report_info(report_files, log_files, answerfile_path, fail=workflow.failure)
+ report_info(context, report_files, log_files, answerfile_path, fail=workflow.failure)
+
if workflow.failure:
sys.exit(1)
diff --git a/commands/upgrade/__init__.py b/commands/upgrade/__init__.py
index b59bf79f..aa327c3b 100644
--- a/commands/upgrade/__init__.py
+++ b/commands/upgrade/__init__.py
@@ -110,7 +110,7 @@ def upgrade(args, breadcrumbs):
util.generate_report_files(context, report_schema)
report_files = util.get_cfg_files('report', cfg)
log_files = util.get_cfg_files('logs', cfg)
- report_info(report_files, log_files, answerfile_path, fail=workflow.failure)
+ report_info(context, report_files, log_files, answerfile_path, fail=workflow.failure)
if workflow.failure:
sys.exit(1)
diff --git a/packaging/leapp-repository.spec b/packaging/leapp-repository.spec
index 2d0d6fd8..0fce25df 100644
--- a/packaging/leapp-repository.spec
+++ b/packaging/leapp-repository.spec
@@ -100,7 +100,7 @@ Requires: leapp-repository-dependencies = %{leapp_repo_deps}
# IMPORTANT: this is capability provided by the leapp framework rpm.
# Check that 'version' instead of the real framework rpm version.
-Requires: leapp-framework >= 3.1, leapp-framework < 4
+Requires: leapp-framework >= 4.0, leapp-framework < 5
# Since we provide sub-commands for the leapp utility, we expect the leapp
# tool to be installed as well.
--
2.41.0

View File

@ -1,663 +0,0 @@
From 2ba44076625e35aabfd2a1f9e45b2934f99f1e8d Mon Sep 17 00:00:00 2001
From: Matej Matuska <mmatuska@redhat.com>
Date: Mon, 20 Mar 2023 13:27:46 +0100
Subject: [PATCH 34/42] Update Grub on component drives if /boot is on md
device
On BIOS systems, previously, if /boot was on md device such as RAID
consisting of multiple partitions on different MBR/GPT partitioned
drives, the part of Grub residing in the 512 Mb after MBR was only
updated for one of the drives. Similar situation occurred on GPT
partitioned drives and the BIOS boot partition. This resulted in
outdated GRUB on the remaining drives which could cause the system to be
unbootable.
Now, Grub is updated on all the component devices of an md array if Grub
was already installed on them before the upgrade.
Jira: OAMG-7835
BZ#2219544
BZ#2140011
---
.../common/actors/checkgrubcore/actor.py | 7 +-
.../checkgrubcore/tests/test_checkgrubcore.py | 9 +-
.../common/actors/scangrubdevice/actor.py | 11 +--
.../tests/test_scangrubdevice.py | 35 +++++++
.../common/actors/updategrubcore/actor.py | 8 +-
.../libraries/updategrubcore.py | 48 ++++++----
.../tests/test_updategrubcore.py | 39 ++++++--
repos/system_upgrade/common/libraries/grub.py | 28 ++++++
.../system_upgrade/common/libraries/mdraid.py | 48 ++++++++++
.../common/libraries/tests/test_grub.py | 71 ++++++++++++--
.../common/libraries/tests/test_mdraid.py | 94 +++++++++++++++++++
.../system_upgrade/common/models/grubinfo.py | 12 +++
12 files changed, 358 insertions(+), 52 deletions(-)
create mode 100644 repos/system_upgrade/common/actors/scangrubdevice/tests/test_scangrubdevice.py
create mode 100644 repos/system_upgrade/common/libraries/mdraid.py
create mode 100644 repos/system_upgrade/common/libraries/tests/test_mdraid.py
diff --git a/repos/system_upgrade/common/actors/checkgrubcore/actor.py b/repos/system_upgrade/common/actors/checkgrubcore/actor.py
index 6aa99797..ae9e53ef 100644
--- a/repos/system_upgrade/common/actors/checkgrubcore/actor.py
+++ b/repos/system_upgrade/common/actors/checkgrubcore/actor.py
@@ -32,7 +32,7 @@ class CheckGrubCore(Actor):
grub_info = next(self.consume(GrubInfo), None)
if not grub_info:
raise StopActorExecutionError('Actor did not receive any GrubInfo message.')
- if grub_info.orig_device_name:
+ if grub_info.orig_devices:
create_report([
reporting.Title(
'GRUB2 core will be automatically updated during the upgrade'
@@ -45,8 +45,9 @@ class CheckGrubCore(Actor):
create_report([
reporting.Title('Leapp could not identify where GRUB2 core is located'),
reporting.Summary(
- 'We assumed GRUB2 core is located on the same device as /boot, however Leapp could not '
- 'detect GRUB2 on the device. GRUB2 core needs to be updated maually on legacy (BIOS) systems. '
+ 'We assumed GRUB2 core is located on the same device(s) as /boot, '
+ 'however Leapp could not detect GRUB2 on the device(s). '
+ 'GRUB2 core needs to be updated maually on legacy (BIOS) systems. '
),
reporting.Severity(reporting.Severity.HIGH),
reporting.Groups([reporting.Groups.BOOT]),
diff --git a/repos/system_upgrade/common/actors/checkgrubcore/tests/test_checkgrubcore.py b/repos/system_upgrade/common/actors/checkgrubcore/tests/test_checkgrubcore.py
index fe15b65b..b834f9fe 100644
--- a/repos/system_upgrade/common/actors/checkgrubcore/tests/test_checkgrubcore.py
+++ b/repos/system_upgrade/common/actors/checkgrubcore/tests/test_checkgrubcore.py
@@ -1,18 +1,17 @@
-import pytest
-
-from leapp.exceptions import StopActorExecutionError
from leapp.libraries.common.config import mock_configs
from leapp.models import FirmwareFacts, GrubInfo
from leapp.reporting import Report
NO_GRUB = 'Leapp could not identify where GRUB2 core is located'
+GRUB = 'GRUB2 core will be automatically updated during the upgrade'
def test_actor_update_grub(current_actor_context):
current_actor_context.feed(FirmwareFacts(firmware='bios'))
- current_actor_context.feed(GrubInfo(orig_device_name='/dev/vda'))
+ current_actor_context.feed(GrubInfo(orig_devices=['/dev/vda', '/dev/vdb']))
current_actor_context.run(config_model=mock_configs.CONFIG)
assert current_actor_context.consume(Report)
+ assert current_actor_context.consume(Report)[0].report['title'].startswith(GRUB)
def test_actor_no_grub_device(current_actor_context):
@@ -31,6 +30,6 @@ def test_actor_with_efi(current_actor_context):
def test_s390x(current_actor_context):
current_actor_context.feed(FirmwareFacts(firmware='bios'))
- current_actor_context.feed(GrubInfo(orig_device_name='/dev/vda'))
+ current_actor_context.feed(GrubInfo(orig_devices=['/dev/vda', '/dev/vdb']))
current_actor_context.run(config_model=mock_configs.CONFIG_S390X)
assert not current_actor_context.consume(Report)
diff --git a/repos/system_upgrade/common/actors/scangrubdevice/actor.py b/repos/system_upgrade/common/actors/scangrubdevice/actor.py
index a12739e1..cb6be7ea 100644
--- a/repos/system_upgrade/common/actors/scangrubdevice/actor.py
+++ b/repos/system_upgrade/common/actors/scangrubdevice/actor.py
@@ -7,7 +7,7 @@ from leapp.tags import FactsPhaseTag, IPUWorkflowTag
class ScanGrubDeviceName(Actor):
"""
- Find the name of the block device where GRUB is located
+ Find the name of the block devices where GRUB is located
"""
name = 'scan_grub_device_name'
@@ -19,8 +19,7 @@ class ScanGrubDeviceName(Actor):
if architecture.matches_architecture(architecture.ARCH_S390X):
return
- device_name = grub.get_grub_device()
- if device_name:
- self.produce(GrubInfo(orig_device_name=device_name))
- else:
- self.produce(GrubInfo())
+ devices = grub.get_grub_devices()
+ grub_info = GrubInfo(orig_devices=devices)
+ grub_info.orig_device_name = devices[0] if len(devices) == 1 else None
+ self.produce(grub_info)
diff --git a/repos/system_upgrade/common/actors/scangrubdevice/tests/test_scangrubdevice.py b/repos/system_upgrade/common/actors/scangrubdevice/tests/test_scangrubdevice.py
new file mode 100644
index 00000000..0114d717
--- /dev/null
+++ b/repos/system_upgrade/common/actors/scangrubdevice/tests/test_scangrubdevice.py
@@ -0,0 +1,35 @@
+from leapp.libraries.common import grub
+from leapp.libraries.common.config import mock_configs
+from leapp.models import GrubInfo
+
+
+def _get_grub_devices_mocked():
+ return ['/dev/vda', '/dev/vdb']
+
+
+def test_actor_scan_grub_device(current_actor_context, monkeypatch):
+ monkeypatch.setattr(grub, 'get_grub_devices', _get_grub_devices_mocked)
+ current_actor_context.run(config_model=mock_configs.CONFIG)
+ info = current_actor_context.consume(GrubInfo)
+ assert info and info[0].orig_devices == ['/dev/vda', '/dev/vdb']
+ assert len(info) == 1, 'Expected just one GrubInfo message'
+ assert not info[0].orig_device_name
+
+
+def test_actor_scan_grub_device_one(current_actor_context, monkeypatch):
+
+ def _get_grub_devices_mocked():
+ return ['/dev/vda']
+
+ monkeypatch.setattr(grub, 'get_grub_devices', _get_grub_devices_mocked)
+ current_actor_context.run(config_model=mock_configs.CONFIG)
+ info = current_actor_context.consume(GrubInfo)
+ assert info and info[0].orig_devices == ['/dev/vda']
+ assert len(info) == 1, 'Expected just one GrubInfo message'
+ assert info[0].orig_device_name == '/dev/vda'
+
+
+def test_actor_scan_grub_device_s390x(current_actor_context, monkeypatch):
+ monkeypatch.setattr(grub, 'get_grub_devices', _get_grub_devices_mocked)
+ current_actor_context.run(config_model=mock_configs.CONFIG_S390X)
+ assert not current_actor_context.consume(GrubInfo)
diff --git a/repos/system_upgrade/common/actors/updategrubcore/actor.py b/repos/system_upgrade/common/actors/updategrubcore/actor.py
index 4545bad6..ac9aa829 100644
--- a/repos/system_upgrade/common/actors/updategrubcore/actor.py
+++ b/repos/system_upgrade/common/actors/updategrubcore/actor.py
@@ -21,8 +21,8 @@ class UpdateGrubCore(Actor):
def process(self):
ff = next(self.consume(FirmwareFacts), None)
if ff and ff.firmware == 'bios':
- grub_dev = grub.get_grub_device()
- if grub_dev:
- update_grub_core(grub_dev)
+ grub_devs = grub.get_grub_devices()
+ if grub_devs:
+ update_grub_core(grub_devs)
else:
- api.current_logger().warning('Leapp could not detect GRUB on {}'.format(grub_dev))
+ api.current_logger().warning('Leapp could not detect GRUB devices')
diff --git a/repos/system_upgrade/common/actors/updategrubcore/libraries/updategrubcore.py b/repos/system_upgrade/common/actors/updategrubcore/libraries/updategrubcore.py
index 22ee3372..2bdad929 100644
--- a/repos/system_upgrade/common/actors/updategrubcore/libraries/updategrubcore.py
+++ b/repos/system_upgrade/common/actors/updategrubcore/libraries/updategrubcore.py
@@ -1,35 +1,43 @@
from leapp import reporting
-from leapp.exceptions import StopActorExecution
from leapp.libraries.stdlib import api, CalledProcessError, config, run
-def update_grub_core(grub_dev):
+def update_grub_core(grub_devs):
"""
Update GRUB core after upgrade from RHEL7 to RHEL8
On legacy systems, GRUB core does not get automatically updated when GRUB packages
are updated.
"""
- cmd = ['grub2-install', grub_dev]
- if config.is_debug():
- cmd += ['-v']
- try:
- run(cmd)
- except CalledProcessError as err:
- reporting.create_report([
- reporting.Title('GRUB core update failed'),
- reporting.Summary(str(err)),
- reporting.Groups([reporting.Groups.BOOT]),
- reporting.Severity(reporting.Severity.HIGH),
- reporting.Remediation(
- hint='Please run "grub2-install <GRUB_DEVICE>" manually after upgrade'
- )
- ])
- api.current_logger().warning('GRUB core update on {} failed'.format(grub_dev))
- raise StopActorExecution()
+
+ successful = []
+ failed = []
+ for dev in grub_devs:
+ cmd = ['grub2-install', dev]
+ if config.is_debug():
+ cmd += ['-v']
+ try:
+ run(cmd)
+ except CalledProcessError as err:
+ api.current_logger().warning('GRUB core update on {} failed: {}'.format(dev, err))
+ failed.append(dev)
+ continue
+
+ successful.append(dev)
+
+ reporting.create_report([
+ reporting.Title('GRUB core update failed'),
+ reporting.Summary('Leapp failed to update GRUB on {}'.format(', '.join(failed))),
+ reporting.Groups([reporting.Groups.BOOT]),
+ reporting.Severity(reporting.Severity.HIGH),
+ reporting.Remediation(
+ hint='Please run "grub2-install <GRUB_DEVICE>" manually after upgrade'
+ )
+ ])
+
reporting.create_report([
reporting.Title('GRUB core successfully updated'),
- reporting.Summary('GRUB core on {} was successfully updated'.format(grub_dev)),
+ reporting.Summary('GRUB core on {} was successfully updated'.format(', '.join(successful))),
reporting.Groups([reporting.Groups.BOOT]),
reporting.Severity(reporting.Severity.INFO)
])
diff --git a/repos/system_upgrade/common/actors/updategrubcore/tests/test_updategrubcore.py b/repos/system_upgrade/common/actors/updategrubcore/tests/test_updategrubcore.py
index e65807a2..fe0cca50 100644
--- a/repos/system_upgrade/common/actors/updategrubcore/tests/test_updategrubcore.py
+++ b/repos/system_upgrade/common/actors/updategrubcore/tests/test_updategrubcore.py
@@ -1,7 +1,6 @@
import pytest
from leapp import reporting
-from leapp.exceptions import StopActorExecution
from leapp.libraries.actor import updategrubcore
from leapp.libraries.common import testutils
from leapp.libraries.stdlib import api, CalledProcessError
@@ -32,21 +31,45 @@ class run_mocked(object):
raise_call_error(args)
-def test_update_grub(monkeypatch):
+@pytest.mark.parametrize('devices', [['/dev/vda'], ['/dev/vda', '/dev/vdb']])
+def test_update_grub(monkeypatch, devices):
monkeypatch.setattr(reporting, "create_report", testutils.create_report_mocked())
monkeypatch.setattr(updategrubcore, 'run', run_mocked())
- updategrubcore.update_grub_core('/dev/vda')
+ updategrubcore.update_grub_core(devices)
assert reporting.create_report.called
- assert UPDATE_OK_TITLE == reporting.create_report.report_fields['title']
+ assert UPDATE_OK_TITLE == reporting.create_report.reports[1]['title']
+ assert all(dev in reporting.create_report.reports[1]['summary'] for dev in devices)
-def test_update_grub_failed(monkeypatch):
+@pytest.mark.parametrize('devices', [['/dev/vda'], ['/dev/vda', '/dev/vdb']])
+def test_update_grub_failed(monkeypatch, devices):
monkeypatch.setattr(reporting, "create_report", testutils.create_report_mocked())
monkeypatch.setattr(updategrubcore, 'run', run_mocked(raise_err=True))
- with pytest.raises(StopActorExecution):
- updategrubcore.update_grub_core('/dev/vda')
+ updategrubcore.update_grub_core(devices)
assert reporting.create_report.called
- assert UPDATE_FAILED_TITLE == reporting.create_report.report_fields['title']
+ assert UPDATE_FAILED_TITLE == reporting.create_report.reports[0]['title']
+ assert all(dev in reporting.create_report.reports[0]['summary'] for dev in devices)
+
+
+def test_update_grub_success_and_fail(monkeypatch):
+ monkeypatch.setattr(reporting, "create_report", testutils.create_report_mocked())
+
+ def run_mocked(args):
+ if args == ['grub2-install', '/dev/vdb']:
+ raise_call_error(args)
+ else:
+ assert args == ['grub2-install', '/dev/vda']
+
+ monkeypatch.setattr(updategrubcore, 'run', run_mocked)
+
+ devices = ['/dev/vda', '/dev/vdb']
+ updategrubcore.update_grub_core(devices)
+
+ assert reporting.create_report.called
+ assert UPDATE_FAILED_TITLE == reporting.create_report.reports[0]['title']
+ assert '/dev/vdb' in reporting.create_report.reports[0]['summary']
+ assert UPDATE_OK_TITLE == reporting.create_report.reports[1]['title']
+ assert '/dev/vda' in reporting.create_report.reports[1]['summary']
def test_update_grub_negative(current_actor_context):
diff --git a/repos/system_upgrade/common/libraries/grub.py b/repos/system_upgrade/common/libraries/grub.py
index f6b00f65..79b3be39 100644
--- a/repos/system_upgrade/common/libraries/grub.py
+++ b/repos/system_upgrade/common/libraries/grub.py
@@ -1,7 +1,9 @@
import os
from leapp.exceptions import StopActorExecution
+from leapp.libraries.common import mdraid
from leapp.libraries.stdlib import api, CalledProcessError, run
+from leapp.utils.deprecation import deprecated
def has_grub(blk_dev):
@@ -59,6 +61,32 @@ def get_boot_partition():
return boot_partition
+def get_grub_devices():
+ """
+ Get block devices where GRUB is located. We assume GRUB is on the same device
+ as /boot partition is. In case that device is an md (Multiple Device) device, all
+ of the component devices of such a device are considered.
+
+ :return: Devices where GRUB is located
+ :rtype: list
+ """
+ boot_device = get_boot_partition()
+ devices = []
+ if mdraid.is_mdraid_dev(boot_device):
+ component_devs = mdraid.get_component_devices(boot_device)
+ blk_devs = [blk_dev_from_partition(dev) for dev in component_devs]
+ # remove duplicates as there might be raid on partitions on the same drive
+ # even if that's very unusual
+ devices = sorted(list(set(blk_devs)))
+ else:
+ devices.append(blk_dev_from_partition(boot_device))
+
+ have_grub = [dev for dev in devices if has_grub(dev)]
+ api.current_logger().info('GRUB is installed on {}'.format(",".join(have_grub)))
+ return have_grub
+
+
+@deprecated(since='2023-06-23', message='This function has been replaced by get_grub_devices')
def get_grub_device():
"""
Get block device where GRUB is located. We assume GRUB is on the same device
diff --git a/repos/system_upgrade/common/libraries/mdraid.py b/repos/system_upgrade/common/libraries/mdraid.py
new file mode 100644
index 00000000..5eb89c56
--- /dev/null
+++ b/repos/system_upgrade/common/libraries/mdraid.py
@@ -0,0 +1,48 @@
+from leapp.libraries.stdlib import api, CalledProcessError, run
+
+
+def is_mdraid_dev(dev):
+ """
+ Check if a given device is an md (Multiple Device) device
+
+ It is expected that the "mdadm" command is available,
+ if it's not it is assumed the device is not an md device.
+
+ :return: True if the device is an md device, False otherwise
+ :raises CalledProcessError: If an error occurred
+ """
+ fail_msg = 'Could not check if device "{}" is an md device: {}'
+ try:
+ result = run(['mdadm', '--query', dev])
+ except OSError as err:
+ api.current_logger().warning(fail_msg.format(dev, err))
+ return False
+ except CalledProcessError as err:
+ err.message = fail_msg.format(dev, err)
+ raise # let the calling actor handle the exception
+
+ return '--detail' in result['stdout']
+
+
+def get_component_devices(raid_dev):
+ """
+ Get list of component devices in an md (Multiple Device) array
+
+ :return: The list of component devices or None in case of error
+ :raises ValueError: If the device is not an mdraid device
+ """
+ try:
+ # using both --verbose and --brief for medium verbosity
+ result = run(['mdadm', '--detail', '--verbose', '--brief', raid_dev])
+ except (OSError, CalledProcessError) as err:
+ api.current_logger().warning(
+ 'Could not get md array component devices: {}'.format(err)
+ )
+ return None
+ # example output:
+ # ARRAY /dev/md0 level=raid1 num-devices=2 metadata=1.2 name=localhost.localdomain:0 UUID=c4acea6e:d56e1598:91822e3f:fb26832c # noqa: E501; pylint: disable=line-too-long
+ # devices=/dev/vda1,/dev/vdb1
+ if 'does not appear to be an md device' in result['stdout']:
+ raise ValueError("Expected md device, but got: {}".format(raid_dev))
+
+ return sorted(result['stdout'].rsplit('=', 2)[-1].strip().split(','))
diff --git a/repos/system_upgrade/common/libraries/tests/test_grub.py b/repos/system_upgrade/common/libraries/tests/test_grub.py
index ba086854..9ced1147 100644
--- a/repos/system_upgrade/common/libraries/tests/test_grub.py
+++ b/repos/system_upgrade/common/libraries/tests/test_grub.py
@@ -3,7 +3,7 @@ import os
import pytest
from leapp.exceptions import StopActorExecution
-from leapp.libraries.common import grub
+from leapp.libraries.common import grub, mdraid
from leapp.libraries.common.testutils import logger_mocked
from leapp.libraries.stdlib import api, CalledProcessError
from leapp.models import DefaultGrub, DefaultGrubInfo
@@ -11,6 +11,9 @@ from leapp.models import DefaultGrub, DefaultGrubInfo
BOOT_PARTITION = '/dev/vda1'
BOOT_DEVICE = '/dev/vda'
+MD_BOOT_DEVICE = '/dev/md0'
+MD_BOOT_DEVICES_WITH_GRUB = ['/dev/sda', '/dev/sdb']
+
VALID_DD = b'GRUB GeomHard DiskRead Error'
INVALID_DD = b'Nothing to see here!'
@@ -27,10 +30,11 @@ def raise_call_error(args=None):
class RunMocked(object):
- def __init__(self, raise_err=False):
+ def __init__(self, raise_err=False, boot_on_raid=False):
self.called = 0
self.args = None
self.raise_err = raise_err
+ self.boot_on_raid = boot_on_raid
def __call__(self, args, encoding=None):
self.called += 1
@@ -39,18 +43,22 @@ class RunMocked(object):
raise_call_error(args)
if self.args == ['grub2-probe', '--target=device', '/boot']:
- stdout = BOOT_PARTITION
+ stdout = MD_BOOT_DEVICE if self.boot_on_raid else BOOT_PARTITION
elif self.args == ['lsblk', '-spnlo', 'name', BOOT_PARTITION]:
stdout = BOOT_DEVICE
+ elif self.args[:-1] == ['lsblk', '-spnlo', 'name']:
+ stdout = self.args[-1][:-1]
return {'stdout': stdout}
def open_mocked(fn, flags):
- return open(
- os.path.join(CUR_DIR, 'grub_valid') if fn == BOOT_DEVICE else os.path.join(CUR_DIR, 'grub_invalid'), 'r'
- )
+ if fn == BOOT_DEVICE or fn in MD_BOOT_DEVICES_WITH_GRUB:
+ path = os.path.join(CUR_DIR, 'grub_valid')
+ else:
+ path = os.path.join(CUR_DIR, 'grub_invalid')
+ return open(path, 'r')
def open_invalid(fn, flags):
@@ -122,3 +130,54 @@ def test_is_blscfg_library(monkeypatch, enabled):
assert result
else:
assert not result
+
+
+def is_mdraid_dev_mocked(dev):
+ return dev == '/dev/md0'
+
+
+def test_get_grub_devices_one_device(monkeypatch):
+ run_mocked = RunMocked()
+ monkeypatch.setattr(grub, 'run', run_mocked)
+ monkeypatch.setattr(os, 'open', open_mocked)
+ monkeypatch.setattr(os, 'read', read_mocked)
+ monkeypatch.setattr(os, 'close', close_mocked)
+ monkeypatch.setattr(api, 'current_logger', logger_mocked())
+ monkeypatch.setattr(mdraid, 'is_mdraid_dev', is_mdraid_dev_mocked)
+
+ result = grub.get_grub_devices()
+ assert grub.run.called == 2
+ assert [BOOT_DEVICE] == result
+ assert not api.current_logger.warnmsg
+ assert 'GRUB is installed on {}'.format(",".join(result)) in api.current_logger.infomsg
+
+
+@pytest.mark.parametrize(
+ ',component_devs,expected',
+ [
+ (['/dev/sda1', '/dev/sdb1'], MD_BOOT_DEVICES_WITH_GRUB),
+ (['/dev/sda1', '/dev/sdb1', '/dev/sdc1', '/dev/sdd1'], MD_BOOT_DEVICES_WITH_GRUB),
+ (['/dev/sda2', '/dev/sdc1'], ['/dev/sda']),
+ (['/dev/sdd3', '/dev/sdb2'], ['/dev/sdb']),
+ ]
+)
+def test_get_grub_devices_raid_device(monkeypatch, component_devs, expected):
+ run_mocked = RunMocked(boot_on_raid=True)
+ monkeypatch.setattr(grub, 'run', run_mocked)
+ monkeypatch.setattr(os, 'open', open_mocked)
+ monkeypatch.setattr(os, 'read', read_mocked)
+ monkeypatch.setattr(os, 'close', close_mocked)
+ monkeypatch.setattr(api, 'current_logger', logger_mocked())
+ monkeypatch.setattr(mdraid, 'is_mdraid_dev', is_mdraid_dev_mocked)
+
+ def get_component_devices_mocked(raid_dev):
+ assert raid_dev == MD_BOOT_DEVICE
+ return component_devs
+
+ monkeypatch.setattr(mdraid, 'get_component_devices', get_component_devices_mocked)
+
+ result = grub.get_grub_devices()
+ assert grub.run.called == 1 + len(component_devs) # grub2-probe + Nx lsblk
+ assert sorted(expected) == result
+ assert not api.current_logger.warnmsg
+ assert 'GRUB is installed on {}'.format(",".join(result)) in api.current_logger.infomsg
diff --git a/repos/system_upgrade/common/libraries/tests/test_mdraid.py b/repos/system_upgrade/common/libraries/tests/test_mdraid.py
new file mode 100644
index 00000000..6a25d736
--- /dev/null
+++ b/repos/system_upgrade/common/libraries/tests/test_mdraid.py
@@ -0,0 +1,94 @@
+import os
+
+import pytest
+
+from leapp.libraries.common import mdraid
+from leapp.libraries.common.testutils import logger_mocked
+from leapp.libraries.stdlib import api, CalledProcessError
+
+MD_DEVICE = '/dev/md0'
+NOT_MD_DEVICE = '/dev/sda'
+
+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 RunMocked(object):
+
+ def __init__(self, raise_err=False):
+ self.called = 0
+ self.args = None
+ self.raise_err = raise_err
+
+ def __call__(self, args, encoding=None):
+ self.called += 1
+ self.args = args
+ if self.raise_err:
+ raise_call_error(args)
+
+ if self.args == ['mdadm', '--query', MD_DEVICE]:
+ stdout = '/dev/md0: 1022.00MiB raid1 2 devices, 0 spares. Use mdadm --detail for more detail.'
+ elif self.args == ['mdadm', '--query', NOT_MD_DEVICE]:
+ stdout = '/dev/sda: is not an md array'
+
+ elif self.args == ['mdadm', '--detail', '--verbose', '--brief', MD_DEVICE]:
+ stdout = 'ARRAY /dev/md0 level=raid1 num-devices=2 metadata=1.2 name=localhost.localdomain:0 UUID=c4acea6e:d56e1598:91822e3f:fb26832c\n devices=/dev/sda1,/dev/sdb1' # noqa: E501; pylint: disable=line-too-long
+ elif self.args == ['mdadm', '--detail', '--verbose', '--brief', NOT_MD_DEVICE]:
+ stdout = 'mdadm: /dev/sda does not appear to be an md device'
+
+ return {'stdout': stdout}
+
+
+@pytest.mark.parametrize('dev,expected', [(MD_DEVICE, True), (NOT_MD_DEVICE, False)])
+def test_is_mdraid_dev(monkeypatch, dev, expected):
+ run_mocked = RunMocked()
+ monkeypatch.setattr(mdraid, 'run', run_mocked)
+ monkeypatch.setattr(api, 'current_logger', logger_mocked())
+
+ result = mdraid.is_mdraid_dev(dev)
+ assert mdraid.run.called == 1
+ assert expected == result
+ assert not api.current_logger.warnmsg
+
+
+def test_is_mdraid_dev_error(monkeypatch):
+ run_mocked = RunMocked(raise_err=True)
+ monkeypatch.setattr(mdraid, 'run', run_mocked)
+ monkeypatch.setattr(api, 'current_logger', logger_mocked())
+
+ with pytest.raises(CalledProcessError) as err:
+ mdraid.is_mdraid_dev(MD_DEVICE)
+
+ assert mdraid.run.called == 1
+ expect_msg = 'Could not check if device "{}" is an md device:'.format(MD_DEVICE)
+ assert expect_msg in err.value.message
+
+
+def test_get_component_devices_ok(monkeypatch):
+ run_mocked = RunMocked()
+ monkeypatch.setattr(mdraid, 'run', run_mocked)
+ monkeypatch.setattr(api, 'current_logger', logger_mocked())
+
+ result = mdraid.get_component_devices(MD_DEVICE)
+ assert mdraid.run.called == 1
+ assert ['/dev/sda1', '/dev/sdb1'] == result
+ assert not api.current_logger.warnmsg
+
+
+def test_get_component_devices_not_md_device(monkeypatch):
+ run_mocked = RunMocked()
+ monkeypatch.setattr(mdraid, 'run', run_mocked)
+
+ with pytest.raises(ValueError) as err:
+ mdraid.get_component_devices(NOT_MD_DEVICE)
+
+ assert mdraid.run.called == 1
+ expect_msg = 'Expected md device, but got: {}'.format(NOT_MD_DEVICE)
+ assert expect_msg in str(err.value)
diff --git a/repos/system_upgrade/common/models/grubinfo.py b/repos/system_upgrade/common/models/grubinfo.py
index 952d01c1..f89770b4 100644
--- a/repos/system_upgrade/common/models/grubinfo.py
+++ b/repos/system_upgrade/common/models/grubinfo.py
@@ -8,6 +8,8 @@ class GrubInfo(Model):
"""
topic = SystemFactsTopic
+ # NOTE: @deprecated is not supported on fields
+ # @deprecated(since='2023-06-23', message='This field has been replaced by orig_devices')
orig_device_name = fields.Nullable(fields.String())
"""
Original name of the block device where Grub is located.
@@ -17,3 +19,13 @@ class GrubInfo(Model):
it's recommended to use `leapp.libraries.common.grub.get_grub_device()` anywhere
else.
"""
+
+ orig_devices = fields.List(fields.String(), default=[])
+ """
+ Original names of the block devices where Grub is located.
+
+ The names are persistent during the boot of the system so it's safe to be used during
+ preupgrade phases. However the names could be different after the reboot, so
+ it's recommended to use `leapp.libraries.common.grub.get_grub_devices()` everywhere
+ else.
+ """
--
2.41.0

View File

@ -1,86 +0,0 @@
From 2e85af59af3429e33cba91af844d50a324512bd4 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Mon, 17 Jul 2023 18:41:18 +0200
Subject: [PATCH 35/42] mdraid.py lib: Check if /usr/sbin/mdadm exists
Praviously the check was implemented using OSError return from `run`
function. However, in this particular case it's not safe and leads
to unexpected behaviour. Check the existence of the file explicitly
instead prior the `run` function is called.
Update existing unit-tests and extend the test case when mdadm
is not installed.
---
repos/system_upgrade/common/libraries/mdraid.py | 10 +++++++---
.../common/libraries/tests/test_mdraid.py | 14 ++++++++++++++
2 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/repos/system_upgrade/common/libraries/mdraid.py b/repos/system_upgrade/common/libraries/mdraid.py
index 5eb89c56..5b59814f 100644
--- a/repos/system_upgrade/common/libraries/mdraid.py
+++ b/repos/system_upgrade/common/libraries/mdraid.py
@@ -1,3 +1,5 @@
+import os
+
from leapp.libraries.stdlib import api, CalledProcessError, run
@@ -12,11 +14,13 @@ def is_mdraid_dev(dev):
:raises CalledProcessError: If an error occurred
"""
fail_msg = 'Could not check if device "{}" is an md device: {}'
+ if not os.path.exists('/usr/sbin/mdadm'):
+ api.current_logger().warning(fail_msg.format(
+ dev, '/usr/sbin/mdadm is not installed.'
+ ))
+ return False
try:
result = run(['mdadm', '--query', dev])
- except OSError as err:
- api.current_logger().warning(fail_msg.format(dev, err))
- return False
except CalledProcessError as err:
err.message = fail_msg.format(dev, err)
raise # let the calling actor handle the exception
diff --git a/repos/system_upgrade/common/libraries/tests/test_mdraid.py b/repos/system_upgrade/common/libraries/tests/test_mdraid.py
index 6a25d736..cb7c1059 100644
--- a/repos/system_upgrade/common/libraries/tests/test_mdraid.py
+++ b/repos/system_upgrade/common/libraries/tests/test_mdraid.py
@@ -51,6 +51,7 @@ def test_is_mdraid_dev(monkeypatch, dev, expected):
run_mocked = RunMocked()
monkeypatch.setattr(mdraid, 'run', run_mocked)
monkeypatch.setattr(api, 'current_logger', logger_mocked())
+ monkeypatch.setattr(os.path, 'exists', lambda dummy: True)
result = mdraid.is_mdraid_dev(dev)
assert mdraid.run.called == 1
@@ -62,6 +63,7 @@ def test_is_mdraid_dev_error(monkeypatch):
run_mocked = RunMocked(raise_err=True)
monkeypatch.setattr(mdraid, 'run', run_mocked)
monkeypatch.setattr(api, 'current_logger', logger_mocked())
+ monkeypatch.setattr(os.path, 'exists', lambda dummy: True)
with pytest.raises(CalledProcessError) as err:
mdraid.is_mdraid_dev(MD_DEVICE)
@@ -71,6 +73,18 @@ def test_is_mdraid_dev_error(monkeypatch):
assert expect_msg in err.value.message
+def test_is_mdraid_dev_notool(monkeypatch):
+ run_mocked = RunMocked(raise_err=True)
+ monkeypatch.setattr(mdraid, 'run', run_mocked)
+ monkeypatch.setattr(api, 'current_logger', logger_mocked())
+ monkeypatch.setattr(os.path, 'exists', lambda dummy: False)
+
+ result = mdraid.is_mdraid_dev(MD_DEVICE)
+ assert not result
+ assert not mdraid.run.called
+ assert api.current_logger.warnmsg
+
+
def test_get_component_devices_ok(monkeypatch):
run_mocked = RunMocked()
monkeypatch.setattr(mdraid, 'run', run_mocked)
--
2.41.0

View File

@ -1,66 +0,0 @@
From e76e5cebeb41125a2075fafaba94faca66df5476 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Thu, 13 Jul 2023 15:38:22 +0200
Subject: [PATCH 36/42] target_userspace_creator: Use MOVE instead of copy for
the persistent cache
If leapp is executed with LEAPP_DEVEL_USE_PERSISTENT_PACKAGE_CACHE=1,
the /var/dnf/cache from the target container has been copied under
/var/lib/leapp/persistent_package_cache
The negative effect was that it took too much space on the disk
(800+ MBs, depends on how much rpms have been downloaded before..)
which could lead easily to the consumed disk space on related partition,
which eventually could stop also the leapp execution as it cannot
do any meaningful operations when the disk is full (e.g. access the
database).
This is done now without nspawn context functions as the move operation
does not make so much sense to be implemented as it's more expected
to copy to/from the container than moving files/dirs.
---
.../libraries/userspacegen.py | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
index cad923fb..4cff7b30 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
@@ -1,5 +1,6 @@
import itertools
import os
+import shutil
from leapp import reporting
from leapp.exceptions import StopActorExecution, StopActorExecutionError
@@ -121,9 +122,12 @@ class _InputData(object):
def _restore_persistent_package_cache(userspace_dir):
if get_env('LEAPP_DEVEL_USE_PERSISTENT_PACKAGE_CACHE', None) == '1':
- if os.path.exists(PERSISTENT_PACKAGE_CACHE_DIR):
- with mounting.NspawnActions(base_dir=userspace_dir) as target_context:
- target_context.copytree_to(PERSISTENT_PACKAGE_CACHE_DIR, '/var/cache/dnf')
+ if not os.path.exists(PERSISTENT_PACKAGE_CACHE_DIR):
+ return
+ dst_cache = os.path.join(userspace_dir, 'var', 'cache', 'dnf')
+ if os.path.exists(dst_cache):
+ run(['rm', '-rf', dst_cache])
+ shutil.move(PERSISTENT_PACKAGE_CACHE_DIR, dst_cache)
# We always want to remove the persistent cache here to unclutter the system
run(['rm', '-rf', PERSISTENT_PACKAGE_CACHE_DIR])
@@ -132,9 +136,9 @@ def _backup_to_persistent_package_cache(userspace_dir):
if get_env('LEAPP_DEVEL_USE_PERSISTENT_PACKAGE_CACHE', None) == '1':
# Clean up any dead bodies, just in case
run(['rm', '-rf', PERSISTENT_PACKAGE_CACHE_DIR])
- if os.path.exists(os.path.join(userspace_dir, 'var', 'cache', 'dnf')):
- with mounting.NspawnActions(base_dir=userspace_dir) as target_context:
- target_context.copytree_from('/var/cache/dnf', PERSISTENT_PACKAGE_CACHE_DIR)
+ src_cache = os.path.join(userspace_dir, 'var', 'cache', 'dnf')
+ if os.path.exists(src_cache):
+ shutil.move(src_cache, PERSISTENT_PACKAGE_CACHE_DIR)
def _the_nogpgcheck_option_used():
--
2.41.0

View File

@ -1,293 +0,0 @@
From e4fa8671351a73ddd6b56c70a7834a2c304df9cc Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Mon, 10 Jul 2023 15:20:24 +0200
Subject: [PATCH 37/42] overlay lib: Deprecate old ovl internal functions
(refactoring)
We are going to redesign the use of overlay images during the upgrade
to resolve number of issues we have with the old solution. However,
we need to keep the old solution as a fallback (read below). This
is small preparation to keep the new and old code separated safely.
Reasoning for the fallback:
* There is a chance the new solution could raise also some problems
mainly for systems with many partitions/volumes in fstab, or when
they are using many loop devices already - as the new solution will
require to create loop device for each partition/volume noted in
the fstab.
* Also RHEL 7 is going to switch to ELS on Jun 2024 after which the
project will be fixing just critical bugfixes for in-place upgrades.
This problem blocking the upgrade is not considered to be critical.
---
.../common/libraries/overlaygen.py | 223 +++++++++---------
1 file changed, 117 insertions(+), 106 deletions(-)
diff --git a/repos/system_upgrade/common/libraries/overlaygen.py b/repos/system_upgrade/common/libraries/overlaygen.py
index b544f88c..e0d88fe5 100644
--- a/repos/system_upgrade/common/libraries/overlaygen.py
+++ b/repos/system_upgrade/common/libraries/overlaygen.py
@@ -13,15 +13,6 @@ OVERLAY_DO_NOT_MOUNT = ('tmpfs', 'devpts', 'sysfs', 'proc', 'cramfs', 'sysv', 'v
MountPoints = namedtuple('MountPoints', ['fs_file', 'fs_vfstype'])
-def _ensure_enough_diskimage_space(space_needed, directory):
- stat = os.statvfs(directory)
- if (stat.f_frsize * stat.f_bavail) < (space_needed * 1024 * 1024):
- message = ('Not enough space available for creating required disk images in {directory}. ' +
- 'Needed: {space_needed} MiB').format(space_needed=space_needed, directory=directory)
- api.current_logger().error(message)
- raise StopActorExecutionError(message)
-
-
def _get_mountpoints(storage_info):
mount_points = set()
for entry in storage_info.fstab:
@@ -43,41 +34,6 @@ def _mount_dir(mounts_dir, mountpoint):
return os.path.join(mounts_dir, _mount_name(mountpoint))
-def _prepare_required_mounts(scratch_dir, mounts_dir, mount_points, xfs_info):
- result = {
- mount_point.fs_file: mounting.NullMount(
- _mount_dir(mounts_dir, mount_point.fs_file)) for mount_point in mount_points
- }
-
- if not xfs_info.mountpoints_without_ftype:
- return result
-
- space_needed = _overlay_disk_size() * len(xfs_info.mountpoints_without_ftype)
- disk_images_directory = os.path.join(scratch_dir, 'diskimages')
-
- # Ensure we cleanup old disk images before we check for space constraints.
- run(['rm', '-rf', disk_images_directory])
- _create_diskimages_dir(scratch_dir, disk_images_directory)
- _ensure_enough_diskimage_space(space_needed, scratch_dir)
-
- mount_names = [mount_point.fs_file for mount_point in mount_points]
-
- # TODO(pstodulk): this (adding rootfs into the set always) is hotfix for
- # bz #1911802 (not ideal one..). The problem occurs one rootfs is ext4 fs,
- # but /var/lib/leapp/... is under XFS without ftype; In such a case we can
- # see still the very same problems as before. But letting you know that
- # probably this is not the final solution, as we could possibly see the
- # same problems on another partitions too (needs to be tested...). However,
- # it could fit for now until we provide the complete solution around XFS
- # workarounds (including management of required spaces for virtual FSs per
- # mountpoints - without that, we cannot fix this properly)
- for mountpoint in set(xfs_info.mountpoints_without_ftype + ['/']):
- if mountpoint in mount_names:
- image = _create_mount_disk_image(disk_images_directory, mountpoint)
- result[mountpoint] = mounting.LoopMount(source=image, target=_mount_dir(mounts_dir, mountpoint))
- return result
-
-
@contextlib.contextmanager
def _build_overlay_mount(root_mount, mounts):
if not root_mount:
@@ -96,21 +52,6 @@ def _build_overlay_mount(root_mount, mounts):
yield mount
-def _overlay_disk_size():
- """
- Convenient function to retrieve the overlay disk size
- """
- try:
- env_size = os.getenv('LEAPP_OVL_SIZE', default='2048')
- disk_size = int(env_size)
- except ValueError:
- disk_size = 2048
- api.current_logger().warning(
- 'Invalid "LEAPP_OVL_SIZE" environment variable "%s". Setting default "%d" value', env_size, disk_size
- )
- return disk_size
-
-
def cleanup_scratch(scratch_dir, mounts_dir):
"""
Function to cleanup the scratch directory
@@ -128,52 +69,6 @@ def cleanup_scratch(scratch_dir, mounts_dir):
api.current_logger().debug('Recursively removed scratch directory %s.', scratch_dir)
-def _create_mount_disk_image(disk_images_directory, path):
- """
- Creates the mount disk image, for cases when we hit XFS with ftype=0
- """
- diskimage_path = os.path.join(disk_images_directory, _mount_name(path))
- disk_size = _overlay_disk_size()
-
- api.current_logger().debug('Attempting to create disk image with size %d MiB at %s', disk_size, diskimage_path)
- utils.call_with_failure_hint(
- cmd=['/bin/dd', 'if=/dev/zero', 'of={}'.format(diskimage_path), 'bs=1M', 'count={}'.format(disk_size)],
- hint='Please ensure that there is enough diskspace in {} at least {} MiB are needed'.format(
- diskimage_path, disk_size)
- )
-
- api.current_logger().debug('Creating ext4 filesystem in disk image at %s', diskimage_path)
- try:
- utils.call_with_oserror_handled(cmd=['/sbin/mkfs.ext4', '-F', diskimage_path])
- except CalledProcessError as e:
- api.current_logger().error('Failed to create ext4 filesystem %s', exc_info=True)
- raise StopActorExecutionError(
- message=str(e)
- )
-
- return diskimage_path
-
-
-def _create_diskimages_dir(scratch_dir, diskimages_dir):
- """
- Prepares directories for disk images
- """
- api.current_logger().debug('Creating disk images directory.')
- try:
- utils.makedirs(diskimages_dir)
- api.current_logger().debug('Done creating disk images directory.')
- except OSError:
- api.current_logger().error('Failed to create disk images directory %s', diskimages_dir, exc_info=True)
-
- # This is an attempt for giving the user a chance to resolve it on their own
- raise StopActorExecutionError(
- message='Failed to prepare environment for package download while creating directories.',
- details={
- 'hint': 'Please ensure that {scratch_dir} is empty and modifiable.'.format(scratch_dir=scratch_dir)
- }
- )
-
-
def _create_mounts_dir(scratch_dir, mounts_dir):
"""
Prepares directories for mounts
@@ -214,7 +109,7 @@ def create_source_overlay(mounts_dir, scratch_dir, xfs_info, storage_info, mount
scratch_dir=scratch_dir, mounts_dir=mounts_dir))
try:
_create_mounts_dir(scratch_dir, mounts_dir)
- mounts = _prepare_required_mounts(scratch_dir, mounts_dir, _get_mountpoints(storage_info), xfs_info)
+ mounts = _prepare_required_mounts_old(scratch_dir, mounts_dir, _get_mountpoints(storage_info), xfs_info)
with mounts.pop('/') as root_mount:
with mounting.OverlayMount(name='system_overlay', source='/', workdir=root_mount.target) as root_overlay:
if mount_target:
@@ -228,3 +123,119 @@ def create_source_overlay(mounts_dir, scratch_dir, xfs_info, storage_info, mount
except Exception:
cleanup_scratch(scratch_dir, mounts_dir)
raise
+
+
+# #############################################################################
+# Deprecated OVL solution ...
+# This is going to be removed in future as the whole functionality is going to
+# be replaced by new one. The problem is that the new solution can potentially
+# negatively affect systems with many loop mountpoints, so let's keep this
+# as a workaround for now. I am separating the old and new code in this way
+# to make the future removal easy.
+# IMPORTANT: Before an update of functions above, ensure the functionality of
+# the code below is not affected, otherwise copy the function below with the
+# "_old" suffix.
+# #############################################################################
+def _ensure_enough_diskimage_space_old(space_needed, directory):
+ stat = os.statvfs(directory)
+ if (stat.f_frsize * stat.f_bavail) < (space_needed * 1024 * 1024):
+ message = ('Not enough space available for creating required disk images in {directory}. ' +
+ 'Needed: {space_needed} MiB').format(space_needed=space_needed, directory=directory)
+ api.current_logger().error(message)
+ raise StopActorExecutionError(message)
+
+
+def _overlay_disk_size_old():
+ """
+ Convenient function to retrieve the overlay disk size
+ """
+ try:
+ env_size = os.getenv('LEAPP_OVL_SIZE', default='2048')
+ disk_size = int(env_size)
+ except ValueError:
+ disk_size = 2048
+ api.current_logger().warning(
+ 'Invalid "LEAPP_OVL_SIZE" environment variable "%s". Setting default "%d" value', env_size, disk_size
+ )
+ return disk_size
+
+
+def _create_diskimages_dir_old(scratch_dir, diskimages_dir):
+ """
+ Prepares directories for disk images
+ """
+ api.current_logger().debug('Creating disk images directory.')
+ try:
+ utils.makedirs(diskimages_dir)
+ api.current_logger().debug('Done creating disk images directory.')
+ except OSError:
+ api.current_logger().error('Failed to create disk images directory %s', diskimages_dir, exc_info=True)
+
+ # This is an attempt for giving the user a chance to resolve it on their own
+ raise StopActorExecutionError(
+ message='Failed to prepare environment for package download while creating directories.',
+ details={
+ 'hint': 'Please ensure that {scratch_dir} is empty and modifiable.'.format(scratch_dir=scratch_dir)
+ }
+ )
+
+
+def _create_mount_disk_image_old(disk_images_directory, path):
+ """
+ Creates the mount disk image, for cases when we hit XFS with ftype=0
+ """
+ diskimage_path = os.path.join(disk_images_directory, _mount_name(path))
+ disk_size = _overlay_disk_size_old()
+
+ api.current_logger().debug('Attempting to create disk image with size %d MiB at %s', disk_size, diskimage_path)
+ utils.call_with_failure_hint(
+ cmd=['/bin/dd', 'if=/dev/zero', 'of={}'.format(diskimage_path), 'bs=1M', 'count={}'.format(disk_size)],
+ hint='Please ensure that there is enough diskspace in {} at least {} MiB are needed'.format(
+ diskimage_path, disk_size)
+ )
+
+ api.current_logger().debug('Creating ext4 filesystem in disk image at %s', diskimage_path)
+ try:
+ utils.call_with_oserror_handled(cmd=['/sbin/mkfs.ext4', '-F', diskimage_path])
+ except CalledProcessError as e:
+ api.current_logger().error('Failed to create ext4 filesystem %s', exc_info=True)
+ raise StopActorExecutionError(
+ message=str(e)
+ )
+
+ return diskimage_path
+
+
+def _prepare_required_mounts_old(scratch_dir, mounts_dir, mount_points, xfs_info):
+ result = {
+ mount_point.fs_file: mounting.NullMount(
+ _mount_dir(mounts_dir, mount_point.fs_file)) for mount_point in mount_points
+ }
+
+ if not xfs_info.mountpoints_without_ftype:
+ return result
+
+ space_needed = _overlay_disk_size_old() * len(xfs_info.mountpoints_without_ftype)
+ disk_images_directory = os.path.join(scratch_dir, 'diskimages')
+
+ # Ensure we cleanup old disk images before we check for space constraints.
+ run(['rm', '-rf', disk_images_directory])
+ _create_diskimages_dir_old(scratch_dir, disk_images_directory)
+ _ensure_enough_diskimage_space_old(space_needed, scratch_dir)
+
+ mount_names = [mount_point.fs_file for mount_point in mount_points]
+
+ # TODO(pstodulk): this (adding rootfs into the set always) is hotfix for
+ # bz #1911802 (not ideal one..). The problem occurs one rootfs is ext4 fs,
+ # but /var/lib/leapp/... is under XFS without ftype; In such a case we can
+ # see still the very same problems as before. But letting you know that
+ # probably this is not the final solution, as we could possibly see the
+ # same problems on another partitions too (needs to be tested...). However,
+ # it could fit for now until we provide the complete solution around XFS
+ # workarounds (including management of required spaces for virtual FSs per
+ # mountpoints - without that, we cannot fix this properly)
+ for mountpoint in set(xfs_info.mountpoints_without_ftype + ['/']):
+ if mountpoint in mount_names:
+ image = _create_mount_disk_image_old(disk_images_directory, mountpoint)
+ result[mountpoint] = mounting.LoopMount(source=image, target=_mount_dir(mounts_dir, mountpoint))
+ return result
--
2.41.0

View File

@ -1,35 +0,0 @@
From dfd1093e9bde660a33e1705143589ec79e9970b1 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Mon, 10 Jul 2023 15:47:19 +0200
Subject: [PATCH 38/42] overlay lib: replace os.getenv common.config.get_env
All LEAPP_* envars are supposed to be read by library function
which ensures persistent behaviour during the whole upgrade process.
---
repos/system_upgrade/common/libraries/overlaygen.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/repos/system_upgrade/common/libraries/overlaygen.py b/repos/system_upgrade/common/libraries/overlaygen.py
index e0d88fe5..1e9c89f6 100644
--- a/repos/system_upgrade/common/libraries/overlaygen.py
+++ b/repos/system_upgrade/common/libraries/overlaygen.py
@@ -5,6 +5,7 @@ from collections import namedtuple
from leapp.exceptions import StopActorExecutionError
from leapp.libraries.common import mounting, utils
+from leapp.libraries.common.config import get_env
from leapp.libraries.stdlib import api, CalledProcessError, run
OVERLAY_DO_NOT_MOUNT = ('tmpfs', 'devpts', 'sysfs', 'proc', 'cramfs', 'sysv', 'vfat')
@@ -150,7 +151,7 @@ def _overlay_disk_size_old():
Convenient function to retrieve the overlay disk size
"""
try:
- env_size = os.getenv('LEAPP_OVL_SIZE', default='2048')
+ env_size = get_env('LEAPP_OVL_SIZE', '2048')
disk_size = int(env_size)
except ValueError:
disk_size = 2048
--
2.41.0

View File

@ -1,652 +0,0 @@
From d074926c75eebc56ca640e7367638bbeaa1b61a2 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Mon, 10 Jul 2023 21:31:24 +0200
Subject: [PATCH 39/42] overlay lib: Redesign creation of the source overlay
composition
The in-place upgrade itself requires to do some changes on the system to be
able to perform the in-place upgrade itself - or even to be able to evaluate
if the system is possible to upgrade. However, we do not want to (and must not)
change the original system until we pass beyond the point of not return.
For that purposes we have to create a layer above the real host file system,
where we can safely perform all operations without affecting the system
setup, rpm database, etc. Currently overlay (OVL) technology showed it is
capable to handle our requirements good enough - with some limitations.
However, the original design we used to compose overlay layer above
the host system had number of problems:
* buggy calculation of the required free space for the upgrade RPM
transaction
* consumed too much space to handle partitions formatted with XFS
without ftype attributes (even tens GBs)
* bad UX as people had to manually adjust size of OVL disk images
* .. and couple of additional issues derivated from problems
listed above
The new solution prepares a disk image (represented by sparse-file)
and an overlay image for each mountpoint configured in /etc/fstab,
excluding those with FS types noted in the `OVERLAY_DO_NOT_MOUNT`
set. Such prepared OVL images are then composed together to reflect
the real host filesystem. In the end everything is cleaned.
The composition could look like this:
orig mountpoint -> disk img -> overlay img -> new mountpoint
-------------------------------------------------------------
/ -> root_ -> root_/ovl -> root_/ovl/
/boot -> root_boot -> root_boot/ovl -> root_/ovl/boot
/var -> root_var -> root_var/ovl -> root_/ovl/var
/var/lib -> root_var_lib -> root_var_lib/ovl -> root_/ovl/var/lib
...
The new solution can be now problematic for system with too many partitions
and loop devices, as each disk image is loop mounted (that's same as
before, but number of disk images will be bigger in total number).
For such systems we keep for now the possibility of the fallback
to an old solution, which has number of issues mentioned above,
but it's a trade of. To fallback to the old solution, set envar:
LEAPP_OVL_LEGACY=1
Disk images created for OVL are formatted with XFS by default. In case of
problems, it's possible to switch to Ext4 FS using:
LEAPP_OVL_IMG_FS_EXT4=1
XFS is better optimized for our use cases (faster initialisation
consuming less space). However we have reported several issues related
to overlay images, that happened so far only on XFS filesystems.
We are not sure about root causes, but having the possibility
to switch to Ext4 seems to be wise. In case of issues, we can simple
ask users to try the switch and see if the problem is fixed or still
present.
Some additional technical details about other changes
* Added simple/naive checks whether the system has enough space on
the partition hosting /var/lib/leapp (usually /var). Consuming the
all space on the partition could lead to unwanted behaviour
- in the worst case if we speak about /var partition it could mean
problems also for other applications running on the system
* In case the container is larger than the expected min default or
the calculation of the required free space is lower than the
minimal protected size, return the protected size constant
(200 MiB).
* Work just with mountpoints (paths) in the _prepare_required_mounts()
instead of with list of MountPoint named tuple. I think about the
removal of the named tuple, but let's keep it for now.
* Make apparent size of created disk images 5% smaller to protect
failed upgrades during the transaction execution due to really
small amount of free space.
* Cleanup the scratch directory at the end to free the consumed
space. Disks are kept after the run of leapp when
LEAPP_DEVEL_KEEP_DISK_IMGS=1
---
.../libraries/userspacegen.py | 4 +-
.../common/libraries/dnfplugin.py | 4 +-
.../common/libraries/overlaygen.py | 441 +++++++++++++++++-
3 files changed, 445 insertions(+), 4 deletions(-)
diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
index 4cff7b30..8400dbe7 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
@@ -766,11 +766,13 @@ def perform():
indata = _InputData()
prod_cert_path = _get_product_certificate_path()
+ reserve_space = overlaygen.get_recommended_leapp_free_space(_get_target_userspace())
with overlaygen.create_source_overlay(
mounts_dir=constants.MOUNTS_DIR,
scratch_dir=constants.SCRATCH_DIR,
storage_info=indata.storage_info,
- xfs_info=indata.xfs_info) as overlay:
+ xfs_info=indata.xfs_info,
+ scratch_reserve=reserve_space) as overlay:
with overlay.nspawn() as context:
# Mount the ISO into the scratch container
target_iso = next(api.consume(TargetOSInstallationImage), None)
diff --git a/repos/system_upgrade/common/libraries/dnfplugin.py b/repos/system_upgrade/common/libraries/dnfplugin.py
index 57b25909..fb0e8ae5 100644
--- a/repos/system_upgrade/common/libraries/dnfplugin.py
+++ b/repos/system_upgrade/common/libraries/dnfplugin.py
@@ -381,12 +381,14 @@ def perform_transaction_install(target_userspace_info, storage_info, used_repos,
@contextlib.contextmanager
def _prepare_perform(used_repos, target_userspace_info, xfs_info, storage_info, target_iso=None):
+ reserve_space = overlaygen.get_recommended_leapp_free_space(target_userspace_info.path)
with _prepare_transaction(used_repos=used_repos,
target_userspace_info=target_userspace_info
) as (context, target_repoids, userspace_info):
with overlaygen.create_source_overlay(mounts_dir=userspace_info.mounts, scratch_dir=userspace_info.scratch,
xfs_info=xfs_info, storage_info=storage_info,
- mount_target=os.path.join(context.base_dir, 'installroot')) as overlay:
+ mount_target=os.path.join(context.base_dir, 'installroot'),
+ scratch_reserve=reserve_space) as overlay:
with mounting.mount_upgrade_iso_to_root_dir(target_userspace_info.path, target_iso):
yield context, overlay, target_repoids
diff --git a/repos/system_upgrade/common/libraries/overlaygen.py b/repos/system_upgrade/common/libraries/overlaygen.py
index 1e9c89f6..3ffdd176 100644
--- a/repos/system_upgrade/common/libraries/overlaygen.py
+++ b/repos/system_upgrade/common/libraries/overlaygen.py
@@ -6,20 +6,204 @@ from collections import namedtuple
from leapp.exceptions import StopActorExecutionError
from leapp.libraries.common import mounting, utils
from leapp.libraries.common.config import get_env
+from leapp.libraries.common.config.version import get_target_major_version
from leapp.libraries.stdlib import api, CalledProcessError, run
OVERLAY_DO_NOT_MOUNT = ('tmpfs', 'devpts', 'sysfs', 'proc', 'cramfs', 'sysv', 'vfat')
+# NOTE(pstodulk): what about using more closer values and than just multiply
+# the final result by magical constant?... this number is most likely going to
+# be lowered and affected by XFS vs EXT4 FSs that needs different spaces each
+# of them.
+_MAGICAL_CONSTANT_OVL_SIZE = 128
+"""
+Average size of created disk space images.
+
+The size can be lower or higher - usually lower. The value is higher as we want
+to rather prevent future actions in advance instead of resolving later issues
+with the missing space.
+
+It's possible that in future we implement better heuristic that will guess
+the needed space based on size of each FS. I have been thinking to lower
+the value, as in my case most of partitions where we do not need to do
+write operations consume just ~ 33MB. However, I decided to keep it as it is
+for now to stay on the safe side.
+"""
+
+_MAGICAL_CONSTANT_MIN_CONTAINER_SIZE_8 = 3200
+"""
+Average space consumed to create target el8userspace container installation + pkg downloads.
+
+Minimal container size is approx. 1GiB without download of packages for the upgrade
+(and without pkgs for the initramfs creation). The total size of the container
+ * with all pkgs downloaded
+ * final initramfs installed package set
+ * created the upgrade initramfs
+is for the minimal system
+ * ~ 2.9 GiB for IPU 7 -> 8
+ * ~ 1.8 GiB for IPU 8 -> 9
+when no other extra packages are installed for the needs of the upgrade.
+Keeping in mind that during the upgrade initramfs creation another 400+ MiB
+is consumed temporarily.
+
+Using higher value to cover also the space that consumes leapp.db records.
+
+This constant is really magical and the value can be changed in future.
+"""
+
+_MAGICAL_CONSTANT_MIN_CONTAINER_SIZE_9 = 2200
+"""
+Average space consumed to create target el9userspace container installation + pkg downloads.
+
+See _MAGICAL_CONSTANT_MIN_CONTAINER_SIZE_8 for more details.
+"""
+
+_MAGICAL_CONSTANT_MIN_PROTECTED_SIZE = 200
+"""
+This is the minimal size (in MiB) that will be always reserved for /var/lib/leapp
+
+In case the size of the container is larger than _MAGICAL_CONSTANT_MIN_PROTECTED_SIZE
+or close to that size, stay always with this minimal protected size defined by
+this constant.
+"""
+
MountPoints = namedtuple('MountPoints', ['fs_file', 'fs_vfstype'])
+def _get_min_container_size():
+ if get_target_major_version() == '8':
+ return _MAGICAL_CONSTANT_MIN_CONTAINER_SIZE_8
+ return _MAGICAL_CONSTANT_MIN_CONTAINER_SIZE_9
+
+
+def get_recommended_leapp_free_space(userspace_path=None):
+ """
+ Return recommended free space for the target container (+ pkg downloads)
+
+ If the path to the container is set, the returned value is updated to
+ reflect already consumed space by the installed container. In case the
+ container is bigger than the minimal protected size, return at least
+ `_MAGICAL_CONSTANT_MIN_PROTECTED_SIZE`.
+
+ It's not recommended to use this function except official actors managed
+ by OAMG group in github.com/oamg/leapp-repository. This function can be
+ changed in future, ignoring the deprecation process.
+
+ TODO(pstodulk): this is so far the best trade off between stay safe and do
+ do not consume too much space. But need to figure out cost of the time
+ consumption.
+
+ TODO(pstodulk): check we are not negatively affected in case of downloaded
+ rpms. We want to prevent situations when we say that customer has enough
+ space for the first run and after the download of packages we inform them
+ they do not have enough free space anymore. Note: such situation can be
+ valid in specific cases - e.g. the space is really consumed already e.g. by
+ leapp.db that has been executed manytimes.
+
+ :param userspace_path: Path to the userspace container.
+ :type userspace_path: str
+ :rtype: int
+ """
+ min_cont_size = _get_min_container_size()
+ if not userspace_path or not os.path.exists(userspace_path):
+ return min_cont_size
+ try:
+ # ignore symlinks and other partitions to be sure we calculate the space
+ # in reasonable time
+ cont_size = run(['du', '-sPmx', userspace_path])['stdout'].split()[0]
+ # the obtained number is in KiB. But we want to work with MiBs rather.
+ cont_size = int(cont_size)
+ except (OSError, CalledProcessError):
+ # do not care about failed cmd, in such a case, just act like userspace_path
+ # has not been set
+ api.current_logger().warning(
+ 'Cannot calculate current container size to estimate correctly required space.'
+ ' Working with the default: {} MiB'
+ .format(min_cont_size)
+ )
+ return min_cont_size
+ if cont_size < 0:
+ api.current_logger().warning(
+ 'Cannot calculate the container size - negative size obtained: {}.'
+ ' Estimate the required size based on the default value: {} MiB'
+ .format(cont_size, min_cont_size)
+ )
+ return min_cont_size
+ prot_size = min_cont_size - cont_size
+ if prot_size < _MAGICAL_CONSTANT_MIN_PROTECTED_SIZE:
+ api.current_logger().debug(
+ 'The size of the container is higher than the expected default.'
+ ' Use the minimal protected size instead: {} MiB.'
+ .format(_MAGICAL_CONSTANT_MIN_PROTECTED_SIZE)
+ )
+ return _MAGICAL_CONSTANT_MIN_PROTECTED_SIZE
+ return prot_size
+
+
+def _get_fspace(path, convert_to_mibs=False, coefficient=1):
+ """
+ Return the free disk space on given path.
+
+ The default is in bytes, but if convert_to_mibs is True, return MiBs instead.
+
+ Raises OSError if nothing exists on the given `path`.
+
+ :param path: Path to an existing file or directory
+ :type path: str
+ :param convert_to_mibs: If True, convert the value to MiBs
+ :type convert_to_mibs: bool
+ :param coefficient: Coefficient to multiply the free space (e.g. 0.9 to have it 10% lower). Max: 1
+ :type coefficient: float
+ :rtype: int
+ """
+ stat = os.statvfs(path)
+
+ # TODO(pstodulk): discuss the function params
+ coefficient = min(coefficient, 1)
+ fspace_bytes = int(stat.f_frsize * stat.f_bavail * coefficient)
+ if convert_to_mibs:
+ return int(fspace_bytes / 1024 / 1024) # noqa: W1619; pylint: disable=old-division
+ return fspace_bytes
+
+
+def _ensure_enough_diskimage_space(space_needed, directory):
+ # TODO(pstodulk): update the error msg/details
+ # imagine situation we inform user we need at least 800MB,
+ # so they clean /var/lib/leapp/* which can provide additional space,
+ # but the calculated required free space takes the existing content under
+ # /var/lib/leapp/ into account, so the next error msg could say:
+ # needed at least 3400 MiB - which could be confusing for users.
+ if _get_fspace(directory) < (space_needed * 1024 * 1024):
+ message = (
+ 'Not enough space available on {directory}: Needed at least {space_needed} MiB.'
+ .format(directory=directory, space_needed=space_needed)
+ )
+ details = {'detail': (
+ 'The file system hosting the {directory} directory does not contain'
+ ' enough free space to proceed all parts of the in-place upgrade.'
+ ' Note the calculated required free space is the minimum derived'
+ ' from upgrades of minimal systems and the actual needed free'
+ ' space could be higher.'
+ '\nNeeded at least: {space_needed} MiB.'
+ '\nSuggested free space: {suggested} MiB (or more).'
+ .format(space_needed=space_needed, directory=directory, suggested=space_needed + 1000)
+ )}
+ if get_env('LEAPP_OVL_SIZE', None):
+ # LEAPP_OVL_SIZE has not effect as we use sparse files now.
+ details['note'] = 'The LEAPP_OVL_SIZE environment variable has no effect anymore.'
+ api.current_logger().error(message)
+ raise StopActorExecutionError(message, details=details)
+
+
def _get_mountpoints(storage_info):
mount_points = set()
for entry in storage_info.fstab:
if os.path.isdir(entry.fs_file) and entry.fs_vfstype not in OVERLAY_DO_NOT_MOUNT:
mount_points.add(MountPoints(entry.fs_file, entry.fs_vfstype))
elif os.path.isdir(entry.fs_file) and entry.fs_vfstype == 'vfat':
+ # VFAT FS is not supported to be used for any system partition,
+ # so we can safely ignore it
api.current_logger().warning(
'Ignoring vfat {} filesystem mount during upgrade process'.format(entry.fs_file)
)
@@ -35,6 +219,81 @@ def _mount_dir(mounts_dir, mountpoint):
return os.path.join(mounts_dir, _mount_name(mountpoint))
+def _get_scratch_mountpoint(mount_points, dir_path):
+ for mp in sorted(mount_points, reverse=True):
+ # we are sure that mountpoint != dir_path in this case, as the latest
+ # valid mountpoint customers could create is the parent directory
+ mod_mp = mp if mp[-1] == '/' else '{}/'.format(mp)
+ if dir_path.startswith(mod_mp):
+ # longest first, so the first one we find, is the last mp on the path
+ return mp
+ return None # making pylint happy; this is basically dead code
+
+
+def _prepare_required_mounts(scratch_dir, mounts_dir, storage_info, scratch_reserve):
+ """
+ Create disk images and loop mount them.
+
+ Ensure to create disk image for each important mountpoint configured
+ in fstab (excluding fs types noted in `OVERLAY_DO_NOT_MOUNT`).
+ Disk images reflect the free space of related partition/volume. In case
+ of partition hosting /var/lib/leapp/* calculate the free space value
+ taking `scratch_reserve` into account, as during the run of the tooling,
+ we will be consuming the space on the partition and we want to be more
+ sure that we do not consume all the space on the partition during the
+ execution - so we reduce the risk we affect run of other applications
+ due to missing space.
+
+ Note: the partition hosting the scratch dir is expected to be the same
+ partition that is hosting the target userspace container, but it does not
+ have to be true if the code changes. Right now, let's live with that.
+
+ See `_create_mount_disk_image` docstring for additional more details.
+
+ :param scratch_dir: Path to the scratch directory.
+ :type scratch_dir: str
+ :param mounts_dir: Path to the directory supposed to be a mountpoint.
+ :type mounts_dir: str
+ :param storage_info: The StorageInfo message.
+ :type storage_info: leapp.models.StorageInfo
+ :param scratch_reserve: Number of MB that should be extra reserved in a partition hosting the scratch_dir.
+ :type scratch_reserve: Optional[int]
+ """
+ mount_points = sorted([mp.fs_file for mp in _get_mountpoints(storage_info)])
+ scratch_mp = _get_scratch_mountpoint(mount_points, scratch_dir)
+ disk_images_directory = os.path.join(scratch_dir, 'diskimages')
+
+ # Ensure we cleanup old disk images before we check for space constraints.
+ # NOTE(pstodulk): Could we improve the process so we create imgs & calculate
+ # the required disk space just once during each leapp (pre)upgrade run?
+ run(['rm', '-rf', disk_images_directory])
+ _create_diskimages_dir(scratch_dir, disk_images_directory)
+
+ # TODO(pstodulk): update the calculation for bind mounted mount_points (skip)
+ # basic check whether we have enough space at all
+ space_needed = scratch_reserve + _MAGICAL_CONSTANT_OVL_SIZE * len(mount_points)
+ _ensure_enough_diskimage_space(space_needed, scratch_dir)
+
+ # free space required on this partition should not be affected by durin the
+ # upgrade transaction execution by space consumed on creation of disk images
+ # as disk images are cleaned in the end of this functions,
+ # but we want to reserve some space in advance.
+ scratch_disk_size = _get_fspace(scratch_dir, convert_to_mibs=True) - scratch_reserve
+
+ result = {}
+ for mountpoint in mount_points:
+ # keep the info about the free space rather 5% lower than the real value
+ disk_size = _get_fspace(mountpoint, convert_to_mibs=True, coefficient=0.95)
+ if mountpoint == scratch_mp:
+ disk_size = scratch_disk_size
+ image = _create_mount_disk_image(disk_images_directory, mountpoint, disk_size)
+ result[mountpoint] = mounting.LoopMount(
+ source=image,
+ target=_mount_dir(mounts_dir, mountpoint)
+ )
+ return result
+
+
@contextlib.contextmanager
def _build_overlay_mount(root_mount, mounts):
if not root_mount:
@@ -56,20 +315,151 @@ def _build_overlay_mount(root_mount, mounts):
def cleanup_scratch(scratch_dir, mounts_dir):
"""
Function to cleanup the scratch directory
+
+ If the mounts_dir is a mountpoint, unmount it first.
+
+ :param scratch_dir: Path to the scratch directory.
+ :type scratch_dir: str
+ :param mounts_dir: Path to the directory supposed to be a mountpoint.
+ :type mounts_dir: str
"""
api.current_logger().debug('Cleaning up mounts')
if os.path.ismount(mounts_dir):
+ # TODO(pstodulk): this is actually obsoleted for years. mounts dir
+ # is not mountpoit anymore, it contains mountpoints. But in time of
+ # this call all MPs should be already umounted as the solution has been
+ # changed also (all MPs are handled by context managers). This code
+ # is basically dead, so keeping it as it does not hurt us now.
api.current_logger().debug('Mounts directory is a mounted disk image - Unmounting.')
try:
run(['/bin/umount', '-fl', mounts_dir])
api.current_logger().debug('Unmounted mounted disk image.')
except (OSError, CalledProcessError) as e:
api.current_logger().warning('Failed to umount %s - message: %s', mounts_dir, str(e))
+ if get_env('LEAPP_DEVEL_KEEP_DISK_IMGS', None) == '1':
+ # NOTE(pstodulk): From time to time, it helps me with some experiments
+ return
api.current_logger().debug('Recursively removing scratch directory %s.', scratch_dir)
shutil.rmtree(scratch_dir, onerror=utils.report_and_ignore_shutil_rmtree_error)
api.current_logger().debug('Recursively removed scratch directory %s.', scratch_dir)
+def _format_disk_image_ext4(diskimage_path):
+ """
+ Format the specified disk image with Ext4 filesystem.
+
+ The formatted file system is optimized for operations we want to do and
+ mainly for the space it needs to take for the initialisation. So use 32MiB
+ journal (that's enough for us as we do not plan to do too many operations
+ inside) for any size of the disk image. Also the lazy
+ initialisation is disabled. The formatting will be slower, but it helps
+ us to estimate better the needed amount of the space for other actions
+ done later.
+ """
+ api.current_logger().debug('Creating ext4 filesystem in disk image at %s', diskimage_path)
+ cmd = [
+ '/sbin/mkfs.ext4',
+ '-J', 'size=32',
+ '-E', 'lazy_itable_init=0,lazy_journal_init=0',
+ '-F', diskimage_path
+ ]
+ try:
+ utils.call_with_oserror_handled(cmd=cmd)
+ except CalledProcessError as e:
+ # FIXME(pstodulk): taken from original, but %s seems to me invalid here
+ api.current_logger().error('Failed to create ext4 filesystem %s', diskimage_path, exc_info=True)
+ raise StopActorExecutionError(
+ message=str(e)
+ )
+
+
+def _format_disk_image_xfs(diskimage_path):
+ """
+ Format the specified disk image with XFS filesystem.
+
+ Set journal just to 32MiB always as we will not need to do too many operation
+ inside, so 32MiB should enough for us.
+ """
+ api.current_logger().debug('Creating XFS filesystem in disk image at %s', diskimage_path)
+ cmd = ['/sbin/mkfs.xfs', '-l', 'size=32m', '-f', diskimage_path]
+ try:
+ utils.call_with_oserror_handled(cmd=cmd)
+ except CalledProcessError as e:
+ # FIXME(pstodulk): taken from original, but %s seems to me invalid here
+ api.current_logger().error('Failed to create XFS filesystem %s', diskimage_path, exc_info=True)
+ raise StopActorExecutionError(
+ message=str(e)
+ )
+
+
+def _create_mount_disk_image(disk_images_directory, path, disk_size):
+ """
+ Creates the mount disk image and return path to it.
+
+ The disk image is represented by a sparse file which apparent size
+ corresponds usually to the free space of a particular partition/volume it
+ represents - in this function it's set by `disk_size` parameter, which should
+ be int representing the free space in MiBs.
+
+ The created disk image is formatted with XFS (default) or Ext4 FS
+ and it's supposed to be used for write directories of an overlayfs built
+ above it.
+
+ The disk image is formatted with Ext4 if (envar) `LEAPP_OVL_IMG_FS_EXT4=1`.
+
+ :param disk_images_directory: Path to the directory where disk images should be stored.
+ :type disk_images_directory: str
+ :param path: Path to the mountpoint of the original (host/source) partition/volume
+ :type path: str
+ :return: Path to the created disk image
+ :rtype: str
+ """
+ diskimage_path = os.path.join(disk_images_directory, _mount_name(path))
+ cmd = [
+ '/bin/dd',
+ 'if=/dev/zero', 'of={}'.format(diskimage_path),
+ 'bs=1M', 'count=0', 'seek={}'.format(disk_size)
+ ]
+ hint = (
+ 'Please ensure that there is enough diskspace on the partition hosting'
+ 'the {} directory.'
+ .format(disk_images_directory)
+ )
+
+ api.current_logger().debug('Attempting to create disk image at %s', diskimage_path)
+ utils.call_with_failure_hint(cmd=cmd, hint=hint)
+
+ if get_env('LEAPP_OVL_IMG_FS_EXT4', '0') == '1':
+ # This is alternative to XFS in case we find some issues, to be able
+ # to switch simply to Ext4, so we will be able to simple investigate
+ # possible issues between overlay <-> XFS if any happens.
+ _format_disk_image_ext4(diskimage_path)
+ else:
+ _format_disk_image_xfs(diskimage_path)
+
+ return diskimage_path
+
+
+def _create_diskimages_dir(scratch_dir, diskimages_dir):
+ """
+ Prepares directories for disk images
+ """
+ api.current_logger().debug('Creating disk images directory.')
+ try:
+ utils.makedirs(diskimages_dir)
+ api.current_logger().debug('Done creating disk images directory.')
+ except OSError:
+ api.current_logger().error('Failed to create disk images directory %s', diskimages_dir, exc_info=True)
+
+ # This is an attempt for giving the user a chance to resolve it on their own
+ raise StopActorExecutionError(
+ message='Failed to prepare environment for package download while creating directories.',
+ details={
+ 'hint': 'Please ensure that {scratch_dir} is empty and modifiable.'.format(scratch_dir=scratch_dir)
+ }
+ )
+
+
def _create_mounts_dir(scratch_dir, mounts_dir):
"""
Prepares directories for mounts
@@ -102,15 +492,59 @@ def _mount_dnf_cache(overlay_target):
@contextlib.contextmanager
-def create_source_overlay(mounts_dir, scratch_dir, xfs_info, storage_info, mount_target=None):
+def create_source_overlay(mounts_dir, scratch_dir, xfs_info, storage_info, mount_target=None, scratch_reserve=0):
"""
Context manager that prepares the source system overlay and yields the mount.
+
+ The in-place upgrade itself requires to do some changes on the system to be
+ able to perform the in-place upgrade itself - or even to be able to evaluate
+ if the system is possible to upgrade. However, we do not want to (and must not)
+ change the original system until we pass beyond the point of not return.
+
+ For that purposes we have to create a layer above the real host file system,
+ where we can safely perform all operations without affecting the system
+ setup, rpm database, etc. Currently overlay (OVL) technology showed it is
+ capable to handle our requirements good enough - with some limitations.
+
+ This function prepares a disk image and an overlay layer for each
+ mountpoint configured in /etc/fstab, excluding those with FS type noted
+ in the OVERLAY_DO_NOT_MOUNT set. Such prepared OVL images are then composed
+ together to reflect the real host filesystem. In the end everything is cleaned.
+
+ The new solution can be now problematic for system with too many partitions
+ and loop devices. For such systems we keep for now the possibility of the
+ fallback to an old solution, which has however number of issues that are
+ fixed by the new design. To fallback to the old solution, set envar:
+ LEAPP_OVL_LEGACY=1
+
+ Disk images created for OVL are formatted with XFS by default. In case of
+ problems, it's possible to switch to Ext4 FS using:
+ LEAPP_OVL_IMG_FS_EXT4=1
+
+ :param mounts_dir: Absolute path to the directory under which all mounts should happen.
+ :type mounts_dir: str
+ :param scratch_dir: Absolute path to the directory in which all disk and OVL images are stored.
+ :type scratch_dir: str
+ :param xfs_info: The XFSPresence message.
+ :type xfs_info: leapp.models.XFSPresence
+ :param storage_info: The StorageInfo message.
+ :type storage_info: leapp.models.StorageInfo
+ :param mount_target: Directory to which whole source OVL layer should be bind mounted.
+ If None (default), mounting.NullMount is created instead
+ :type mount_target: Optional[str]
+ :param scratch_reserve: Number of MB that should be extra reserved in a partition hosting the scratch_dir.
+ :type scratch_reserve: Optional[int]
+ :rtype: mounting.BindMount or mounting.NullMount
"""
api.current_logger().debug('Creating source overlay in {scratch_dir} with mounts in {mounts_dir}'.format(
scratch_dir=scratch_dir, mounts_dir=mounts_dir))
try:
_create_mounts_dir(scratch_dir, mounts_dir)
- mounts = _prepare_required_mounts_old(scratch_dir, mounts_dir, _get_mountpoints(storage_info), xfs_info)
+ if get_env('LEAPP_OVL_LEGACY', '0') != '1':
+ mounts = _prepare_required_mounts(scratch_dir, mounts_dir, storage_info, scratch_reserve)
+ else:
+ # fallback to the deprecated OVL solution
+ mounts = _prepare_required_mounts_old(scratch_dir, mounts_dir, _get_mountpoints(storage_info), xfs_info)
with mounts.pop('/') as root_mount:
with mounting.OverlayMount(name='system_overlay', source='/', workdir=root_mount.target) as root_overlay:
if mount_target:
@@ -124,6 +558,8 @@ def create_source_overlay(mounts_dir, scratch_dir, xfs_info, storage_info, mount
except Exception:
cleanup_scratch(scratch_dir, mounts_dir)
raise
+ # cleanup always now
+ cleanup_scratch(scratch_dir, mounts_dir)
# #############################################################################
@@ -133,6 +569,7 @@ def create_source_overlay(mounts_dir, scratch_dir, xfs_info, storage_info, mount
# negatively affect systems with many loop mountpoints, so let's keep this
# as a workaround for now. I am separating the old and new code in this way
# to make the future removal easy.
+# The code below is triggered when LEAPP_OVL_LEGACY=1 envar is set.
# IMPORTANT: Before an update of functions above, ensure the functionality of
# the code below is not affected, otherwise copy the function below with the
# "_old" suffix.
--
2.41.0

View File

@ -1,159 +0,0 @@
From 025b97088d30d5bd41a4d0b610cf2232ef150ece Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Fri, 14 Jul 2023 13:42:48 +0200
Subject: [PATCH 40/42] dnfplugin.py: Update err msgs and handle transaction
issues better
With the redesigned overlay solution, original error messages are
misleading. Keeping original error msgs when LEAPP_OVL_LEGACY=1.
Also handle better the error msgs generated when installing initramfs
dependencies. In case of the missing space the error has been
unhandled. Now it is handled with the correct msg also.
---
.../common/libraries/dnfplugin.py | 101 ++++++++++++++----
1 file changed, 80 insertions(+), 21 deletions(-)
diff --git a/repos/system_upgrade/common/libraries/dnfplugin.py b/repos/system_upgrade/common/libraries/dnfplugin.py
index fb0e8ae5..ffde211f 100644
--- a/repos/system_upgrade/common/libraries/dnfplugin.py
+++ b/repos/system_upgrade/common/libraries/dnfplugin.py
@@ -2,6 +2,7 @@ import contextlib
import itertools
import json
import os
+import re
import shutil
from leapp.exceptions import StopActorExecutionError
@@ -12,6 +13,7 @@ from leapp.libraries.stdlib import api, CalledProcessError, config
from leapp.models import DNFWorkaround
DNF_PLUGIN_NAME = 'rhel_upgrade.py'
+_DEDICATED_URL = 'https://access.redhat.com/solutions/7011704'
class _DnfPluginPathStr(str):
@@ -146,6 +148,75 @@ def backup_debug_data(context):
api.current_logger().warning('Failed to copy debugdata. Message: {}'.format(str(e)), exc_info=True)
+def _handle_transaction_err_msg_old(stage, xfs_info, err):
+ # NOTE(pstodulk): This is going to be removed in future!
+ message = 'DNF execution failed with non zero exit code.'
+ details = {'STDOUT': err.stdout, 'STDERR': err.stderr}
+
+ if 'more space needed on the' in err.stderr and stage != 'upgrade':
+ # Disk Requirements:
+ # At least <size> more space needed on the <path> filesystem.
+ #
+ article_section = 'Generic case'
+ if xfs_info.present and xfs_info.without_ftype:
+ article_section = 'XFS ftype=0 case'
+
+ message = ('There is not enough space on the file system hosting /var/lib/leapp directory '
+ 'to extract the packages.')
+ details = {'hint': "Please follow the instructions in the '{}' section of the article at: "
+ "link: https://access.redhat.com/solutions/5057391".format(article_section)}
+
+ raise StopActorExecutionError(message=message, details=details)
+
+
+def _handle_transaction_err_msg(stage, xfs_info, err, is_container=False):
+ # ignore the fallback when the error is related to the container issue
+ # e.g. installation of packages inside the container; so it's unrelated
+ # to the upgrade transactions.
+ if get_env('LEAPP_OVL_LEGACY', '0') == '1' and not is_container:
+ _handle_transaction_err_msg_old(stage, xfs_info, err)
+ return # not needed actually as the above function raises error, but for visibility
+ NO_SPACE_STR = 'more space needed on the'
+ message = 'DNF execution failed with non zero exit code.'
+ details = {'STDOUT': err.stdout, 'STDERR': err.stderr}
+ if NO_SPACE_STR not in err.stderr:
+ raise StopActorExecutionError(message=message, details=details)
+
+ # Disk Requirements:
+ # At least <size> more space needed on the <path> filesystem.
+ #
+ missing_space = [line.strip() for line in err.stderr.split('\n') if NO_SPACE_STR in line]
+ if is_container:
+ size_str = re.match(r'At least (.*) more space needed', missing_space[0]).group(1)
+ message = 'There is not enough space on the file system hosting /var/lib/leapp.'
+ hint = (
+ 'Increase the free space on the filesystem hosting'
+ ' /var/lib/leapp by {} at minimum. It is suggested to provide'
+ ' reasonably more space to be able to perform all planned actions'
+ ' (e.g. when 200MB is missing, add 1700MB or more).\n\n'
+ 'It is also a good practice to create dedicated partition'
+ ' for /var/lib/leapp when more space is needed, which can be'
+ ' dropped after the system upgrade is fully completed'
+ ' For more info, see: {}'
+ .format(size_str, _DEDICATED_URL)
+ )
+ # we do not want to confuse customers by the orig msg speaking about
+ # missing space on '/'. Skip the Disk Requirements section.
+ # The information is part of the hint.
+ details = {'hint': hint}
+ else:
+ message = 'There is not enough space on some file systems to perform the upgrade transaction.'
+ hint = (
+ 'Increase the free space on listed filesystems. Presented values'
+ ' are required minimum calculated by RPM and it is suggested to'
+ ' provide reasonably more free space (e.g. when 200 MB is missing'
+ ' on /usr, add 1200MB or more).'
+ )
+ details = {'hint': hint, 'Disk Requirements': '\n'.join(missing_space)}
+
+ raise StopActorExecutionError(message=message, details=details)
+
+
def _transaction(context, stage, target_repoids, tasks, plugin_info, xfs_info,
test=False, cmd_prefix=None, on_aws=False):
"""
@@ -219,26 +290,8 @@ def _transaction(context, stage, target_repoids, tasks, plugin_info, xfs_info,
message='Failed to execute dnf. Reason: {}'.format(str(e))
)
except CalledProcessError as e:
- api.current_logger().error('DNF execution failed: ')
-
- message = 'DNF execution failed with non zero exit code.'
- details = {'STDOUT': e.stdout, 'STDERR': e.stderr}
-
- if 'more space needed on the' in e.stderr:
- # The stderr contains this error summary:
- # Disk Requirements:
- # At least <size> more space needed on the <path> filesystem.
-
- article_section = 'Generic case'
- if xfs_info.present and xfs_info.without_ftype:
- article_section = 'XFS ftype=0 case'
-
- message = ('There is not enough space on the file system hosting /var/lib/leapp directory '
- 'to extract the packages.')
- details = {'hint': "Please follow the instructions in the '{}' section of the article at: "
- "link: https://access.redhat.com/solutions/5057391".format(article_section)}
-
- raise StopActorExecutionError(message=message, details=details)
+ api.current_logger().error('Cannot calculate, check, test, or perform the upgrade transaction.')
+ _handle_transaction_err_msg(stage, xfs_info, e, is_container=False)
finally:
if stage == 'check':
backup_debug_data(context=context)
@@ -307,7 +360,13 @@ def install_initramdisk_requirements(packages, target_userspace_info, used_repos
if get_target_major_version() == '9':
# allow handling new RHEL 9 syscalls by systemd-nspawn
env = {'SYSTEMD_SECCOMP': '0'}
- context.call(cmd, env=env)
+ try:
+ context.call(cmd, env=env)
+ except CalledProcessError as e:
+ api.current_logger().error(
+ 'Cannot install packages in the target container required to build the upgrade initramfs.'
+ )
+ _handle_transaction_err_msg('', None, e, is_container=True)
def perform_transaction_install(target_userspace_info, storage_info, used_repos, tasks, plugin_info, xfs_info):
--
2.41.0

View File

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

View File

@ -1,113 +0,0 @@
From 5015311197efe5f700e6d44cab7f3d49f50925c9 Mon Sep 17 00:00:00 2001
From: Petr Stodulka <pstodulk@redhat.com>
Date: Sat, 15 Jul 2023 20:20:25 +0200
Subject: [PATCH 42/42] targetuserspacecreator: Update err msg when installing
the container
Regarding the changes around source OVL, we need to update the error
msg properly in case the installation of the target userspace container
fails. In this case, we want to change only the part when the upgrade
fails due to missing space.
---
.../libraries/userspacegen.py | 61 +++++++++++++++----
1 file changed, 50 insertions(+), 11 deletions(-)
diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
index 8400dbe7..fdf873e1 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
@@ -1,5 +1,6 @@
import itertools
import os
+import re
import shutil
from leapp import reporting
@@ -55,6 +56,7 @@ from leapp.utils.deprecation import suppress_deprecation
PROD_CERTS_FOLDER = 'prod-certs'
GPG_CERTS_FOLDER = 'rpm-gpg'
PERSISTENT_PACKAGE_CACHE_DIR = '/var/lib/leapp/persistent_package_cache'
+DEDICATED_LEAPP_PART_URL = 'https://access.redhat.com/solutions/7011704'
def _check_deprecated_rhsm_skip():
@@ -172,6 +174,53 @@ def _import_gpg_keys(context, install_root_dir, target_major_version):
)
+def _handle_transaction_err_msg_size_old(err):
+ # NOTE(pstodulk): This is going to be removed in future!
+
+ article_section = 'Generic case'
+ xfs_info = next(api.consume(XFSPresence), XFSPresence())
+ if xfs_info.present and xfs_info.without_ftype:
+ article_section = 'XFS ftype=0 case'
+
+ message = ('There is not enough space on the file system hosting /var/lib/leapp directory '
+ 'to extract the packages.')
+ details = {'hint': "Please follow the instructions in the '{}' section of the article at: "
+ "link: https://access.redhat.com/solutions/5057391".format(article_section)}
+
+ raise StopActorExecutionError(message=message, details=details)
+
+
+def _handle_transaction_err_msg_size(err):
+ if get_env('LEAPP_OVL_LEGACY', '0') == '1':
+ _handle_transaction_err_msg_size_old(err)
+ return # not needed actually as the above function raises error, but for visibility
+ NO_SPACE_STR = 'more space needed on the'
+
+ # Disk Requirements:
+ # At least <size> more space needed on the <path> filesystem.
+ #
+ missing_space = [line.strip() for line in err.stderr.split('\n') if NO_SPACE_STR in line]
+ size_str = re.match(r'At least (.*) more space needed', missing_space[0]).group(1)
+ message = 'There is not enough space on the file system hosting /var/lib/leapp.'
+ hint = (
+ 'Increase the free space on the filesystem hosting'
+ ' /var/lib/leapp by {} at minimum. It is suggested to provide'
+ ' reasonably more space to be able to perform all planned actions'
+ ' (e.g. when 200MB is missing, add 1700MB or more).\n\n'
+ 'It is also a good practice to create dedicated partition'
+ ' for /var/lib/leapp when more space is needed, which can be'
+ ' dropped after the system upgrade is fully completed'
+ ' For more info, see: {}'
+ .format(size_str, DEDICATED_LEAPP_PART_URL)
+ )
+ # we do not want to confuse customers by the orig msg speaking about
+ # missing space on '/'. Skip the Disk Requirements section.
+ # The information is part of the hint.
+ details = {'hint': hint}
+
+ raise StopActorExecutionError(message=message, details=details)
+
+
def prepare_target_userspace(context, userspace_dir, enabled_repos, packages):
"""
Implement the creation of the target userspace.
@@ -210,21 +259,11 @@ def prepare_target_userspace(context, userspace_dir, enabled_repos, packages):
message = 'Unable to install RHEL {} userspace packages.'.format(target_major_version)
details = {'details': str(exc), 'stderr': exc.stderr}
- xfs_info = next(api.consume(XFSPresence), XFSPresence())
if 'more space needed on the' in exc.stderr:
# The stderr contains this error summary:
# Disk Requirements:
# At least <size> more space needed on the <path> filesystem.
-
- article_section = 'Generic case'
- if xfs_info.present and xfs_info.without_ftype:
- article_section = 'XFS ftype=0 case'
-
- message = ('There is not enough space on the file system hosting /var/lib/leapp directory '
- 'to extract the packages.')
- details = {'hint': "Please follow the instructions in the '{}' section of the article at: "
- "link: https://access.redhat.com/solutions/5057391".format(article_section)}
- raise StopActorExecutionError(message=message, details=details)
+ _handle_transaction_err_msg_size(exc)
# If a proxy was set in dnf config, it should be the reason why dnf
# failed since leapp does not support updates behind proxy yet.
--
2.41.0

View File

@ -41,8 +41,8 @@ py2_byte_compile "%1" "%2"}
# RHEL 8+ packages to be consistent with other leapp projects in future.
Name: leapp-repository
Version: 0.18.0
Release: 5%{?dist}
Version: 0.19.0
Release: 1%{?dist}
Summary: Repositories for leapp
License: ASL 2.0
@ -55,48 +55,6 @@ BuildArch: noarch
### PATCHES HERE
# Patch0001: filename.patch
Patch0001: 0001-Add-leapp-pkgs-rpm-verification-into-the-breadcrumbs.patch
Patch0002: 0002-Update-codespell-ignorelist-couldn-repositor.patch
Patch0003: 0003-Fix-dead-link-in-checkipaserver-actor.patch
Patch0004: 0004-checkhybridimage-Fix-the-produce-of-the-report.patch
Patch0005: 0005-Upgrade-packit.yaml-config-to-have-integration-tests.patch
Patch0006: 0006-Update-packit-config-to-match-the-leapp-repositoyr-t.patch
Patch0007: 0007-Add-new-environment-variable-to-8.8to9.2.patch
Patch0008: 0008-Stop-mentioning-the-releasever-file-removal.patch
Patch0009: 0009-Fix-trace-with-impossible-LEAPP_DEVEL_TARGET_RELEASE.patch
Patch0010: 0010-Make-copr-build-functioning-again.patch
Patch0011: 0011-Add-tag-in-packit.yaml-to-enable-cost-metrics-collec.patch
Patch0012: 0012-Workaround-packit-2010-issue.patch
Patch0013: 0013-Improve-the-checkgrubcore-report-message.patch
Patch0014: 0014-Update-pr-welcome-msg-with-packit-tests-info.patch
Patch0015: 0015-Further-tune-welcome-bot-message.patch
Patch0016: 0016-Remove-note-about-leapp-ci-build.patch
Patch0017: 0017-Fix-false-positive-non-utf-symlinks-reported.patch
Patch0018: 0018-Refactor-rootscanner-to-use-library.patch
Patch0019: 0019-update-.pylintrc.patch
Patch0020: 0020-Set-encoding-for-tests.patch
Patch0021: 0021-Introduce-leapp-data-in-the-RPM-repository.patch
Patch0022: 0022-Add-el8toel9-actor-to-handle-directory-symlink-with-.patch
Patch0023: 0023-Enable-8-9-upgrades-with-FIPS-enabled-1053.patch
Patch0024: 0024-Change-the-upgrade-paths-for-SAP-HANA.patch
Patch0025: 0025-Inhibit-unsupported-x86-64-microarchitecture-RHEL9.patch
Patch0026: 0026-Fix-doc-link-in-checktargetrepos.py.patch
Patch0027: 0027-Update-the-repomap.json-file-to-address-changes-in-R.patch
Patch0028: 0028-Add-prod-certs-and-upgrade-paths-for-8.9-9.3.patch
Patch0029: 0029-Update-leapp-data-files-1.1-2.0-and-requires-repomap.patch
Patch0030: 0030-el8toel9-Warn-about-deprecated-Xorg-drivers.patch
Patch0031: 0031-Add-possibility-to-add-kernel-drivers-to-initrd.patch
Patch0032: 0032-Use-correct-flag-and-ENV-var-to-disable-insights-reg.patch
Patch0033: 0033-CLI-Use-new-Leapp-output-APIs-reports-summary-better.patch
Patch0034: 0034-Update-Grub-on-component-drives-if-boot-is-on-md-dev.patch
Patch0035: 0035-mdraid.py-lib-Check-if-usr-sbin-mdadm-exists.patch
Patch0036: 0036-target_userspace_creator-Use-MOVE-instead-of-copy-fo.patch
Patch0037: 0037-overlay-lib-Deprecate-old-ovl-internal-functions-ref.patch
Patch0038: 0038-overlay-lib-replace-os.getenv-common.config.get_env.patch
Patch0039: 0039-overlay-lib-Redesign-creation-of-the-source-overlay-.patch
Patch0040: 0040-dnfplugin.py-Update-err-msgs-and-handle-transaction-.patch
Patch0041: 0041-upgradeinitramfsgenerator-Check-the-free-space-prior.patch
Patch0042: 0042-targetuserspacecreator-Update-err-msg-when-installin.patch
%description
@ -142,7 +100,7 @@ Requires: leapp-repository-dependencies = %{leapp_repo_deps}
# IMPORTANT: this is capability provided by the leapp framework rpm.
# Check that 'version' instead of the real framework rpm version.
Requires: leapp-framework >= 4.0
Requires: leapp-framework >= 5.0
# Since we provide sub-commands for the leapp utility, we expect the leapp
# tool to be installed as well.
@ -239,48 +197,6 @@ Requires: python3-gobject-base
# APPLY PATCHES HERE
# %%patch0001 -p1
%patch0001 -p1
%patch0002 -p1
%patch0003 -p1
%patch0004 -p1
%patch0005 -p1
%patch0006 -p1
%patch0007 -p1
%patch0008 -p1
%patch0009 -p1
%patch0010 -p1
%patch0011 -p1
%patch0012 -p1
%patch0013 -p1
%patch0014 -p1
%patch0015 -p1
%patch0016 -p1
%patch0017 -p1
%patch0018 -p1
%patch0019 -p1
%patch0020 -p1
%patch0021 -p1
%patch0022 -p1
%patch0023 -p1
%patch0024 -p1
%patch0025 -p1
%patch0026 -p1
%patch0027 -p1
%patch0028 -p1
%patch0029 -p1
%patch0030 -p1
%patch0031 -p1
%patch0032 -p1
%patch0033 -p1
%patch0034 -p1
%patch0035 -p1
%patch0036 -p1
%patch0037 -p1
%patch0038 -p1
%patch0039 -p1
%patch0040 -p1
%patch0041 -p1
%patch0042 -p1
%build
@ -358,6 +274,17 @@ done;
# no files here
%changelog
* Wed Aug 23 2023 Petr Stodulka <pstodulk@redhat.com> - 0.19.0-1
- Rebase to v0.19.0
- Requires leapp-framework 5.0
- Handle correctly the installed certificates to allow upgrades with custom repositories using HTTPs with enabled SSL verification
- Fix failing upgrades with devtmpfs file systems specified in FSTAB
- Do not try to update GRUB core on IBM Z systems
- Minor improvements and fixes of various reports and error messages
- Redesign handling of information about kernel (booted and target) to reflect changes in RHEL 9.3
- Use new leapp CLI API which provides better report summary output
- Resolves: rhbz#2215997, rhbz#2222861, rhbz#2232618
* Mon Jul 18 2023 Petr Stodulka <pstodulk@redhat.com> - 0.18.0-5
- Fix the calculation of the required free space on each partitions/volume for the upgrade transactions
- Create source overlay images with dynamic sizes to optimize disk space consumption

View File

@ -1,2 +1,2 @@
SHA512 (deps-pkgs-9.tar.gz) = 55593b4384b1fbfbf150585d2a124d9b0fdb8cb1e7449a372be5b2889b04fe72fc5cb567f9ee2b2a573d630b50e16f13467ad94596306fafad9658b9964fb84e
SHA512 (leapp-repository-0.18.0.tar.gz) = 2e9a9f2dd70fc337d59abe89abbae2823ae1e8bf5311f9a6b5ef101c03c78f0b954205f14e6bec89b371222c892c91db30f32408b576c4dcd298bc14dffe7512
SHA512 (leapp-repository-0.19.0.tar.gz) = e7e913cd635c8101dc5dcd65929d19a21ce72fd9291b84ea60a20e6dbdf4a65553c890770bf16000145f601242ed7f047cae1e283966c8b385ea9bf61e04ef65