diff --git a/convert2rhel/pkgmanager/handlers/yum/__init__.py b/convert2rhel/pkgmanager/handlers/yum/__init__.py index 7f3c7b7901..1ea9640beb 100644 --- a/convert2rhel/pkgmanager/handlers/yum/__init__.py +++ b/convert2rhel/pkgmanager/handlers/yum/__init__.py @@ -126,7 +126,11 @@ def _set_up_base(self): self._base.conf.yumvar["releasever"] = system_info.releasever def _enable_repos(self): - """Enable a list of required repositories.""" + """Enable a list of required repositories. + + :raises SystemInfo: If there is no way to connect to the mirrors in the + repos. + """ self._base.repos.disableRepo("*") # Set the download progress display self._base.repos.setProgressBar(PackageDownloadCallback()) @@ -149,22 +153,23 @@ def _perform_operations(self): loggerinst.info("Adding %s packages to the yum transaction set.", system_info.name) - for pkg in original_os_pkgs: - self._base.update(pattern=pkg) - try: - self._base.reinstall(pattern=pkg) - except ( - pkgmanager.Errors.ReinstallInstallError, - pkgmanager.Errors.ReinstallRemoveError, - ): + try: + for pkg in original_os_pkgs: + self._base.update(pattern=pkg) try: - self._base.downgrade(pattern=pkg) - except ( - pkgmanager.Errors.ReinstallInstallError, - pkgmanager.Errors.ReinstallRemoveError, - pkgmanager.Errors.DowngradeError, - ): - loggerinst.warning("Package %s not available in RHEL repositories.", pkg) + self._base.reinstall(pattern=pkg) + except (pkgmanager.Errors.ReinstallInstallError, pkgmanager.Errors.ReinstallRemoveError): + try: + self._base.downgrade(pattern=pkg) + except ( + pkgmanager.Errors.ReinstallInstallError, + pkgmanager.Errors.ReinstallRemoveError, + pkgmanager.Errors.DowngradeError, + ): + loggerinst.warning("Package %s not available in RHEL repositories.", pkg) + except pkgmanager.Errors.NoMoreMirrorsRepoError as e: + loggerinst.debug("Got the following exception message: %s", e) + loggerinst.critical("There are no suitable mirrors available for the loaded repositories.") def _resolve_dependencies(self, validate_transaction): """Try to resolve the transaction dependencies. diff --git a/convert2rhel/unit_tests/pkgmanager/handlers/yum/yum_test.py b/convert2rhel/unit_tests/pkgmanager/handlers/yum/yum_test.py index d9e49a201e..5db38a12e1 100644 --- a/convert2rhel/unit_tests/pkgmanager/handlers/yum/yum_test.py +++ b/convert2rhel/unit_tests/pkgmanager/handlers/yum/yum_test.py @@ -129,6 +129,15 @@ def test_perform_operations_downgrade_exception( assert pkgmanager.YumBase.downgrade.call_count == len(system_packages) assert "not available in RHEL repositories." in caplog.records[-1].message + @centos7 + def test_perform_operations_no_more_mirrors_repo_exception(self, pretend_os, _mock_yum_api_calls, monkeypatch): + monkeypatch.setattr(pkgmanager.handlers.yum, "get_system_packages_for_replacement", lambda: ["pkg-1"]) + pkgmanager.YumBase.update.side_effect = pkgmanager.Errors.NoMoreMirrorsRepoError + instance = YumTransactionHandler() + + with pytest.raises(SystemExit, match="There are no suitable mirrors available for the loaded repositories."): + instance._perform_operations() + @centos7 @pytest.mark.parametrize( ("ret_code", "message", "validate_transaction", "expected"), diff --git a/plans/tier0.fmf b/plans/tier0.fmf index 2655e3580b..e4e8c8f3a0 100644 --- a/plans/tier0.fmf +++ b/plans/tier0.fmf @@ -77,3 +77,7 @@ /log_command_verification: discover+: test: log-command + +/single_yum_transaction_validation: + discover+: + test: single-yum-transaction-validation diff --git a/tests/integration/tier0/single-yum-transaction-validation/main.fmf b/tests/integration/tier0/single-yum-transaction-validation/main.fmf new file mode 100644 index 0000000000..2f94c6e8c8 --- /dev/null +++ b/tests/integration/tier0/single-yum-transaction-validation/main.fmf @@ -0,0 +1,33 @@ +summary: Verify single yum transaction validation + +description: > + Verify that we are doing a proper rollback during the validation phase in + our transactions. + + If any errors occurs during the transaction resolution, either by + downloading a package, dependency resolver and etc... A rollback should + start and revert the changes to the system. + +link: https://issues.redhat.com/browse/RHELC-576 + +tier: 0 + +tag+: + - yum + - dnf + - transaction + +/transaction_validation_error: + adjust+: + - enabled: false + when: distro == centos-8 or distro == oraclelinux-8 + tag+: + - transaction-validation-error + test: | + pytest -svv -m transaction_validation_error + +/package_download_error: + tag+: + - package-download-error + test: | + pytest -svv -m package_download_error diff --git a/tests/integration/tier0/single-yum-transaction-validation/test_single_yum_transaction_validation.py b/tests/integration/tier0/single-yum-transaction-validation/test_single_yum_transaction_validation.py new file mode 100644 index 0000000000..01a4ae916d --- /dev/null +++ b/tests/integration/tier0/single-yum-transaction-validation/test_single_yum_transaction_validation.py @@ -0,0 +1,100 @@ +import os +import shutil + +import pytest + +from conftest import SYSTEM_RELEASE_ENV +from envparse import env + + +PKI_ENTITLEMENT_CERTS_PATH = "/etc/pki/entitlement" + + +def remove_entitlement_certs(): + """ + Utility function to remove the entitlement certificate as soon as we + notice it in the `PKI_ENTITLEMENT_CERTS_PATH`. + + We don't need to back it up and then restore it because the PKI_ENTITLEMENT_CERTS_PATH folder is only created during + the conversion when the subscription-manager package is installed. And the .pem certificate is being generated by + subscription-manager in the folder during the system registration. So to have the test system clean after the test + finishes the certs shouldn't be present. + """ + for cert_filename in os.listdir(PKI_ENTITLEMENT_CERTS_PATH): + cert_path = os.path.join(PKI_ENTITLEMENT_CERTS_PATH, cert_filename) + try: + os.unlink(cert_path) + except Exception as e: + print("Failed to delete %s. Reason: %s" % (cert_path, e)) + + +@pytest.mark.package_download_error +def test_package_download_error(convert2rhel): + """ + Remove the entitlement certs found at /etc/pki/entitlement during package + download phase for both yum and dnf transactions. + + This will run the conversion up to the point where we valiate the + transaction, when it reaches a specific point of the validation, we remove + the entitlement certs found in /etc/pki/entitlement/*.pem to ensure that the + tool is doing a proper rollback when there is any failure during the package + download. + + The package download happens in different phases for yum and dnf, yum + download the packages during the `processTransaction` method call, while dnf + has a specific method that process and download the packages in the + transaction. + """ + + server_sub = "CentOS Linux" + pkgmanager = "yum" + final_message = "There are no suitable mirrors available for the loaded repositories." + + if "oracle" in SYSTEM_RELEASE_ENV: + server_sub = "Oracle Linux Server" + + if "8" in SYSTEM_RELEASE_ENV: + pkgmanager = "dnf" + final_message = "Failed to download the transaction packages." + + with convert2rhel( + "-y --no-rpm-va --serverurl {} --username {} --password {} --pool {} --debug".format( + env.str("RHSM_SERVER_URL"), + env.str("RHSM_USERNAME"), + env.str("RHSM_PASSWORD"), + env.str("RHSM_POOL"), + ) + ) as c2r: + c2r.expect("Adding {} packages to the {} transaction set.".format(server_sub, pkgmanager)) + remove_entitlement_certs() + assert c2r.expect_exact(final_message, timeout=600) == 0 + + assert c2r.exitstatus == 1 + + +@pytest.mark.transaction_validation_error +def test_transaction_validation_error(convert2rhel): + """ + Remove the entitlement certs found at /etc/pki/entitlement during transaction + processing to throw the following yum error: pkgmanager.Errors.YumDownloadError + + This will run the conversion up to the point where we valiate the + transaction, when it reaches a specific point of the validation, we remove + the entitlement certs found in /etc/pki/entitlement/*.pem to ensure that the + tool is doing a proper rollback when the transaction is being processed. + """ + with convert2rhel( + "-y --no-rpm-va --serverurl {} --username {} --password {} --pool {} --debug".format( + env.str("RHSM_SERVER_URL"), + env.str("RHSM_USERNAME"), + env.str("RHSM_PASSWORD"), + env.str("RHSM_POOL"), + ) + ) as c2r: + c2r.expect( + "Downloading and validating the yum transaction set, no modifications to the system will happen this time." + ) + remove_entitlement_certs() + assert c2r.expect_exact("Failed to validate the yum transaction.", timeout=600) == 0 + + assert c2r.exitstatus == 1 diff --git a/tests/integration/tier1/single-yum-transaction/main.fmf b/tests/integration/tier1/single-yum-transaction/main.fmf index 62d1a719cb..55f918d317 100644 --- a/tests/integration/tier1/single-yum-transaction/main.fmf +++ b/tests/integration/tier1/single-yum-transaction/main.fmf @@ -1,8 +1,9 @@ -summary: Single yum transaction +summary: Verify the single yum transaction description: | - Handle the unified yum transactions so that it handles packages without error. Previous iterations used a lot of - different steps, whereas now it is one transaction that can be rolled back more easily. + Handle the unified yum transactions so that it handles packages without + error. Previous iterations used a lot of different steps, whereas now it is + one transaction that can be rolled back more easily. link: https://issues.redhat.com/browse/RHELC-576