diff --git a/SOURCES/leapp-repository-0.16.0-elevate.patch b/SOURCES/leapp-repository-0.16.0-elevate.patch index 0064b33..a6d8069 100644 --- a/SOURCES/leapp-repository-0.16.0-elevate.patch +++ b/SOURCES/leapp-repository-0.16.0-elevate.patch @@ -1165,22 +1165,24 @@ index 0000000..1b1ffbc + checkpanelmemory.process() diff --git a/repos/system_upgrade/cloudlinux/actors/checkpanelmemory/libraries/checkpanelmemory.py b/repos/system_upgrade/cloudlinux/actors/checkpanelmemory/libraries/checkpanelmemory.py new file mode 100644 -index 0000000..3d77ec1 +index 0000000..81c6566 --- /dev/null +++ b/repos/system_upgrade/cloudlinux/actors/checkpanelmemory/libraries/checkpanelmemory.py -@@ -0,0 +1,55 @@ +@@ -0,0 +1,57 @@ +from leapp import reporting +from leapp.exceptions import StopActorExecutionError +from leapp.libraries.stdlib import api +from leapp.models import MemoryInfo, InstalledControlPanel + +from leapp.libraries.common.detectcontrolpanel import ( ++ NOPANEL_NAME, + UNKNOWN_NAME, + INTEGRATED_NAME, + CPANEL_NAME, +) + +required_memory = { ++ NOPANEL_NAME: 1536 * 1024, # 1.5 Gb + UNKNOWN_NAME: 1536 * 1024, # 1.5 Gb + INTEGRATED_NAME: 1536 * 1024, # 1.5 Gb + CPANEL_NAME: 2048 * 1024, # 2 Gb @@ -1832,10 +1834,10 @@ index 0000000..1d5e4a0 + )) diff --git a/repos/system_upgrade/cloudlinux/actors/detectcontrolpanel/actor.py b/repos/system_upgrade/cloudlinux/actors/detectcontrolpanel/actor.py new file mode 100644 -index 0000000..4eed3ec +index 0000000..75904d9 --- /dev/null +++ b/repos/system_upgrade/cloudlinux/actors/detectcontrolpanel/actor.py -@@ -0,0 +1,53 @@ +@@ -0,0 +1,54 @@ +from leapp.actors import Actor +from leapp import reporting +from leapp.reporting import Report @@ -1845,6 +1847,7 @@ index 0000000..4eed3ec + +from leapp.libraries.common.cllaunch import run_on_cloudlinux +from leapp.libraries.common.detectcontrolpanel import ( ++ NOPANEL_NAME, + UNKNOWN_NAME, + INTEGRATED_NAME, + CPANEL_NAME, @@ -1869,7 +1872,7 @@ index 0000000..4eed3ec + + if panel.name == CPANEL_NAME: + self.log.debug('cPanel detected, upgrade proceeding') -+ elif panel.name == INTEGRATED_NAME or panel.name == UNKNOWN_NAME: ++ elif panel.name == INTEGRATED_NAME or panel.name == UNKNOWN_NAME or panel.name == NOPANEL_NAME: + self.log.debug('Integrated/no panel detected, upgrade proceeding') + elif panel: + # Block the upgrade on any systems with a non-supported panel detected. @@ -2024,21 +2027,23 @@ index 0000000..358403b + ) diff --git a/repos/system_upgrade/cloudlinux/actors/replacerpmnewconfigs/actor.py b/repos/system_upgrade/cloudlinux/actors/replacerpmnewconfigs/actor.py new file mode 100644 -index 0000000..4ddb755 +index 0000000..56cce4f --- /dev/null +++ b/repos/system_upgrade/cloudlinux/actors/replacerpmnewconfigs/actor.py -@@ -0,0 +1,65 @@ +@@ -0,0 +1,81 @@ +from __future__ import print_function +import os +import fileinput + +from leapp.actors import Actor -+from leapp.tags import FirstBootPhaseTag, IPUWorkflowTag ++from leapp.tags import ApplicationsPhaseTag, IPUWorkflowTag +from leapp import reporting ++from leapp.reporting import Report +from leapp.libraries.common.cllaunch import run_on_cloudlinux + +REPO_DIR = '/etc/yum.repos.d' -+CL_MARKERS = ['cloudlinux', 'imunify'] ++REPO_DELETE_MARKERS = ['cloudlinux', 'imunify', 'epel'] ++REPO_BACKUP_MARKERS = [] +RPMNEW = '.rpmnew' +LEAPP_BACKUP_SUFFIX = '.leapp-backup' + @@ -2050,16 +2055,27 @@ index 0000000..4ddb755 + + name = 'replace_rpmnew_configs' + consumes = () -+ produces = () -+ tags = (FirstBootPhaseTag, IPUWorkflowTag) ++ produces = (Report,) ++ tags = (ApplicationsPhaseTag, IPUWorkflowTag) + + @run_on_cloudlinux + def process(self): ++ deleted_repofiles = [] + renamed_repofiles = [] + + for reponame in os.listdir(REPO_DIR): -+ if any(mark in reponame for mark in CL_MARKERS) and RPMNEW in reponame: -+ base_reponame = reponame[:-7] ++ if any(mark in reponame for mark in REPO_DELETE_MARKERS) and RPMNEW in reponame: ++ base_reponame = reponame[:-len(RPMNEW)] ++ base_path = os.path.join(REPO_DIR, base_reponame) ++ new_file_path = os.path.join(REPO_DIR, reponame) ++ ++ os.unlink(base_path) ++ os.rename(new_file_path, base_path) ++ deleted_repofiles.append(base_reponame) ++ self.log.debug('Yum repofile replaced: {}'.format(base_path)) ++ ++ if any(mark in reponame for mark in REPO_BACKUP_MARKERS) and RPMNEW in reponame: ++ base_reponame = reponame[:-len(RPMNEW)] + base_path = os.path.join(REPO_DIR, base_reponame) + new_file_path = os.path.join(REPO_DIR, reponame) + backup_path = os.path.join(REPO_DIR, base_reponame + LEAPP_BACKUP_SUFFIX) @@ -2067,6 +2083,7 @@ index 0000000..4ddb755 + os.rename(base_path, backup_path) + os.rename(new_file_path, base_path) + renamed_repofiles.append(base_reponame) ++ self.log.debug('Yum repofile replaced with backup: {}'.format(base_path)) + + # Disable any old repositories. + for reponame in os.listdir(REPO_DIR): @@ -2078,17 +2095,19 @@ index 0000000..4ddb755 + else: + print(line, end='') + -+ if renamed_repofiles: -+ replaced_string = '\n'.join(['- {}'.format(repofile_name) for repofile_name in renamed_repofiles]) ++ if renamed_repofiles or deleted_repofiles: ++ deleted_string = '\n'.join(['{}'.format(repofile_name) for repofile_name in deleted_repofiles]) ++ replaced_string = '\n'.join(['{}'.format(repofile_name) for repofile_name in renamed_repofiles]) + reporting.create_report([ + reporting.Title('CloudLinux repository config files replaced by updated versions'), + reporting.Summary( -+ 'One or more RPM repository configuration files related to CloudLinux ' ++ 'One or more RPM repository configuration files ' + 'have been replaced with new versions provided by the upgraded packages. ' + 'Any manual modifications to these files have been overriden by this process. ' -+ 'Old versions of files were backed up to files with a naming pattern ' ++ 'Old versions of backed up files are contained in files with a naming pattern ' + '.leapp-backup. ' -+ 'Replaced repository files: \n{}'.format(replaced_string) ++ 'Deleted repository files: \n{}\n' ++ 'Backed up repository files: \n{}'.format(deleted_string, replaced_string) + ), + reporting.Severity(reporting.Severity.MEDIUM), + reporting.Tags([reporting.Tags.UPGRADE_PROCESS]) @@ -2126,15 +2145,17 @@ index 0000000..21b2164 + f.writelines(config_data) diff --git a/repos/system_upgrade/cloudlinux/actors/restoremysqldata/actor.py b/repos/system_upgrade/cloudlinux/actors/restoremysqldata/actor.py new file mode 100644 -index 0000000..d1ec819 +index 0000000..8e27d99 --- /dev/null +++ b/repos/system_upgrade/cloudlinux/actors/restoremysqldata/actor.py -@@ -0,0 +1,22 @@ +@@ -0,0 +1,46 @@ +import os +from leapp.actors import Actor ++from leapp import reporting ++from leapp.models import Report +from leapp.tags import ThirdPartyApplicationsPhaseTag, IPUWorkflowTag +from leapp.libraries.common.cllaunch import run_on_cloudlinux -+from leapp.libraries.common.backup import restore_file, CLSQL_BACKUP_FILES ++from leapp.libraries.common.backup import restore_file, CLSQL_BACKUP_FILES, BACKUP_DIR + + +class RestoreMySqlData(Actor): @@ -2144,14 +2165,36 @@ index 0000000..d1ec819 + + name = 'restore_my_sql_data' + consumes = () -+ produces = () ++ produces = (Report,) + tags = (ThirdPartyApplicationsPhaseTag, IPUWorkflowTag) + + @run_on_cloudlinux + def process(self): -+ for filename in CLSQL_BACKUP_FILES: -+ if os.path.isfile(filename): -+ restore_file(filename, os.path.basename(filename)) ++ failed_files = [] ++ ++ for filepath in CLSQL_BACKUP_FILES: ++ try: ++ restore_file(os.path.basename(filepath), filepath) ++ except OSError as e: ++ failed_files.append(filepath) ++ self.log.error('Could not restore file {}: {}'.format(filepath, e.strerror)) ++ ++ if failed_files: ++ title = "Failed to restore backed up configuration files" ++ summary = ( ++ "Some backed up configuration files were unable to be restored automatically." ++ " Please check the upgrade log for detailed error descriptions" ++ " and restore the files from the backup directory {} manually if needed." ++ " Files not restored: {}".format(BACKUP_DIR, failed_files) ++ ) ++ reporting.create_report( ++ [ ++ reporting.Title(title), ++ reporting.Summary(summary), ++ reporting.Severity(reporting.Severity.HIGH), ++ reporting.Tags([reporting.Tags.UPGRADE_PROCESS]), ++ ] ++ ) diff --git a/repos/system_upgrade/cloudlinux/actors/scancontrolpanel/actor.py b/repos/system_upgrade/cloudlinux/actors/scancontrolpanel/actor.py new file mode 100644 index 0000000..96524ed @@ -2507,22 +2550,23 @@ index 0000000..f04f6c5 + return None diff --git a/repos/system_upgrade/cloudlinux/libraries/detectcontrolpanel.py b/repos/system_upgrade/cloudlinux/libraries/detectcontrolpanel.py new file mode 100644 -index 0000000..15b797a +index 0000000..7c92f10 --- /dev/null +++ b/repos/system_upgrade/cloudlinux/libraries/detectcontrolpanel.py -@@ -0,0 +1,68 @@ +@@ -0,0 +1,69 @@ +import os +import os.path + +from leapp.libraries.stdlib import api + + ++NOPANEL_NAME = 'No panel' +CPANEL_NAME = 'cPanel' +DIRECTADMIN_NAME = 'DirectAdmin' +PLESK_NAME = 'Plesk' +ISPMANAGER_NAME = 'ISPManager' +INTERWORX_NAME = 'InterWorx' -+UNKNOWN_NAME = 'Unknown' ++UNKNOWN_NAME = 'Unknown (legacy)' +INTEGRATED_NAME = 'Integrated' + +CLSYSCONFIG = '/etc/sysconfig/cloudlinux' @@ -2558,7 +2602,7 @@ index 0000000..15b797a + This function will try to detect control panels supported by CloudLinux + :return: Detected control panel name or None + """ -+ panel_name = None ++ panel_name = NOPANEL_NAME + if os.path.isfile('/opt/cpvendor/etc/integration.ini'): + panel_name = INTEGRATED_NAME + elif os.path.isfile('/usr/local/cpanel/cpanel'): @@ -2653,7 +2697,7 @@ index bb89c9f..2b8e7c8 100644 '--args', diff --git a/repos/system_upgrade/common/actors/checkenabledvendorrepos/actor.py b/repos/system_upgrade/common/actors/checkenabledvendorrepos/actor.py new file mode 100644 -index 0000000..5284aec +index 0000000..52f5af9 --- /dev/null +++ b/repos/system_upgrade/common/actors/checkenabledvendorrepos/actor.py @@ -0,0 +1,53 @@ @@ -2669,7 +2713,7 @@ index 0000000..5284aec + +class CheckEnabledVendorRepos(Actor): + """ -+ Create a list of vendors whose repositories are present on the system. ++ Create a list of vendors whose repositories are present on the system and enabled. + Only those vendors' configurations (new repositories, PES actions, etc.) + will be included in the upgrade process. + """ @@ -2683,24 +2727,24 @@ index 0000000..5284aec + vendor_mapping_data = {} + active_vendors = set() + -+ # Make a dict for easy lookup of repoid -> vendor name. ++ # Make a dict for easy mapping of repoid -> corresponding vendor name. + for vendor_src_repodata in api.consume(VendorSourceRepos): + for vendor_src_repo in vendor_src_repodata.source_repoids: + vendor_mapping_data[vendor_src_repo] = vendor_src_repodata.vendor + + # Is the repo listed in the vendor map as from_repoid present on the system? -+ for repos in api.consume(RepositoriesFacts): -+ for repo_file in repos.repositories: -+ for repo in repo_file.data: ++ for repos_facts in api.consume(RepositoriesFacts): ++ for repo_file in repos_facts.repositories: ++ for repo_data in repo_file.data: + self.log.debug( -+ "Looking for repository {} in vendor maps".format(repo.repoid) ++ "Looking for repository {} in vendor maps".format(repo_data.repoid) + ) -+ if repo.repoid in vendor_mapping_data: -+ # If the vendor's repository is present in the system, count the vendor as active. -+ new_vendor = vendor_mapping_data[repo.repoid] ++ if repo_data.enabled and repo_data.repoid in vendor_mapping_data: ++ # If the vendor's repository is present in the system and enabled, count the vendor as active. ++ new_vendor = vendor_mapping_data[repo_data.repoid] + self.log.debug( -+ "Repository {} found, enabling vendor {}".format( -+ repo.repoid, new_vendor ++ "Repository {} found and enabled, enabling vendor {}".format( ++ repo_data.repoid, new_vendor + ) + ) + active_vendors.add(new_vendor) @@ -2710,6 +2754,37 @@ index 0000000..5284aec + api.produce(ActiveVendorList(data=list(active_vendors))) + else: + self.log.info("No active vendors found, vendor list not generated") +diff --git a/repos/system_upgrade/common/actors/checketcreleasever/libraries/checketcreleasever.py b/repos/system_upgrade/common/actors/checketcreleasever/libraries/checketcreleasever.py +index ed5089e..8cf4b75 100644 +--- a/repos/system_upgrade/common/actors/checketcreleasever/libraries/checketcreleasever.py ++++ b/repos/system_upgrade/common/actors/checketcreleasever/libraries/checketcreleasever.py +@@ -1,22 +1,21 @@ + from leapp import reporting + from leapp.models import PkgManagerInfo, RHUIInfo + from leapp.libraries.stdlib import api ++from leapp.libraries.common.config.version import get_target_major_version + + + def handle_etc_releasever(): + +- target_version = api.current_actor().configuration.version.target ++ target_version = get_target_major_version() + reporting.create_report([ + reporting.Title( +- 'Release version in /etc/dnf/vars/releasever will be set to the current target release' ++ 'Release version in /etc/dnf/vars/releasever will be set to the major target release' + ), + reporting.Summary( + 'On this system, Leapp detected "releasever" variable is either configured through DNF/YUM configuration ' + 'file and/or the system is using RHUI infrastructure. In order to avoid issues with repofile URLs ' + '(when --release option is not provided) in cases where there is the previous major.minor version value ' +- 'in the configuration, release version will be set to the target release version ({}). This will also ' +- 'ensure the system stays on the target version after the upgrade. In order to enable latest minor version ' +- 'updates, you can remove "/etc/dnf/vars/releasever" file.'.format( ++ 'in the configuration, release version will be set to the major target release version ({}).'.format( + target_version + ) + ), diff --git a/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/85sys-upgrade-redhat/do-upgrade.sh b/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/85sys-upgrade-redhat/do-upgrade.sh index acdb93b..da1e814 100755 --- a/repos/system_upgrade/common/actors/commonleappdracutmodules/files/dracut/85sys-upgrade-redhat/do-upgrade.sh @@ -3486,6 +3561,193 @@ index 01f6df3..9a4990e 100644 self.produce(signed_pkgs) self.produce(unsigned_pkgs) +diff --git a/repos/system_upgrade/common/actors/removeobsoletegpgkeys/actor.py b/repos/system_upgrade/common/actors/removeobsoletegpgkeys/actor.py +new file mode 100644 +index 0000000..5674ee3 +--- /dev/null ++++ b/repos/system_upgrade/common/actors/removeobsoletegpgkeys/actor.py +@@ -0,0 +1,24 @@ ++from leapp.actors import Actor ++from leapp.libraries.actor import removeobsoleterpmgpgkeys ++from leapp.models import DNFWorkaround, InstalledRPM ++from leapp.tags import FactsPhaseTag, IPUWorkflowTag ++ ++ ++class RemoveObsoleteGpgKeys(Actor): ++ """ ++ Remove obsoleted RPM GPG keys. ++ ++ New version might make existing RPM GPG keys obsolete. This might be caused ++ for example by the hashing algorithm becoming deprecated or by the key ++ getting replaced. ++ ++ A DNFWorkaround is registered to actually remove the keys. ++ """ ++ ++ name = "remove_obsolete_gpg_keys" ++ consumes = (InstalledRPM,) ++ produces = (DNFWorkaround,) ++ tags = (FactsPhaseTag, IPUWorkflowTag) ++ ++ def process(self): ++ removeobsoleterpmgpgkeys.process() +diff --git a/repos/system_upgrade/common/actors/removeobsoletegpgkeys/libraries/removeobsoleterpmgpgkeys.py b/repos/system_upgrade/common/actors/removeobsoletegpgkeys/libraries/removeobsoleterpmgpgkeys.py +new file mode 100644 +index 0000000..11c61e3 +--- /dev/null ++++ b/repos/system_upgrade/common/actors/removeobsoletegpgkeys/libraries/removeobsoleterpmgpgkeys.py +@@ -0,0 +1,51 @@ ++from leapp.libraries.common.config.version import get_target_major_version ++from leapp.libraries.common.rpms import has_package ++from leapp.libraries.stdlib import api ++from leapp.models import DNFWorkaround, InstalledRPM ++ ++# maps target version to keys obsoleted in that version ++OBSOLETED_KEYS_MAP = { ++ 7: [], ++ 8: [ ++ "gpg-pubkey-2fa658e0-45700c69", ++ "gpg-pubkey-37017186-45761324", ++ "gpg-pubkey-db42a60e-37ea5438", ++ ], ++ 9: [ ++ "gpg-pubkey-d4082792-5b32db75", ++ "gpg-pubkey-3abb34f8-5ffd890e", ++ "gpg-pubkey-6275f250-5e26cb2e", ++ ], ++} ++ ++ ++def _get_obsolete_keys(): ++ """ ++ Return keys obsoleted in target and previous versions ++ """ ++ keys = [] ++ for version in range(7, int(get_target_major_version()) + 1): ++ for key in OBSOLETED_KEYS_MAP[version]: ++ name, version, release = key.rsplit("-", 2) ++ if has_package(InstalledRPM, name, version=version, release=release): ++ keys.append(key) ++ ++ return keys ++ ++ ++def register_dnfworkaround(keys): ++ api.produce( ++ DNFWorkaround( ++ display_name="remove obsolete RPM GPG keys from RPM DB", ++ script_path=api.current_actor().get_common_tool_path("removerpmgpgkeys"), ++ script_args=keys, ++ ) ++ ) ++ ++ ++def process(): ++ keys = _get_obsolete_keys() ++ if not keys: ++ return ++ ++ register_dnfworkaround(keys) +diff --git a/repos/system_upgrade/common/actors/removeobsoletegpgkeys/tests/test_removeobsoleterpmgpgkeys.py b/repos/system_upgrade/common/actors/removeobsoletegpgkeys/tests/test_removeobsoleterpmgpgkeys.py +new file mode 100644 +index 0000000..1d48781 +--- /dev/null ++++ b/repos/system_upgrade/common/actors/removeobsoletegpgkeys/tests/test_removeobsoleterpmgpgkeys.py +@@ -0,0 +1,94 @@ ++import pytest ++ ++from leapp.libraries.actor import removeobsoleterpmgpgkeys ++from leapp.libraries.common.config.version import get_target_major_version ++from leapp.libraries.common.rpms import has_package ++from leapp.libraries.common.testutils import CurrentActorMocked, produce_mocked ++from leapp.libraries.stdlib import api ++from leapp.models import DNFWorkaround, InstalledRPM, RPM ++ ++ ++def _get_test_installedrpm(): ++ return InstalledRPM( ++ items=[ ++ RPM( ++ name='gpg-pubkey', ++ version='d4082792', ++ release='5b32db75', ++ epoch='0', ++ packager='Red Hat, Inc. (auxiliary key 2) ', ++ arch='noarch', ++ pgpsig='' ++ ), ++ RPM( ++ name='gpg-pubkey', ++ version='2fa658e0', ++ release='45700c69', ++ epoch='0', ++ packager='Red Hat, Inc. (auxiliary key) ', ++ arch='noarch', ++ pgpsig='' ++ ), ++ RPM( ++ name='gpg-pubkey', ++ version='12345678', ++ release='abcdefgh', ++ epoch='0', ++ packager='made up', ++ arch='noarch', ++ pgpsig='' ++ ), ++ ] ++ ) ++ ++ ++@pytest.mark.parametrize( ++ "version, expected", ++ [ ++ (9, ["gpg-pubkey-d4082792-5b32db75", "gpg-pubkey-2fa658e0-45700c69"]), ++ (8, ["gpg-pubkey-2fa658e0-45700c69"]) ++ ] ++) ++def test_get_obsolete_keys(monkeypatch, version, expected): ++ def get_target_major_version_mocked(): ++ return version ++ ++ monkeypatch.setattr( ++ removeobsoleterpmgpgkeys, ++ "get_target_major_version", ++ get_target_major_version_mocked, ++ ) ++ ++ monkeypatch.setattr( ++ api, ++ "current_actor", ++ CurrentActorMocked( ++ msgs=[_get_test_installedrpm()] ++ ), ++ ) ++ ++ keys = removeobsoleterpmgpgkeys._get_obsolete_keys() ++ assert set(keys) == set(expected) ++ ++ ++@pytest.mark.parametrize( ++ "keys, should_register", ++ [ ++ (["gpg-pubkey-d4082792-5b32db75"], True), ++ ([], False) ++ ] ++) ++def test_workaround_should_register(monkeypatch, keys, should_register): ++ def get_obsolete_keys_mocked(): ++ return keys ++ ++ monkeypatch.setattr( ++ removeobsoleterpmgpgkeys, ++ '_get_obsolete_keys', ++ get_obsolete_keys_mocked ++ ) ++ monkeypatch.setattr(api, 'produce', produce_mocked()) ++ monkeypatch.setattr(api, "current_actor", CurrentActorMocked()) ++ ++ removeobsoleterpmgpgkeys.process() ++ assert api.produce.called == should_register diff --git a/repos/system_upgrade/common/actors/repositoriesmapping/libraries/repositoriesmapping.py b/repos/system_upgrade/common/actors/repositoriesmapping/libraries/repositoriesmapping.py index b2d00f3..e9458c5 100644 --- a/repos/system_upgrade/common/actors/repositoriesmapping/libraries/repositoriesmapping.py @@ -4075,6 +4337,26 @@ index 0000000..cb5c7ab + msg = "The {} file exists, but is empty. Nothing to do.".format(scancustomrepofile.CUSTOM_REPO_PATH) + assert api.current_logger.infomsg == msg + assert not api.produce.called +diff --git a/repos/system_upgrade/common/actors/setetcreleasever/libraries/setetcreleasever.py b/repos/system_upgrade/common/actors/setetcreleasever/libraries/setetcreleasever.py +index 73d1ffd..046f3fb 100644 +--- a/repos/system_upgrade/common/actors/setetcreleasever/libraries/setetcreleasever.py ++++ b/repos/system_upgrade/common/actors/setetcreleasever/libraries/setetcreleasever.py +@@ -1,5 +1,6 @@ + from leapp.libraries.stdlib import api + from leapp.models import PkgManagerInfo, RHUIInfo ++from leapp.libraries.common.config.version import get_target_major_version + + + def _set_releasever(releasever): +@@ -10,7 +11,7 @@ def _set_releasever(releasever): + + + def process(): +- target_version = api.current_actor().configuration.version.target ++ target_version = get_target_major_version() + + pkg_facts = next(api.consume(PkgManagerInfo), None) + rhui_facts = next(api.consume(RHUIInfo), None) diff --git a/repos/system_upgrade/common/actors/setuptargetrepos/actor.py b/repos/system_upgrade/common/actors/setuptargetrepos/actor.py index 00de073..95cedcd 100644 --- a/repos/system_upgrade/common/actors/setuptargetrepos/actor.py @@ -4485,7 +4767,7 @@ index 03f3cd4..2ab78ea 100644 diff --git a/repos/system_upgrade/common/libraries/dnfplugin.py b/repos/system_upgrade/common/libraries/dnfplugin.py -index 4010e9f..09085c0 100644 +index 4010e9f..f095575 100644 --- a/repos/system_upgrade/common/libraries/dnfplugin.py +++ b/repos/system_upgrade/common/libraries/dnfplugin.py @@ -4,6 +4,8 @@ import json @@ -4524,6 +4806,22 @@ index 4010e9f..09085c0 100644 ) finally: if stage == 'check': +@@ -241,7 +251,14 @@ def apply_workarounds(context=None): + for workaround in api.consume(DNFWorkaround): + try: + api.show_message('Applying transaction workaround - {}'.format(workaround.display_name)) +- context.call(['/bin/bash', '-c', workaround.script_path]) ++ if workaround.script_args: ++ cmd_str = '{script} {args}'.format( ++ script=workaround.script_path, ++ args=' '.join(workaround.script_args) ++ ) ++ else: ++ cmd_str = workaround.script_path ++ context.call(['/bin/bash', '-c', cmd_str]) + except (OSError, CalledProcessError) as e: + raise StopActorExecutionError( + message=('Failed to exceute script to apply transaction workaround {display_name}.' diff --git a/repos/system_upgrade/common/libraries/fetch.py b/repos/system_upgrade/common/libraries/fetch.py index 1c58148..37313b6 100644 --- a/repos/system_upgrade/common/libraries/fetch.py @@ -4786,6 +5084,43 @@ index b7e4b21..dc038bf 100644 def with_rhsm(f): +diff --git a/repos/system_upgrade/common/libraries/rpms.py b/repos/system_upgrade/common/libraries/rpms.py +index 86767c7..1bc93ca 100644 +--- a/repos/system_upgrade/common/libraries/rpms.py ++++ b/repos/system_upgrade/common/libraries/rpms.py +@@ -39,18 +39,28 @@ def create_lookup(model, field, keys, context=stdlib.api): + return set() + + +-def has_package(model, package_name, arch=None, context=stdlib.api): ++def has_package(model, package_name, arch=None, version=None, release=None, context=stdlib.api): + """ + Expects a model InstalledRedHatSignedRPM or InstalledUnsignedRPM. + Can be useful in cases like a quick item presence check, ex. check in actor that + a certain package is installed. +- + :param model: model class + :param package_name: package to be checked + :param arch: filter by architecture. None means all arches. ++ :param version: filter by version. None means all versions. ++ :param release: filter by release. None means all releases. + """ + if not (isinstance(model, type) and issubclass(model, InstalledRPM)): + return False +- keys = ('name',) if not arch else ('name', 'arch') ++ keys = ['name'] ++ if arch: ++ keys.append('arch') ++ if version: ++ keys.append('version') ++ if release: ++ keys.append('release') ++ ++ attributes = [package_name] ++ attributes += [attr for attr in (arch, version, release) if attr is not None] + rpm_lookup = create_lookup(model, field='items', keys=keys, context=context) +- return (package_name, arch) in rpm_lookup if arch else (package_name,) in rpm_lookup ++ return tuple(attributes) in rpm_lookup diff --git a/repos/system_upgrade/common/libraries/utils.py b/repos/system_upgrade/common/libraries/utils.py index 6793de6..d201677 100644 --- a/repos/system_upgrade/common/libraries/utils.py @@ -4818,6 +5153,33 @@ index 0000000..de4056f +class ActiveVendorList(Model): + topic = VendorTopic + data = fields.List(fields.String()) +diff --git a/repos/system_upgrade/common/models/dnfworkaround.py b/repos/system_upgrade/common/models/dnfworkaround.py +index c921c5f..4a813dc 100644 +--- a/repos/system_upgrade/common/models/dnfworkaround.py ++++ b/repos/system_upgrade/common/models/dnfworkaround.py +@@ -15,6 +15,20 @@ class DNFWorkaround(Model): + topic = SystemInfoTopic + + script_path = fields.String() +- """ Absolute path to a bash script to execute """ ++ """ ++ Absolute path to a bash script to execute ++ """ ++ ++ script_args = fields.List(fields.String(), default=[]) ++ """ ++ Arguments with which the script should be executed ++ ++ In case that an argument contains a whitespace or an escapable character, ++ the argument must be already treated correctly. e.g. ++ `script_args = ['-i', 'my\\ string'] ++ """ ++ + display_name = fields.String() +- """ Name to display for this script when executed """ ++ """ ++ Name to display for this script when executed ++ """ diff --git a/repos/system_upgrade/common/models/installedrpm.py b/repos/system_upgrade/common/models/installedrpm.py index 28b0aba..e53ab93 100644 --- a/repos/system_upgrade/common/models/installedrpm.py @@ -4901,6 +5263,25 @@ index 0000000..b7a219b + topic = VendorTopic + vendor = fields.String() + source_repoids = fields.List(fields.String()) +diff --git a/repos/system_upgrade/common/tools/removerpmgpgkeys b/repos/system_upgrade/common/tools/removerpmgpgkeys +new file mode 100644 +index 0000000..afe1906 +--- /dev/null ++++ b/repos/system_upgrade/common/tools/removerpmgpgkeys +@@ -0,0 +1,13 @@ ++#!/usr/bin/sh ++ ++exit_code=0 ++ ++for key in "$@"; do ++ echo >&2 "Info: Removing RPM GPG key: $key" ++ rpm --erase "$key" || { ++ exit_code=1 ++ echo >&2 "Error: Failed to remove RPM GPG key: $key" ++ } ++done ++ ++exit $exit_code diff --git a/repos/system_upgrade/common/topics/vendortopic.py b/repos/system_upgrade/common/topics/vendortopic.py new file mode 100644 index 0000000..014b7af @@ -4913,7 +5294,7 @@ index 0000000..014b7af +class VendorTopic(Topic): + name = 'vendor_topic' diff --git a/repos/system_upgrade/el7toel8/actors/checkleftoverpackages/actor.py b/repos/system_upgrade/el7toel8/actors/checkleftoverpackages/actor.py -index 0c53950..7840219 100644 +index 0c53950..33d7c1f 100644 --- a/repos/system_upgrade/el7toel8/actors/checkleftoverpackages/actor.py +++ b/repos/system_upgrade/el7toel8/actors/checkleftoverpackages/actor.py @@ -1,8 +1,24 @@ @@ -4954,7 +5335,7 @@ index 0c53950..7840219 100644 + def skip_leftover_pkg(self, name, unsigned_set): + # Packages like these are expected to be not updated. -+ is_unsigned = name not in unsigned_set ++ is_unsigned = name in unsigned_set + # Packages like these are updated outside of Leapp. + is_external = name.startswith(CPANEL_SUFFIX) + diff --git a/SPECS/leapp-repository.spec b/SPECS/leapp-repository.spec index 9c5d64b..0f4ae91 100644 --- a/SPECS/leapp-repository.spec +++ b/SPECS/leapp-repository.spec @@ -43,7 +43,7 @@ py2_byte_compile "%1" "%2"} Epoch: 1 Name: leapp-repository Version: 0.16.0 -Release: 6%{?dist}.elevate.9 +Release: 6%{?dist}.elevate.10 Summary: Repositories for leapp License: ASL 2.0