diff --git a/convert2rhel/checks.py b/convert2rhel/checks.py index a2605de141..5483b4638a 100644 --- a/convert2rhel/checks.py +++ b/convert2rhel/checks.py @@ -21,11 +21,12 @@ import os import os.path import re +import shutil import tempfile import rpm -from convert2rhel import __version__ as convert2rhel_version +from convert2rhel import __version__ as installed_convert2rhel_version from convert2rhel import grub, pkgmanager, utils from convert2rhel.pkghandler import ( call_yum_cmd, @@ -46,6 +47,25 @@ KERNEL_REPO_VER_SPLIT_RE = re.compile(r"\W+") BAD_KERNEL_RELEASE_SUBSTRINGS = ("uek", "rt", "linode") +RPM_GPG_KEY_PATH = os.path.join(utils.DATA_DIR, "gpg-keys", "RPM-GPG-KEY-redhat-release") +# The SSL certificate of the https://cdn.redhat.com/ server +SSL_CERT_PATH = os.path.join(utils.DATA_DIR, "redhat-uep.pem") +CDN_URL = "https://cdn.redhat.com/content/public/convert2rhel/$releasever/$basearch/os/" +CONVERT2RHEL_REPO_CONTENT = """\ +[convert2rhel] +name=Convert2RHEL Repository +baseurl=%s +gpgcheck=1 +enabled=1 +sslcacert=%s +gpgkey=file://%s""" % ( + CDN_URL, + SSL_CERT_PATH, + RPM_GPG_KEY_PATH, +) + +PKG_NEVR = r"\b(\S+)-(?:([0-9]+):)?(\S+)-(\S+)\b" + LINK_KMODS_RH_POLICY = "https://access.redhat.com/third-party-software-support" # The kernel version stays the same throughout a RHEL major version COMPATIBLE_KERNELS_VERS = { @@ -76,81 +96,91 @@ def perform_pre_ponr_checks(): def check_convert2rhel_latest(): - """Make sure that we are running the latest version of convert2rhel""" - gpg_path = os.path.join(utils.DATA_DIR, "gpg-keys", "RPM-GPG-KEY-redhat-release") - ssl_cert_path = os.path.join(utils.DATA_DIR, "redhat-uep.pem") - repo_content = ( - "[convert2rhel]\n" - "name=Convert2RHEL Repository\n" - "baseurl=https://cdn.redhat.com/content/public/convert2rhel/$releasever/x86_64/os/\n" - "gpgcheck=1\n" - "enabled=1\n" - "sslcacert=%s\n" - "gpgkey=file://%s\n" % (ssl_cert_path, gpg_path) - ) + """Make sure that we are running the latest downstream version of convert2rhel""" + logger.task("Prepare: Checking if this is the latest version of Convert2RHEL") + + if not system_info.has_internet_access: + logger.warning("Skipping the check because no internet connection has been detected.") + return + + repo_dir = tempfile.mkdtemp(prefix="convert2rhel_repo.", dir=utils.TMP_DIR) + repo_path = os.path.join(repo_dir, "convert2rhel.repo") + store_content_to_file(filename=repo_path, content=CONVERT2RHEL_REPO_CONTENT) cmd = [ "repoquery", + "--disablerepo=*", + "--enablerepo=convert2rhel", "--releasever=%s" % system_info.version.major, + "--setopt=reposdir=%s" % repo_dir, + "convert2rhel", ] - repo_dir = tempfile.mkdtemp(prefix="convert2rhel_repo.", dir=utils.TMP_DIR) + # Note: This is safe because we're creating in utils.TMP_DIR which is hardcoded to + # /var/lib/convert2rhel which does not have any world-writable directory components. utils.mkdir_p(repo_dir) - repo_path = os.path.join(repo_dir, "convert2rhel.repo") - store_content_to_file(filename=repo_path, content=repo_content) - - cmd.append("--setopt=reposdir=%s" % repo_dir) - cmd.append("convert2rhel") - raw_output_convert2rhel_versions, return_code = run_subprocess(cmd, print_output=False) + try: + raw_output_convert2rhel_versions, return_code = run_subprocess(cmd, print_output=False) + finally: + shutil.rmtree(repo_dir) if return_code != 0: logger.warning( - "Couldn't check if this is the latest version of convert2rhel\n" - "repoquery failed %s, %s" % (return_code, raw_output_convert2rhel_versions) + "Couldn't check if the current installed Convert2RHEL is the latest version.\n" + "repoquery failed with the following output:\n%s" % (raw_output_convert2rhel_versions) ) return - PKG_NEVR = r"\b(\S+)-(?:([0-9]+):)?(\S+)-(\S+)\b" convert2rhel_versions = re.findall(PKG_NEVR, raw_output_convert2rhel_versions, re.MULTILINE) - latest_version = ("0", "0.00", "0") + logger.debug("Found %s convert2rhel package(s)" % len(convert2rhel_versions)) + latest_available_version = ("0", "0.00", "0") + # This loop will determine the latest available convert2rhel version in the yum repo. + # It assigns the epoch, version, and release ex: ("0", "0.26", "1.el7") to the latest_available_version variable. for package_version in convert2rhel_versions: - # rpm.lableCompare(pkg1, pkg2) compare two kernel version strings and return - # -1 if str2 is greater then str1, 0 if they are equal, 1 if str1 is greater the str2 - ver_compare = rpm.labelCompare(package_version[1:], latest_version) + # rpm.labelCompare(pkg1, pkg2) compare two package version strings and return + # -1 if latest_version is greater than package_version, 0 if they are equal, 1 if package_version is greater than latest_version + ver_compare = rpm.labelCompare(package_version[1:], latest_available_version) if ver_compare > 0: - latest_version = package_version[1:] - - # After the for loop latest_version will have the epoch ,version, and release ex:("0" "0.26" "1.el7") information from convert2rhel yum repo. - # the release for latest_verion will be "1.el7" and the relase for convert2rhel_version will be hard coded as "0" below, - # therefore when the versions are the same the latest_version's release field will cause it to evaluate as later - ver_compare = rpm.labelCompare(("0", convert2rhel_version, "0"), ("0", latest_version[1], "0")) + logger.debug( + "...convert2rhel version %s is newer than %s, updating latest_available_version variable" + % (package_version[1:][1], latest_available_version[1]) + ) + latest_available_version = package_version[1:] + + # After the for loop, the latest_available_version variable will gain the epoch, version, and release + # (e.g. ("0" "0.26" "1.el7")) information from the Convert2RHEL yum repo + # when the versions are the same the latest_available_version's release field will cause it to evaluate as a later version. + # Therefore we need to hardcode "0" for both the epoch and release below for installed_convert2rhel_version + # and latest_available_version respectively, to compare **just** the version field. + ver_compare = rpm.labelCompare(("0", installed_convert2rhel_version, "0"), ("0", latest_available_version[1], "0")) if ver_compare < 0: - if "CONVERT2RHEL_UNSUPPORTED_VERSION" in os.environ: + if "CONVERT2RHEL_ALLOW_OLDER_VERSION" in os.environ: logger.warning( - "You are currently running %s and the latest version of convert2rhel is %s.\n" - "'CONVERT2RHEL_UNSUPPORTED_VERSION' environment detected, continuing conversion" - % (convert2rhel_version, latest_version[1]) + "You are currently running %s and the latest version of Convert2RHEL is %s.\n" + "'CONVERT2RHEL_ALLOW_OLDER_VERSION' environment variable detected, continuing conversion" + % (installed_convert2rhel_version, latest_available_version[1]) ) else: if int(system_info.version.major) <= 6: logger.warning( - "You are currently running %s and the latest version of convert2rhel is %s.\n" - "Only the latest version is supported for conversion." % (convert2rhel_version, latest_version[1]) + "You are currently running %s and the latest version of Convert2RHEL is %s.\n" + "We encourage you to update to the latest version." + % (installed_convert2rhel_version, latest_available_version[1]) ) else: logger.critical( - "You are currently running %s and the latest version of convert2rhel is %s.\n" + "You are currently running %s and the latest version of Convert2RHEL is %s.\n" "Only the latest version is supported for conversion. If you want to ignore" - " this you can set 'CONVERT2RHEL_UNSUPPORTED_VERSION' to continue" - % (convert2rhel_version, latest_version[1]) + " this check, then set the environment variable 'CONVERT2RHEL_ALLOW_OLDER_VERSION=1' to continue." + % (installed_convert2rhel_version, latest_available_version[1]) ) else: - logger.debug("Latest available convert2rhel version is installed.\n" "Continuing conversion.") + logger.debug("Latest available Convert2RHEL version is installed.\n" "Continuing conversion.") def check_efi(): diff --git a/convert2rhel/unit_tests/checks_test.py b/convert2rhel/unit_tests/checks_test.py index 17f1872e69..3e47ff2993 100644 --- a/convert2rhel/unit_tests/checks_test.py +++ b/convert2rhel/unit_tests/checks_test.py @@ -94,14 +94,17 @@ @pytest.fixture -def convert2rhel_latest_version_test(monkeypatch, tmpdir, request): +def convert2rhel_latest_version_test(monkeypatch, tmpdir, request, global_system_info): + monkeypatch.setattr(checks, "system_info", global_system_info) + global_system_info.has_internet_access = True + marker = request.param - monkeypatch.setattr(checks, "convert2rhel_version", marker["local_version"]) + monkeypatch.setattr(checks, "installed_convert2rhel_version", marker["local_version"]) run_subprocess_mocked = mock.Mock(spec=run_subprocess, return_value=(marker["package_version"], 0)) monkeypatch.setattr(checks, "run_subprocess", run_subprocess_mocked) - monkeypatch.setattr(system_info, "version", namedtuple("Version", ["major", "minor"])(marker["pmajor"], 0)) + monkeypatch.setattr(global_system_info, "version", namedtuple("Version", ["major", "minor"])(marker["pmajor"], 0)) monkeypatch.setattr(utils, "TMP_DIR", str(tmpdir)) return marker["local_version"], marker["package_version"] @@ -187,36 +190,36 @@ def test_pre_ponr_checks(monkeypatch): create_transaction_handler_mock.assert_called_once() -def test_repoquery__failure(caplog, monkeypatch, tmpdir, request): - repoquery_output = " error message" - return_code = 1 - run_subprocess_mocked = mock.Mock(spec=run_subprocess, return_value=(repoquery_output, return_code)) - - monkeypatch.setattr(checks, "run_subprocess", run_subprocess_mocked) - monkeypatch.setattr(system_info, "version", namedtuple("Version", ["major", "minor"])(6, 0)) - monkeypatch.setattr(utils, "TMP_DIR", str(tmpdir)) - +@pytest.mark.parametrize( + ("convert2rhel_latest_version_test",), + ([{"local_version": "0.20", "package_version": "convert2rhel-0:0.22-1.el7.noarch", "pmajor": "7"}],), + indirect=True, +) +def test_convert2rhel_latest_offline(caplog, convert2rhel_latest_version_test, global_system_info): + global_system_info.has_internet_access = False checks.check_convert2rhel_latest() - log_msg = "Couldn't check if this is the latest version of convert2rhel\n" "repoquery failed %s, %s" % ( - return_code, - repoquery_output, - ) + convert2rhel_latest_version_test + log_msg = "Skipping the check because no internet connection has been detected." assert log_msg in caplog.text @pytest.mark.parametrize( ("convert2rhel_latest_version_test",), - ([{"local_version": "0.20", "package_version": "convert2rhel-0:0.22-1.el7.noarch", "pmajor": "6"}],), + ( + [{"local_version": "0.20", "package_version": "convert2rhel-0:0.22-1.el7.noarch", "pmajor": "6"}], + [{"local_version": "0.18", "package_version": "convert2rhel-0:1.10-1.el7.noarch", "pmajor": "6"}], + ), indirect=True, ) def test_convert2rhel_latest_out_of_date_el6(caplog, convert2rhel_latest_version_test): checks.check_convert2rhel_latest() - local_version, dummy_ = convert2rhel_latest_version_test + local_version, package_version = convert2rhel_latest_version_test + package_version = package_version[15:19] log_msg = ( - "You are currently running %s and the latest version of convert2rhel is 0.22.\n" - "Only the latest version is supported for conversion." % (local_version) + "You are currently running %s and the latest version of Convert2RHEL is %s.\n" + "We encourage you to update to the latest version." % (local_version, package_version) ) assert log_msg in caplog.text @@ -225,19 +228,21 @@ def test_convert2rhel_latest_out_of_date_el6(caplog, convert2rhel_latest_version ("convert2rhel_latest_version_test",), ( [{"local_version": "0.21", "package_version": "convert2rhel-0:0.22-1.el7.noarch", "pmajor": "7"}], - [{"local_version": "0.21", "package_version": "convert2rhel-0:0.22-1.el7.noarch", "pmajor": "8"}], + [{"local_version": "0.21", "package_version": "convert2rhel-0:1.10-1.el7.noarch", "pmajor": "7"}], ), indirect=True, ) def test_convert2rhel_latest_log_check_exit(caplog, convert2rhel_latest_version_test): with pytest.raises(SystemExit): checks.check_convert2rhel_latest() - local_version, dummy_ = convert2rhel_latest_version_test + local_version, package_version = convert2rhel_latest_version_test + package_version = package_version[15:19] log_msg = ( - "You are currently running %s and the latest version of convert2rhel is 0.22.\n" - "Only the latest version is supported for conversion. If you want to ignore this you can set 'CONVERT2RHEL_UNSUPPORTED_VERSION' to continue" - % (local_version) + "You are currently running %s and the latest version of Convert2RHEL is %s.\n" + "Only the latest version is supported for conversion. If you want to ignore" + " this check, then set the environment variable 'CONVERT2RHEL_ALLOW_OLDER_VERSION=1' to continue." + % (local_version, package_version) ) assert log_msg in caplog.text @@ -269,18 +274,29 @@ def test_convert2rhel_latest_log_check_exit(caplog, convert2rhel_latest_version_ "enset": "1", } ], + [ + { + "local_version": "0.18", + "package_version": "convert2rhel-0:1.10-1.el7.noarch", + "pmajor": "8", + "enset": "1", + } + ], ), indirect=True, ) def test_convert2rhel_latest_log_check_env(caplog, monkeypatch, convert2rhel_latest_version_test): - monkeypatch.setattr(os, "environ", {"CONVERT2RHEL_UNSUPPORTED_VERSION": "1"}) + monkeypatch.setattr(os, "environ", {"CONVERT2RHEL_ALLOW_OLDER_VERSION": "1"}) checks.check_convert2rhel_latest() - local_version, dummy_ = convert2rhel_latest_version_test + local_version, package_version = convert2rhel_latest_version_test + package_version = package_version[15:19] log_msg = ( - "You are currently running %s and the latest version of convert2rhel is 0.22.\n" - "'CONVERT2RHEL_UNSUPPORTED_VERSION' environment detected, continuing conversion" % (local_version) + "You are currently running %s and the latest version of Convert2RHEL is %s.\n" + "'CONVERT2RHEL_ALLOW_OLDER_VERSION' environment variable detected, continuing conversion" + % (local_version, package_version) ) + assert log_msg in caplog.text @@ -293,6 +309,7 @@ def test_convert2rhel_latest_log_check_env(caplog, monkeypatch, convert2rhel_lat [{"local_version": "0.25", "package_version": "convert2rhel-0:0.17-1.el7.noarch", "pmajor": "6"}], [{"local_version": "0.25", "package_version": "convert2rhel-0:0.17-1.el7.noarch", "pmajor": "7"}], [{"local_version": "0.25", "package_version": "convert2rhel-0:0.17-1.el7.noarch", "pmajor": "8"}], + [{"local_version": "1.10", "package_version": "convert2rhel-0:0.18-1.el7.noarch", "pmajor": "8"}], ), indirect=True, ) @@ -300,7 +317,51 @@ def test_c2r_up_to_date(caplog, monkeypatch, convert2rhel_latest_version_test): checks.check_convert2rhel_latest() local_version, dummy_ = convert2rhel_latest_version_test - log_msg = "Latest available convert2rhel version is installed.\n" "Continuing conversion." + log_msg = "Latest available Convert2RHEL version is installed.\n" "Continuing conversion." + assert log_msg in caplog.text + + +@pytest.mark.parametrize( + ("convert2rhel_latest_version_test",), + ([{"local_version": "1.10", "package_version": "convert2rhel-0:0.18-1.el7.noarch", "pmajor": "8"}],), + indirect=True, +) +def test_c2r_up_to_date_repoquery_error(caplog, convert2rhel_latest_version_test, monkeypatch): + monkeypatch.setattr(checks, "run_subprocess", mock.Mock(return_value=("Repoquery did not run", 1))) + + checks.check_convert2rhel_latest() + + log_msg = ( + "Couldn't check if the current installed Convert2RHEL is the latest version.\n" + "repoquery failed with the following output:\nRepoquery did not run" + ) + assert log_msg in caplog.text + + +@pytest.mark.parametrize( + ("convert2rhel_latest_version_test",), + ( + [ + { + "local_version": "0.19", + "package_version": "convert2rhel-0:0.18-1.el7.noarch\nconvert2rhel-0:0.17-1.el7.noarch\nconvert2rhel-0:0.20-1.el7.noarch", + "pmajor": "8", + } + ], + ), + indirect=True, +) +def test_c2r_up_to_date_multiple_packages(caplog, convert2rhel_latest_version_test, monkeypatch): + + with pytest.raises(SystemExit): + checks.check_convert2rhel_latest() + + log_msg = ( + "You are currently running 0.19 and the latest version of Convert2RHEL is 0.20.\n" + "Only the latest version is supported for conversion. If you want to ignore" + " this check, then set the environment variable 'CONVERT2RHEL_ALLOW_OLDER_VERSION=1' to continue." + ) + assert log_msg in caplog.text diff --git a/tests/integration/tier0/basic-sanity-checks/test_basic_sanity_checks.py b/tests/integration/tier0/basic-sanity-checks/test_basic_sanity_checks.py index 162f788d77..0570ef8599 100644 --- a/tests/integration/tier0/basic-sanity-checks/test_basic_sanity_checks.py +++ b/tests/integration/tier0/basic-sanity-checks/test_basic_sanity_checks.py @@ -65,8 +65,9 @@ def test_c2r_latest_newer(convert2rhel): change_c2r_version(42.0) with convert2rhel(f"--no-rpm-va --debug") as c2r: - assert c2r.expect("Latest available convert2rhel version is installed.", timeout=300) == 0 + assert c2r.expect("Latest available Convert2RHEL version is installed.", timeout=300) == 0 assert c2r.expect("Continuing conversion.", timeout=300) == 0 + c2r.expect("Continue with the system conversion?") c2r.sendline("n") @@ -92,12 +93,12 @@ def test_c2r_latest_older_inhibit(convert2rhel): def test_c2r_latest_older_unsupported_version(convert2rhel): """ Check if running older version with the environment - variable "CONVERT2RHEL_UNSUPPORTED_VERSION" continues the conversion. + variable "CONVERT2RHEL_ALLOW_OLDER_VERSION" continues the conversion. Running older version of Convert2RHEL on epel major version 6 or older should inhibit either way. """ change_c2r_version(0.01) - os.environ["CONVERT2RHEL_UNSUPPORTED_VERSION"] = "1" + os.environ["CONVERT2RHEL_ALLOW_OLDER_VERSION"] = "1" with convert2rhel(f"--no-rpm-va --debug") as c2r: if "centos-6" in booted_os or "oracle-6" in booted_os: @@ -108,7 +109,8 @@ def test_c2r_latest_older_unsupported_version(convert2rhel): assert c2r.expect("You are currently running 0.01", timeout=300) == 0 assert ( c2r.expect( - "'CONVERT2RHEL_UNSUPPORTED_VERSION' environment detected, continuing conversion", timeout=300 + "'CONVERT2RHEL_ALLOW_OLDER_VERSION' environment variable detected, continuing conversion", + timeout=300, ) == 0 ) @@ -118,7 +120,7 @@ def test_c2r_latest_older_unsupported_version(convert2rhel): # Clean up os.system(f"cp /tmp/__init__.py {PATH_TO_VERSION}") - del os.environ["CONVERT2RHEL_UNSUPPORTED_VERSION"] + del os.environ["CONVERT2RHEL_ALLOW_OLDER_VERSION"] def test_clean_cache(convert2rhel):