leapp-repository/0026-rhui-bootstrap-target-rhui-clients-in-scratch-contai.patch

1739 lines
82 KiB
Diff
Raw Normal View History

From bbed72d18dabb9c47aed4f2e760ee637decc30f1 Mon Sep 17 00:00:00 2001
From: Michal Hecko <mhecko@redhat.com>
Date: Wed, 8 Mar 2023 12:41:03 +0100
Subject: [PATCH 26/38] rhui: bootstrap target rhui clients in scratch
container
In order to upgrade a RHUI system leapp uses custom `leapp-rhui-
X` packages providing leapp with necessary repository definitions as
well as certs and keys to access these repositories. The content of
the `leapp-rhui-X` packages is therefore almost identical to the RHUI
client(s) found on the target systems, implying that leapp's rhui
packages must actively mirror any changes to the target client packages.
This patch modifies leapp so that leapp uses the `leapp-rhui-X` package
only to provide a definion of the repository where a target RHUI client
can be found. The current RHUI client and target RHUI client is then
(bootstrapped) atomically swapped in the scratch container, allowing the
upgrade process to access target content. This change thus minimizes
the effort put into maintaining leapp-rhui-X.
This patch also does redesigns the "cloud map" to contain declarative
descriptions of setups, allowing to produce different the client
bootstrap steps if desired (not implemented). The new map also contains
information about content channel used on known rhui systems, laying the
necessary foundation for better error messages when the user forgets to
run leapp with --channel.
Finally, the RHUI-handling logic has been mostly isolated into a fully
unit-tested actor, whereas the implemented userspacegen modifications
have the nature of somehow blindly following the instructions produced
by the RHUI actor.
Jira: OAMG-8599
---
.../tests/test_checketcreleasever.py | 36 +-
.../libraries/checkhybridimage.py | 17 +-
.../common/actors/cloud/checkrhui/actor.py | 93 +----
.../cloud/checkrhui/libraries/checkrhui.py | 250 +++++++++++++
.../tests/component_test_checkrhui.py | 339 ++++++++++++++++--
.../libraries/pes_events_scanner.py | 5 +-
.../actors/redhatsignedrpmscanner/actor.py | 21 +-
.../tests/test_setetcreleasever.py | 25 +-
.../libraries/setuptargetrepos.py | 7 +-
.../libraries/userspacegen.py | 196 +++++++---
.../tests/unit_test_targetuserspacecreator.py | 7 +-
repos/system_upgrade/common/libraries/rhui.py | 266 ++++++++++++--
.../system_upgrade/common/models/rhuiinfo.py | 52 ++-
13 files changed, 1066 insertions(+), 248 deletions(-)
create mode 100644 repos/system_upgrade/common/actors/cloud/checkrhui/libraries/checkrhui.py
diff --git a/repos/system_upgrade/common/actors/checketcreleasever/tests/test_checketcreleasever.py b/repos/system_upgrade/common/actors/checketcreleasever/tests/test_checketcreleasever.py
index 82eb0847..1310ace2 100644
--- a/repos/system_upgrade/common/actors/checketcreleasever/tests/test_checketcreleasever.py
+++ b/repos/system_upgrade/common/actors/checketcreleasever/tests/test_checketcreleasever.py
@@ -4,13 +4,16 @@ import pytest
from leapp import reporting
from leapp.libraries.actor import checketcreleasever
-from leapp.libraries.common.testutils import (
- create_report_mocked,
- CurrentActorMocked,
- logger_mocked
-)
+from leapp.libraries.common.testutils import create_report_mocked, CurrentActorMocked, logger_mocked
from leapp.libraries.stdlib import api
-from leapp.models import PkgManagerInfo, Report, RHUIInfo
+from leapp.models import (
+ PkgManagerInfo,
+ Report,
+ RHUIInfo,
+ TargetRHUIPostInstallTasks,
+ TargetRHUIPreInstallTasks,
+ TargetRHUISetupInfo
+)
@pytest.mark.parametrize('exists', [True, False])
@@ -55,9 +58,24 @@ def test_etc_releasever_empty(monkeypatch):
assert api.current_logger.dbgmsg
+def mk_rhui_info():
+ preinstall_tasks = TargetRHUIPreInstallTasks()
+ postinstall_tasks = TargetRHUIPostInstallTasks()
+ setup_info = TargetRHUISetupInfo(preinstall_tasks=preinstall_tasks, postinstall_tasks=postinstall_tasks)
+ rhui_info = RHUIInfo(provider='aws',
+ src_client_pkg_names=['rh-amazon-rhui-client'],
+ target_client_pkg_names=['rh-amazon-rhui-client'],
+ target_client_setup_info=setup_info)
+ return rhui_info
+
+
@pytest.mark.parametrize('is_rhui', [True, False])
def test_etc_releasever_rhui(monkeypatch, is_rhui):
- rhui_msg = [RHUIInfo(provider='aws')] if is_rhui else []
+ if is_rhui:
+ rhui_msg = [mk_rhui_info()]
+ else:
+ rhui_msg = []
+
expected_rel_ver = '6.10'
mocked_report = create_report_mocked()
@@ -92,7 +110,9 @@ def test_etc_releasever_neither(monkeypatch):
def test_etc_releasever_both(monkeypatch):
- msgs = [RHUIInfo(provider='aws'), PkgManagerInfo(etc_releasever='7.7')]
+ rhui_info = mk_rhui_info()
+
+ msgs = [rhui_info, PkgManagerInfo(etc_releasever='7.7')]
expected_rel_ver = '6.10'
mocked_report = create_report_mocked()
diff --git a/repos/system_upgrade/common/actors/cloud/checkhybridimage/libraries/checkhybridimage.py b/repos/system_upgrade/common/actors/cloud/checkhybridimage/libraries/checkhybridimage.py
index e894683b..e2b7f5b2 100644
--- a/repos/system_upgrade/common/actors/cloud/checkhybridimage/libraries/checkhybridimage.py
+++ b/repos/system_upgrade/common/actors/cloud/checkhybridimage/libraries/checkhybridimage.py
@@ -2,6 +2,7 @@ import os
from leapp import reporting
from leapp.libraries.common import rhui
+from leapp.libraries.common.config.version import get_source_major_version
from leapp.libraries.common.rpms import has_package
from leapp.libraries.stdlib import api
from leapp.models import FirmwareFacts, HybridImage, InstalledRPM
@@ -20,8 +21,20 @@ def is_grubenv_symlink_to_efi():
def is_azure_agent_installed():
"""Check whether 'WALinuxAgent' package is installed."""
- upg_path = rhui.get_upg_path()
- agent_pkg = rhui.RHUI_CLOUD_MAP[upg_path].get('azure', {}).get('agent_pkg', '')
+ src_ver_major = get_source_major_version()
+
+ family = rhui.RHUIFamily(rhui.RHUIProvider.AZURE)
+ azure_setups = rhui.RHUI_SETUPS.get(family, [])
+
+ agent_pkg = None
+ for setup in azure_setups:
+ if setup.os_version == src_ver_major:
+ agent_pkg = setup.extra_info.get('agent_pkg')
+ break
+
+ if not agent_pkg:
+ return False
+
return has_package(InstalledRPM, agent_pkg)
diff --git a/repos/system_upgrade/common/actors/cloud/checkrhui/actor.py b/repos/system_upgrade/common/actors/cloud/checkrhui/actor.py
index 9cf69dad..593e73e5 100644
--- a/repos/system_upgrade/common/actors/cloud/checkrhui/actor.py
+++ b/repos/system_upgrade/common/actors/cloud/checkrhui/actor.py
@@ -1,11 +1,5 @@
-import os
-
-from leapp import reporting
from leapp.actors import Actor
-from leapp.libraries.common import rhsm, rhui
-from leapp.libraries.common.config.version import get_source_major_version
-from leapp.libraries.common.rpms import has_package
-from leapp.libraries.stdlib import api
+from leapp.libraries.actor import checkrhui as checkrhui_lib
from leapp.models import (
CopyFile,
DNFPluginTask,
@@ -16,7 +10,7 @@ from leapp.models import (
RpmTransactionTasks,
TargetUserSpacePreupgradeTasks
)
-from leapp.reporting import create_report, Report
+from leapp.reporting import Report
from leapp.tags import FactsPhaseTag, IPUWorkflowTag
@@ -40,85 +34,4 @@ class CheckRHUI(Actor):
tags = (FactsPhaseTag, IPUWorkflowTag)
def process(self):
- upg_path = rhui.get_upg_path()
- for provider, info in rhui.RHUI_CLOUD_MAP[upg_path].items():
- if has_package(InstalledRPM, info['src_pkg']):
- # we need to do this workaround in order to overcome our RHUI handling limitation
- # in case there are more client packages on the source system
- # @Note(mhecko): Azure has changed the structure of their images to not use a pair of RHUI clients and
- # # instead they started to use a single package. However, it could happen that a user
- # # does not run `dnf upgrade` and thus has both packages installed.
- if 'azure' in info['src_pkg']:
- azure_sap_variants = ['azure-sap-ha', 'azure-sap-apps']
- for azure_sap_variant in azure_sap_variants:
- sap_variant_info = rhui.RHUI_CLOUD_MAP[upg_path][azure_sap_variant]
- if has_package(InstalledRPM, sap_variant_info['src_pkg']):
- info = sap_variant_info
- provider = azure_sap_variant
-
- if provider.startswith('google'):
- rhui_dir = api.get_common_folder_path('rhui')
- repofile = os.path.join(rhui_dir, provider, 'leapp-{}.repo'.format(provider))
- api.produce(
- TargetUserSpacePreupgradeTasks(
- copy_files=[CopyFile(src=repofile, dst='/etc/yum.repos.d/leapp-google-copied.repo')]
- )
- )
-
- if not rhsm.skip_rhsm():
- create_report([
- reporting.Title('Upgrade initiated with RHSM on public cloud with RHUI infrastructure'),
- reporting.Summary(
- 'Leapp detected this system is on public cloud with RHUI infrastructure '
- 'but the process was initiated without "--no-rhsm" command line option '
- 'which implies RHSM usage (valid subscription is needed).'
- ),
- reporting.Severity(reporting.Severity.INFO),
- reporting.Groups([reporting.Groups.PUBLIC_CLOUD]),
- ])
- return
-
- # When upgrading with RHUI we cannot switch certs and let RHSM provide us repos for target OS content.
- # Instead, Leapp's provider-specific package containing target OS certs and repos has to be installed.
- if not has_package(InstalledRPM, info['leapp_pkg']):
- create_report([
- reporting.Title('Package "{}" is missing'.format(info['leapp_pkg'])),
- reporting.Summary(
- 'On {} using RHUI infrastructure, a package "{}" is needed for '
- 'in-place upgrade'.format(provider.upper(), info['leapp_pkg'])
- ),
- reporting.Severity(reporting.Severity.HIGH),
- reporting.RelatedResource('package', info['leapp_pkg']),
- reporting.Groups([reporting.Groups.INHIBITOR]),
- reporting.Groups([reporting.Groups.PUBLIC_CLOUD, reporting.Groups.RHUI]),
- reporting.Remediation(commands=[['yum', 'install', '-y', info['leapp_pkg']]])
- ])
- return
-
- # there are several "variants" related to the *AWS* provider (aws, aws-sap)
- if provider.startswith('aws'):
- # We have to disable Amazon-id plugin in the initramdisk phase as the network
- # is down at the time
- self.produce(DNFPluginTask(name='amazon-id', disable_in=['upgrade']))
-
- # If source OS and target OS packages differ we must remove the source pkg, and install the target pkg.
- # If the packages do not differ, it is sufficient to upgrade them during the upgrade
- if info['src_pkg'] != info['target_pkg']:
- self.produce(RpmTransactionTasks(to_install=[info['target_pkg']]))
- self.produce(RpmTransactionTasks(to_remove=[info['src_pkg']]))
-
- # Although SAP systems on Azure should not rely on a pair of RHUI clients, it is still possible
- # that the source system has both clients installed, and it is safer to remove both of them.
- azure_nonsap_pkg = None
- if provider == 'azure-sap-ha':
- azure_nonsap_pkg = rhui.RHUI_CLOUD_MAP[upg_path]['azure']['src_pkg']
- elif provider == 'azure-sap-apps':
- # SAP Apps systems have EUS content channel from RHEL8+
- src_rhel_content_type = 'azure' if get_source_major_version() == '7' else 'azure-eus'
- azure_nonsap_pkg = rhui.RHUI_CLOUD_MAP[upg_path][src_rhel_content_type]['src_pkg']
- if azure_nonsap_pkg and has_package(InstalledRPM, azure_nonsap_pkg):
- self.produce(RpmTransactionTasks(to_remove=[azure_nonsap_pkg]))
-
- self.produce(RHUIInfo(provider=provider))
- self.produce(RequiredTargetUserspacePackages(packages=[info['target_pkg']]))
- return
+ checkrhui_lib.process()
diff --git a/repos/system_upgrade/common/actors/cloud/checkrhui/libraries/checkrhui.py b/repos/system_upgrade/common/actors/cloud/checkrhui/libraries/checkrhui.py
new file mode 100644
index 00000000..84ab40e3
--- /dev/null
+++ b/repos/system_upgrade/common/actors/cloud/checkrhui/libraries/checkrhui.py
@@ -0,0 +1,250 @@
+import itertools
+import os
+from collections import namedtuple
+
+from leapp import reporting
+from leapp.exceptions import StopActorExecutionError
+from leapp.libraries.common import rhsm, rhui
+from leapp.libraries.common.config import version
+from leapp.libraries.stdlib import api
+from leapp.models import (
+ CopyFile,
+ DNFPluginTask,
+ InstalledRPM,
+ RHUIInfo,
+ RpmTransactionTasks,
+ TargetRHUIPostInstallTasks,
+ TargetRHUIPreInstallTasks,
+ TargetRHUISetupInfo,
+ TargetUserSpacePreupgradeTasks
+)
+
+MatchingSetup = namedtuple('MatchingSetup', ['family', 'description'])
+
+
+def into_set(pkgs):
+ if isinstance(pkgs, set):
+ return pkgs
+ if isinstance(pkgs, str):
+ return {pkgs}
+ return set(pkgs)
+
+
+def find_rhui_setup_matching_src_system(installed_pkgs, rhui_map):
+ src_ver = version.get_source_major_version()
+ arch = api.current_actor().configuration.architecture
+
+ matching_setups = []
+ for rhui_family, family_setups in rhui_map.items():
+ if rhui_family.arch != arch:
+ continue
+
+ for setup in family_setups:
+ if setup.os_version != src_ver:
+ continue
+ if setup.clients.issubset(installed_pkgs):
+ matching_setups.append(MatchingSetup(family=rhui_family, description=setup))
+
+ if not matching_setups:
+ return None
+
+ # In case that a RHUI variant uses a combination of clients identify the maximal client set
+ matching_setups_by_size = sorted(matching_setups, key=lambda match: -len(match.description.clients))
+
+ match = matching_setups_by_size[0] # Matching setup with the highest number of clients
+ if len(matching_setups) == 1:
+ return match
+
+ if len(matching_setups_by_size[0].description.clients) == len(matching_setups_by_size[1].description.clients):
+ # Should not happen as no cloud providers use multi-client setups (at the moment)
+ msg = 'Could not identify the source RHUI setup (ambiguous setup)'
+
+ variant_detail_table = {
+ rhui.RHUIVariant.ORDINARY: '',
+ rhui.RHUIVariant.SAP: ' for SAP',
+ rhui.RHUIVariant.SAP_APPS: ' for SAP Applications',
+ rhui.RHUIVariant.SAP_HA: ' for SAP HA',
+ }
+
+ match0 = matching_setups_by_size[0]
+ variant0_detail = variant_detail_table[match0.family.variant]
+ clients0 = ' '.join(match0.description.clients)
+
+ match1 = matching_setups_by_size[1]
+ variant1_detail = variant_detail_table[match1.family.variant]
+ clients1 = ' '.join(match1.description.clients)
+
+ details = ('Leapp uses client-based identification of the used RHUI setup in order to determine what the '
+ 'target RHEL content should be. According to the installed RHUI clients the system should be '
+ 'RHEL {os_major}{variant0_detail} ({provider0}) (identified by clients {clients0}) but also '
+ 'RHEL {os_major}{variant1_detail} ({provider1}) (identified by clients {clients1}).')
+ details = details.format(os_major=version.get_source_major_version(),
+ variant0_detail=variant0_detail, clients0=clients0, provider0=match0.family.provider,
+ variant1_detail=variant1_detail, clients1=clients1, provider1=match1.family.provider)
+
+ raise StopActorExecutionError(message=msg, details={'details': details})
+
+ return match
+
+
+def determine_target_setup_desc(cloud_map, rhui_family):
+ variant_setups = cloud_map[rhui_family]
+ target_major = version.get_target_major_version()
+
+ for setup in variant_setups:
+ if setup.os_version == target_major:
+ return setup
+ return None
+
+
+def inhibit_if_leapp_pkg_to_access_target_missing(installed_pkgs, rhui_family, target_setup_desc):
+ pkg_name = target_setup_desc.leapp_pkg
+
+ if pkg_name not in installed_pkgs:
+ summary = 'On {provider} the "{pkg}" is required to perform an in-place upgrade'
+ summary = summary.format(provider=rhui_family.provider, pkg=pkg_name)
+ reporting.create_report([
+ reporting.Title('Package "{}" is not installed'.format(pkg_name)),
+ reporting.Summary(summary),
+ reporting.Severity(reporting.Severity.HIGH),
+ reporting.RelatedResource('package', pkg_name),
+ reporting.Groups([reporting.Groups.INHIBITOR]),
+ reporting.Groups([reporting.Groups.PUBLIC_CLOUD, reporting.Groups.RHUI]),
+ reporting.Remediation(commands=[['yum', 'install', '-y', pkg_name]])
+ ])
+ return True
+ return False
+
+
+def stop_due_to_unknown_target_system_setup(rhui_family):
+ msg = 'Failed to identify target RHUI setup'
+ variant_detail = ' ({rhui_family.variant})' if rhui_family.variant != rhui.RHUIVariant.ORDINARY else ''
+ details = ('Leapp successfully identified the current RHUI setup as a system provided by '
+ '{provider}{variant_detail}, but it failed to determine'
+ ' equivalent RHUI setup for the target OS.')
+ details = details.format(provider=rhui_family.provider, variant_detail=variant_detail)
+ raise StopActorExecutionError(message=msg, details={'details': details})
+
+
+def customize_rhui_setup_for_gcp(rhui_family, setup_info):
+ if not rhui_family.provider == rhui.RHUIProvider.GOOGLE:
+ return
+
+ # The google-cloud.repo repofile provides the repository containing the target clients. However, its repoid is the
+ # same across all rhel versions, therefore, we need to remove the source google-cloud.repo to enable
+ # correct target one.
+ setup_info.preinstall_tasks.files_to_remove.append('/etc/yum.repos.d/google-cloud.repo')
+
+
+def customize_rhui_setup_for_aws(rhui_family, setup_info):
+ if rhui_family.provider != rhui.RHUIProvider.AWS:
+ return
+
+ target_version = version.get_target_major_version()
+ if target_version == '8':
+ return # The rhel8 plugin is packed into leapp-rhui-aws as we need python2 compatible client
+
+ amazon_plugin_copy_task = CopyFile(src='/usr/lib/python3.9/site-packages/dnf-plugins/amazon-id.py',
+ dst='/usr/lib/python3.6/site-packages/dnf-plugins/')
+ setup_info.postinstall_tasks.files_to_copy.append(amazon_plugin_copy_task)
+
+
+def produce_rhui_info_to_setup_target(rhui_family, source_setup_desc, target_setup_desc):
+ rhui_files_location = os.path.join(api.get_common_folder_path('rhui'), rhui_family.client_files_folder)
+
+ files_to_access_target_client_repo = []
+ for filename, target_path in target_setup_desc.mandatory_files:
+ src_path = os.path.join(rhui_files_location, filename)
+ files_to_access_target_client_repo.append(CopyFile(src=src_path, dst=target_path))
+
+ for filename, target_path in target_setup_desc.optional_files:
+ src_path = os.path.join(rhui_files_location, filename)
+
+ if not os.path.exists(src_path):
+ msg = "Optional file {} is present, will be used to setup target RHUI."
+ api.current_logger().debug(msg.format(src_path))
+ continue
+
+ files_to_access_target_client_repo.append(CopyFile(src=src_path, dst=target_path))
+
+ preinstall_tasks = TargetRHUIPreInstallTasks(files_to_copy_into_overlay=files_to_access_target_client_repo)
+
+ files_supporting_client_operation = sorted(
+ os.path.join(rhui_files_location, file) for file in target_setup_desc.files_supporting_client_operation
+ )
+
+ target_client_setup_info = TargetRHUISetupInfo(
+ preinstall_tasks=preinstall_tasks,
+ postinstall_tasks=TargetRHUIPostInstallTasks(),
+ files_supporting_client_operation=files_supporting_client_operation
+ )
+
+ customize_rhui_setup_for_gcp(rhui_family, target_client_setup_info)
+ customize_rhui_setup_for_aws(rhui_family, target_client_setup_info)
+
+ rhui_info = RHUIInfo(
+ provider=rhui_family.provider.lower(),
+ variant=rhui_family.variant,
+ src_client_pkg_names=sorted(source_setup_desc.clients),
+ target_client_pkg_names=sorted(target_setup_desc.clients),
+ target_client_setup_info=target_client_setup_info
+ )
+ api.produce(rhui_info)
+
+
+def produce_rpms_to_install_into_target(source_setup, target_setup):
+ to_install = sorted(target_setup.clients - source_setup.clients)
+ to_remove = sorted(source_setup.clients - target_setup.clients)
+
+ api.produce(TargetUserSpacePreupgradeTasks(install_rpms=sorted(target_setup.clients)))
+ if to_install or to_remove:
+ api.produce(RpmTransactionTasks(to_install=to_install, to_remove=to_remove))
+
+
+def inform_about_upgrade_with_rhui_without_no_rhsm():
+ if not rhsm.skip_rhsm():
+ reporting.create_report([
+ reporting.Title('Upgrade initiated with RHSM on public cloud with RHUI infrastructure'),
+ reporting.Summary(
+ 'Leapp detected this system is on public cloud with RHUI infrastructure '
+ 'but the process was initiated without "--no-rhsm" command line option '
+ 'which implies RHSM usage (valid subscription is needed).'
+ ),
+ reporting.Severity(reporting.Severity.INFO),
+ reporting.Groups([reporting.Groups.PUBLIC_CLOUD]),
+ ])
+ return True
+ return False
+
+
+def process():
+ installed_rpm = itertools.chain(*[installed_rpm_msg.items for installed_rpm_msg in api.consume(InstalledRPM)])
+ installed_pkgs = {rpm.name for rpm in installed_rpm}
+
+ src_rhui_setup = find_rhui_setup_matching_src_system(installed_pkgs, rhui.RHUI_SETUPS)
+ if not src_rhui_setup:
+ return
+ api.current_logger().debug("The RHUI family of the source system is {}".format(src_rhui_setup.family))
+
+ target_setup_desc = determine_target_setup_desc(rhui.RHUI_SETUPS, src_rhui_setup.family)
+
+ if not target_setup_desc:
+ # We know that we are on RHUI because we have identified what RHUI variant it is, but we don't know how does
+ # the target system look like. Likely, our knowledge of what RHUI setups are there (RHUI_SETUPS) is incomplete.
+ stop_due_to_unknown_target_system_setup(src_rhui_setup.family)
+ return
+
+ if inform_about_upgrade_with_rhui_without_no_rhsm():
+ return
+
+ if inhibit_if_leapp_pkg_to_access_target_missing(installed_pkgs, src_rhui_setup.family, target_setup_desc):
+ return
+
+ # Instruction on how to access the target content
+ produce_rhui_info_to_setup_target(src_rhui_setup.family, src_rhui_setup.description, target_setup_desc)
+
+ produce_rpms_to_install_into_target(src_rhui_setup.description, target_setup_desc)
+
+ if src_rhui_setup.family.provider == rhui.RHUIProvider.AWS:
+ # We have to disable Amazon-id plugin in the initramdisk phase as there is no network
+ api.produce(DNFPluginTask(name='amazon-id', disable_in=['upgrade']))
diff --git a/repos/system_upgrade/common/actors/cloud/checkrhui/tests/component_test_checkrhui.py b/repos/system_upgrade/common/actors/cloud/checkrhui/tests/component_test_checkrhui.py
index fde5ea72..93f13a00 100644
--- a/repos/system_upgrade/common/actors/cloud/checkrhui/tests/component_test_checkrhui.py
+++ b/repos/system_upgrade/common/actors/cloud/checkrhui/tests/component_test_checkrhui.py
@@ -1,60 +1,329 @@
from collections import namedtuple
+from enum import Enum
import pytest
-from leapp.libraries.common import rhsm
-from leapp.libraries.common.config import mock_configs
+from leapp import reporting
+from leapp.exceptions import StopActorExecutionError
+from leapp.libraries.actor import checkrhui as checkrhui_lib
+from leapp.libraries.common import rhsm, rhui
+from leapp.libraries.common.config import mock_configs, version
+from leapp.libraries.common.rhui import mk_rhui_setup, RHUIFamily
+from leapp.libraries.common.testutils import create_report_mocked, CurrentActorMocked, produce_mocked
+from leapp.libraries.stdlib import api
from leapp.models import (
+ CopyFile,
InstalledRedHatSignedRPM,
InstalledRPM,
RequiredTargetUserspacePackages,
RHUIInfo,
- RPM
+ RPM,
+ RpmTransactionTasks,
+ TargetRHUIPostInstallTasks,
+ TargetRHUIPreInstallTasks,
+ TargetRHUISetupInfo,
+ TargetUserSpacePreupgradeTasks
)
from leapp.reporting import Report
from leapp.snactor.fixture import current_actor_context
RH_PACKAGER = 'Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla>'
-NO_RHUI = [
- RPM(name='yolo', version='0.1', release='1.sm01', epoch='1', packager=RH_PACKAGER, arch='noarch',
- pgpsig='RSA/SHA256, Mon 01 Jan 1970 00:00:00 AM -03, Key ID 199e2f91fd431d51'),
-]
-ON_AWS_WITHOUT_LEAPP_PKG = [
- RPM(name='rh-amazon-rhui-client', version='0.1', release='1.sm01', epoch='1', packager=RH_PACKAGER,
- arch='noarch', pgpsig='RSA/SHA256, Mon 01 Jan 1970 00:00:00 AM -03, Key ID 199e2f91fd431d51'),
-]
+def mk_pkg(name):
+ return RPM(name=name, version='0.1', release='1.sm01', epoch='1', packager=RH_PACKAGER, arch='noarch',
+ pgpsig='RSA/SHA256, Mon 01 Jan 1970 00:00:00 AM -03, Key ID 199e2f91fd431d51')
-ON_AWS_WITH_LEAPP_PKG = [
- RPM(name='rh-amazon-rhui-client', version='0.1', release='1.sm01', epoch='1', packager=RH_PACKAGER,
- arch='noarch', pgpsig='RSA/SHA256, Mon 01 Jan 1970 00:00:00 AM -03, Key ID 199e2f91fd431d51'),
- RPM(name='leapp-rhui-aws', version='0.1', release='1.sm01', epoch='1', packager=RH_PACKAGER,
- arch='noarch', pgpsig='RSA/SHA256, Mon 01 Jan 1970 00:00:00 AM -03, Key ID 199e2f91fd431d51')
-]
+def mk_setup_info():
+ pre_tasks = TargetRHUIPreInstallTasks()
+ post_tasks = TargetRHUIPostInstallTasks()
+ return TargetRHUISetupInfo(preinstall_tasks=pre_tasks, postinstall_tasks=post_tasks)
-def create_modulesfacts(installed_rpm):
- return InstalledRPM(items=installed_rpm)
+def iter_known_rhui_setups():
+ for upgrade_path, providers in rhui.RHUI_CLOUD_MAP.items():
+ for provider_variant, variant_description in providers.items():
+ src_clients = variant_description['src_pkg']
+ if isinstance(src_clients, str):
+ src_clients = {src_clients, }
-msgs_received = namedtuple('MsgsReceived', ['report', 'rhui_info', 'req_target_userspace'])
+ yield provider_variant, upgrade_path, src_clients
-@pytest.mark.parametrize('skip_rhsm, msgs_received, installed_rpms', [
- (False, msgs_received(False, False, False), NO_RHUI),
- (True, msgs_received(True, False, False), ON_AWS_WITHOUT_LEAPP_PKG),
- (True, msgs_received(False, True, True), ON_AWS_WITH_LEAPP_PKG),
- (False, msgs_received(True, False, False), ON_AWS_WITH_LEAPP_PKG)
-])
-def test_check_rhui_actor(
- monkeypatch, current_actor_context, skip_rhsm, msgs_received, installed_rpms
-):
+def mk_cloud_map(variants):
+ upg_path = {}
+ for variant_desc in variants:
+ provider, desc = next(iter(variant_desc.items()))
+ upg_path[provider] = desc
+ return upg_path
+
+
+@pytest.mark.parametrize(
+ ('extra_pkgs', 'rhui_setups', 'expected_result'),
+ [
+ (
+ ['client'],
+ {RHUIFamily('provider'): [mk_rhui_setup(clients={'client'})]},
+ RHUIFamily('provider')
+ ),
+ (
+ ['client'],
+ {RHUIFamily('provider'): [mk_rhui_setup(clients={'missing_client'})]},
+ None
+ ),
+ (
+ ['clientA', 'clientB'],
+ {RHUIFamily('provider'): [mk_rhui_setup(clients={'clientB'})]},
+ RHUIFamily('provider')
+ ),
+ (
+ ['clientA', 'clientB'],
+ {
+ RHUIFamily('provider'): [mk_rhui_setup(clients={'clientA'})],
+ RHUIFamily('provider+'): [mk_rhui_setup(clients={'clientA', 'clientB'})],
+ },
+ RHUIFamily('provider+')
+ ),
+ (
+ ['client'],
+ {
+ RHUIFamily('providerA'): [mk_rhui_setup(clients={'client'})],
+ RHUIFamily('providerB'): [mk_rhui_setup(clients={'client'})],
+ },
+ StopActorExecutionError
+ ),
+ ]
+)
+def test_determine_rhui_src_variant(monkeypatch, extra_pkgs, rhui_setups, expected_result):
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(src_ver='7.9'))
+ installed_pkgs = {'zip', 'zsh', 'bash', 'grubby'}.union(set(extra_pkgs))
+
+ if expected_result and not isinstance(expected_result, RHUIFamily): # An exception
+ with pytest.raises(expected_result) as err:
+ checkrhui_lib.find_rhui_setup_matching_src_system(installed_pkgs, rhui_setups)
+ assert 'ambiguous' in str(err)
+ return
+
+ variant_setup_pair = checkrhui_lib.find_rhui_setup_matching_src_system(installed_pkgs, rhui_setups)
+ if not expected_result:
+ assert variant_setup_pair == expected_result
+ else:
+ variant = variant_setup_pair[0]
+ assert variant == expected_result
+
+
+@pytest.mark.parametrize(
+ ('extra_pkgs', 'target_rhui_setup', 'should_inhibit'),
+ [
+ (['pkg'], mk_rhui_setup(leapp_pkg='pkg'), False),
+ ([], mk_rhui_setup(leapp_pkg='pkg'), True),
+ ]
+)
+def test_inhibit_on_missing_leapp_rhui_pkg(monkeypatch, extra_pkgs, target_rhui_setup, should_inhibit):
+ installed_pkgs = set(['bash', 'zsh', 'zip'] + extra_pkgs)
+ monkeypatch.setattr(reporting, 'create_report', create_report_mocked())
+ checkrhui_lib.inhibit_if_leapp_pkg_to_access_target_missing(installed_pkgs,
+ RHUIFamily('rhui-variant'),
+ target_rhui_setup)
+ assert bool(reporting.create_report.called) == should_inhibit
+
+
+def are_setup_infos_eq(actual, expected):
+ eq = True
+ eq &= actual.enable_only_repoids_in_copied_files == expected.enable_only_repoids_in_copied_files
+ eq &= actual.files_supporting_client_operation == expected.files_supporting_client_operation
+ eq &= actual.preinstall_tasks.files_to_remove == expected.preinstall_tasks.files_to_remove
+ eq &= actual.preinstall_tasks.files_to_copy_into_overlay == expected.preinstall_tasks.files_to_copy_into_overlay
+ eq &= actual.postinstall_tasks.files_to_copy == expected.postinstall_tasks.files_to_copy
+ return eq
+
+
+@pytest.mark.parametrize(
+ ('provider', 'should_mutate'),
+ [
+ (RHUIFamily(rhui.RHUIProvider.GOOGLE), True),
+ (RHUIFamily(rhui.RHUIProvider.GOOGLE, variant=rhui.RHUIVariant.SAP), True),
+ (RHUIFamily('azure'), False),
+ ]
+)
+def test_google_specific_customization(provider, should_mutate):
+ setup_info = mk_setup_info()
+ checkrhui_lib.customize_rhui_setup_for_gcp(provider, setup_info)
+
+ if should_mutate:
+ assert setup_info != mk_setup_info()
+ else:
+ assert setup_info == mk_setup_info()
+
+
+@pytest.mark.parametrize(
+ ('rhui_family', 'target_major', 'should_mutate'),
+ [
+ (RHUIFamily(rhui.RHUIProvider.AWS), '8', False),
+ (RHUIFamily(rhui.RHUIProvider.AWS), '9', True),
+ (RHUIFamily(rhui.RHUIProvider.AWS, variant=rhui.RHUIVariant.SAP), '9', True),
+ (RHUIFamily('azure'), '9', False),
+ ]
+)
+def test_aws_specific_customization(monkeypatch, rhui_family, target_major, should_mutate):
+ dst_ver = '{major}.0'.format(major=target_major)
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(dst_ver=dst_ver))
+
+ setup_info = mk_setup_info()
+ checkrhui_lib.customize_rhui_setup_for_aws(rhui_family, setup_info)
+
+ was_mutated = not are_setup_infos_eq(setup_info, mk_setup_info())
+ assert should_mutate == was_mutated
+
+
+def produce_rhui_info_to_setup_target(monkeypatch):
+ source_rhui_setup = mk_rhui_setup(
+ clients={'src_pkg'},
+ leapp_pkg='leapp_pkg',
+ mandatory_files=[('src_file1', '/etc'), ('src_file2', '/var')],
+ )
+
+ target_rhui_setup = mk_rhui_setup(
+ clients={'target_pkg'},
+ leapp_pkg='leapp_pkg',
+ mandatory_files=[('target_file1', '/etc'), ('target_file2', '/var')],
+ )
+
+ monkeypatch.setattr(api, 'get_common_folder_path', lambda dummy: 'common_folder')
+ monkeypatch.setattr(api, 'produce', produce_mocked())
+
+ checkrhui_lib.produce_rhui_info_to_setup_target('provider', source_rhui_setup, target_rhui_setup)
+
+ assert len(api.produce.model_instances) == 1
+
+ rhui_info = api.produce.model_instances[0]
+ assert rhui_info.provider == 'provider'
+ assert rhui_info.src_client_pkg_names == ['src_pkg']
+ assert rhui_info.target_client_pkg_names == ['target_pkg']
+
+ setup_info = rhui_info.target_client_setup_info
+
+ expected_copies = {
+ ('common_folder/provider/target_file1', '/etc'),
+ ('common_folder/provider/target_file2', '/var')
+ }
+ actual_copies = {(instr.src, instr.dst) for instr in setup_info.preinstall_tasks.files_to_copy_in}
+
+ assert expected_copies == actual_copies
+
+ assert not setup_info.postinstall_tasks.files_to_copy
+
+
+def test_produce_rpms_to_install_into_target(monkeypatch):
+ source_rhui_setup = mk_rhui_setup(clients={'src_pkg'}, leapp_pkg='leapp_pkg')
+ target_rhui_setup = mk_rhui_setup(clients={'target_pkg'}, leapp_pkg='leapp_pkg')
+
+ monkeypatch.setattr(api, 'produce', produce_mocked())
+
+ checkrhui_lib.produce_rpms_to_install_into_target(source_rhui_setup, target_rhui_setup)
+
+ assert len(api.produce.model_instances) == 2
+ userspace_tasks, target_rpm_tasks = api.produce.model_instances[0], api.produce.model_instances[1]
+
+ if isinstance(target_rpm_tasks, TargetUserSpacePreupgradeTasks):
+ userspace_tasks, target_rpm_tasks = target_rpm_tasks, userspace_tasks
+
+ assert 'target_pkg' in target_rpm_tasks.to_install
+ assert 'src_pkg' in target_rpm_tasks.to_remove
+ assert 'target_pkg' in userspace_tasks.install_rpms
+
+
+@pytest.mark.parametrize('skip_rhsm', (True, False))
+def test_inform_about_upgrade_with_rhui_without_no_rhsm(monkeypatch, skip_rhsm):
+ monkeypatch.setattr(rhsm, 'skip_rhsm', lambda: skip_rhsm)
+ monkeypatch.setattr(reporting, 'create_report', create_report_mocked())
+
+ checkrhui_lib.inform_about_upgrade_with_rhui_without_no_rhsm()
+
+ assert bool(reporting.create_report.called) is not skip_rhsm
+
+
+class ExpectedAction(Enum):
+ NOTHING = 1 # Actor should not produce anything
+ INHIBIT = 2
+ PRODUCE = 3 # Actor should produce RHUI related info
+
+
+# Scenarios to cover:
+# 1. source client + NO_RHSM -> RPMs are produced, and setup info is produced
+# 2. source client -> inhibit
+# 3. leapp pkg missing -> inhibit
+@pytest.mark.parametrize(
+ ('extra_installed_pkgs', 'skip_rhsm', 'expected_action'),
+ [
+ (['src_pkg', 'leapp_pkg'], True, ExpectedAction.PRODUCE), # Everything OK
+ (['src_pkg', 'leapp_pkg'], False, ExpectedAction.INHIBIT), # No --no-rhsm
+ (['src_pkg'], True, ExpectedAction.INHIBIT), # Missing leapp-rhui package
+ ([], True, ExpectedAction.NOTHING) # Not a RHUI system
+ ]
+)
+def test_process(monkeypatch, extra_installed_pkgs, skip_rhsm, expected_action):
+ known_setups = {
+ RHUIFamily('rhui-variant'): [
+ mk_rhui_setup(clients={'src_pkg'}, os_version='7'),
+ mk_rhui_setup(clients={'target_pkg'}, os_version='8', leapp_pkg='leapp_pkg',
+ mandatory_files=[('file1', '/etc'), ('file2', '/var')]),
+ ]
+ }
+
+ installed_pkgs = {'zip', 'kernel-core', 'python'}.union(set(extra_installed_pkgs))
+ installed_pkgs = [mk_pkg(pkg_name) for pkg_name in installed_pkgs]
+ installed_rpms = InstalledRPM(items=installed_pkgs)
+
+ monkeypatch.setattr(api, 'produce', produce_mocked())
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(src_ver='7.9', msgs=[installed_rpms]))
+ monkeypatch.setattr(reporting, 'create_report', create_report_mocked())
monkeypatch.setattr(rhsm, 'skip_rhsm', lambda: skip_rhsm)
+ monkeypatch.setattr(rhui, 'RHUI_SETUPS', known_setups)
+
+ checkrhui_lib.process()
+
+ if expected_action == ExpectedAction.NOTHING:
+ assert not api.produce.called
+ assert not reporting.create_report.called
+ elif expected_action == ExpectedAction.INHIBIT:
+ assert not api.produce.called
+ assert len(reporting.create_report.reports) == 1
+ else: # expected_action = ExpectedAction.PRODUCE
+ assert not reporting.create_report.called
+ assert len(api.produce.model_instances) == 3
+ assert any(isinstance(pkg, RpmTransactionTasks) for pkg in api.produce.model_instances)
+ assert any(isinstance(pkg, RHUIInfo) for pkg in api.produce.model_instances)
+ assert any(isinstance(pkg, TargetUserSpacePreupgradeTasks) for pkg in api.produce.model_instances)
+
+
+@pytest.mark.parametrize('is_target_setup_known', (False, True))
+def test_unknown_target_rhui_setup(monkeypatch, is_target_setup_known):
+ rhui_family = RHUIFamily('rhui-variant')
+ known_setups = {
+ rhui_family: [
+ mk_rhui_setup(clients={'src_pkg'}, os_version='7'),
+ ]
+ }
+
+ if is_target_setup_known:
+ target_setup = mk_rhui_setup(clients={'target_pkg'}, os_version='8', leapp_pkg='leapp_pkg')
+ known_setups[rhui_family].append(target_setup)
+
+ installed_pkgs = {'zip', 'kernel-core', 'python', 'src_pkg', 'leapp_pkg'}
+ installed_pkgs = [mk_pkg(pkg_name) for pkg_name in installed_pkgs]
+ installed_rpms = InstalledRPM(items=installed_pkgs)
+
+ monkeypatch.setattr(api, 'produce', produce_mocked())
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(src_ver='7.9', msgs=[installed_rpms]))
+ monkeypatch.setattr(reporting, 'create_report', create_report_mocked())
+ monkeypatch.setattr(rhsm, 'skip_rhsm', lambda: True)
+ monkeypatch.setattr(rhui, 'RHUI_SETUPS', known_setups)
- current_actor_context.feed(create_modulesfacts(installed_rpm=installed_rpms))
- current_actor_context.run(config_model=mock_configs.CONFIG)
- assert bool(current_actor_context.consume(Report)) is msgs_received.report
- assert bool(current_actor_context.consume(RHUIInfo)) is msgs_received.rhui_info
- assert bool(current_actor_context.consume(
- RequiredTargetUserspacePackages)) is msgs_received.req_target_userspace
+ if is_target_setup_known:
+ checkrhui_lib.process()
+ assert api.produce.called
+ else:
+ with pytest.raises(StopActorExecutionError):
+ checkrhui_lib.process()
diff --git a/repos/system_upgrade/common/actors/peseventsscanner/libraries/pes_events_scanner.py b/repos/system_upgrade/common/actors/peseventsscanner/libraries/pes_events_scanner.py
index 01457f2a..f8d8dcfc 100644
--- a/repos/system_upgrade/common/actors/peseventsscanner/libraries/pes_events_scanner.py
+++ b/repos/system_upgrade/common/actors/peseventsscanner/libraries/pes_events_scanner.py
@@ -355,9 +355,10 @@ def get_pesid_to_repoid_map(target_pesids):
details={'Problem': 'Did not receive a message with mapped repositories'}
)
- rhui_info = next(api.consume(RHUIInfo), RHUIInfo(provider=''))
+ rhui_info = next(api.consume(RHUIInfo), None)
+ cloud_provider = rhui_info.provider if rhui_info else ''
- repomap = peseventsscanner_repomap.RepoMapDataHandler(repositories_map_msg, cloud_provider=rhui_info.provider)
+ repomap = peseventsscanner_repomap.RepoMapDataHandler(repositories_map_msg, cloud_provider=cloud_provider)
# NOTE: We have to calculate expected target repositories like in the setuptargetrepos actor.
# It's planned to handle this in different a way in future...
diff --git a/repos/system_upgrade/common/actors/redhatsignedrpmscanner/actor.py b/repos/system_upgrade/common/actors/redhatsignedrpmscanner/actor.py
index 1085beee..41f9d343 100644
--- a/repos/system_upgrade/common/actors/redhatsignedrpmscanner/actor.py
+++ b/repos/system_upgrade/common/actors/redhatsignedrpmscanner/actor.py
@@ -54,26 +54,7 @@ class RedHatSignedRpmScanner(Actor):
"""Whitelist the katello package."""
return pkg.name.startswith('katello-ca-consumer')
- upg_path = rhui.get_upg_path()
- # AWS RHUI packages do not have to be whitelisted because they are signed by RedHat
- whitelisted_cloud_flavours = (
- 'azure',
- 'azure-eus',
- 'azure-sap-ha',
- 'azure-sap-apps',
- 'google',
- 'google-sap',
- 'alibaba'
- )
- whitelisted_cloud_pkgs = {
- rhui.RHUI_CLOUD_MAP[upg_path].get(flavour, {}).get('src_pkg') for flavour in whitelisted_cloud_flavours
- }
- whitelisted_cloud_pkgs.update(
- rhui.RHUI_CLOUD_MAP[upg_path].get(flavour, {}).get('target_pkg') for flavour in whitelisted_cloud_flavours
- )
- whitelisted_cloud_pkgs.update(
- rhui.RHUI_CLOUD_MAP[upg_path].get(flavour, {}).get('leapp_pkg') for flavour in whitelisted_cloud_flavours
- )
+ whitelisted_cloud_pkgs = rhui.get_all_known_rhui_pkgs_for_current_upg()
for rpm_pkgs in self.consume(InstalledRPM):
for pkg in rpm_pkgs.items:
diff --git a/repos/system_upgrade/common/actors/setetcreleasever/tests/test_setetcreleasever.py b/repos/system_upgrade/common/actors/setetcreleasever/tests/test_setetcreleasever.py
index d86ac926..a14dd2b8 100644
--- a/repos/system_upgrade/common/actors/setetcreleasever/tests/test_setetcreleasever.py
+++ b/repos/system_upgrade/common/actors/setetcreleasever/tests/test_setetcreleasever.py
@@ -3,13 +3,15 @@ import os
import pytest
from leapp.libraries.actor import setetcreleasever
-from leapp.libraries.common.testutils import (
- create_report_mocked,
- CurrentActorMocked,
- logger_mocked
-)
+from leapp.libraries.common.testutils import create_report_mocked, CurrentActorMocked, logger_mocked
from leapp.libraries.stdlib import api
-from leapp.models import PkgManagerInfo, RHUIInfo
+from leapp.models import (
+ PkgManagerInfo,
+ RHUIInfo,
+ TargetRHUIPostInstallTasks,
+ TargetRHUIPreInstallTasks,
+ TargetRHUISetupInfo
+)
CUR_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -33,8 +35,15 @@ class mocked_set_releasever(object):
def test_set_releasever(monkeypatch, current_actor_context):
-
- msgs = [RHUIInfo(provider='aws'), PkgManagerInfo(etc_releasever='7.7')]
+ preinstall_tasks = TargetRHUIPreInstallTasks()
+ postinstall_tasks = TargetRHUIPostInstallTasks()
+ setup_info = TargetRHUISetupInfo(preinstall_tasks=preinstall_tasks, postinstall_tasks=postinstall_tasks)
+ rhui_info = RHUIInfo(provider='aws',
+ src_client_pkg_names=['rh-amazon-rhui-client'],
+ target_client_pkg_names=['rh-amazon-rhui-client'],
+ target_client_setup_info=setup_info)
+
+ msgs = [rhui_info, PkgManagerInfo(etc_releasever='7.7')]
expected_rel_ver = '8.0'
monkeypatch.setattr(setetcreleasever, '_set_releasever', mocked_set_releasever())
diff --git a/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos.py b/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos.py
index 4b8405d0..2b14a29a 100644
--- a/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos.py
+++ b/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos.py
@@ -85,8 +85,11 @@ def process():
# Setup repomap handler
repo_mappig_msg = next(api.consume(RepositoriesMapping), RepositoriesMapping())
- rhui_info = next(api.consume(RHUIInfo), RHUIInfo(provider=''))
- repomap = setuptargetrepos_repomap.RepoMapDataHandler(repo_mappig_msg, cloud_provider=rhui_info.provider)
+
+ rhui_info = next(api.consume(RHUIInfo), None)
+ cloud_provider = rhui_info.provider if rhui_info else ''
+
+ repomap = setuptargetrepos_repomap.RepoMapDataHandler(repo_mappig_msg, cloud_provider=cloud_provider)
# Filter set of repoids from installed packages so that it contains only repoids with mapping
repoids_from_installed_packages_with_mapping = _get_mapped_repoids(repomap, repoids_from_installed_packages)
diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
index 0982a796..039b99a5 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py
@@ -6,7 +6,7 @@ import shutil
from leapp import reporting
from leapp.exceptions import StopActorExecution, StopActorExecutionError
from leapp.libraries.actor import constants
-from leapp.libraries.common import dnfplugin, mounting, overlaygen, repofileutils, rhsm, rhui, utils
+from leapp.libraries.common import dnfplugin, mounting, overlaygen, repofileutils, rhsm, utils
from leapp.libraries.common.config import get_env, get_product_type
from leapp.libraries.common.config.version import get_target_major_version
from leapp.libraries.stdlib import api, CalledProcessError, config, run
@@ -282,25 +282,11 @@ def prepare_target_userspace(context, userspace_dir, enabled_repos, packages):
raise StopActorExecutionError(message=message, details=details)
-def _get_all_rhui_pkgs():
- """
- Return the list of rhui packages
-
- Currently, do not care about what rhui we have, release, etc.
- Just take all packages. We need them just for the purpose of filtering
- what files we have to remove (see _prep_repository_access) and it's ok
- for us to use whatever rhui rpms (the relevant rpms catch the problem,
- the others are just taking bytes in memory...). It's a hot-fix. We are going
- to refactor the library later completely..
- """
- upg_path = rhui.get_upg_path()
- pkgs = []
- for rhui_map in rhui.RHUI_CLOUD_MAP[upg_path].values():
- for key in rhui_map.keys():
- if not key.endswith('pkg'):
- continue
- pkgs.append(rhui_map[key])
- return pkgs
+def _query_rpm_for_pkg_files(context, pkgs):
+ files_owned_by_rpm = set()
+ rpm_query_result = context.call(['rpm', '-ql'] + pkgs, split=True)
+ files_owned_by_rpm.update(rpm_query_result['stdout'])
+ return files_owned_by_rpm
def _get_files_owned_by_rpms(context, dirpath, pkgs=None, recursive=False):
@@ -405,42 +391,30 @@ def _prep_repository_access(context, target_userspace):
if not rhsm.skip_rhsm():
run(['rm', '-rf', os.path.join(target_etc, 'rhsm')])
context.copytree_from('/etc/rhsm', os.path.join(target_etc, 'rhsm'))
- # NOTE: we cannot just remove the original target yum.repos.d dir
- # as e.g. in case of RHUI a special RHUI repofiles are installed by a pkg
- # when the target userspace container is created. Removing these files we loose
- # RHUI target repositories. So ...->
- # -> detect such a files...
+
+ # NOTE: We cannot just remove the target yum.repos.d dir and replace it with yum.repos.d from the scratch
+ # # that we've used to obtain the new DNF stack and install it into the target userspace. Although
+ # # RHUI clients are being installed in both scratch and target containers, users can request their package
+ # # to be installed into target userspace that might add some repos to yum.repos.d that are not in scratch.
+
+ # Detect files that are owned by some RPM - these cannot be deleted
with mounting.NspawnActions(base_dir=target_userspace) as target_context:
files_owned_by_rpms = _get_files_owned_by_rpms(target_context, '/etc/yum.repos.d')
- # -> backup the orig dir & install the new one
+ # Backup the target yum.repos.d so we can always copy the files installed by some RPM back into yum.repos.d
+ # when we modify it
run(['mv', target_yum_repos_d, backup_yum_repos_d])
- context.copytree_from('/etc/yum.repos.d', target_yum_repos_d)
- # -> find old rhui repo files (we have to remove these as they cause duplicates)
- rhui_pkgs = _get_all_rhui_pkgs()
- old_files_owned_by_rhui_rpms = _get_files_owned_by_rpms(context, '/etc/yum.repos.d', rhui_pkgs)
- for fname in old_files_owned_by_rhui_rpms:
- api.current_logger().debug('Remove the old repofile: {}'.format(fname))
- run(['rm', '-f', os.path.join(target_yum_repos_d, fname)])
- # .. continue: remove our leapp rhui repo file (do not care if we are on rhui or not)
- for rhui_map in rhui.gen_rhui_files_map().values():
- for item in rhui_map:
- if item[1] != rhui.YUM_REPOS_PATH:
- continue
- target_leapp_repofile = os.path.join(target_yum_repos_d, item[0])
- if not os.path.isfile(target_leapp_repofile):
- continue
- # we found it!!
- run(['rm', '-f', target_leapp_repofile])
- break
+ # Copy the yum.repos.d from scratch - preserve any custom repositories. No need to clean-up old RHUI clients,
+ # we swap them for the new RHUI client in scratch (so the old one is not installed).
+ context.copytree_from('/etc/yum.repos.d', target_yum_repos_d)
- # -> copy expected files back
+ # Copy back files owned by some RPM
for fname in files_owned_by_rpms:
api.current_logger().debug('Copy the backed up repo file: {}'.format(fname))
run(['mv', os.path.join(backup_yum_repos_d, fname), os.path.join(target_yum_repos_d, fname)])
- # -> remove the backed up dir
+ # Cleanup - remove the backed up dir
run(['rm', '-rf', backup_yum_repos_d])
@@ -637,22 +611,71 @@ def _get_rhui_available_repoids(context, cloud_repo):
return set(repoids)
+def get_copy_location_from_copy_in_task(context, copy_task):
+ basename = os.path.basename(copy_task.src)
+ dest_in_container = context.full_path(copy_task.dst)
+ if os.path.isdir(dest_in_container):
+ return os.path.join(copy_task.dst, basename)
+ return copy_task.dst
+
+
def _get_rh_available_repoids(context, indata):
"""
RH repositories are provided either by RHSM or are stored in the expected repo file provided by
RHUI special packages (every cloud provider has itw own rpm).
"""
- upg_path = rhui.get_upg_path()
-
rh_repoids = _get_rhsm_available_repoids(context)
+ # If we are upgrading a RHUI system, check what repositories are provided by the (already installed) target clients
if indata and indata.rhui_info:
- cloud_repo = os.path.join(
- '/etc/yum.repos.d/', rhui.RHUI_CLOUD_MAP[upg_path][indata.rhui_info.provider]['leapp_pkg_repo']
+ files_provided_by_clients = _query_rpm_for_pkg_files(context, indata.rhui_info.target_client_pkg_names)
+
+ def is_repofile(path):
+ return os.path.dirname(path) == '/etc/yum.repos.d' and os.path.basename(path).endswith('.repo')
+
+ def extract_repoid_from_line(line):
+ return line.split(':', 1)[1].strip()
+
+ target_ver = api.current_actor().configuration.version.target
+ setup_tasks = indata.rhui_info.target_client_setup_info.preinstall_tasks.files_to_copy_into_overlay
+
+ yum_repos_d = context.full_path('/etc/yum.repos.d')
+ all_repofiles = {os.path.join(yum_repos_d, path) for path in os.listdir(yum_repos_d) if path.endswith('.repo')}
+ client_repofiles = {context.full_path(path) for path in files_provided_by_clients if is_repofile(path)}
+
+ # Exclude repofiles used to setup the target rhui access as on some platforms the repos provided by
+ # the client are not sufficient to install the client into target userspace (GCP)
+ rhui_setup_repofile_tasks = [task for task in setup_tasks if task.src.endswith('repo')]
+ rhui_setup_repofiles = (
+ get_copy_location_from_copy_in_task(context, copy_task) for copy_task in rhui_setup_repofile_tasks
)
- rhui_repoids = _get_rhui_available_repoids(context, cloud_repo)
- rh_repoids.update(rhui_repoids)
+ rhui_setup_repofiles = {context.full_path(repofile) for repofile in rhui_setup_repofiles}
+
+ foreign_repofiles = all_repofiles - client_repofiles - rhui_setup_repofiles
+
+ # Rename non-client repofiles so they will not be recognized when running dnf repolist
+ for foreign_repofile in foreign_repofiles:
+ os.rename(foreign_repofile, '{0}.back'.format(foreign_repofile))
+
+ try:
+ dnf_cmd = ['dnf', 'repolist', '--releasever', target_ver, '-v']
+ repolist_result = context.call(dnf_cmd)['stdout']
+ repoid_lines = [line for line in repolist_result.split('\n') if line.startswith('Repo-id')]
+ rhui_repoids = {extract_repoid_from_line(line) for line in repoid_lines}
+ rh_repoids.update(rhui_repoids)
+
+ except CalledProcessError as err:
+ details = {'err': err.stderr, 'details': str(err)}
+ raise StopActorExecutionError(
+ message='Failed to retrieve repoids provided by target RHUI clients.',
+ details=details
+ )
+
+ finally:
+ # Revert the renaming of non-client repofiles
+ for foreign_repofile in foreign_repofiles:
+ os.rename('{0}.back'.format(foreign_repofile), foreign_repofile)
return rh_repoids
@@ -790,8 +813,7 @@ def _gather_target_repositories(context, indata, prod_cert_path):
"""
rhsm.set_container_mode(context)
rhsm.switch_certificate(context, indata.rhsm_info, prod_cert_path)
- if indata.rhui_info:
- rhui.copy_rhui_data(context, indata.rhui_info.provider)
+
_install_custom_repofiles(context, indata.custom_repofiles)
return gather_target_repositories(context, indata)
@@ -834,6 +856,69 @@ def _create_target_userspace(context, packages, files, target_repoids):
rhsm.set_container_mode(target_context)
+def install_target_rhui_client_if_needed(context, indata):
+ if not indata.rhui_info:
+ return
+
+ target_major_version = get_target_major_version()
+ userspace_dir = _get_target_userspace()
+ _create_target_userspace_directories(userspace_dir)
+
+ setup_info = indata.rhui_info.target_client_setup_info
+ if setup_info.preinstall_tasks:
+ preinstall_tasks = setup_info.preinstall_tasks
+
+ for file_to_remove in preinstall_tasks.files_to_remove:
+ context.remove(file_to_remove)
+
+ for copy_info in preinstall_tasks.files_to_copy_into_overlay:
+ context.makedirs(os.path.dirname(copy_info.dst), exists_ok=True)
+ context.copy_to(copy_info.src, copy_info.dst)
+
+ cmd = ['dnf', '-y']
+
+ if setup_info.enable_only_repoids_in_copied_files and setup_info.preinstall_tasks:
+ copy_tasks = setup_info.preinstall_tasks.files_to_copy_into_overlay
+ copied_repofiles = [copy.src for copy in copy_tasks if copy.src.endswith('.repo')]
+ copied_repoids = set()
+ for repofile in copied_repofiles:
+ repofile_contents = repofileutils.parse_repofile(repofile)
+ copied_repoids.update(entry.repoid for entry in repofile_contents.data)
+
+ cmd += ['--disablerepo', '*']
+ for copied_repoid in copied_repoids:
+ cmd.extend(('--enablerepo', copied_repoid))
+
+ src_client_remove_steps = ['remove {0}'.format(client) for client in indata.rhui_info.src_client_pkg_names]
+ target_client_install_steps = ['install {0}'.format(client) for client in indata.rhui_info.target_client_pkg_names]
+
+ dnf_transaction_steps = src_client_remove_steps + target_client_install_steps + ['transaction run']
+
+ cmd += [
+ '--setopt=module_platform_id=platform:el{}'.format(target_major_version),
+ '--setopt=keepcache=1',
+ '--releasever', api.current_actor().configuration.version.target,
+ '--disableplugin', 'subscription-manager',
+ 'shell'
+ ]
+
+ context.call(cmd, callback_raw=utils.logging_handler, stdin='\n'.join(dnf_transaction_steps))
+
+ if setup_info.postinstall_tasks:
+ for copy_info in setup_info.postinstall_tasks.files_to_copy:
+ context.makedirs(os.path.dirname(copy_info.dst), exists_ok=True)
+ context.call(['cp', copy_info.src, copy_info.dst])
+
+ # Do a cleanup so there are not duplicit repoids
+ files_owned_by_clients = _query_rpm_for_pkg_files(context, indata.rhui_info.target_client_pkg_names)
+
+ for copy_task in setup_info.preinstall_tasks.files_to_copy_into_overlay:
+ dest = get_copy_location_from_copy_in_task(context, copy_task)
+ can_be_cleaned_up = copy_task.src not in setup_info.files_supporting_client_operation
+ if dest not in files_owned_by_clients and can_be_cleaned_up:
+ context.remove(dest)
+
+
@suppress_deprecation(TMPTargetRepositoriesFacts)
def perform():
# NOTE: this one action is out of unit-tests completely; we do not use
@@ -853,6 +938,9 @@ def perform():
# Mount the ISO into the scratch container
target_iso = next(api.consume(TargetOSInstallationImage), None)
with mounting.mount_upgrade_iso_to_root_dir(overlay.target, target_iso):
+
+ install_target_rhui_client_if_needed(context, indata)
+
target_repoids = _gather_target_repositories(context, indata, prod_cert_path)
_create_target_userspace(context, indata.packages, indata.files, target_repoids)
# TODO: this is tmp solution as proper one needs significant refactoring
diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py b/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
index a519275e..cc684c7d 100644
--- a/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
+++ b/repos/system_upgrade/common/actors/targetuserspacecreator/tests/unit_test_targetuserspacecreator.py
@@ -85,7 +85,12 @@ def _gen_packages_msgs():
_PACKAGES_MSGS = _gen_packages_msgs()
_RHSMINFO_MSG = models.RHSMInfo(attached_skus=['testing-sku'])
-_RHUIINFO_MSG = models.RHUIInfo(provider='aws')
+_RHUIINFO_MSG = models.RHUIInfo(provider='aws',
+ src_client_pkg_names=['rh-amazon-rhui-client'],
+ target_client_pkg_names=['rh-amazon-rhui-client'],
+ target_client_setup_info=models.TargetRHUISetupInfo(
+ preinstall_tasks=models.TargetRHUIPreInstallTasks(),
+ postinstall_tasks=models.TargetRHUIPostInstallTasks()))
_XFS_MSG = models.XFSPresence()
_STORAGEINFO_MSG = models.StorageInfo()
_CTRF_MSGS = [
diff --git a/repos/system_upgrade/common/libraries/rhui.py b/repos/system_upgrade/common/libraries/rhui.py
index 14a91c42..aa40b597 100644
--- a/repos/system_upgrade/common/libraries/rhui.py
+++ b/repos/system_upgrade/common/libraries/rhui.py
@@ -1,9 +1,12 @@
import os
+from collections import namedtuple
import six
-from leapp.libraries.common.config.version import get_target_major_version
+from leapp.libraries.common.config import architecture as arch
+from leapp.libraries.common.config.version import get_source_major_version, get_target_major_version
from leapp.libraries.stdlib import api
+from leapp.utils.deprecation import deprecated
# when on AWS and upgrading from RHEL 7, we need also Python2 version of "Amazon-id" dnf
# plugin which is served by "leapp-rhui-aws" rpm package (please note this package is not
@@ -18,10 +21,233 @@ RHUI_PKI_PRIVATE_DIR = os.path.join(RHUI_PKI_DIR, 'private')
AWS_DNF_PLUGIN_NAME = 'amazon-id.py'
+class ContentChannel(object):
+ GA = 'ga'
+ TUV = 'tuv'
+ E4S = 'e4s'
+ EUS = 'eus'
+ AUS = 'aus'
+ BETA = 'beta'
+
+
+class RHUIVariant(object):
+ ORDINARY = 'ordinary' # Special value - not displayed in report/errors
+ SAP = 'sap'
+ SAP_APPS = 'sap-apps'
+ SAP_HA = 'sap-ha'
+
+
+class RHUIProvider(object):
+ GOOGLE = 'Google'
+ AZURE = 'Azure'
+ AWS = 'AWS'
+ ALIBABA = 'Alibaba'
+
+
# The files in 'files_map' are provided by special Leapp rpms (per cloud) and
# are delivered into "repos/system_upgrade/common/files/rhui/<PROVIDER>
+RHUISetup = namedtuple(
+ 'RHUISetup',
+ ('clients', 'leapp_pkg', 'mandatory_files', 'optional_files', 'extra_info', 'os_version',
+ 'arch', 'content_channel', 'files_supporting_client_operation')
+)
+"""RHUI-Setup-specific details used during IPU
+.. py:attribute:: clients
+ A set of RHUI clients present on the system.
+.. py:attribute:: leapp_pkg
+ The name of leapp's rhui-specific pkg providing repofiles, certs and keys to access package of the setup.
+.. py:attribute:: mandatory_files
+ Mandatory files and their destinations to copy into target userspace container required to access the target OS
+ content. If not present, an exception will be raised.
+.. py:attribute:: optional_files
+ Optional files and their destinations to copy into target userspace container required to access the target OS
+ content. Nonexistence of any of these files is ignored.
+.. py:attribute:: extra_info
+ Extra information about the setup.
+.. py:attribute:: os_version
+ The major OS version of the RHUI system.
+.. py:attribute:: content_channel
+ Content channel used by the RHUI setup.
+.. py:attribute:: files_supporting_client_operation
+ A subset of files from ``mandatory_files`` that are necessary for client to work (cannot be cleaned up).
+"""
+
+
+class RHUIFamily(object):
+ def __init__(self, provider, client_files_folder='', variant=RHUIVariant.ORDINARY, arch=arch.ARCH_X86_64,):
+ self.provider = provider
+ self.client_files_folder = client_files_folder
+ self.variant = variant
+ self.arch = arch
+
+ def __hash__(self):
+ return hash((self.provider, self.variant, self.arch))
+
+ def __eq__(self, other):
+ if not isinstance(other, RHUIFamily):
+ return False
+ self_repr = (self.provider, self.variant, self.arch)
+ other_repr = (other.provider, other.variant, other.arch)
+ return self_repr == other_repr
+
+ def full_eq(self, other):
+ partial_eq = self == other
+ return partial_eq and self.client_files_folder == other.client_files_folder
+
+ def __str__(self):
+ template = 'RHUIFamily(provider={provider}, variant={variant}, arch={arch})'
+ return template.format(provider=self.provider, variant=self.variant, arch=self.arch)
+
+
+def mk_rhui_setup(clients=None, leapp_pkg='', mandatory_files=None, optional_files=None,
+ extra_info=None, os_version='7', arch=arch.ARCH_X86_64, content_channel=ContentChannel.GA,
+ files_supporting_client_operation=None):
+ clients = clients or set()
+ mandatory_files = mandatory_files or []
+ extra_info = extra_info or {}
+ files_supporting_client_operation = files_supporting_client_operation or []
+ # Since the default optional files are not [], we cannot use the same construction as above
+ # to allow the caller to specify empty optional files
+ default_opt_files = [('content-leapp.crt', RHUI_PKI_PRODUCT_DIR), ('key-leapp.pem', RHUI_PKI_DIR)]
+ optional_files = default_opt_files if optional_files is None else optional_files
+
+ return RHUISetup(clients=clients, leapp_pkg=leapp_pkg, mandatory_files=mandatory_files, arch=arch,
+ content_channel=content_channel, optional_files=optional_files, extra_info=extra_info,
+ os_version=os_version, files_supporting_client_operation=files_supporting_client_operation)
+
+
+# This will be the new "cloud map". Essentially a directed graph with edges defined implicitly by OS versions +
+# setup family identification. In theory, we can make the variant be part of rhui setups, but this way we don't
+# have to repeatedly write it to every known setup there is (a sort of compression). Furthermore, it limits
+# the search for target equivalent to setups sharing the same family, and thus reducing a chance of error.
+RHUI_SETUPS = {
+ RHUIFamily(RHUIProvider.AWS, client_files_folder='aws'): [
+ mk_rhui_setup(clients={'rh-amazon-rhui-client'}, optional_files=[], os_version='7'),
+ mk_rhui_setup(clients={'rh-amazon-rhui-client'}, leapp_pkg='leapp-rhui-aws',
+ mandatory_files=[
+ ('rhui-client-config-server-8.crt', RHUI_PKI_PRODUCT_DIR),
+ ('rhui-client-config-server-8.key', RHUI_PKI_DIR),
+ (AWS_DNF_PLUGIN_NAME, DNF_PLUGIN_PATH_PY2),
+ ('leapp-aws.repo', YUM_REPOS_PATH)
+ ],
+ files_supporting_client_operation=[AWS_DNF_PLUGIN_NAME],
+ optional_files=[], os_version='8'),
+ # @Note(mhecko): We don't need to deal with AWS_DNF_PLUGIN_NAME here as on rhel8+ we can use the plugin
+ # # provided by the target client - there is no Python2 incompatibility issue there.
+ mk_rhui_setup(clients={'rh-amazon-rhui-client'}, leapp_pkg='leapp-rhui-aws',
+ mandatory_files=[
+ ('rhui-client-config-server-9.crt', RHUI_PKI_PRODUCT_DIR),
+ ('rhui-client-config-server-9.key', RHUI_PKI_DIR),
+ ('leapp-aws.repo', YUM_REPOS_PATH)
+ ],
+ optional_files=[], os_version='9'),
+ ],
+ RHUIFamily(RHUIProvider.AWS, arch=arch.ARCH_ARM64, client_files_folder='aws'): [
+ mk_rhui_setup(clients={'rh-amazon-rhui-client-arm'}, optional_files=[], os_version='7', arch=arch.ARCH_ARM64),
+ mk_rhui_setup(clients={'rh-amazon-rhui-client-arm'}, leapp_pkg='leapp-rhui-aws',
+ mandatory_files=[
+ ('rhui-client-config-server-8.crt', RHUI_PKI_PRODUCT_DIR),
+ ('rhui-client-config-server-8.key', RHUI_PKI_DIR),
+ (AWS_DNF_PLUGIN_NAME, DNF_PLUGIN_PATH_PY2),
+ ('leapp-aws.repo', YUM_REPOS_PATH)
+ ],
+ files_supporting_client_operation=[AWS_DNF_PLUGIN_NAME],
+ optional_files=[], os_version='8', arch=arch.ARCH_ARM64),
+ mk_rhui_setup(clients={'rh-amazon-rhui-client-arm'}, leapp_pkg='leapp-rhui-aws',
+ mandatory_files=[
+ ('rhui-client-config-server-9.crt', RHUI_PKI_PRODUCT_DIR),
+ ('rhui-client-config-server-9.key', RHUI_PKI_DIR),
+ ('leapp-aws.repo', YUM_REPOS_PATH)
+ ],
+ optional_files=[], os_version='9', arch=arch.ARCH_ARM64),
+ ],
+ RHUIFamily(RHUIProvider.AWS, variant=RHUIVariant.SAP, client_files_folder='aws-sap-e4s'): [
+ mk_rhui_setup(clients={'rh-amazon-rhui-client-sap-bundle'}, optional_files=[], os_version='7',
+ content_channel=ContentChannel.E4S),
+ mk_rhui_setup(clients={'rh-amazon-rhui-client-sap-bundle-e4s'}, leapp_pkg='leapp-rhui-aws-sap-e4s',
+ mandatory_files=[
+ ('rhui-client-config-server-8-sap-bundle.crt', RHUI_PKI_PRODUCT_DIR),
+ ('rhui-client-config-server-8-sap-bundle.key', RHUI_PKI_DIR),
+ (AWS_DNF_PLUGIN_NAME, DNF_PLUGIN_PATH_PY2),
+ ('leapp-aws-sap-e4s.repo', YUM_REPOS_PATH)
+ ],
+ files_supporting_client_operation=[AWS_DNF_PLUGIN_NAME],
+ optional_files=[], os_version='8', content_channel=ContentChannel.E4S),
+ mk_rhui_setup(clients={'rh-amazon-rhui-client-sap-bundle-e4s'}, leapp_pkg='leapp-rhui-aws-sap-e4s',
+ mandatory_files=[
+ ('rhui-client-config-server-9-sap-bundle.crt', RHUI_PKI_PRODUCT_DIR),
+ ('rhui-client-config-server-9-sap-bundle.key', RHUI_PKI_DIR),
+ ('leapp-aws-sap-e4s.repo', YUM_REPOS_PATH)
+ ],
+ optional_files=[], os_version='9', content_channel=ContentChannel.E4S),
+ ],
+ RHUIFamily(RHUIProvider.AZURE, client_files_folder='azure'): [
+ mk_rhui_setup(clients={'rhui-azure-rhel7'}, os_version='7',
+ extra_info={'agent_pkg': 'WALinuxAgent'}),
+ mk_rhui_setup(clients={'rhui-azure-rhel8'}, leapp_pkg='leapp-rhui-azure',
+ mandatory_files=[('leapp-azure.repo', YUM_REPOS_PATH)],
+ extra_info={'agent_pkg': 'WALinuxAgent'},
+ os_version='8'),
+ mk_rhui_setup(clients={'rhui-azure-rhel9'}, leapp_pkg='leapp-rhui-azure',
+ mandatory_files=[('leapp-azure.repo', YUM_REPOS_PATH)],
+ extra_info={'agent_pkg': 'WALinuxAgent'},
+ os_version='9'),
+ ],
+ RHUIFamily(RHUIProvider.AZURE, variant=RHUIVariant.SAP_APPS, client_files_folder='azure-sap-apps'): [
+ mk_rhui_setup(clients={'rhui-azure-rhel7-base-sap-apps'}, os_version='7', content_channel=ContentChannel.EUS),
+ mk_rhui_setup(clients={'rhui-azure-rhel8-sapapps'}, leapp_pkg='leapp-rhui-azure-sap',
+ mandatory_files=[('leapp-azure-sap-apps.repo', YUM_REPOS_PATH)],
+ extra_info={'agent_pkg': 'WALinuxAgent'},
+ os_version='8', content_channel=ContentChannel.EUS),
+ mk_rhui_setup(clients={'rhui-azure-rhel9-sapapps'}, leapp_pkg='leapp-rhui-azure-sap',
+ mandatory_files=[('leapp-azure-sap-apps.repo', YUM_REPOS_PATH)],
+ extra_info={'agent_pkg': 'WALinuxAgent'},
+ os_version='9', content_channel=ContentChannel.EUS),
+ ],
+ RHUIFamily(RHUIProvider.AZURE, variant=RHUIVariant.SAP_HA, client_files_folder='azure-sap-ha'): [
+ mk_rhui_setup(clients={'rhui-azure-rhel7-base-sap-ha'}, os_version='7', content_channel=ContentChannel.E4S),
+ mk_rhui_setup(clients={'rhui-azure-rhel8-sap-ha'}, leapp_pkg='leapp-rhui-azure-sap',
+ mandatory_files=[('leapp-azure-sap-ha.repo', YUM_REPOS_PATH)],
+ extra_info={'agent_pkg': 'WALinuxAgent'},
+ os_version='8', content_channel=ContentChannel.E4S),
+ mk_rhui_setup(clients={'rhui-azure-rhel9-sap-ha'}, leapp_pkg='leapp-rhui-azure-sap',
+ mandatory_files=[('leapp-azure-sap-ha.repo', YUM_REPOS_PATH)],
+ extra_info={'agent_pkg': 'WALinuxAgent'},
+ os_version='9', content_channel=ContentChannel.E4S),
+ ],
+ RHUIFamily(RHUIProvider.GOOGLE, client_files_folder='google'): [
+ mk_rhui_setup(clients={'google-rhui-client-rhel7'}, os_version='7'),
+ mk_rhui_setup(clients={'google-rhui-client-rhel8'}, leapp_pkg='leapp-rhui-google',
+ mandatory_files=[('leapp-google.repo', YUM_REPOS_PATH)],
+ files_supporting_client_operation=['leapp-google.repo'],
+ os_version='8'),
+ mk_rhui_setup(clients={'google-rhui-client-rhel9'}, leapp_pkg='leapp-rhui-google',
+ mandatory_files=[('leapp-google.repo', YUM_REPOS_PATH)],
+ files_supporting_client_operation=['leapp-google.repo'],
+ os_version='9'),
+ ],
+ RHUIFamily(RHUIProvider.GOOGLE, variant=RHUIVariant.SAP, client_files_folder='google-sap'): [
+ mk_rhui_setup(clients={'google-rhui-client-rhel79-sap'}, os_version='7', content_channel=ContentChannel.E4S),
+ mk_rhui_setup(clients={'google-rhui-client-rhel8-sap'}, leapp_pkg='leapp-rhui-google-sap',
+ mandatory_files=[('leapp-google-sap.repo', YUM_REPOS_PATH)],
+ files_supporting_client_operation=['leapp-google-sap.repo'],
+ os_version='8', content_channel=ContentChannel.E4S),
+ mk_rhui_setup(clients={'google-rhui-client-rhel9-sap'}, leapp_pkg='leapp-rhui-google-sap',
+ mandatory_files=[('leapp-google-sap.repo', YUM_REPOS_PATH)],
+ files_supporting_client_operation=['leapp-google-sap.repo'],
+ os_version='9', content_channel=ContentChannel.E4S),
+ ],
+ RHUIFamily(RHUIProvider.ALIBABA, client_files_folder='alibaba'): [
+ mk_rhui_setup(clients={'client-rhel7'}, os_version='7'),
+ mk_rhui_setup(clients={'aliyun_rhui_rhel8'}, leapp_pkg='leapp-rhui-alibaba',
+ mandatory_files=[('leapp-alibaba.repo', YUM_REPOS_PATH)], os_version='8'),
+ ]
+}
+
+
+# DEPRECATED, use RHUI_SETUPS instead
RHUI_CLOUD_MAP = {
'7to8': {
'aws': {
@@ -32,8 +258,6 @@ RHUI_CLOUD_MAP = {
'files_map': [
('rhui-client-config-server-8.crt', RHUI_PKI_PRODUCT_DIR),
('rhui-client-config-server-8.key', RHUI_PKI_DIR),
- ('content-rhel8.crt', RHUI_PKI_PRODUCT_DIR),
- ('content-rhel8.key', RHUI_PKI_DIR),
('cdn.redhat.com-chain.crt', RHUI_PKI_DIR),
(AWS_DNF_PLUGIN_NAME, DNF_PLUGIN_PATH_PY2),
('leapp-aws.repo', YUM_REPOS_PATH)
@@ -47,8 +271,6 @@ RHUI_CLOUD_MAP = {
'files_map': [
('rhui-client-config-server-8-sap-bundle.crt', RHUI_PKI_PRODUCT_DIR),
('rhui-client-config-server-8-sap-bundle.key', RHUI_PKI_DIR),
- ('content-rhel8-sap.crt', RHUI_PKI_PRODUCT_DIR),
- ('content-rhel8-sap.key', RHUI_PKI_DIR),
('cdn.redhat.com-chain.crt', RHUI_PKI_DIR),
(AWS_DNF_PLUGIN_NAME, DNF_PLUGIN_PATH_PY2),
('leapp-aws-sap-e4s.repo', YUM_REPOS_PATH)
@@ -61,8 +283,6 @@ RHUI_CLOUD_MAP = {
'leapp_pkg': 'leapp-rhui-azure',
'leapp_pkg_repo': 'leapp-azure.repo',
'files_map': [
- ('content.crt', RHUI_PKI_PRODUCT_DIR),
- ('key.pem', RHUI_PKI_PRIVATE_DIR),
('leapp-azure.repo', YUM_REPOS_PATH)
],
},
@@ -73,8 +293,6 @@ RHUI_CLOUD_MAP = {
'leapp_pkg': 'leapp-rhui-azure-sap',
'leapp_pkg_repo': 'leapp-azure-sap-apps.repo',
'files_map': [
- ('content-sapapps.crt', RHUI_PKI_PRODUCT_DIR),
- ('key-sapapps.pem', RHUI_PKI_PRIVATE_DIR),
('leapp-azure-sap-apps.repo', YUM_REPOS_PATH),
],
},
@@ -85,8 +303,6 @@ RHUI_CLOUD_MAP = {
'leapp_pkg': 'leapp-rhui-azure-sap',
'leapp_pkg_repo': 'leapp-azure-sap-ha.repo',
'files_map': [
- ('content-sap-ha.crt', RHUI_PKI_PRODUCT_DIR),
- ('key-sap-ha.pem', RHUI_PKI_PRIVATE_DIR),
('leapp-azure-sap-ha.repo', YUM_REPOS_PATH)
],
},
@@ -133,8 +349,6 @@ RHUI_CLOUD_MAP = {
'files_map': [
('rhui-client-config-server-9.crt', RHUI_PKI_PRODUCT_DIR),
('rhui-client-config-server-9.key', RHUI_PKI_DIR),
- ('content-rhel9.crt', RHUI_PKI_PRODUCT_DIR),
- ('content-rhel9.key', RHUI_PKI_DIR),
('cdn.redhat.com-chain.crt', RHUI_PKI_DIR),
('leapp-aws.repo', YUM_REPOS_PATH)
],
@@ -147,8 +361,6 @@ RHUI_CLOUD_MAP = {
'files_map': [
('rhui-client-config-server-9-sap-bundle.crt', RHUI_PKI_PRODUCT_DIR),
('rhui-client-config-server-9-sap-bundle.key', RHUI_PKI_DIR),
- ('content-rhel9-sap-bundle-e4s.crt', RHUI_PKI_PRODUCT_DIR),
- ('content-rhel9-sap-bundle-e4s.key', RHUI_PKI_DIR),
('cdn.redhat.com-chain.crt', RHUI_PKI_DIR),
('leapp-aws-sap-e4s.repo', YUM_REPOS_PATH)
],
@@ -160,8 +372,6 @@ RHUI_CLOUD_MAP = {
'leapp_pkg': 'leapp-rhui-azure',
'leapp_pkg_repo': 'leapp-azure.repo',
'files_map': [
- ('content.crt', RHUI_PKI_PRODUCT_DIR),
- ('key.pem', RHUI_PKI_PRIVATE_DIR),
('leapp-azure.repo', YUM_REPOS_PATH)
],
},
@@ -178,8 +388,6 @@ RHUI_CLOUD_MAP = {
'leapp_pkg': 'leapp-rhui-azure-eus',
'leapp_pkg_repo': 'leapp-azure.repo',
'files_map': [
- ('content.crt', RHUI_PKI_PRODUCT_DIR),
- ('key.pem', RHUI_PKI_PRIVATE_DIR),
('leapp-azure.repo', YUM_REPOS_PATH)
],
},
@@ -190,8 +398,6 @@ RHUI_CLOUD_MAP = {
'leapp_pkg': 'leapp-rhui-azure-sap',
'leapp_pkg_repo': 'leapp-azure-sap-ha.repo',
'files_map': [
- ('content-sap-ha.crt', RHUI_PKI_PRODUCT_DIR),
- ('key-sap-ha.pem', RHUI_PKI_DIR),
('leapp-azure-sap-ha.repo', YUM_REPOS_PATH)
],
},
@@ -202,8 +408,6 @@ RHUI_CLOUD_MAP = {
'leapp_pkg': 'leapp-rhui-azure-sap',
'leapp_pkg_repo': 'leapp-azure-sap-apps.repo',
'files_map': [
- ('content-sapapps.crt', RHUI_PKI_PRODUCT_DIR),
- ('key-sapapps.pem', RHUI_PKI_PRIVATE_DIR),
('leapp-azure-sap-apps.repo', YUM_REPOS_PATH)
],
},
@@ -240,6 +444,7 @@ def get_upg_path():
return '7to8' if get_target_major_version() == '8' else '8to9'
+@deprecated(since='2023-07-27', message='This functionality has been replaced with the RHUIInfo message.')
def gen_rhui_files_map():
"""
Generate RHUI files map based on architecture and upgrade path
@@ -256,6 +461,7 @@ def gen_rhui_files_map():
return files_map
+@deprecated(since='2023-07-27', message='This functionality has been integrated into target_userspace_creator.')
def copy_rhui_data(context, provider):
"""
Copy relevant RHUI certificates and key into the target userspace container
@@ -268,3 +474,17 @@ def copy_rhui_data(context, provider):
for path_ in gen_rhui_files_map().get(provider, ()):
context.copy_to(os.path.join(data_dir, path_[0]), path_[1])
+
+
+def get_all_known_rhui_pkgs_for_current_upg():
+ upg_major_versions = (get_source_major_version(), get_target_major_version())
+
+ known_pkgs = set()
+ for setup_family in RHUI_SETUPS.values():
+ for setup in setup_family:
+ if setup.os_version not in upg_major_versions:
+ continue
+ known_pkgs.update(setup.clients)
+ known_pkgs.add(setup.leapp_pkg)
+
+ return known_pkgs
diff --git a/repos/system_upgrade/common/models/rhuiinfo.py b/repos/system_upgrade/common/models/rhuiinfo.py
index 0b518928..3eaa4826 100644
--- a/repos/system_upgrade/common/models/rhuiinfo.py
+++ b/repos/system_upgrade/common/models/rhuiinfo.py
@@ -1,12 +1,58 @@
-from leapp.models import fields, Model
+from leapp.models import CopyFile, fields, Model
from leapp.topics import SystemInfoTopic
+class TargetRHUIPreInstallTasks(Model):
+ """Tasks required to be executed before target RHUI clients are installed"""
+ topic = SystemInfoTopic
+
+ files_to_remove = fields.List(fields.String(), default=[])
+ """Files to remove from the source system in order to setup target RHUI access"""
+
+ files_to_copy_into_overlay = fields.List(fields.Model(CopyFile), default=[])
+ """Files to copy into the scratch (overlayfs) container in order to setup target RHUI access"""
+
+
+class TargetRHUIPostInstallTasks(Model):
+ """Tasks required to be executed after target RHUI clients are installed to facilitate access to target content."""
+ topic = SystemInfoTopic
+
+ files_to_copy = fields.List(fields.Model(CopyFile), default=[])
+ """Source and destination are paths inside the container"""
+
+
+class TargetRHUISetupInfo(Model):
+ topic = SystemInfoTopic
+
+ enable_only_repoids_in_copied_files = fields.Boolean(default=True)
+ """If True (default) only the repoids from copied files will be enabled during client installation"""
+
+ preinstall_tasks = fields.Model(TargetRHUIPreInstallTasks)
+ """Tasks that must be performed before attempting to install the target client(s)"""
+
+ postinstall_tasks = fields.Model(TargetRHUIPostInstallTasks)
+ """Tasks that must be performed after the target client is installed (before any other content is accessed)"""
+
+ files_supporting_client_operation = fields.List(fields.String(), default=[])
+ """A subset of files copied in preinstall tasks that should not be cleaned up."""
+
+
class RHUIInfo(Model):
"""
- Facts about public cloud provider and RHUI infrastructure
+ Facts about public cloud variant and RHUI infrastructure
"""
topic = SystemInfoTopic
provider = fields.String()
- """ Provider name """
+ """Provider name"""
+
+ variant = fields.StringEnum(['ordinary', 'sap', 'sap-apps', 'sap-ha'], default='ordinary')
+ """Variant of the system"""
+
+ src_client_pkg_names = fields.List(fields.String())
+ """Names of the RHUI client packages providing repofiles to the source system"""
+
+ target_client_pkg_names = fields.List(fields.String())
+ """Names of the RHUI client packages providing repofiles to the target system"""
+
+ target_client_setup_info = fields.Model(TargetRHUISetupInfo)
--
2.41.0