From 2af314efebaf09c3108a376c38dac8784eb6fe75 Mon Sep 17 00:00:00 2001 From: Oleksandr Shyshatskyi Date: Thu, 6 Feb 2025 19:15:25 +0200 Subject: [PATCH 1/9] switch cln channel only inside overlayfs for preupgrade check --- .../actors/switchclnchannelreset/actor.py | 51 ------------------- .../libraries/userspacegen.py | 13 ++--- 2 files changed, 4 insertions(+), 60 deletions(-) delete mode 100644 repos/system_upgrade/cloudlinux/actors/switchclnchannelreset/actor.py diff --git a/repos/system_upgrade/cloudlinux/actors/switchclnchannelreset/actor.py b/repos/system_upgrade/cloudlinux/actors/switchclnchannelreset/actor.py deleted file mode 100644 index 637cefb571..0000000000 --- a/repos/system_upgrade/cloudlinux/actors/switchclnchannelreset/actor.py +++ /dev/null @@ -1,51 +0,0 @@ -from leapp.actors import Actor -from leapp.libraries.stdlib import api -from leapp.tags import IPUWorkflowTag, TargetTransactionChecksPhaseTag -from leapp.libraries.stdlib import CalledProcessError -from leapp.libraries.common.cllaunch import run_on_cloudlinux -from leapp.libraries.common.cln_switch import cln_switch -from leapp.libraries.common.config.version import get_source_major_version -from leapp import reporting -from leapp.reporting import Report - - -class SwitchClnChannelReset(Actor): - """ - Reset the CLN channel to CL7 to keep the system state consistent before the main upgrade phase. - """ - - name = "switch_cln_channel_reset" - consumes = () - produces = (Report,) - tags = (IPUWorkflowTag, TargetTransactionChecksPhaseTag.After) - - @run_on_cloudlinux - def process(self): - try: - cln_switch(target=get_source_major_version()) - except CalledProcessError as e: - reporting.create_report( - [ - reporting.Title( - "Failed to switch CloudLinux Network channel." - ), - reporting.Summary( - "Command {} failed with exit code {}." - " The most probable cause of that is a problem with this system's" - " CloudLinux Network registration.".format(e.command, e.exit_code) - ), - reporting.Remediation( - hint="Check the state of this system's registration with \'rhn_check\'." - " Attempt to re-register the system with \'rhnreg_ks --force\'." - ), - reporting.Severity(reporting.Severity.HIGH), - reporting.Groups( - [reporting.Groups.OS_FACTS, reporting.Groups.AUTHENTICATION] - ), - reporting.Groups([reporting.Groups.INHIBITOR]), - ] - ) - except OSError as e: - api.current_logger().error( - "Could not call RHN command: Message: %s", str(e), exc_info=True - ) diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py index dce6735389..3db329cb63 100644 --- a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py +++ b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py @@ -332,16 +332,11 @@ def prepare_target_userspace(context, userspace_dir, enabled_repos, packages): api.current_logger().debug('Checking the CLN registration status') context.call(['rhn_check'], callback_raw=utils.logging_handler) - # To get packages from Spacewalk repos (aka CLN) we need to switch the CLN channel. - - # Note that this switches the channel for the entire host system, not just the target userspace - - # so if we don't reset it back to the original channel, the host system will be left in an inconsistent state. - # The 'switch_cln_channel_reset' actor should reset the channel back to the original state after the - # transaction check phase is done - so the preupgrade checks won't affect the host system. - # The 'switch_cln_channel_download' actor should take care of switching the channel back to the CL8 channel - # when it's time to download the upgrade packages. - cln_switch(target=int(target_major_version)) + # To get packages from Spacewalk repos (aka CLN) we need to switch the CLN channel. + # localonly flag switches channel only inside of the overlayfs + api.current_logger().debug('Switching channel to %s' % target_major_version) + context.call(['cln-switch-channel', '-t', str(target_major_version), '--localonly']) def _query_rpm_for_pkg_files(context, pkgs): From 2c5c019e7289b7d7b5b5c0dd54784d37ea52284b Mon Sep 17 00:00:00 2001 From: Oleksandr Shyshatskyi Date: Mon, 10 Feb 2025 11:46:55 +0200 Subject: [PATCH 2/9] add requirement for new rhn-client-tools --- packaging/leapp-repository.spec | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packaging/leapp-repository.spec b/packaging/leapp-repository.spec index 413b25798b..d967174c0e 100644 --- a/packaging/leapp-repository.spec +++ b/packaging/leapp-repository.spec @@ -94,6 +94,9 @@ Conflicts: leapp-upgrade-el7toel8 %endif +# Requires tools which allow switching between channels +Requires: cln-switch-channel = 2 + # IMPORTANT: every time the requirements are changed, increment number by one # - same for Provides in deps subpackage Requires: leapp-repository-dependencies = %{leapp_repo_deps} From 21a5ba7e732d45a79c02399db1d1fd3ada397955 Mon Sep 17 00:00:00 2001 From: Oleksandr Shyshatskyi Date: Tue, 11 Feb 2025 14:34:12 +0200 Subject: [PATCH 3/9] fix channel override override channel only after all files are copied to target namespace --- .../libraries/userspacegen.py | 21 ++++++----------- .../common/libraries/cln_switch.py | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py index 3db329cb63..8e4579a7ec 100644 --- a/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py +++ b/repos/system_upgrade/common/actors/targetuserspacecreator/libraries/userspacegen.py @@ -10,7 +10,7 @@ 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.common.gpg import get_path_to_gpg_certs, is_nogpgcheck_set -from leapp.libraries.common.cln_switch import cln_switch +from leapp.libraries.common.cln_switch import override_channel from leapp.libraries.stdlib import api, CalledProcessError, config, run from leapp.models import RequiredTargetUserspacePackages # deprecated from leapp.models import TMPTargetRepositoriesFacts # deprecated all the time @@ -330,14 +330,6 @@ def prepare_target_userspace(context, userspace_dir, enabled_repos, packages): raise StopActorExecutionError(message=message, details=details) - api.current_logger().debug('Checking the CLN registration status') - context.call(['rhn_check'], callback_raw=utils.logging_handler) - - # To get packages from Spacewalk repos (aka CLN) we need to switch the CLN channel. - # localonly flag switches channel only inside of the overlayfs - api.current_logger().debug('Switching channel to %s' % target_major_version) - context.call(['cln-switch-channel', '-t', str(target_major_version), '--localonly']) - def _query_rpm_for_pkg_files(context, pkgs): files_owned_by_rpm = set() @@ -689,11 +681,7 @@ def _prep_repository_access(context, target_userspace): run(['rm', '-rf', os.path.join(target_etc, 'rhsm')]) context.copytree_from('/etc/rhsm', os.path.join(target_etc, 'rhsm')) - # Copy RHN data independent from RHSM config if os.path.isdir('/etc/sysconfig/rhn'): - context.call(['/usr/sbin/rhn_check'], callback_raw=utils.logging_handler) - run(['rm', '-rf', os.path.join(target_etc, 'sysconfig/rhn')]) - context.copytree_from('/etc/sysconfig/rhn', os.path.join(target_etc, 'sysconfig/rhn')) # Set up spacewalk plugin config with open(os.path.join(target_etc, 'dnf/plugins/spacewalk.conf'), 'r') as f: lines = f.readlines() @@ -1182,6 +1170,11 @@ def _create_target_userspace(context, packages, files, target_repoids): _copy_files(target_context, files) dnfplugin.install(_get_target_userspace()) + # do not switch channel before this stage because _copy_files above copies + # related configuration files from host to target userspace + target_major_version = get_target_major_version() + override_channel(os.path.join(_get_target_userspace(), 'etc/sysconfig/rhn/up2date'), target_major_version) + # and do not forget to set the rhsm into the container mode again with mounting.NspawnActions(_get_target_userspace()) as target_context: rhsm.set_container_mode(target_context) @@ -1283,4 +1276,4 @@ def perform(): api.produce(TargetUserSpaceInfo( path=_get_target_userspace(), scratch=constants.SCRATCH_DIR, - mounts=constants.MOUNTS_DIR)) + mounts=constants.MOUNTS_DIR)) \ No newline at end of file diff --git a/repos/system_upgrade/common/libraries/cln_switch.py b/repos/system_upgrade/common/libraries/cln_switch.py index ddd9331c43..de7970abbf 100644 --- a/repos/system_upgrade/common/libraries/cln_switch.py +++ b/repos/system_upgrade/common/libraries/cln_switch.py @@ -33,6 +33,7 @@ def get_cln_cacheonly_flag_path(): """ return os.path.join(get_target_userspace_path(), CLN_CACHEONLY_MARKER.lstrip('/')) + def cln_switch(target): """ Switch the CloudLinux Network channel to the specified target OS. @@ -47,3 +48,25 @@ def cln_switch(target): api.current_logger().debug('Channel switch result: %s', res) res = run(yum_clean_cmd) # required to update the repolist api.current_logger().debug('yum cleanup result: %s', res) + + +def override_channel(config_path, target): + """ + Override cln channel locally (not affecting information on CLN side) + aboit which channel we must use for upgrade. + """ + replaced = False + with open(config_path, 'r') as f: + lines = f.readlines() + new_lines = [] + for line in lines: + if line.startswith('channelOverride'): + line = 'channelOverride = cloudlinux-x86_64-server-%s\n' % target + replaced = True + new_lines.append(line) + + if not replaced: + new_lines.append('channelOverride = cloudlinux-x86_64-server-%s\n' % target) + + with open(config_path, 'w') as f: + f.writelines(new_lines) From 1ffc487f901387b8f5bea22137c0f90fc7a2ed25 Mon Sep 17 00:00:00 2001 From: Oleksandr Shyshatskyi Date: Tue, 11 Feb 2025 16:52:35 +0200 Subject: [PATCH 4/9] split checking cl license and copying files to container Intead of checking cl license and at the same time providing TargetUserSpacePreupgradeTasks in on actor, split this logic into two Also stop producing TargetUserSpaceUpgradeTasks as requirements will be already fulfilled with TargetUserSpacePreupgradeTasks execution. --- .../cloudlinux/actors/checkcllicense/actor.py | 27 +----------- .../cloudlinux/actors/copycllicense/actor.py | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+), 26 deletions(-) create mode 100644 repos/system_upgrade/cloudlinux/actors/copycllicense/actor.py diff --git a/repos/system_upgrade/cloudlinux/actors/checkcllicense/actor.py b/repos/system_upgrade/cloudlinux/actors/checkcllicense/actor.py index bf7b583a85..ad95dc1861 100644 --- a/repos/system_upgrade/cloudlinux/actors/checkcllicense/actor.py +++ b/repos/system_upgrade/cloudlinux/actors/checkcllicense/actor.py @@ -13,24 +13,6 @@ import os -RHN_CONFIG_DIR = '/etc/sysconfig/rhn' -REQUIRED_PKGS = ['dnf-plugin-spacewalk', 'rhn-client-tools'] - - -def rhn_to_target_userspace(): - """ - Produce messages to copy RHN configuration files and packages to the target userspace - """ - files_to_copy = [] - for dirpath, _, filenames in os.walk(RHN_CONFIG_DIR): - for filename in filenames: - src_path = os.path.join(dirpath, filename) - if os.path.isfile(src_path): - files_to_copy.append(CopyFile(src=src_path)) - - api.produce(TargetUserSpacePreupgradeTasks(install_rpms=REQUIRED_PKGS, copy_files=files_to_copy)) - api.produce(TargetUserSpaceUpgradeTasks(install_rpms=REQUIRED_PKGS, copy_files=files_to_copy)) - class CheckClLicense(Actor): """ @@ -39,17 +21,12 @@ class CheckClLicense(Actor): name = 'check_cl_license' consumes = () - produces = (Report, TargetUserSpacePreupgradeTasks, TargetUserSpaceUpgradeTasks) + produces = (Report,) tags = (ChecksPhaseTag, IPUWorkflowTag) system_id_path = '/etc/sysconfig/rhn/systemid' rhn_check_bin = '/usr/sbin/rhn_check' - # # Copy RHN data independent from RHSM config - # if os.path.isdir('/etc/sysconfig/rhn'): - # run(['rm', '-rf', os.path.join(target_etc, 'sysconfig/rhn')]) - # context.copytree_from('/etc/sysconfig/rhn', os.path.join(target_etc, 'sysconfig/rhn')) - @run_on_cloudlinux def process(self): res = None @@ -69,5 +46,3 @@ def process(self): reporting.Groups([reporting.Groups.INHIBITOR]), reporting.Remediation(hint=remediation), ]) - else: - rhn_to_target_userspace() diff --git a/repos/system_upgrade/cloudlinux/actors/copycllicense/actor.py b/repos/system_upgrade/cloudlinux/actors/copycllicense/actor.py new file mode 100644 index 0000000000..8d7ec3e841 --- /dev/null +++ b/repos/system_upgrade/cloudlinux/actors/copycllicense/actor.py @@ -0,0 +1,44 @@ +import os +from leapp.actors import Actor +from leapp.reporting import Report +from leapp.tags import ChecksPhaseTag, IPUWorkflowTag +from leapp.libraries.common.cllaunch import run_on_cloudlinux +from leapp.libraries.stdlib import api +from leapp.models import ( + TargetUserSpacePreupgradeTasks, + CopyFile +) + + +RHN_CONFIG_DIR = '/etc/sysconfig/rhn' +REQUIRED_PKGS = ['dnf-plugin-spacewalk', 'rhn-client-tools'] + + +class CopyClLicense(Actor): + """ + Produce task to copy CloudLinux license files to target system. + """ + + name = 'copy_rhn_client_tools_config' + consumes = () + produces = (Report, TargetUserSpacePreupgradeTasks) + tags = (ChecksPhaseTag, IPUWorkflowTag) + + @run_on_cloudlinux + def process(self): + """ + Produce artifacts to copy RHN configuration files + and install packages to the target userspace, + including up2date and systemid. + """ + files_to_copy = [] + for dirpath, _, filenames in os.walk(RHN_CONFIG_DIR): + for filename in filenames: + src_path = os.path.join(dirpath, filename) + if os.path.isfile(src_path): + files_to_copy.append(CopyFile(src=src_path)) + + api.produce(TargetUserSpacePreupgradeTasks( + install_rpms=REQUIRED_PKGS, + copy_files=files_to_copy + )) From 23db38990f9725d3c6bee89ad0e8050460a9d39f Mon Sep 17 00:00:00 2001 From: Oleksandr Shyshatskyi Date: Tue, 11 Feb 2025 16:54:06 +0200 Subject: [PATCH 5/9] remove inhibitor for rhn-client-tools version With recent changes in spec file, we require proper version to be installed using yum/dnf instead of manual version checking. --- .../actors/checkrhnclienttools/actor.py | 61 ------------------- .../checkrhnclienttools/libraries/version.py | 46 -------------- 2 files changed, 107 deletions(-) delete mode 100644 repos/system_upgrade/cloudlinux/actors/checkrhnclienttools/actor.py delete mode 100644 repos/system_upgrade/cloudlinux/actors/checkrhnclienttools/libraries/version.py diff --git a/repos/system_upgrade/cloudlinux/actors/checkrhnclienttools/actor.py b/repos/system_upgrade/cloudlinux/actors/checkrhnclienttools/actor.py deleted file mode 100644 index a36712ba45..0000000000 --- a/repos/system_upgrade/cloudlinux/actors/checkrhnclienttools/actor.py +++ /dev/null @@ -1,61 +0,0 @@ -from leapp.actors import Actor -from leapp import reporting -from leapp.reporting import Report -from leapp.tags import ChecksPhaseTag, IPUWorkflowTag -from leapp.libraries.common.cllaunch import run_on_cloudlinux - -from leapp.libraries.actor.version import ( - Version, VersionParsingError, -) - -import subprocess - - -class CheckRhnClientToolsVersion(Actor): - """ - Check the rhn-client-tools package version - """ - - name = 'check_rhn_client_tools_version' - consumes = () - produces = (Report,) - tags = (ChecksPhaseTag, IPUWorkflowTag) - - minimal_version = Version('2.0.2') - minimal_release_int = 43 - minimal_release = '%s.el7.cloudlinux' % minimal_release_int - - @run_on_cloudlinux - def process(self): - # todo: (CLOS-3202) update the actor - return - - title, summary, remediation = None, None, None - # ex: - # Version : 2.0.2 - # Release : 43.el7.cloudlinux - # res is: b'2.0.2\n43.el7.cloudlinux\n' - cmd = "yum info installed rhn-client-tools | grep '^Version' -A 1 | awk '{print $3}'" - res = subprocess.check_output(cmd, shell=True) - rhn_version, rhn_release = res.decode().split() - self.log.info('Current rhn-client-tools version: "%s"', rhn_version) - try: - current_version = Version(rhn_version) - except VersionParsingError: - title = 'rhn-client-tools: package is not installed' - summary = 'rhn-client-tools package is required to perform elevation.' - remediation = 'Install rhn-client-tools "%s" version before running Leapp again.' % self.minimal_version - else: - if current_version < self.minimal_version or int(rhn_release.split('.')[0]) < self.minimal_release_int: - title = 'rhn-client-tools: package version is too low' - summary = 'Current version of the rhn-client-tools package has no capability to perform elevation.' - remediation = 'Update rhn-client-tools to "%s %s" version before running Leapp again.' % (self.minimal_version, self.minimal_release) - if title: - reporting.create_report([ - reporting.Title(title), - reporting.Summary(summary), - reporting.Severity(reporting.Severity.HIGH), - reporting.Groups([reporting.Groups.OS_FACTS]), - reporting.Groups([reporting.Groups.INHIBITOR]), - reporting.Remediation(hint=remediation), - ]) diff --git a/repos/system_upgrade/cloudlinux/actors/checkrhnclienttools/libraries/version.py b/repos/system_upgrade/cloudlinux/actors/checkrhnclienttools/libraries/version.py deleted file mode 100644 index 149bce23ed..0000000000 --- a/repos/system_upgrade/cloudlinux/actors/checkrhnclienttools/libraries/version.py +++ /dev/null @@ -1,46 +0,0 @@ -from six import reraise as raise_ -import sys - - -class VersionException(Exception): - pass - - -class VersionParsingError(VersionException): - pass - - -class Version(object): - def __init__(self, version): - self._raw = version - try: - self.value = tuple( - map(lambda x: int(x), version.split('.')) - ) - except Exception: - tb = sys.exc_info()[2] - raise_(VersionParsingError, 'failed to parse version: "%s"' % self._raw, tb) - - def __eq__(self, other): - return self.value == other.value - - def __gt__(self, other): - return any( - [v[0] > v[1] for v in zip(self.value, other.value)] - ) - - def __ge__(self, other): - return all( - [v[0] >= v[1] for v in zip(self.value, other.value)] - ) - - def __lt__(self, other): - return any( - [v[0] < v[1] for v in zip(self.value, other.value)] - ) - - def __le__(self, other): - return all( - [v[0] <= v[1] for v in zip(self.value, other.value)] - ) - From 93075b8e7bd5a0bdbe703ee3908bab372ef75b29 Mon Sep 17 00:00:00 2001 From: Oleksandr Shyshatskyi Date: Tue, 11 Feb 2025 16:57:21 +0200 Subject: [PATCH 6/9] split actor that switches channel and pins mirror --- .../cloudlinux/actors/pinclnmirror/actor.py | 59 ++++++++++ .../actors/switchclnchannel/actor.py | 57 ++++++++++ .../actors/switchclnchanneldownload/actor.py | 101 ------------------ 3 files changed, 116 insertions(+), 101 deletions(-) create mode 100644 repos/system_upgrade/cloudlinux/actors/pinclnmirror/actor.py create mode 100644 repos/system_upgrade/cloudlinux/actors/switchclnchannel/actor.py delete mode 100644 repos/system_upgrade/cloudlinux/actors/switchclnchanneldownload/actor.py diff --git a/repos/system_upgrade/cloudlinux/actors/pinclnmirror/actor.py b/repos/system_upgrade/cloudlinux/actors/pinclnmirror/actor.py new file mode 100644 index 0000000000..bc1686233f --- /dev/null +++ b/repos/system_upgrade/cloudlinux/actors/pinclnmirror/actor.py @@ -0,0 +1,59 @@ +import json +import os + +from leapp.actors import Actor +from leapp.libraries.stdlib import api +from leapp.libraries.common.cllaunch import run_on_cloudlinux +from leapp.libraries.common.cln_switch import get_target_userspace_path +from leapp.tags import DownloadPhaseTag, IPUWorkflowTag +from leapp.libraries.common.config.version import get_target_major_version + + +class PinClnMirror(Actor): + """ + Save CLN mirror that was used last time. + """ + + name = 'pin_cln_mirror' + consumes = () + produces = () + tags = (IPUWorkflowTag, DownloadPhaseTag.Before) + + CLN_REPO_ID = "cloudlinux-x86_64-server-%s" + DEFAULT_CLN_MIRROR = "https://xmlrpc.cln.cloudlinux.com/XMLRPC/" + + @run_on_cloudlinux + def process(self): + """Pin CLN mirror""" + target_userspace = get_target_userspace_path() + api.current_logger().info("Pin CLN mirror: target userspace=%s", target_userspace) + + # load last mirror URL from dnf spacewalk plugin cache + spacewalk_settings = {} + + # find the mirror used in the last transaction + # (expecting to find the one used in dnf_package_download actor) + spacewalk_json_path = os.path.join(target_userspace, 'var/lib/dnf/_spacewalk.json') + try: + with open(spacewalk_json_path) as file: + spacewalk_settings = json.load(file) + except (OSError, IOError, ValueError): + api.current_logger().error( + "No spacewalk settings found in %s - can't identify the last used CLN mirror", + spacewalk_json_path, + ) + + mirror_url = spacewalk_settings.get( + self.CLN_REPO_ID % get_target_major_version(), {} + ).get("url", [self.DEFAULT_CLN_MIRROR])[0] + + # pin mirror + mirrorlist_path = os.path.join(target_userspace, 'etc/mirrorlist') + with open(mirrorlist_path, 'w') as file: + file.write(mirror_url + '\n') + api.current_logger().info("Pin CLN mirror %s in %s", mirror_url, mirrorlist_path) + + up2date_path = os.path.join(target_userspace, 'etc/sysconfig/rhn/up2date') + with open(up2date_path, 'a+') as file: + file.write('\nmirrorURL[comment]=Set mirror URL to /etc/mirrorlist\nmirrorURL=file:///etc/mirrorlist\n') + api.current_logger().info("Updated up2date_path %s", up2date_path) diff --git a/repos/system_upgrade/cloudlinux/actors/switchclnchannel/actor.py b/repos/system_upgrade/cloudlinux/actors/switchclnchannel/actor.py new file mode 100644 index 0000000000..f66b9e5d21 --- /dev/null +++ b/repos/system_upgrade/cloudlinux/actors/switchclnchannel/actor.py @@ -0,0 +1,57 @@ +import os +import json + +from leapp.actors import Actor +from leapp.libraries.stdlib import api +from leapp.tags import FinalizationPhaseTag, IPUWorkflowTag +from leapp.libraries.stdlib import CalledProcessError +from leapp.libraries.common.cllaunch import run_on_cloudlinux +from leapp.libraries.common.cln_switch import cln_switch, get_target_userspace_path +from leapp import reporting +from leapp.reporting import Report +from leapp.libraries.common.config.version import get_target_major_version + + +DEFAULT_CLN_MIRROR = "https://xmlrpc.cln.cloudlinux.com/XMLRPC/" + + +class SwitchClnChannelDownload(Actor): + """ + Permanently switch CLN channel to target os version. + """ + + name = "switch_cln_channel" + consumes = () + produces = (Report,) + tags = (FinalizationPhaseTag, IPUWorkflowTag) + + @run_on_cloudlinux + def process(self): + try: + cln_switch(target=int(get_target_major_version())) + except CalledProcessError as e: + reporting.create_report( + [ + reporting.Title( + "Failed to switch CloudLinux Network channel from 7 to 8." + ), + reporting.Summary( + "Command {} failed with exit code {}." + " The most probable cause of that is a problem with this system's" + " CloudLinux Network registration.".format(e.command, e.exit_code) + ), + reporting.Remediation( + hint="Check the state of this system's registration with \'rhn_check\'." + " Attempt to re-register the system with \'rhnreg_ks --force\'." + ), + reporting.Severity(reporting.Severity.HIGH), + reporting.Groups( + [reporting.Groups.OS_FACTS, reporting.Groups.AUTHENTICATION] + ), + reporting.Groups([reporting.Groups.INHIBITOR]), + ] + ) + except OSError as e: + api.current_logger().error( + "Could not call RHN command: Message: %s", str(e), exc_info=True + ) diff --git a/repos/system_upgrade/cloudlinux/actors/switchclnchanneldownload/actor.py b/repos/system_upgrade/cloudlinux/actors/switchclnchanneldownload/actor.py deleted file mode 100644 index bc1c9f5075..0000000000 --- a/repos/system_upgrade/cloudlinux/actors/switchclnchanneldownload/actor.py +++ /dev/null @@ -1,101 +0,0 @@ -import os -import json - -from leapp.actors import Actor -from leapp.libraries.stdlib import api -from leapp.tags import DownloadPhaseTag, IPUWorkflowTag -from leapp.libraries.stdlib import CalledProcessError -from leapp.libraries.common.cllaunch import run_on_cloudlinux -from leapp.libraries.common.cln_switch import cln_switch, get_target_userspace_path -from leapp import reporting -from leapp.reporting import Report -from leapp.libraries.common.config.version import get_target_major_version - - - -CLN_REPO_ID = "cloudlinux-x86_64-server-8" -DEFAULT_CLN_MIRROR = "https://xmlrpc.cln.cloudlinux.com/XMLRPC/" - - -class SwitchClnChannelDownload(Actor): - """ - Switch CLN channel from 7 to 8 to be able to download upgrade packages. - """ - - name = "switch_cln_channel_download" - consumes = () - produces = (Report,) - tags = (IPUWorkflowTag, DownloadPhaseTag.Before) - - @run_on_cloudlinux - def process(self): - try: - cln_switch(target=int(get_target_major_version())) - except CalledProcessError as e: - reporting.create_report( - [ - reporting.Title( - "Failed to switch CloudLinux Network channel from 7 to 8." - ), - reporting.Summary( - "Command {} failed with exit code {}." - " The most probable cause of that is a problem with this system's" - " CloudLinux Network registration.".format(e.command, e.exit_code) - ), - reporting.Remediation( - hint="Check the state of this system's registration with \'rhn_check\'." - " Attempt to re-register the system with \'rhnreg_ks --force\'." - ), - reporting.Severity(reporting.Severity.HIGH), - reporting.Groups( - [reporting.Groups.OS_FACTS, reporting.Groups.AUTHENTICATION] - ), - reporting.Groups([reporting.Groups.INHIBITOR]), - ] - ) - except OSError as e: - api.current_logger().error( - "Could not call RHN command: Message: %s", str(e), exc_info=True - ) - - self._pin_cln_mirror() - - def _pin_cln_mirror(self): - """Pin CLN mirror""" - target_userspace = get_target_userspace_path() - api.current_logger().info("Pin CLN mirror: target userspace=%s", target_userspace) - - # load last mirror URL from dnf spacewalk plugin cache - spacewalk_settings = {} - - # find the mirror used in the last transaction - # (expecting to find the one used in dnf_package_download actor) - spacewalk_json_path = os.path.join(target_userspace, 'var/lib/dnf/_spacewalk.json') - try: - with open(spacewalk_json_path) as file: - spacewalk_settings = json.load(file) - except (OSError, IOError, ValueError): - api.current_logger().error( - "No spacewalk settings found in %s - can't identify the last used CLN mirror", - spacewalk_json_path, - ) - - mirror_url = spacewalk_settings.get(CLN_REPO_ID, {}).get("url", [DEFAULT_CLN_MIRROR])[0] - - # pin mirror - for mirrorlist_path in [ - '/etc/mirrorlist', - os.path.join(target_userspace, 'etc/mirrorlist'), - ]: - with open(mirrorlist_path, 'w') as file: - file.write(mirror_url + '\n') - api.current_logger().info("Pin CLN mirror %s in %s", mirror_url, mirrorlist_path) - - for up2date_path in [ - '/etc/sysconfig/rhn/up2date', - os.path.join(target_userspace, 'etc/sysconfig/rhn/up2date'), - ]: - # At some point up2date in `target_userspace` might be overwritten by a default one - with open(up2date_path, 'a+') as file: - file.write('\nmirrorURL[comment]=Set mirror URL to /etc/mirrorlist\nmirrorURL=file:///etc/mirrorlist\n') - api.current_logger().info("Updated up2date_path %s", up2date_path) From 36b6bdacb5b07e51f8b852612c38de654ec5fda9 Mon Sep 17 00:00:00 2001 From: Oleksandr Shyshatskyi Date: Tue, 11 Feb 2025 17:03:27 +0200 Subject: [PATCH 7/9] when unpinning mirror, do not modify host config --- .../cloudlinux/actors/unpinclnmirror/actor.py | 40 ++++++++----------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/repos/system_upgrade/cloudlinux/actors/unpinclnmirror/actor.py b/repos/system_upgrade/cloudlinux/actors/unpinclnmirror/actor.py index ce123925d9..8e7ffc93a0 100644 --- a/repos/system_upgrade/cloudlinux/actors/unpinclnmirror/actor.py +++ b/repos/system_upgrade/cloudlinux/actors/unpinclnmirror/actor.py @@ -5,6 +5,7 @@ from leapp.libraries.common.cln_switch import get_target_userspace_path from leapp.tags import FirstBootPhaseTag, IPUWorkflowTag + class UnpinClnMirror(Actor): """ Remove the pinned CLN mirror. @@ -16,32 +17,23 @@ class UnpinClnMirror(Actor): produces = () tags = (IPUWorkflowTag, FirstBootPhaseTag) - CLN_REPO_ID = "cloudlinux-x86_64-server-8" - DEFAULT_CLN_MIRROR = "https://xmlrpc.cln.cloudlinux.com/XMLRPC/" - @run_on_cloudlinux def process(self): target_userspace = get_target_userspace_path() - for mirrorlist_path in [ - '/etc/mirrorlist', - os.path.join(target_userspace, 'etc/mirrorlist'), - ]: - try: - os.remove(mirrorlist_path) - except OSError: - self.log.info('Can\'t remove %s, file does not exist, doing nothing', mirrorlist_path) + mirrorlist_path = os.path.join(target_userspace, 'etc/mirrorlist') + try: + os.remove(mirrorlist_path) + except OSError: + self.log.info('Can\'t remove %s, file does not exist, doing nothing', mirrorlist_path) - for up2date_path in [ - '/etc/sysconfig/rhn/up2date', - os.path.join(target_userspace, 'etc/sysconfig/rhn/up2date'), - ]: - try: - with open(up2date_path, 'r') as file: - lines = [ - line for line in file.readlines() if 'etc/mirrorlist' not in line - ] - with open(up2date_path, 'w') as file: - file.writelines(lines) - except (OSError, IOError, ValueError): - self.log.info('Can update %s file, doing nothing', up2date_path) + up2date_path = os.path.join(target_userspace, 'etc/sysconfig/rhn/up2date') + try: + with open(up2date_path, 'r') as file: + lines = [ + line for line in file.readlines() if 'etc/mirrorlist' not in line + ] + with open(up2date_path, 'w') as file: + file.writelines(lines) + except (OSError, IOError, ValueError): + self.log.info('Can update %s file, doing nothing', up2date_path) From 92f56acae3aad5788e623907cbfe371e909b4a18 Mon Sep 17 00:00:00 2001 From: Oleksandr Shyshatskyi Date: Tue, 11 Feb 2025 21:04:23 +0200 Subject: [PATCH 8/9] move switch_cln_channel to first boot stage --- .../cloudlinux/actors/switchclnchannel/actor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/repos/system_upgrade/cloudlinux/actors/switchclnchannel/actor.py b/repos/system_upgrade/cloudlinux/actors/switchclnchannel/actor.py index f66b9e5d21..d8b3f8baf8 100644 --- a/repos/system_upgrade/cloudlinux/actors/switchclnchannel/actor.py +++ b/repos/system_upgrade/cloudlinux/actors/switchclnchannel/actor.py @@ -3,7 +3,7 @@ from leapp.actors import Actor from leapp.libraries.stdlib import api -from leapp.tags import FinalizationPhaseTag, IPUWorkflowTag +from leapp.tags import FirstBootPhaseTag, IPUWorkflowTag from leapp.libraries.stdlib import CalledProcessError from leapp.libraries.common.cllaunch import run_on_cloudlinux from leapp.libraries.common.cln_switch import cln_switch, get_target_userspace_path @@ -23,7 +23,7 @@ class SwitchClnChannelDownload(Actor): name = "switch_cln_channel" consumes = () produces = (Report,) - tags = (FinalizationPhaseTag, IPUWorkflowTag) + tags = (FirstBootPhaseTag, IPUWorkflowTag) @run_on_cloudlinux def process(self): From 1f86500704e43d339120a7676806aad6e111e18d Mon Sep 17 00:00:00 2001 From: Oleksandr Shyshatskyi Date: Fri, 14 Feb 2025 09:48:58 +0200 Subject: [PATCH 9/9] fix incorrect message in switch_cln_channel actor --- .../cloudlinux/actors/switchclnchannel/actor.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/repos/system_upgrade/cloudlinux/actors/switchclnchannel/actor.py b/repos/system_upgrade/cloudlinux/actors/switchclnchannel/actor.py index d8b3f8baf8..86421856b2 100644 --- a/repos/system_upgrade/cloudlinux/actors/switchclnchannel/actor.py +++ b/repos/system_upgrade/cloudlinux/actors/switchclnchannel/actor.py @@ -1,6 +1,3 @@ -import os -import json - from leapp.actors import Actor from leapp.libraries.stdlib import api from leapp.tags import FirstBootPhaseTag, IPUWorkflowTag @@ -12,12 +9,10 @@ from leapp.libraries.common.config.version import get_target_major_version -DEFAULT_CLN_MIRROR = "https://xmlrpc.cln.cloudlinux.com/XMLRPC/" - - -class SwitchClnChannelDownload(Actor): +class SwitchClnChannel(Actor): """ - Permanently switch CLN channel to target os version. + Permanently switch CLN channel to target os version + when upgrade is complete. """ name = "switch_cln_channel" @@ -33,7 +28,7 @@ def process(self): reporting.create_report( [ reporting.Title( - "Failed to switch CloudLinux Network channel from 7 to 8." + "Failed to switch CloudLinux Network channel" ), reporting.Summary( "Command {} failed with exit code {}."