From 970a267d2ce535e0e4e7e181fbd216f100e456b4 Mon Sep 17 00:00:00 2001 From: Rodolfo Olivieri Date: Thu, 2 Jun 2022 13:11:28 -0400 Subject: [PATCH] Add hardcoded repofiles for EUS (#458) Allow conversions to RHEL 8.4 EUS minor version From CentOS and Oracle Linux 8.4. * Add official CentOS Linux repositories for EUS Add the official CentOS Linux repositories for versions 8.4 & 8.5 to the data folder to enable EUS support for those systems. * Update the functions that check if there is any package to be updated with the support of the EUS. This change reflects only the DNF API as the EUS is only supported in RHEL8+ and we manage the CentOS Linux 8+ repos. * Add a new option to the config files Add another option to the config files to represent the eus repoids in RHEL. Since we are supporting only EUS in RHEL8 and not 7, we are just adding these repoids to the specific versions. The RHEL7 config file option is empty on purpose. * Remove old rhn* packages from OL8 config The rhn* packages are causing problems during the conversion in OL8.4 (EUS), since in the EUS version we are not enabling the appstream repositories (as OracleLinux does not make appstream public for older versions) we were facing problems with these specific packages. Since the rhn* packages were used in the past in conjunction with Satellite 5, and both are EOL, we decided to remove this package as it does not affect the conversion in any way and it should not be used. * Disable new checks for OL8.4 We have decided to disable the checks `is_installed_kernel` and `check_package_updates` for OL8.4. The reason for that, is that every OL distribution has enabled by default the repository `ol8_baseos_latest`, which will have the latest packages available when a new release is made public (8.6, 8.7, 8.8 and so on...) Since we can't easily tell whether the system is the latest OL release, we voted to just disable the checks for any version that is below OL8.latest, that means, for now, OL8.6. * Add a rhsm releasever lock for EUS conversions Without the RHSM releasever lock, any yum call after the conversion would fail as the baseurl of EUS repositories points to a non-existing URL ($releasever is expanded to '8' by default instead of the needed '8.4', for instance). Jira reference (If any): https://issues.redhat.com/browse/OAMG-6511 Signed-off-by: Rodolfo Olivieri Co-authored-by: Martin Litwora Co-authored-by: Daniel Diblik --- .packit.yaml | 2 +- convert2rhel/backup.py | 209 +++++++++ convert2rhel/checks.py | 82 +++- .../data/7/x86_64/configs/centos-7-x86_64.cfg | 4 + .../data/7/x86_64/configs/oracle-7-x86_64.cfg | 4 + .../7/x86_64/configs/scientific-7-x86_64.cfg | 4 + .../8/x86_64/configs/almalinux-8-x86_64.cfg | 8 +- .../data/8/x86_64/configs/centos-8-x86_64.cfg | 8 +- .../data/8/x86_64/configs/oracle-8-x86_64.cfg | 8 +- .../data/8/x86_64/configs/rocky-8-x86_64.cfg | 8 +- .../centos-8.4/CentOS-Linux-AppStream.repo | 17 + .../repos/centos-8.4/CentOS-Linux-BaseOS.repo | 17 + .../CentOS-Linux-ContinuousRelease.repo | 35 ++ .../repos/centos-8.4/CentOS-Linux-Devel.repo | 17 + .../repos/centos-8.4/CentOS-Linux-Extras.repo | 17 + .../centos-8.4/CentOS-Linux-FastTrack.repo | 17 + .../CentOS-Linux-HighAvailability.repo | 17 + .../repos/centos-8.4/CentOS-Linux-Plus.repo | 17 + .../centos-8.4/CentOS-Linux-PowerTools.repo | 17 + .../centos-8.4/CentOS-Linux-Sources.repo | 36 ++ .../centos-8.5/CentOS-Linux-AppStream.repo | 17 + .../repos/centos-8.5/CentOS-Linux-BaseOS.repo | 17 + .../centos-8.5/CentOS-Linux-Debuginfo.repo | 11 + .../repos/centos-8.5/CentOS-Linux-Devel.repo | 17 + .../repos/centos-8.5/CentOS-Linux-Extras.repo | 17 + .../centos-8.5/CentOS-Linux-FastTrack.repo | 17 + .../CentOS-Linux-HighAvailability.repo | 17 + .../repos/centos-8.5/CentOS-Linux-Plus.repo | 17 + .../centos-8.5/CentOS-Linux-PowerTools.repo | 17 + .../centos-8.5/CentOS-Linux-Sources.repo | 36 ++ convert2rhel/main.py | 6 +- convert2rhel/pkghandler.py | 73 ++-- convert2rhel/redhatrelease.py | 6 +- convert2rhel/repo.py | 40 +- convert2rhel/special_cases.py | 3 +- convert2rhel/subscription.py | 98 ++++- convert2rhel/systeminfo.py | 64 ++- convert2rhel/unit_tests/backup_test.py | 401 ++++++++++++++++++ convert2rhel/unit_tests/checks_test.py | 138 +++++- convert2rhel/unit_tests/main_test.py | 37 +- convert2rhel/unit_tests/pkghandler_test.py | 104 +++-- convert2rhel/unit_tests/repo_test.py | 57 ++- convert2rhel/unit_tests/subscription_test.py | 229 +++++++++- convert2rhel/unit_tests/systeminfo_test.py | 55 ++- convert2rhel/unit_tests/utils_test.py | 123 ++---- convert2rhel/utils.py | 191 +-------- plans/main.fmf | 8 + plans/tier1.fmf | 25 +- tests/ansible_collections/main.yml | 3 + .../roles/add-custom-repos/main.yml | 6 +- .../add-custom-repos/rhel8-eus-repos.yml | 19 + .../tasks/centos-repos.yml | 32 ++ .../tasks/main.yml | 2 + .../roles/install-testing-deps/tasks/main.yml | 6 +- .../roles/update-system/tasks/main.yml | 5 + tests/integration/conftest.py | 2 +- .../backup-release/test_backup_release.py | 33 +- .../check-custom-repo/test_custom_repos.py | 9 +- .../check-user-response/test_user_response.py | 12 +- .../test_kmods_not_supported.py | 20 +- .../test_check_rollback_handling.py | 20 +- .../changed-yum-conf/test_patch_yum_conf.py | 4 +- .../test_enabled_repositories.py | 28 ++ .../test_release_version.py | 29 ++ .../convert-offline-systems/prepare_system.py | 9 +- .../convert-offline-systems/run_conversion.py | 35 +- .../integration/tier1/method/custom_repos.py | 23 +- tests/integration/tier1/method/satellite.py | 30 +- .../one-kernel-scenario/run_conversion.py | 10 + .../test_no_submgr_pkg_installed.py | 17 +- .../tier1/satellite_non_eus_repos/main.fmf | 6 + .../satellite_non_eus_repos.py | 31 ++ .../install_non_latest_kernel.py | 25 +- .../test_non_latest_kernel_inhibitor.py | 15 +- .../test_system_up_to_date.py | 18 +- .../yum-distro-sync/test_yum_distro_sync.py | 5 +- 76 files changed, 2355 insertions(+), 484 deletions(-) create mode 100644 convert2rhel/backup.py create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-AppStream.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-BaseOS.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-ContinuousRelease.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-Devel.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-Extras.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-FastTrack.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-HighAvailability.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-Plus.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-PowerTools.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-Sources.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-AppStream.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-BaseOS.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Debuginfo.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Devel.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Extras.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-FastTrack.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-HighAvailability.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Plus.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-PowerTools.repo create mode 100644 convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Sources.repo create mode 100644 convert2rhel/unit_tests/backup_test.py create mode 100644 tests/ansible_collections/roles/add-custom-repos/rhel8-eus-repos.yml create mode 100644 tests/ansible_collections/roles/hardcode-minor-version-repos/tasks/centos-repos.yml create mode 100644 tests/ansible_collections/roles/hardcode-minor-version-repos/tasks/main.yml create mode 100644 tests/integration/tier1/checks-after-conversion/test_enabled_repositories.py create mode 100644 tests/integration/tier1/satellite_non_eus_repos/main.fmf create mode 100644 tests/integration/tier1/satellite_non_eus_repos/satellite_non_eus_repos.py diff --git a/.packit.yaml b/.packit.yaml index a36a20b12c..e4bdce5110 100644 --- a/.packit.yaml +++ b/.packit.yaml @@ -43,6 +43,6 @@ jobs: epel-7-x86_64: distros: [centos-7, oraclelinux-7] epel-8-x86_64: - distros: [centos-8, oraclelinux-8] + distros: [centos-8.4, centos-8, oraclelinux-8.4, oraclelinux-8] use_internal_tf: True trigger: pull_request diff --git a/convert2rhel/backup.py b/convert2rhel/backup.py new file mode 100644 index 0000000000..5c09b35b12 --- /dev/null +++ b/convert2rhel/backup.py @@ -0,0 +1,209 @@ +# -*- coding: utf-8 -*- +# +# Copyright(C) 2022 Red Hat, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import logging +import os +import shutil + +from convert2rhel.repo import get_hardcoded_repofiles_dir +from convert2rhel.systeminfo import system_info +from convert2rhel.utils import BACKUP_DIR, download_pkg, remove_orphan_folders, run_subprocess + + +loggerinst = logging.getLogger(__name__) + + +class ChangedRPMPackagesController(object): + """Keep control of installed/removed RPM pkgs for backup/restore.""" + + def __init__(self): + self.installed_pkgs = [] + self.removed_pkgs = [] + + def track_installed_pkg(self, pkg): + """Add a installed RPM pkg to the list of installed pkgs.""" + self.installed_pkgs.append(pkg) + + def track_installed_pkgs(self, pkgs): + """Track packages installed before the PONR to be able to remove them later (roll them back) if needed.""" + self.installed_pkgs += pkgs + + def backup_and_track_removed_pkg(self, pkg): + """Add a removed RPM pkg to the list of removed pkgs.""" + restorable_pkg = RestorablePackage(pkg) + restorable_pkg.backup() + self.removed_pkgs.append(restorable_pkg) + + def _remove_installed_pkgs(self): + """For each package installed during conversion remove it.""" + loggerinst.task("Rollback: Removing installed packages") + remove_pkgs(self.installed_pkgs, backup=False, critical=False) + + def _install_removed_pkgs(self): + """For each package removed during conversion install it.""" + loggerinst.task("Rollback: Installing removed packages") + pkgs_to_install = [] + for restorable_pkg in self.removed_pkgs: + if restorable_pkg.path is None: + loggerinst.warning("Couldn't find a backup for %s package." % restorable_pkg.name) + continue + pkgs_to_install.append(restorable_pkg.path) + + self._install_local_rpms(pkgs_to_install, replace=True, critical=False) + + def _install_local_rpms(self, pkgs_to_install, replace=False, critical=True): + """Install packages locally available.""" + + if not pkgs_to_install: + loggerinst.info("No package to install") + return False + + cmd_param = ["rpm", "-i"] + if replace: + cmd_param.append("--replacepkgs") + + loggerinst.info("Installing packages:") + for pkg in pkgs_to_install: + loggerinst.info("\t%s" % pkg) + + cmd = cmd_param + pkgs_to_install + output, ret_code = run_subprocess(cmd, print_output=False) + if ret_code != 0: + pkgs_as_str = " ".join(pkgs_to_install) + loggerinst.debug(output.strip()) + if critical: + loggerinst.critical("Error: Couldn't install %s packages." % pkgs_as_str) + + loggerinst.warning("Couldn't install %s packages." % pkgs_as_str) + return False + + for path in pkgs_to_install: + nvra, _ = os.path.splitext(os.path.basename(path)) + self.track_installed_pkg(nvra) + + return True + + def restore_pkgs(self): + """Restore system to the original state.""" + self._remove_installed_pkgs() + remove_orphan_folders() + self._install_removed_pkgs() + + +class RestorableFile(object): + def __init__(self, filepath): + self.filepath = filepath + + def backup(self): + """Save current version of a file""" + loggerinst.info("Backing up %s." % self.filepath) + if os.path.isfile(self.filepath): + try: + loggerinst.debug("Copying %s to %s." % (self.filepath, BACKUP_DIR)) + shutil.copy2(self.filepath, BACKUP_DIR) + except (OSError, IOError) as err: + # IOError for py2 and OSError for py3 + loggerinst.critical("Error(%s): %s" % (err.errno, err.strerror)) + else: + loggerinst.info("Can't find %s.", self.filepath) + + def restore(self): + """Restore a previously backed up file""" + backup_filepath = os.path.join(BACKUP_DIR, os.path.basename(self.filepath)) + loggerinst.task("Rollback: Restoring %s from backup" % self.filepath) + + if not os.path.isfile(backup_filepath): + loggerinst.warning("%s hasn't been backed up" % self.filepath) + return + try: + shutil.copy2(backup_filepath, self.filepath) + except (OSError, IOError) as err: + # Do not call 'critical' which would halt the program. We are in + # a rollback phase now and we want to rollback as much as possible. + # IOError for py2 and OSError for py3 + loggerinst.warning("Error(%s): %s" % (err.errno, err.strerror)) + return + loggerinst.info("File %s restored" % self.filepath) + + +class RestorablePackage(object): + def __init__(self, pkgname): + self.name = pkgname + self.path = None + + def backup(self): + """Save version of RPM package""" + loggerinst.info("Backing up %s" % self.name) + if os.path.isdir(BACKUP_DIR): + reposdir = get_hardcoded_repofiles_dir() + + # One of the reasons we hardcode repofiles pointing to archived repositories of older system + # minor versions is that we need to be able to download an older package version as a backup. + # Because for example the default repofiles on CentOS Linux 8.4 point only to 8.latest repositories + # that already don't contain 8.4 packages. + if not system_info.has_internet_access: + if reposdir: + loggerinst.debug( + "Not using repository files stored in %s due to the absence of internet access." % reposdir + ) + self.path = download_pkg(self.name, dest=BACKUP_DIR, set_releasever=False) + else: + if reposdir: + loggerinst.debug("Using repository files stored in %s." % reposdir) + self.path = download_pkg( + self.name, + dest=BACKUP_DIR, + set_releasever=False, + reposdir=reposdir, + ) + else: + loggerinst.warning("Can't access %s" % BACKUP_DIR) + + +def remove_pkgs(pkgs_to_remove, backup=True, critical=True): + """Remove packages not heeding to their dependencies.""" + + # NOTE(r0x0d): This function is tied to the class ChangedRPMPackagesController and + # a couple of other places too, ideally, we should decide if we want to use + # this function as an entrypoint or the variable `changed_pkgs_control`, so + # we can move this piece of code to the `pkghandler.py` where it should be. + # Right now, if we move this code to the `pkghandler.py`, we have a + # *circular import dependency error*. + # @abadger has an implementation in mind to address some of those issues + # and actually place a controller in front of classes like this. + if backup: + # Some packages, when removed, will also remove repo files, making it + # impossible to access the repositories to download a backup. For this + # reason we first backup all packages and only after that we remove + for nvra in pkgs_to_remove: + changed_pkgs_control.backup_and_track_removed_pkg(nvra) + + if not pkgs_to_remove: + loggerinst.info("No package to remove") + return + + for nvra in pkgs_to_remove: + loggerinst.info("Removing package: %s" % nvra) + _, ret_code = run_subprocess(["rpm", "-e", "--nodeps", nvra]) + if ret_code != 0: + if critical: + loggerinst.critical("Error: Couldn't remove %s." % nvra) + else: + loggerinst.warning("Couldn't remove %s." % nvra) + + +changed_pkgs_control = ChangedRPMPackagesController() # pylint: disable=C0103 diff --git a/convert2rhel/checks.py b/convert2rhel/checks.py index 7d477b0f00..76e99880ba 100644 --- a/convert2rhel/checks.py +++ b/convert2rhel/checks.py @@ -33,6 +33,7 @@ get_pkg_fingerprint, get_total_packages_to_update, ) +from convert2rhel.repo import get_hardcoded_repofiles_dir from convert2rhel.systeminfo import system_info from convert2rhel.toolopts import tool_opts from convert2rhel.utils import ask_to_continue, get_file_content, run_subprocess, store_content_to_file @@ -546,9 +547,26 @@ def check_package_updates(): """Ensure that the system packages installed are up-to-date.""" logger.task("Prepare: Checking if the packages are up-to-date") + if system_info.id == "oracle" and system_info.corresponds_to_rhel_eus_release(): + logger.info( + "Skipping the check because there are no publicly available %s %d.%d repositories available." + % (system_info.name, system_info.version.major, system_info.version.minor) + ) + return + + reposdir = get_hardcoded_repofiles_dir() + + if reposdir and not system_info.has_internet_access: + logger.warning("Skipping the check as no internet connection has been detected.") + return + try: - packages_to_update = get_total_packages_to_update() + packages_to_update = get_total_packages_to_update(reposdir=reposdir) except pkgmanager.RepoError as e: + # As both yum and dnf have the same error class (RepoError), to identify any problems when interacting with the + # repositories, we use this to catch exceptions when verifying if there is any packages to update on the system. + # Beware that the `RepoError` exception is based on the `pkgmanager` module and the message sent to the output + # can differ depending if the code is running in RHEL7 (yum) or RHEL8 (dnf). logger.warning( "There was an error while checking whether the installed packages are up-to-date. Having updated system is " "an important prerequisite for a successful conversion. Consider stopping the conversion to " @@ -559,12 +577,15 @@ def check_package_updates(): return if len(packages_to_update) > 0: + repos_message = ( + "on the enabled system repos" if not reposdir else "on repositories defined in the %s folder" % reposdir + ) logger.warning( - "The system has %s packages not updated.\n" + "The system has %s packages not updated based %s.\n" "List of packages to update: %s.\n\n" "Not updating the packages may cause the conversion to fail.\n" "Consider stopping the conversion and update the packages before re-running convert2rhel." - % (len(packages_to_update), " ".join(packages_to_update)) + % (len(packages_to_update), repos_message, " ".join(packages_to_update)) ) ask_to_continue() else: @@ -575,15 +596,40 @@ def is_loaded_kernel_latest(): """Check if the loaded kernel is behind or of the same version as in yum repos.""" logger.task("Prepare: Checking if the loaded kernel version is the most recent") + if system_info.id == "oracle" and system_info.corresponds_to_rhel_eus_release(): + logger.info( + "Skipping the check because there are no publicly available %s %d.%d repositories available." + % (system_info.name, system_info.version.major, system_info.version.minor) + ) + return + + reposdir = get_hardcoded_repofiles_dir() + + if reposdir and not system_info.has_internet_access: + logger.warning("Skipping the check as no internet connection has been detected.") + return + + cmd = ["repoquery", "--quiet", "--qf", '"%{BUILDTIME}\\t%{VERSION}-%{RELEASE}\\t%{REPOID}"'] + + # If the reposdir variable is not empty, meaning that it detected the hardcoded repofiles, we should use that + # instead of the system repositories located under /etc/yum.repos.d + if reposdir: + cmd.append("--setopt=reposdir=%s" % reposdir) + # For Oracle/CentOS Linux 8 the `kernel` is just a meta package, instead, we check for `kernel-core`. # But for 6 and 7 releases, the correct way to check is using `kernel`. package_to_check = "kernel-core" if system_info.version.major >= 8 else "kernel" - # The latest kernel version on repo - repoquery_output, _ = run_subprocess( - ["repoquery", "--quiet", "--qf", '"%{BUILDTIME}\\t%{VERSION}-%{RELEASE}"', package_to_check], - print_output=False, - ) + # Append the package name as the last item on the list + cmd.append(package_to_check) + + # Search for available kernel package versions available in different repositories using the `repoquery` command. + # If convert2rhel is running on a EUS system, then repoquery will use the hardcoded repofiles available under + # /usr/share/convert2rhel/repos, meaning that the tool will fetch only the latest kernels available for that EUS + # version, and not the most updated version from other newer versions. + # If the case is that convert2rhel is not running on a EUS system, for example, Oracle Linux 8.5, then it will use + # the system repofiles. + repoquery_output, _ = run_subprocess(cmd, print_output=False) # Repoquery doesn't return any text at all when it can't find any matches for the query (when used with --quiet) if len(repoquery_output) > 0: @@ -593,7 +639,7 @@ def is_loaded_kernel_latest(): # This later check is supposed to avoid duplicate repofiles being defined in the system, # this is a super corner case and should not happen everytime, but if it does, we are aware now. packages = [ - tuple(str(line).split("\t")) + tuple(str(line).replace('"', "").split("\t")) for line in repoquery_output.split("\n") if (line.strip() and "listed more than once in the configuration" not in line.lower()) ] @@ -601,8 +647,9 @@ def is_loaded_kernel_latest(): # Sort out for the most recent kernel with reverse order # In case `repoquery` returns more than one kernel in the output # We display the latest one to the user. - _, latest_kernel = sorted(packages, reverse=True)[0] - latest_kernel = latest_kernel.replace('"', "") + packages.sort(key=lambda x: x[0], reverse=True) + + _, latest_kernel, repoid = packages[0] # The loaded kernel version uname_output, _ = run_subprocess(["uname", "-r"], print_output=False) @@ -612,13 +659,18 @@ def is_loaded_kernel_latest(): if match == 0: logger.info("Kernel currently loaded is at the latest version.") else: + repos_message = ( + "on the enabled system repositories" + if not reposdir + else "on repositories defined in the %s folder" % reposdir + ) logger.critical( - "The current kernel version loaded is different from the latest version in your repos.\n" - " Latest kernel version: %s\n" - " Current loaded kernel: %s\n\n" + "The version of the loaded kernel is different from the latest version %s.\n" + " Latest kernel version available in %s: %s\n" + " Loaded kernel version: %s\n\n" "To proceed with the conversion, update the kernel version by executing the following step:\n\n" "1. yum install %s-%s -y\n" - "2. reboot" % (latest_kernel, loaded_kernel, package_to_check, latest_kernel) + "2. reboot" % (repos_message, repoid, latest_kernel, loaded_kernel, package_to_check, latest_kernel) ) else: # Repoquery failed to detected any kernel or kernel-core packages in it's repositories diff --git a/convert2rhel/data/7/x86_64/configs/centos-7-x86_64.cfg b/convert2rhel/data/7/x86_64/configs/centos-7-x86_64.cfg index 5f76e4bc89..dcf97562da 100644 --- a/convert2rhel/data/7/x86_64/configs/centos-7-x86_64.cfg +++ b/convert2rhel/data/7/x86_64/configs/centos-7-x86_64.cfg @@ -31,6 +31,10 @@ repofile_pkgs = # Delimited by any whitespace(s). default_rhsm_repoids = rhel-7-server-rpms +# List of Extended Update Support (EUS) repoids to enable through subscription-manager when the --enablerepo option is +# not used. Delimited by any whitespace(s). +eus_rhsm_repoids = + # If defined, it overrides the default releasever defined by RELEASE_VER_MAPPING. # The value is passed to the yum calls through the --releasever option when accessing RHEL repos. Its purpose is to # substitute the $releasever variable in a repository baseurl. diff --git a/convert2rhel/data/7/x86_64/configs/oracle-7-x86_64.cfg b/convert2rhel/data/7/x86_64/configs/oracle-7-x86_64.cfg index c323b5da00..34809330dd 100644 --- a/convert2rhel/data/7/x86_64/configs/oracle-7-x86_64.cfg +++ b/convert2rhel/data/7/x86_64/configs/oracle-7-x86_64.cfg @@ -37,6 +37,10 @@ repofile_pkgs = # Delimited by any whitespace(s). default_rhsm_repoids = rhel-7-server-rpms +# List of Extended Update Support (EUS) repoids to enable through subscription-manager when the --enablerepo option is +# not used. Delimited by any whitespace(s). +eus_rhsm_repoids = + # If defined, it overrides the default releasever defined by RELEASE_VER_MAPPING. # The value is passed to the yum calls through the --releasever option when accessing RHEL repos. Its purpose is to # substitute the $releasever variable in a repository baseurl. diff --git a/convert2rhel/data/7/x86_64/configs/scientific-7-x86_64.cfg b/convert2rhel/data/7/x86_64/configs/scientific-7-x86_64.cfg index fbbfd5b6a4..6550f6940d 100644 --- a/convert2rhel/data/7/x86_64/configs/scientific-7-x86_64.cfg +++ b/convert2rhel/data/7/x86_64/configs/scientific-7-x86_64.cfg @@ -45,6 +45,10 @@ repofile_pkgs = # Delimited by any whitespace(s). default_rhsm_repoids = rhel-7-server-rpms rhel-7-server-optional-rpms +# List of Extended Update Support (EUS) repoids to enable through subscription-manager when the --enablerepo option is +# not used. Delimited by any whitespace(s). +eus_rhsm_repoids = + # If defined, it overrides the default releasever defined by RELEASE_VER_MAPPING. # The value is passed to the yum calls through the --releasever option when accessing RHEL repos. Its purpose is to # substitute the $releasever variable in a repository baseurl. diff --git a/convert2rhel/data/8/x86_64/configs/almalinux-8-x86_64.cfg b/convert2rhel/data/8/x86_64/configs/almalinux-8-x86_64.cfg index e928e774f7..4abe5e3438 100644 --- a/convert2rhel/data/8/x86_64/configs/almalinux-8-x86_64.cfg +++ b/convert2rhel/data/8/x86_64/configs/almalinux-8-x86_64.cfg @@ -12,8 +12,6 @@ excluded_pkgs = almalinux-indexhtml almalinux-gpg-keys almalinux-backgrounds* - rhn* - python3-rhn* # List of packages that either contain repofiles or affect variables in the repofiles (e.g. $releasever). # Delimited by any whitespace(s). @@ -29,6 +27,12 @@ default_rhsm_repoids = rhel-8-for-x86_64-baseos-rpms rhel-8-for-x86_64-appstream-rpms +# List of Extended Update Support (EUS) repoids to enable through subscription-manager when the --enablerepo option is +# not used. Delimited by any whitespace(s). +eus_rhsm_repoids = + rhel-8-for-x86_64-baseos-eus-rpms + rhel-8-for-x86_64-appstream-eus-rpms + # If defined, it overrides the default releasever defined by RELEASE_VER_MAPPING. # The value is passed to the yum calls through the --releasever option when accessing RHEL repos. Its purpose is to # substitute the $releasever variable in a repository baseurl. diff --git a/convert2rhel/data/8/x86_64/configs/centos-8-x86_64.cfg b/convert2rhel/data/8/x86_64/configs/centos-8-x86_64.cfg index af88601258..ae3870b4e1 100644 --- a/convert2rhel/data/8/x86_64/configs/centos-8-x86_64.cfg +++ b/convert2rhel/data/8/x86_64/configs/centos-8-x86_64.cfg @@ -11,8 +11,6 @@ excluded_pkgs = centos-logos* centos-indexhtml centos-obsolete-packages - rhn* - python3-rhn* centos-gpg-keys centos-backgrounds @@ -32,6 +30,12 @@ default_rhsm_repoids = rhel-8-for-x86_64-baseos-rpms rhel-8-for-x86_64-appstream-rpms +# List of Extended Update Support (EUS) repoids to enable through subscription-manager when the --enablerepo option is +# not used. Delimited by any whitespace(s). +eus_rhsm_repoids = + rhel-8-for-x86_64-baseos-eus-rpms + rhel-8-for-x86_64-appstream-eus-rpms + # If defined, it overrides the default releasever defined by RELEASE_VER_MAPPING. # The value is passed to the yum calls through the --releasever option when accessing RHEL repos. Its purpose is to # substitute the $releasever variable in a repository baseurl. diff --git a/convert2rhel/data/8/x86_64/configs/oracle-8-x86_64.cfg b/convert2rhel/data/8/x86_64/configs/oracle-8-x86_64.cfg index 417eadadf6..63764a3632 100644 --- a/convert2rhel/data/8/x86_64/configs/oracle-8-x86_64.cfg +++ b/convert2rhel/data/8/x86_64/configs/oracle-8-x86_64.cfg @@ -11,8 +11,6 @@ excluded_pkgs = oracle-logos* oracle-indexhtml oracle-backgrounds - rhn* - python3-rhn* # List of packages that either contain repofiles or affect variables in the repofiles (e.g. $releasever). # Delimited by any whitespace(s). @@ -27,6 +25,12 @@ default_rhsm_repoids = rhel-8-for-x86_64-baseos-rpms rhel-8-for-x86_64-appstream-rpms +# List of Extended Update Support (EUS) repoids to enable through subscription-manager when the --enablerepo option is +# not used. Delimited by any whitespace(s). +eus_rhsm_repoids = + rhel-8-for-x86_64-baseos-eus-rpms + rhel-8-for-x86_64-appstream-eus-rpms + # If defined, it overrides the default releasever defined by RELEASE_VER_MAPPING. # The value is passed to the yum calls through the --releasever option when accessing RHEL repos. Its purpose is to # substitute the $releasever variable in a repository baseurl. diff --git a/convert2rhel/data/8/x86_64/configs/rocky-8-x86_64.cfg b/convert2rhel/data/8/x86_64/configs/rocky-8-x86_64.cfg index 9632a793fb..77bfe2af77 100644 --- a/convert2rhel/data/8/x86_64/configs/rocky-8-x86_64.cfg +++ b/convert2rhel/data/8/x86_64/configs/rocky-8-x86_64.cfg @@ -11,8 +11,6 @@ excluded_pkgs = rocky-logos* rocky-indexhtml rocky-obsolete-packages - rhn* - python3-rhn* rocky-gpg-keys rocky-backgrounds @@ -31,6 +29,12 @@ default_rhsm_repoids = rhel-8-for-x86_64-baseos-rpms rhel-8-for-x86_64-appstream-rpms +# List of Extended Update Support (EUS) repoids to enable through subscription-manager when the --enablerepo option is +# not used. Delimited by any whitespace(s). +eus_rhsm_repoids = + rhel-8-for-x86_64-baseos-eus-rpms + rhel-8-for-x86_64-appstream-eus-rpms + # If defined, it overrides the default releasever defined by RELEASE_VER_MAPPING. # The value is passed to the yum calls through the --releasever option when accessing RHEL repos. Its purpose is to # substitute the $releasever variable in a repository baseurl. diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-AppStream.repo b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-AppStream.repo new file mode 100644 index 0000000000..185b2b8f45 --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-AppStream.repo @@ -0,0 +1,17 @@ +# CentOS-Linux-AppStream.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. + +[appstream] +name=CentOS Linux 8.4.2105 - AppStream +#mirrorlist=http://#mirrorlist.centos.org/?release=8.4.2105&arch=$basearch&repo=AppStream&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.4.2105/AppStream/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-BaseOS.repo b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-BaseOS.repo new file mode 100644 index 0000000000..a2411f416c --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-BaseOS.repo @@ -0,0 +1,17 @@ +# CentOS-Linux-BaseOS.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. + +[baseos] +name=CentOS Linux 8.4.2105 - BaseOS +#mirrorlist=http://#mirrorlist.centos.org/?release=8.4.2105&arch=$basearch&repo=BaseOS&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.4.2105/BaseOS/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-ContinuousRelease.repo b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-ContinuousRelease.repo new file mode 100644 index 0000000000..f6281c8744 --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-ContinuousRelease.repo @@ -0,0 +1,35 @@ +# CentOS-Linux-ContinuousRelease.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. +# +# The Continuous Release (CR) repository contains packages for the next minor +# release of CentOS Linux. This repository only has content in the time period +# between an upstream release and the official CentOS Linux release. These +# packages have not been fully tested yet and should be considered beta +# quality. They are made available for people willing to test and provide +# feedback for the next release. + +[cr] +name=CentOS Linux 8.4.2105 - ContinuousRelease +#mirrorlist=http://#mirrorlist.centos.org/?release=8.4.2105&arch=$basearch&repo=cr&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.4.2105/cr/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial +# CentOS-Linux-Debuginfo.repo +# +# All debug packages are merged into a single repo, split by basearch, and are +# not signed. + +[debuginfo] +name=CentOS Linux 8.4.2105 - Debuginfo +baseurl=http://debuginfo.centos.org/8.4.2105/$basearch/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-Devel.repo b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-Devel.repo new file mode 100644 index 0000000000..c391f8b6ca --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-Devel.repo @@ -0,0 +1,17 @@ +# CentOS-Linux-Devel.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. + +[devel] +name=CentOS Linux 8.4.2105 - Devel WARNING! FOR BUILDROOT USE ONLY! +#mirrorlist=http://#mirrorlist.centos.org/?release=8.4.2105&arch=$basearch&repo=Devel&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.4.2105/Devel/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-Extras.repo b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-Extras.repo new file mode 100644 index 0000000000..b2c06c7a9d --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-Extras.repo @@ -0,0 +1,17 @@ +# CentOS-Linux-Extras.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. + +[extras] +name=CentOS Linux 8.4.2105 - Extras +#mirrorlist=http://#mirrorlist.centos.org/?release=8.4.2105&arch=$basearch&repo=extras&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.4.2105/extras/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-FastTrack.repo b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-FastTrack.repo new file mode 100644 index 0000000000..ca53e77632 --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-FastTrack.repo @@ -0,0 +1,17 @@ +# CentOS-Linux-FastTrack.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. + +[fasttrack] +name=CentOS Linux 8.4.2105 - FastTrack +#mirrorlist=http://#mirrorlist.centos.org/?release=8.4.2105&arch=$basearch&repo=fasttrack&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.4.2105/fasttrack/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-HighAvailability.repo b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-HighAvailability.repo new file mode 100644 index 0000000000..00fa639bec --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-HighAvailability.repo @@ -0,0 +1,17 @@ +# CentOS-Linux-HighAvailability.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. + +[ha] +name=CentOS Linux 8.4.2105 - HighAvailability +#mirrorlist=http://#mirrorlist.centos.org/?release=8.4.2105&arch=$basearch&repo=HighAvailability&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.4.2105/HighAvailability/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-Plus.repo b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-Plus.repo new file mode 100644 index 0000000000..d203a63ae6 --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-Plus.repo @@ -0,0 +1,17 @@ +# CentOS-Linux-Plus.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. + +[plus] +name=CentOS Linux 8.4.2105 - Plus +#mirrorlist=http://#mirrorlist.centos.org/?release=8.4.2105&arch=$basearch&repo=centosplus&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.4.2105/centosplus/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-PowerTools.repo b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-PowerTools.repo new file mode 100644 index 0000000000..234c4196e3 --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-PowerTools.repo @@ -0,0 +1,17 @@ +# CentOS-Linux-PowerTools.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. + +[powertools] +name=CentOS Linux 8.4.2105 - PowerTools +#mirrorlist=http://#mirrorlist.centos.org/?release=8.4.2105&arch=$basearch&repo=PowerTools&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.4.2105/PowerTools/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-Sources.repo b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-Sources.repo new file mode 100644 index 0000000000..6ac45b3045 --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.4/CentOS-Linux-Sources.repo @@ -0,0 +1,36 @@ +# CentOS-Linux-Sources.repo + +[baseos-source] +name=CentOS Linux 8.4.2105 - BaseOS - Source +baseurl=https://vault.centos.org/$contentdir/8.4.2105/BaseOS/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[appstream-source] +name=CentOS Linux 8.4.2105 - AppStream - Source +baseurl=https://vault.centos.org/$contentdir/8.4.2105/AppStream/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[powertools-source] +name=CentOS Linux 8.4.2105 - PowerTools - Source +baseurl=https://vault.centos.org/$contentdir/8.4.2105/PowerTools/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[extras-source] +name=CentOS Linux 8.4.2105 - Extras - Source +baseurl=https://vault.centos.org/$contentdir/8.4.2105/extras/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[plus-source] +name=CentOS Linux 8.4.2105 - Plus - Source +baseurl=https://vault.centos.org/$contentdir/8.4.2105/centosplus/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-AppStream.repo b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-AppStream.repo new file mode 100644 index 0000000000..6f069267cb --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-AppStream.repo @@ -0,0 +1,17 @@ +# CentOS-Linux-AppStream.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. + +[appstream] +name=CentOS Linux 8.5.2111 - AppStream +#mirrorlist=http://#mirrorlist.centos.org/?release=8.5.2111&arch=$basearch&repo=AppStream&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.5.2111/AppStream/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-BaseOS.repo b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-BaseOS.repo new file mode 100644 index 0000000000..b8a127d321 --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-BaseOS.repo @@ -0,0 +1,17 @@ +# CentOS-Linux-BaseOS.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. + +[baseos] +name=CentOS Linux 8.5.2111 - BaseOS +#mirrorlist=http://#mirrorlist.centos.org/?release=8.5.2111&arch=$basearch&repo=BaseOS&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.5.2111/BaseOS/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Debuginfo.repo b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Debuginfo.repo new file mode 100644 index 0000000000..2ef5ed0873 --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Debuginfo.repo @@ -0,0 +1,11 @@ +# CentOS-Linux-Debuginfo.repo +# +# All debug packages are merged into a single repo, split by basearch, and are +# not signed. + +[debuginfo] +name=CentOS Linux 8.5.2111 - Debuginfo +baseurl=http://debuginfo.centos.org/8.5.2111/$basearch/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Devel.repo b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Devel.repo new file mode 100644 index 0000000000..5e2ef09ea6 --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Devel.repo @@ -0,0 +1,17 @@ +# CentOS-Linux-Devel.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. + +[devel] +name=CentOS Linux 8.5.2111 - Devel WARNING! FOR BUILDROOT USE ONLY! +#mirrorlist=http://#mirrorlist.centos.org/?release=8.5.2111&arch=$basearch&repo=Devel&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.5.2111/Devel/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Extras.repo b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Extras.repo new file mode 100644 index 0000000000..ddc32ad737 --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Extras.repo @@ -0,0 +1,17 @@ +# CentOS-Linux-Extras.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. + +[extras] +name=CentOS Linux 8.5.2111 - Extras +#mirrorlist=http://#mirrorlist.centos.org/?release=8.5.2111&arch=$basearch&repo=extras&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.5.2111/extras/$basearch/os/ +gpgcheck=1 +enabled=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-FastTrack.repo b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-FastTrack.repo new file mode 100644 index 0000000000..91aefbe490 --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-FastTrack.repo @@ -0,0 +1,17 @@ +# CentOS-Linux-FastTrack.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. + +[fasttrack] +name=CentOS Linux 8.5.2111 - FastTrack +#mirrorlist=http://#mirrorlist.centos.org/?release=8.5.2111&arch=$basearch&repo=fasttrack&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.5.2111/fasttrack/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-HighAvailability.repo b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-HighAvailability.repo new file mode 100644 index 0000000000..c913c7d670 --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-HighAvailability.repo @@ -0,0 +1,17 @@ +# CentOS-Linux-HighAvailability.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. + +[ha] +name=CentOS Linux 8.5.2111 - HighAvailability +#mirrorlist=http://#mirrorlist.centos.org/?release=8.5.2111&arch=$basearch&repo=HighAvailability&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.5.2111/HighAvailability/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Plus.repo b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Plus.repo new file mode 100644 index 0000000000..65b46d3146 --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Plus.repo @@ -0,0 +1,17 @@ +# CentOS-Linux-Plus.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. + +[plus] +name=CentOS Linux 8.5.2111 - Plus +#mirrorlist=http://#mirrorlist.centos.org/?release=8.5.2111&arch=$basearch&repo=centosplus&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.5.2111/centosplus/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-PowerTools.repo b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-PowerTools.repo new file mode 100644 index 0000000000..827b4ce959 --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-PowerTools.repo @@ -0,0 +1,17 @@ +# CentOS-Linux-PowerTools.repo +# +# The #mirrorlist system uses the connecting IP address of the client and the +# update status of each mirror to pick current mirrors that are geographically +# close to the client. You should use this for CentOS updates unless you are +# manually picking other mirrors. +# +# If the #mirrorlist does not work for you, you can try the commented out +# baseurl line instead. + +[powertools] +name=CentOS Linux 8.5.2111 - PowerTools +#mirrorlist=http://#mirrorlist.centos.org/?release=8.5.2111&arch=$basearch&repo=PowerTools&infra=$infra +baseurl=https://vault.centos.org/$contentdir/8.5.2111/PowerTools/$basearch/os/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Sources.repo b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Sources.repo new file mode 100644 index 0000000000..0b1ce5c0b1 --- /dev/null +++ b/convert2rhel/data/8/x86_64/repos/centos-8.5/CentOS-Linux-Sources.repo @@ -0,0 +1,36 @@ +# CentOS-Linux-Sources.repo + +[baseos-source] +name=CentOS Linux 8.5.2111 - BaseOS - Source +baseurl=https://vault.centos.org/$contentdir/8.5.2111/BaseOS/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[appstream-source] +name=CentOS Linux 8.5.2111 - AppStream - Source +baseurl=https://vault.centos.org/$contentdir/8.5.2111/AppStream/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[powertools-source] +name=CentOS Linux 8.5.2111 - PowerTools - Source +baseurl=https://vault.centos.org/$contentdir/8.5.2111/PowerTools/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[extras-source] +name=CentOS Linux 8.5.2111 - Extras - Source +baseurl=https://vault.centos.org/$contentdir/8.5.2111/extras/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + +[plus-source] +name=CentOS Linux 8.5.2111 - Plus - Source +baseurl=https://vault.centos.org/$contentdir/8.5.2111/centosplus/Source/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial diff --git a/convert2rhel/main.py b/convert2rhel/main.py index 0d61191d97..e752baa139 100644 --- a/convert2rhel/main.py +++ b/convert2rhel/main.py @@ -19,7 +19,7 @@ import os import sys -from convert2rhel import breadcrumbs, cert, checks, grub +from convert2rhel import backup, breadcrumbs, cert, checks, grub from convert2rhel import logger as logger_module from convert2rhel import pkghandler, redhatrelease, repo, special_cases, subscription, systeminfo, toolopts, utils @@ -234,6 +234,8 @@ def post_ponr_conversion(): grub.post_ponr_set_efi_configuration() loggerinst.task("Convert: Patch yum configuration file") redhatrelease.YumConf().patch() + loggerinst.task("Convert: Lock releasever in RHEL repositories") + subscription.lock_releasever_in_rhel_repositories() breadcrumbs.breadcrumbs.finish_success() @@ -254,7 +256,7 @@ def rollback_changes(): loggerinst.warning("Abnormal exit! Performing rollback ...") subscription.rollback() - utils.changed_pkgs_control.restore_pkgs() + backup.changed_pkgs_control.restore_pkgs() repo.restore_yum_repos() redhatrelease.system_release_file.restore() redhatrelease.os_release_file.restore() diff --git a/convert2rhel/pkghandler.py b/convert2rhel/pkghandler.py index b1209e9bcc..01cb6af079 100644 --- a/convert2rhel/pkghandler.py +++ b/convert2rhel/pkghandler.py @@ -24,6 +24,7 @@ import rpm from convert2rhel import pkgmanager, utils +from convert2rhel.backup import RestorableFile, remove_pkgs from convert2rhel.systeminfo import system_info from convert2rhel.toolopts import tool_opts @@ -35,7 +36,7 @@ MAX_YUM_CMD_CALLS = 3 _VERSIONLOCK_FILE_PATH = "/etc/yum/pluginconf.d/versionlock.list" # This file is used by the dnf plugin as well -versionlock_file = utils.RestorableFile(_VERSIONLOCK_FILE_PATH) # pylint: disable=C0103 +versionlock_file = RestorableFile(_VERSIONLOCK_FILE_PATH) # pylint: disable=C0103 # # Regular expressions used to find package names in yum output @@ -104,7 +105,7 @@ def call_yum_cmd_w_downgrades(cmd, pkgs, retries=MAX_YUM_CMD_CALLS): to_remove = problematic_pkgs["errors"] | problematic_pkgs["mismatches"] if to_remove: loggerinst.warning("Removing problematic packages to continue with conversion:\n%s" % "\n".join(to_remove)) - utils.remove_pkgs(to_remove, backup=False, critical=False) + remove_pkgs(to_remove, backup=False, critical=False) return call_yum_cmd_w_downgrades(cmd, pkgs, retries - 1) @@ -604,7 +605,7 @@ def remove_pkgs_with_confirm(pkgs, backup=True): loggerinst.warning("The following packages will be removed...") print_pkg_info(pkgs_to_remove) utils.ask_to_continue() - utils.remove_pkgs([get_pkg_nvra(pkg) for pkg in pkgs_to_remove], backup=backup) + remove_pkgs([get_pkg_nvra(pkg) for pkg in pkgs_to_remove], backup=backup) loggerinst.debug("Successfully removed %s packages" % str(len(pkgs_to_remove))) @@ -714,7 +715,7 @@ def handle_no_newer_rhel_kernel_available(): # of them - the one that has the same version as the available RHEL # kernel older = available[-1] - utils.remove_pkgs(pkgs_to_remove=["kernel-%s" % older], backup=False) + remove_pkgs(pkgs_to_remove=["kernel-%s" % older], backup=False) call_yum_cmd(command="install", args=["kernel-%s" % older]) else: replace_non_rhel_installed_kernel(installed[0]) @@ -769,7 +770,14 @@ def replace_non_rhel_installed_kernel(version): output, ret_code = utils.run_subprocess( # The --nodeps is needed as some kernels depend on system-release (alias for redhat-release) and that package # is not installed at this stage. - ["rpm", "-i", "--force", "--nodeps", "--replacepkgs", "%s*" % os.path.join(utils.TMP_DIR, pkg)], + [ + "rpm", + "-i", + "--force", + "--nodeps", + "--replacepkgs", + "%s*" % os.path.join(utils.TMP_DIR, pkg), + ], print_output=False, ) if ret_code != 0: @@ -799,7 +807,7 @@ def remove_non_rhel_kernels(): if non_rhel_kernels: loggerinst.info("Removing non-RHEL kernels") print_pkg_info(non_rhel_kernels) - utils.remove_pkgs( + remove_pkgs( pkgs_to_remove=[get_pkg_nvra(pkg) for pkg in non_rhel_kernels], backup=False, ) @@ -1004,21 +1012,28 @@ def compare_package_versions(version1, version2): return rpm.labelCompare(evr1, evr2) -def get_total_packages_to_update(): +def get_total_packages_to_update(reposdir): """Return the total number of packages to update in the system - It uses both yum/dnf depending on weather they are installed on the system, - if it's Oracle/CentOS Linux 7 or 6, it will use `yum`, otherwise it should use `dnf`. + It uses both yum/dnf depending on whether they are installed on the system, + In case of RHEL 6 or 7 derivative distributions, it uses `yum`, otherwise it uses `dnf`. + + To check whether the system is updated or not, we use original vendor repofiles which we ship within the + convert2rhel RPM. The reason is that we can't rely on the repofiles available on the to-be-converted system. + + :param reposdir: The path to the hardcoded repositories for EUS (If any). + :type reposdir: str | None :return: The packages that need to be updated. - :rtype: List[str] + :rtype: list[str] """ packages = [] if pkgmanager.TYPE == "yum": packages = _get_packages_to_update_yum() elif pkgmanager.TYPE == "dnf": - packages = _get_packages_to_update_dnf() + # We're using the reposdir with dnf only because we currently hardcode the repofiles for RHEL 8 derivatives only. + packages = _get_packages_to_update_dnf(reposdir=reposdir) return set(packages) @@ -1034,22 +1049,32 @@ def _get_packages_to_update_yum(): return all_packages -def _get_packages_to_update_dnf(): - """Query all the packages with dnf that has an update pending on the system.""" +def _get_packages_to_update_dnf(reposdir): + """Query all the packages with dnf that has an update pending on the + system. + + :param reposdir: The path to the hardcoded repositories for EUS (If any). + :type reposdir: str | None + """ packages = [] base = pkgmanager.Base() - # Fix the case when we are trying to query packages in Oracle Linux 8 - # when the DNF API gets called, those variables are not populated by default. - if system_info.id == "oracle": - base.conf.substitutions["ocidomain"] = "oracle.com" - base.conf.substitutions["ociregion"] = "" - - # Same thing for CentOS, but this time, the URL for the vault has changed - # and instead of just ussing $releasever (8.5, 8.4...), we need either - # using the correct $releasever (8.5.2111) or setting up the $contentdir - elif system_info.id == "centos": - base.conf.substitutions["contentdir"] = system_info.id + # If we have an reposdir, that means we are trying to check the packages under + # CentOS Linux 8.4 or 8.5 and Oracle Linux 8.4. + # That means we need to use our hardcoded repository files instead of the system ones. + if reposdir: + base.conf.reposdir = reposdir + + # Set DNF to read from the proper config files, at this moment, DNF can't + # automatically read and load the config files + # so we have to specify it to him. + # We set the PRIO_MAINCONFIG as the base config file to be read. + # We also set the folder /etc/dnf/vars as the main point for vars + # replacement in repo files. + # See this bugzilla comment: + # https://bugzilla.redhat.com/show_bug.cgi?id=1920735#c2 + base.conf.read(priority=pkgmanager.dnf.conf.PRIO_MAINCONFIG) + base.conf.substitutions.update_from_etc(installroot=base.conf.installroot, varsdir=base.conf.varsdir) base.read_all_repos() base.fill_sack() diff --git a/convert2rhel/redhatrelease.py b/convert2rhel/redhatrelease.py index a34388e640..aad4958047 100644 --- a/convert2rhel/redhatrelease.py +++ b/convert2rhel/redhatrelease.py @@ -19,7 +19,7 @@ import os import re -from convert2rhel import pkgmanager, utils +from convert2rhel import backup, pkgmanager, utils from convert2rhel.systeminfo import system_info @@ -107,5 +107,5 @@ def is_modified(): # Code to be executed upon module import -system_release_file = utils.RestorableFile(get_system_release_filepath()) # pylint: disable=C0103 -os_release_file = utils.RestorableFile(OS_RELEASE_FILEPATH) # pylint: disable=C0103 +system_release_file = backup.RestorableFile(get_system_release_filepath()) # pylint: disable=C0103 +os_release_file = backup.RestorableFile(OS_RELEASE_FILEPATH) # pylint: disable=C0103 diff --git a/convert2rhel/repo.py b/convert2rhel/repo.py index d11b59b8c5..b6d22da2be 100644 --- a/convert2rhel/repo.py +++ b/convert2rhel/repo.py @@ -20,15 +20,24 @@ import shutil from convert2rhel.systeminfo import system_info -from convert2rhel.utils import BACKUP_DIR +from convert2rhel.utils import BACKUP_DIR, DATA_DIR loggerinst = logging.getLogger(__name__) def get_rhel_repoids(): - """Get IDs of the Red Hat CDN repositories that correspond to the current system.""" - repos_needed = system_info.default_rhsm_repoids + """Get IDs of the Red Hat CDN repositories that correspond to the current system. + + In case the to-be-converted-OS minor version corresponds to RHEL Extended Update Support (EUS) release, + we preferably enable the RHEL EUS repoids as those provide security updates over two years, in comparison to 6 months + in case of the standard non-EUS repoids. + """ + + if system_info.corresponds_to_rhel_eus_release(): + repos_needed = system_info.eus_rhsm_repoids + else: + repos_needed = system_info.default_rhsm_repoids loggerinst.info("RHEL repository IDs to enable: %s" % ", ".join(repos_needed)) @@ -68,3 +77,28 @@ def restore_yum_repos(): if not repo_has_restored: loggerinst.info("No .repo files to rollback") + + +def get_hardcoded_repofiles_dir(): + """Get the path to the hardcoded repofiles for CentOS/Oracle Linux. + + We use hardcoded original vendor repofiles to be able to check whether the system is updated before the conversion. + To be able to download backup of packages before we remove them, we can't rely on the repofiles available on + the system. + + :return: The return can be either the path to the eus repos, or None, meaning we don't have any hardcoded repo files. + :rtype: str | None + """ + hardcoded_repofiles = os.path.join( + DATA_DIR, + "repos/%s-%s.%s" + % ( + system_info.id, + system_info.version.major, + system_info.version.minor, + ), + ) + if os.path.exists(hardcoded_repofiles): + return hardcoded_repofiles + + return None diff --git a/convert2rhel/special_cases.py b/convert2rhel/special_cases.py index 47e193ef93..1ae70c9bcd 100644 --- a/convert2rhel/special_cases.py +++ b/convert2rhel/special_cases.py @@ -18,9 +18,10 @@ import logging import os +from convert2rhel.backup import RestorableFile from convert2rhel.grub import is_efi from convert2rhel.systeminfo import system_info -from convert2rhel.utils import RestorableFile, mkdir_p, run_subprocess +from convert2rhel.utils import mkdir_p, run_subprocess OPENJDK_RPM_STATE_DIR = "/var/lib/rpm-state/" diff --git a/convert2rhel/subscription.py b/convert2rhel/subscription.py index c990e4c1c3..dcdaf4e19a 100644 --- a/convert2rhel/subscription.py +++ b/convert2rhel/subscription.py @@ -22,7 +22,7 @@ from collections import namedtuple from time import sleep -from convert2rhel import pkghandler, utils +from convert2rhel import backup, pkghandler, utils from convert2rhel.systeminfo import system_info from convert2rhel.toolopts import tool_opts @@ -99,7 +99,11 @@ def unregister_system(): unregistration_cmd = ["subscription-manager", "unregister"] output, ret_code = utils.run_subprocess(unregistration_cmd, print_output=False) if ret_code != 0: - loggerinst.warning("System unregistration failed with return code %d and message:\n%s", ret_code, output) + loggerinst.warning( + "System unregistration failed with return code %d and message:\n%s", + ret_code, + output, + ) else: loggerinst.info("System unregistered successfully.") @@ -113,8 +117,14 @@ def register_system(): registration_cmd = RegistrationCommand.from_tool_opts(tool_opts) attempt_msg = "" if attempt > 0: - attempt_msg = "Attempt %d of %d: " % (attempt + 1, MAX_NUM_OF_ATTEMPTS_TO_SUBSCRIBE) - loggerinst.info("%sRegistering the system using subscription-manager ...", attempt_msg) + attempt_msg = "Attempt %d of %d: " % ( + attempt + 1, + MAX_NUM_OF_ATTEMPTS_TO_SUBSCRIBE, + ) + loggerinst.info( + "%sRegistering the system using subscription-manager ...", + attempt_msg, + ) output, ret_code = registration_cmd() if ret_code == 0: @@ -383,11 +393,11 @@ def remove_original_subscription_manager(): # removed from CentOS Linux 8.5 and causes conversion to fail if # it's installed on that system because it's not possible to back it up. # https://bugzilla.redhat.com/show_bug.cgi?id=2046292 - utils.remove_pkgs([_SUBMGR_PKG_REMOVED_IN_CL_85], backup=False, critical=False) + backup.remove_pkgs([_SUBMGR_PKG_REMOVED_IN_CL_85], backup=False, critical=False) submgr_pkg_names.remove(_SUBMGR_PKG_REMOVED_IN_CL_85) # Remove any oter subscription-manager packages present on the system - utils.remove_pkgs(submgr_pkg_names, critical=False) + backup.remove_pkgs(submgr_pkg_names, critical=False) def install_rhel_subscription_manager(): @@ -446,7 +456,7 @@ def track_installed_submgr_pkgs(installed_pkg_names, pkgs_to_not_track): loggerinst.debug("Skipping tracking previously installed package: %s" % installed_pkg) loggerinst.debug("Tracking installed packages: %r" % pkgs_to_track) - utils.changed_pkgs_control.track_installed_pkgs(pkgs_to_track) + backup.changed_pkgs_control.track_installed_pkgs(pkgs_to_track) def attach_subscription(): @@ -514,7 +524,11 @@ def get_avail_subs(): def get_sub(subs_raw): """Generator that provides subscriptions available to a logged-in user.""" # Split all the available subscriptions per one subscription - for sub_raw in re.findall(r"Subscription Name.*?Type:\s+\w+\n\n", subs_raw, re.DOTALL | re.MULTILINE): + for sub_raw in re.findall( + r"Subscription Name.*?Type:\s+\w+\n\n", + subs_raw, + re.DOTALL | re.MULTILINE, + ): pool_id = get_pool_id(sub_raw) yield namedtuple("Sub", ["pool_id", "sub_raw"])(pool_id, sub_raw) @@ -599,6 +613,33 @@ def enable_repos(rhel_repoids): else: repos_to_enable = rhel_repoids + if repos_to_enable == system_info.eus_rhsm_repoids: + try: + loggerinst.info( + "The system version corresponds to a RHEL Extended Update Support (EUS) release. " + "Trying to enable RHEL EUS repositories." + ) + # Try first if it's possible to enable EUS repoids. Otherwise try enabling the default RHSM repoids. + # Otherwise, if it raiess an exception, try to enable the default rhsm-repos + _submgr_enable_repos(repos_to_enable) + except SystemExit: + loggerinst.info( + "The RHEL EUS repositories are not possible to enable.\n" + "Trying to enable standard RHEL repositories as a fallback." + ) + # Fallback to the default_rhsm_repoids + repos_to_enable = system_info.default_rhsm_repoids + _submgr_enable_repos(repos_to_enable) + else: + # This could be either the default_rhsm repos or any user specific + # repoids + _submgr_enable_repos(repos_to_enable) + + system_info.submgr_enabled_repos = repos_to_enable + + +def _submgr_enable_repos(repos_to_enable): + """Go through subscription manager repos and try to enable them through subscription-manager.""" enable_cmd = ["subscription-manager", "repos"] for repo in repos_to_enable: enable_cmd.append("--enable=%s" % repo) @@ -607,8 +648,6 @@ def enable_repos(rhel_repoids): loggerinst.critical("Repos were not possible to enable through subscription-manager:\n%s" % output) loggerinst.info("Repositories enabled through subscription-manager") - system_info.submgr_enabled_repos = repos_to_enable - def rollback(): """Rollback subscription related changes""" @@ -651,7 +690,10 @@ def download_rhsm_pkgs(): loggerinst.info("Skipping due to the use of --keep-rhsm.") return utils.mkdir_p(_RHSM_TMP_DIR) - pkgs_to_download = ["subscription-manager", "subscription-manager-rhsm-certificates"] + pkgs_to_download = [ + "subscription-manager", + "subscription-manager-rhsm-certificates", + ] if system_info.version.major == 6: pkgs_to_download.append("subscription-manager-rhsm") @@ -686,3 +728,37 @@ def exit_on_failed_download(paths): " the failed yumdownloader call above. These packages are necessary for the conversion" " unless you use the --no-rhsm option." ) + + +def lock_releasever_in_rhel_repositories(): + """Lock the releasever in the RHEL repositories located under /etc/yum.repos.d/redhat.repo + + After converting to a RHEL EUS minor version, we need to lock the releasever in the redhat.repo file + to prevent future errors such as, running `yum update` and not being able to find the repositories metadata. + + .. note:: + This function should only run if the system corresponds to a RHEL EUS version to make sure the converted system + keeps receiving updates for the specific EUS minor version instead of the latest minor version which is the + default. + """ + + # We only lock the releasever on rhel repos if we detect that the running system is an EUS correspondent and if + # rhsm is used, otherwise, there's no need to lock the releasever as the subscription-manager won't be available. + if system_info.corresponds_to_rhel_eus_release() and not tool_opts.no_rhsm: + loggerinst.info( + "Updating /etc/yum.repos.d/rehat.repo to point to RHEL %s instead of the default latest minor version." + % system_info.releasever + ) + cmd = ["subscription-manager", "release", "--set=%s" % system_info.releasever] + + output, ret_code = utils.run_subprocess(cmd, print_output=False) + if ret_code != 0: + loggerinst.warning( + "Locking RHEL repositories failed with return code %d and message:\n%s", + ret_code, + output, + ) + else: + loggerinst.info("RHEL repositories locked to the %s minor version." % system_info.releasever) + else: + loggerinst.info("Skipping locking RHEL repositories to a specific EUS minor version.") diff --git a/convert2rhel/systeminfo.py b/convert2rhel/systeminfo.py index 62410e0eb3..8d1fcea6ad 100644 --- a/convert2rhel/systeminfo.py +++ b/convert2rhel/systeminfo.py @@ -14,6 +14,7 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import socket from collections import namedtuple @@ -35,7 +36,7 @@ # Allowed conversion paths to RHEL. We want to prevent a conversion and minor -# version update at the same time. +# version update at the same time. RELEASE_VER_MAPPING = { "8.10": "8.10", "8.9": "8.9", @@ -54,6 +55,9 @@ # For a list of modified rpm files after the conversion finishes for comparison purposes POST_RPM_VA_LOG_FILENAME = "rpm_va_after_conversion.log" +# List of EUS minor versions supported +EUS_MINOR_VERSIONS = ["8.4"] + Version = namedtuple("Version", ["major", "minor"]) @@ -89,6 +93,8 @@ def __init__(self): self.logger = None # IDs of the default Red Hat CDN repositories that correspond to the current system self.default_rhsm_repoids = None + # IDs of the Extended Update Support (EUS) Red Hat CDN repositories that correspond to the current system + self.eus_rhsm_repoids = None # List of repositories enabled through subscription-manager self.submgr_enabled_repos = [] # Value to use for substituting the $releasever variable in the url of RHEL repositories @@ -111,11 +117,13 @@ def resolve_system_info(self): self.excluded_pkgs = self._get_excluded_pkgs() self.repofile_pkgs = self._get_repofile_pkgs() self.default_rhsm_repoids = self._get_default_rhsm_repoids() + self.eus_rhsm_repoids = self._get_eus_rhsm_repoids() self.fingerprints_orig_os = self._get_gpg_key_fingerprints() self.generate_rpm_va() self.releasever = self._get_releasever() self.kmods_to_ignore = self._get_kmods_to_ignore() self.booted_kernel = self._get_booted_kernel() + self.has_internet_access = self._check_internet_access() @staticmethod def _get_system_release_file_content(): @@ -190,6 +198,9 @@ def _get_cfg_section(self, section_name): def _get_default_rhsm_repoids(self): return self._get_cfg_opt("default_rhsm_repoids").split() + def _get_eus_rhsm_repoids(self): + return self._get_cfg_opt("eus_rhsm_repoids").split() + def _get_cfg_opt(self, option_name): """Return value of a specific configuration file option.""" if option_name in self.cfg_content: @@ -227,7 +238,12 @@ def _get_releasever(self): self.logger.critical( "%s of version %d.%d is not allowed for conversion.\n" "Allowed versions are: %s" - % (self.name, self.version.major, self.version.minor, list(RELEASE_VER_MAPPING.keys())) + % ( + self.name, + self.version.major, + self.version.minor, + list(RELEASE_VER_MAPPING.keys()), + ) ) def _get_kmods_to_ignore(self): @@ -305,6 +321,50 @@ def get_enabled_rhel_repos(self): # ) return self.submgr_enabled_repos if not tool_opts.no_rhsm else tool_opts.enablerepo + def _check_internet_access(self, host="8.8.8.8", port=53, timeout=3): + """Check whether or not the machine is connected to the internet. + + This method will try to estabilish a socket connection through the + default host in the method signature (8.8.8.8). If it's connected + successfully, then we know that internet is accessible from the host. + + .. warnings:: + We might have some problems with this if the host machine is using + a NAT gateway to route the outbound requests + + .. seealso:: + * Comparison of different methods to check internet connections: https://stackoverflow.com/a/33117579 + * Redirecting IP addresses: https://superuser.com/questions/954665/how-to-redirect-route-ip-address-to-another-ip-address + + :param host: The host to establish a connection to. Defaults to "8.8.8.8". + :type host: str + :param port: The port for the connection. Defaults to 53. + :type port: int + :param timeout: The timeout in seconds for the connection. Defaults to 3. + :type port: int + :return: Return boolean indicating whether or not we have internet access. + :rtype: bool + """ + try: + self.logger.info("Checking internet connectivity using host '%s' and port '%s'." % (host, port)) + socket.setdefaulttimeout(timeout) + socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, port)) + return True + except (socket.timeout, socket.error): + self.logger.warning("Couldn't connect to the host '%s'." % host) + return False + + def corresponds_to_rhel_eus_release(self): + """Return whether the current minor version corresponds to a RHEL Extended Update Support (EUS) release. + + For example if we detect CentOS Linux 8.4, the corresponding RHEL 8.4 is an EUS release, but if we detect + CentOS Linux 8.5, the corresponding RHEL 8.5 is not an EUS release. + + :return: Whether or not the current system has a EUS correspondent in RHEL. + :rtype: bool + """ + return self.releasever in EUS_MINOR_VERSIONS + # Code to be executed upon module import system_info = SystemInfo() # pylint: disable=C0103 diff --git a/convert2rhel/unit_tests/backup_test.py b/convert2rhel/unit_tests/backup_test.py new file mode 100644 index 0000000000..5c3a63338c --- /dev/null +++ b/convert2rhel/unit_tests/backup_test.py @@ -0,0 +1,401 @@ +import os +import sys +import unittest + +import pytest + +from convert2rhel import backup, repo, unit_tests # Imports unit_tests/__init__.py +from convert2rhel.unit_tests.conftest import all_systems, centos8 + + +if sys.version_info[:2] <= (2, 7): + import mock # pylint: disable=import-error +else: + from unittest import mock # pylint: disable=no-name-in-module + + +class TestBackup(unittest.TestCase): + class RunSubprocessMocked(unit_tests.MockFunction): + def __init__(self, output="Test output", ret_code=0): + self.cmd = [] + self.cmds = [] + self.called = 0 + self.output = output + self.ret_code = ret_code + + def __call__(self, cmd, print_cmd=True, print_output=True): + self.cmd = cmd + self.cmds.append(cmd) + self.called += 1 + return self.output, self.ret_code + + class DummyFuncMocked(unit_tests.MockFunction): + def __init__(self): + self.called = 0 + + def __call__(self, *args, **kargs): + self.called += 1 + + class RemovePkgsMocked(unit_tests.MockFunction): + def __init__(self): + self.pkgs = None + self.should_bkp = False + self.critical = False + + def __call__(self, pkgs_to_remove, backup=False, critical=False): + self.pkgs = pkgs_to_remove + self.should_bkp = backup + self.critical = critical + + @unit_tests.mock( + backup.changed_pkgs_control, + "backup_and_track_removed_pkg", + DummyFuncMocked(), + ) + @unit_tests.mock(backup, "run_subprocess", RunSubprocessMocked()) + def test_remove_pkgs_without_backup(self): + pkgs = ["pkg1", "pkg2", "pkg3"] + backup.remove_pkgs(pkgs, False) + self.assertEqual(backup.changed_pkgs_control.backup_and_track_removed_pkg.called, 0) + + self.assertEqual(backup.run_subprocess.called, len(pkgs)) + + rpm_remove_cmd = ["rpm", "-e", "--nodeps"] + for cmd, pkg in zip(backup.run_subprocess.cmds, pkgs): + self.assertEqual(rpm_remove_cmd + [pkg], cmd) + + @unit_tests.mock( + backup.ChangedRPMPackagesController, + "backup_and_track_removed_pkg", + DummyFuncMocked(), + ) + @unit_tests.mock(backup, "run_subprocess", RunSubprocessMocked()) + def test_remove_pkgs_with_backup(self): + pkgs = ["pkg1", "pkg2", "pkg3"] + backup.remove_pkgs(pkgs) + self.assertEqual( + backup.ChangedRPMPackagesController.backup_and_track_removed_pkg.called, + len(pkgs), + ) + + self.assertEqual(backup.run_subprocess.called, len(pkgs)) + + rpm_remove_cmd = ["rpm", "-e", "--nodeps"] + for cmd, pkg in zip(backup.run_subprocess.cmds, pkgs): + self.assertEqual(rpm_remove_cmd + [pkg], cmd) + + @unit_tests.mock(backup.RestorablePackage, "backup", DummyFuncMocked()) + def test_backup_and_track_removed_pkg(self): + control = backup.ChangedRPMPackagesController() + pkgs = ["pkg1", "pkg2", "pkg3"] + for pkg in pkgs: + control.backup_and_track_removed_pkg(pkg) + self.assertEqual(backup.RestorablePackage.backup.called, len(pkgs)) + self.assertEqual(len(control.removed_pkgs), len(pkgs)) + + @unit_tests.mock(backup, "run_subprocess", RunSubprocessMocked()) + def test_install_local_rpms_with_empty_list(self): + backup.changed_pkgs_control._install_local_rpms([]) + self.assertEqual(backup.run_subprocess.called, 0) + + @unit_tests.mock(backup.changed_pkgs_control, "track_installed_pkg", DummyFuncMocked()) + @unit_tests.mock(backup, "run_subprocess", RunSubprocessMocked()) + def test_install_local_rpms_without_replace(self): + pkgs = ["pkg1", "pkg2", "pkg3"] + backup.changed_pkgs_control._install_local_rpms(pkgs) + self.assertEqual(backup.changed_pkgs_control.track_installed_pkg.called, len(pkgs)) + + self.assertEqual(backup.run_subprocess.called, 1) + self.assertEqual(["rpm", "-i", "pkg1", "pkg2", "pkg3"], backup.run_subprocess.cmd) + + @unit_tests.mock(backup.changed_pkgs_control, "track_installed_pkg", DummyFuncMocked()) + @unit_tests.mock(backup, "run_subprocess", RunSubprocessMocked()) + def test_install_local_rpms_with_replace(self): + pkgs = ["pkg1", "pkg2", "pkg3"] + backup.changed_pkgs_control._install_local_rpms(pkgs, replace=True) + self.assertEqual(backup.changed_pkgs_control.track_installed_pkg.called, len(pkgs)) + + self.assertEqual(backup.run_subprocess.called, 1) + self.assertEqual( + ["rpm", "-i", "--replacepkgs", "pkg1", "pkg2", "pkg3"], + backup.run_subprocess.cmd, + ) + + +def test_remove_pkgs_with_empty_list(caplog): + backup.remove_pkgs([]) + assert "No package to remove" in caplog.messages[-1] + + +def test_track_installed_pkg(): + control = backup.ChangedRPMPackagesController() + pkgs = ["pkg1", "pkg2", "pkg3"] + for pkg in pkgs: + control.track_installed_pkg(pkg) + assert control.installed_pkgs == pkgs + + +def test_track_installed_pkgs(): + control = backup.ChangedRPMPackagesController() + pkgs = ["pkg1", "pkg2", "pkg3"] + control.track_installed_pkgs(pkgs) + assert control.installed_pkgs == pkgs + + +def test_changed_pkgs_control_remove_installed_pkgs(monkeypatch, caplog): + removed_pkgs = ["pkg_1"] + run_subprocess_mock = mock.Mock( + side_effect=unit_tests.run_subprocess_side_effect( + (("rpm", "-e", "--nodeps", removed_pkgs[0]), ("test", 0)), + ) + ) + monkeypatch.setattr( + backup, + "run_subprocess", + value=run_subprocess_mock, + ) + + control = backup.ChangedRPMPackagesController() + control.installed_pkgs = removed_pkgs + control._remove_installed_pkgs() + assert "Removing package: %s" % removed_pkgs[0] in caplog.records[-1].message + + +def test_changed_pkgs_control_install_removed_pkgs(monkeypatch): + install_local_rpms_mock = mock.Mock() + removed_pkgs = [mock.Mock()] + monkeypatch.setattr( + backup.changed_pkgs_control, + "_install_local_rpms", + value=install_local_rpms_mock, + ) + backup.changed_pkgs_control.removed_pkgs = removed_pkgs + backup.changed_pkgs_control._install_removed_pkgs() + assert install_local_rpms_mock.call_count == 1 + + +def test_changed_pkgs_control_install_removed_pkgs_without_path(monkeypatch, caplog): + install_local_rpms_mock = mock.Mock() + removed_pkgs = [mock.Mock()] + monkeypatch.setattr( + backup.changed_pkgs_control, + "_install_local_rpms", + value=install_local_rpms_mock, + ) + backup.changed_pkgs_control.removed_pkgs = removed_pkgs + backup.changed_pkgs_control.removed_pkgs[0].path = None + backup.changed_pkgs_control._install_removed_pkgs() + assert install_local_rpms_mock.call_count == 1 + assert "Couldn't find a backup" in caplog.records[-1].message + + +def test_changed_pkgs_control_restore_pkgs(monkeypatch): + install_local_rpms_mock = mock.Mock() + remove_pkgs_mock = mock.Mock() + monkeypatch.setattr( + backup.changed_pkgs_control, + "_install_local_rpms", + value=install_local_rpms_mock, + ) + monkeypatch.setattr(backup, "remove_pkgs", value=remove_pkgs_mock) + + backup.changed_pkgs_control.restore_pkgs() + assert install_local_rpms_mock.call_count == 1 + assert remove_pkgs_mock.call_count == 1 + + +@pytest.mark.parametrize( + ("filepath", "backup_dir", "file_content", "expected"), + ( + ("test.rpm", "backup", "test", None), + ("test.rpm", "backup", "", "Can't find"), + ), +) +def test_restorable_file_backup(filepath, backup_dir, file_content, expected, tmpdir, monkeypatch, caplog): + tmp_file = tmpdir.join(filepath) + tmp_backup = tmpdir.mkdir(backup_dir) + if file_content: + tmp_file.write(file_content) + + monkeypatch.setattr(backup, "BACKUP_DIR", str(tmp_backup)) + rf = backup.RestorableFile(filepath=str(tmp_file)) + rf.backup() + + if expected: + assert expected in caplog.records[-1].message + + +def test_restorable_file_backup_oserror(tmpdir, caplog): + tmp_file = tmpdir.join("test.rpm") + tmp_file.write("test") + rf = backup.RestorableFile(filepath=str(tmp_file)) + + with pytest.raises(SystemExit): + rf.backup() + + assert "Error(2): No such file or directory" in caplog.records[-1].message + + +@pytest.mark.parametrize( + ("filepath", "backup_dir", "file_content", "expected"), + ( + ("test.rpm", "backup", "test", "restored"), + ("test.rpm", "backup", "", "hasn't been backed up"), + ), +) +def test_restorable_file_restore(filepath, backup_dir, file_content, expected, tmpdir, monkeypatch, caplog): + tmp_backup = tmpdir + tmp_file = tmpdir.join(filepath) + tmp_backup = tmp_backup.mkdir(backup_dir).join(filepath) + if file_content: + tmp_backup.write(file_content) + + monkeypatch.setattr(backup, "BACKUP_DIR", os.path.dirname(str(tmp_backup))) + rf = backup.RestorableFile(filepath=str(tmp_file)) + rf.restore() + + if expected: + assert expected in caplog.records[-1].message + + +def test_restorable_file_restore_oserror(tmpdir, caplog, monkeypatch): + tmp_backup = tmpdir + tmp_backup = tmp_backup.mkdir("backup").join("test.rpm") + tmp_backup.write("test") + + monkeypatch.setattr(backup, "BACKUP_DIR", os.path.dirname(str(tmp_backup))) + + rf = backup.RestorableFile(filepath="/non-existing/test.rpm") + rf.restore() + + # Source and dest files are the same, which throws this error + assert "Error(2): No such file or directory" in caplog.records[-1].message + + +@pytest.mark.parametrize( + ("pkgs_to_remove", "ret_code", "backup_pkg", "critical", "expected"), + ( + (["pkg1"], 1, False, True, "Error: Couldn't remove {}."), + (["pkg1"], 1, False, False, "Couldn't remove {}."), + ), +) +def test_remove_pkgs_failed_to_remove( + pkgs_to_remove, + ret_code, + backup_pkg, + critical, + expected, + monkeypatch, + caplog, +): + run_subprocess_mock = mock.Mock( + side_effect=unit_tests.run_subprocess_side_effect( + (("rpm", "-e", "--nodeps", pkgs_to_remove[0]), ("test", ret_code)), + ) + ) + monkeypatch.setattr( + backup, + "run_subprocess", + value=run_subprocess_mock, + ) + + if critical: + with pytest.raises(SystemExit): + backup.remove_pkgs( + pkgs_to_remove=pkgs_to_remove, + backup=backup_pkg, + critical=critical, + ) + else: + backup.remove_pkgs(pkgs_to_remove=pkgs_to_remove, backup=backup_pkg, critical=critical) + + assert expected.format(pkgs_to_remove[0]) in caplog.records[-1].message + + +@centos8 +def test_restorable_package_backup(pretend_os, monkeypatch, tmpdir): + backup_dir = str(tmpdir) + data_dir = str(tmpdir.join("data-dir")) + dowloaded_pkg_dir = str(tmpdir.join("some-path")) + download_pkg_mock = mock.Mock(return_value=dowloaded_pkg_dir) + monkeypatch.setattr(backup, "BACKUP_DIR", backup_dir) + monkeypatch.setattr(repo, "DATA_DIR", data_dir) + monkeypatch.setattr(backup, "download_pkg", download_pkg_mock) + rp = backup.RestorablePackage(pkgname="pkg-1") + rp.backup() + + assert download_pkg_mock.call_count == 1 + assert rp.path == dowloaded_pkg_dir + + +def test_restorable_package_backup_without_dir(monkeypatch, tmpdir, caplog): + backup_dir = str(tmpdir.join("non-existing")) + monkeypatch.setattr(backup, "BACKUP_DIR", backup_dir) + rp = backup.RestorablePackage(pkgname="pkg-1") + rp.backup() + + assert "Can't access %s" % backup_dir in caplog.records[-1].message + + +def test_changedrpms_packages_controller_install_local_rpms(monkeypatch, caplog): + pkgs = ["pkg-1"] + run_subprocess_mock = mock.Mock( + side_effect=unit_tests.run_subprocess_side_effect( + (("rpm", "-i", pkgs[0]), ("test", 1)), + ) + ) + monkeypatch.setattr( + backup, + "run_subprocess", + value=run_subprocess_mock, + ) + + control = backup.ChangedRPMPackagesController() + result = control._install_local_rpms(pkgs_to_install=pkgs, replace=False, critical=False) + + assert result == False + assert run_subprocess_mock.call_count == 1 + assert "Couldn't install %s packages." % pkgs[0] in caplog.records[-1].message + + +def test_changedrpms_packages_controller_install_local_rpms_system_exit(monkeypatch, caplog): + pkgs = ["pkg-1"] + run_subprocess_mock = mock.Mock( + side_effect=unit_tests.run_subprocess_side_effect( + (("rpm", "-i", pkgs[0]), ("test", 1)), + ) + ) + monkeypatch.setattr( + backup, + "run_subprocess", + value=run_subprocess_mock, + ) + + control = backup.ChangedRPMPackagesController() + with pytest.raises(SystemExit): + control._install_local_rpms(pkgs_to_install=pkgs, replace=False, critical=True) + + assert run_subprocess_mock.call_count == 1 + assert "Error: Couldn't install %s packages." % pkgs[0] in caplog.records[-1].message + + +@pytest.mark.parametrize( + ("is_eus_system", "has_internet_access"), + ((True, True), (False, False), (True, False), (False, True)), +) +@centos8 +def test_restorable_package_backup(pretend_os, is_eus_system, has_internet_access, tmpdir, monkeypatch): + pkg_to_backup = "pkg-1" + + # Python 2.7 needs a string or buffer and not a LocalPath + tmpdir = str(tmpdir) + download_pkg_mock = mock.Mock() + monkeypatch.setattr(backup, "download_pkg", value=download_pkg_mock) + monkeypatch.setattr(backup, "BACKUP_DIR", value=tmpdir) + monkeypatch.setattr(backup.system_info, "corresponds_to_rhel_eus_release", value=lambda: is_eus_system) + monkeypatch.setattr(backup, "get_hardcoded_repofiles_dir", value=lambda: tmpdir if is_eus_system else None) + backup.system_info.has_internet_access = has_internet_access + + rp = backup.RestorablePackage(pkgname=pkg_to_backup) + rp.backup() + assert download_pkg_mock.call_count == 1 diff --git a/convert2rhel/unit_tests/checks_test.py b/convert2rhel/unit_tests/checks_test.py index dad659e690..e794e79542 100644 --- a/convert2rhel/unit_tests/checks_test.py +++ b/convert2rhel/unit_tests/checks_test.py @@ -35,7 +35,7 @@ from convert2rhel.systeminfo import system_info from convert2rhel.toolopts import tool_opts from convert2rhel.unit_tests import GetFileContentMocked, GetLoggerMocked, run_subprocess_side_effect -from convert2rhel.unit_tests.conftest import centos7, centos8 +from convert2rhel.unit_tests.conftest import centos7, centos8, oracle8 from convert2rhel.utils import run_subprocess @@ -949,15 +949,27 @@ def test_custom_repos_are_invalid(self): self.assertTrue("Unable to access the repositories passed through " in checks.logger.critical_msgs[0]) +@oracle8 +def test_check_package_updates_skip_on_not_latest_ol(pretend_os, caplog): + message = ( + "Skipping the check because there are no publicly available Oracle Linux Server 8.4 repositories available." + ) + + check_package_updates() + + assert message in caplog.records[-1].message + + @pytest.mark.parametrize( ("packages", "exception", "expected"), ( - (["package-1", "package-2"], True, "The system has {} packages not updated."), + (["package-1", "package-2"], True, "The system has {} packages not updated"), ([], False, "System is up-to-date."), ), ) -def test_check_package_updates(packages, exception, expected, monkeypatch, caplog): - monkeypatch.setattr(checks, "get_total_packages_to_update", value=lambda: packages) +@centos8 +def test_check_package_updates(pretend_os, packages, exception, expected, monkeypatch, caplog): + monkeypatch.setattr(checks, "get_total_packages_to_update", value=lambda reposdir: packages) monkeypatch.setattr(checks, "ask_to_continue", value=lambda: mock.Mock()) check_package_updates() @@ -979,24 +991,108 @@ def test_check_package_updates_with_repoerror(monkeypatch, caplog): ) +@centos8 +def test_check_package_updates_without_internet(pretend_os, tmpdir, monkeypatch, caplog): + monkeypatch.setattr(checks, "get_hardcoded_repofiles_dir", value=lambda: str(tmpdir)) + system_info.has_internet_access = False + check_package_updates() + + assert "Skipping the check as no internet connection has been detected." in caplog.records[-1].message + + +@oracle8 +def test_is_loaded_kernel_latest_skip_on_not_latest_ol(pretend_os, caplog): + message = ( + "Skipping the check because there are no publicly available Oracle Linux Server 8.4 repositories available." + ) + + is_loaded_kernel_latest() + + assert message in caplog.records[-1].message + + @pytest.mark.parametrize( ("repoquery_version", "uname_version", "return_code", "major_ver", "package_name", "raise_system_exit"), ( - ("1634146676\t3.10.0-1160.45.1.el7", "3.10.0-1160.42.2.el7.x86_64", 0, 8, "kernel-core", True), - ("1634146676\t3.10.0-1160.45.1.el7", "3.10.0-1160.45.1.el7.x86_64", 0, 7, "kernel", False), - ("1634146676\t3.10.0-1160.45.1.el7", "3.10.0-1160.45.1.el7.x86_64", 0, 6, "kernel", False), + ("1634146676\t3.10.0-1160.45.1.el7\tbaseos", "3.10.0-1160.42.2.el7.x86_64", 0, 8, "kernel-core", True), + ("1634146676\t3.10.0-1160.45.1.el7\tbaseos", "3.10.0-1160.45.1.el7.x86_64", 0, 7, "kernel", False), + ("1634146676\t3.10.0-1160.45.1.el7\tbaseos", "3.10.0-1160.45.1.el7.x86_64", 0, 6, "kernel", False), ), ) def test_is_loaded_kernel_latest( repoquery_version, uname_version, return_code, major_ver, package_name, raise_system_exit, monkeypatch, caplog ): Version = namedtuple("Version", ("major", "minor")) + # Using the minor version as 99, so the tests should never fail because of a constraint in the code, since we don't + # mind the minor version number (for now), and require only that the major version to be in the range of 6 to 8, + # we can set the minor version to 99 to avoid hardcoded checks in the code. monkeypatch.setattr( checks.system_info, "version", - value=Version(major=major_ver, minor=0), + value=Version(major=major_ver, minor=99), ) + system_info.id = "centos" + run_subprocess_mocked = mock.Mock( + spec=run_subprocess, + side_effect=run_subprocess_side_effect( + ( + ( + "repoquery", + "--quiet", + "--qf", + '"%{BUILDTIME}\\t%{VERSION}-%{RELEASE}\\t%{REPOID}"', + package_name, + ), + ( + repoquery_version, + return_code, + ), + ), + (("uname", "-r"), (uname_version, return_code)), + ), + ) + monkeypatch.setattr( + checks, + "run_subprocess", + value=run_subprocess_mocked, + ) + + if raise_system_exit: + with pytest.raises(SystemExit): + is_loaded_kernel_latest() + + repoquery_kernel_version = repoquery_version.split("\t")[1] + uname_kernel_version = uname_version.rsplit(".", 1)[0] + assert ( + "Latest kernel version available in baseos: %s\n" % repoquery_kernel_version in caplog.records[-1].message + ) + assert "Loaded kernel version: %s\n" % uname_kernel_version in caplog.records[-1].message + else: + is_loaded_kernel_latest() + assert "Kernel currently loaded is at the latest version." in caplog.records[-1].message + +@pytest.mark.parametrize( + ("repoquery_version", "uname_version", "return_code", "package_name", "raise_system_exit"), + ( + ("1634146676\t3.10.0-1160.45.1.el7\tbaseos", "3.10.0-1160.42.2.el7.x86_64", 0, "kernel-core", True), + ("1634146676\t3.10.0-1160.45.1.el7\tbaseos", "3.10.0-1160.45.1.el7.x86_64", 0, "kernel-core", False), + ), +) +@centos8 +def test_is_loaded_kernel_latest_eus_system( + pretend_os, + repoquery_version, + uname_version, + return_code, + package_name, + raise_system_exit, + tmpdir, + monkeypatch, + caplog, +): + fake_reposdir_path = str(tmpdir) + monkeypatch.setattr(checks, "get_hardcoded_repofiles_dir", value=lambda: fake_reposdir_path) run_subprocess_mocked = mock.Mock( spec=run_subprocess, side_effect=run_subprocess_side_effect( @@ -1005,7 +1101,8 @@ def test_is_loaded_kernel_latest( "repoquery", "--quiet", "--qf", - '"%{BUILDTIME}\\t%{VERSION}-%{RELEASE}"', + '"%{BUILDTIME}\\t%{VERSION}-%{RELEASE}\\t%{REPOID}"', + "--setopt=reposdir=%s" % fake_reposdir_path, package_name, ), ( @@ -1026,15 +1123,30 @@ def test_is_loaded_kernel_latest( with pytest.raises(SystemExit): is_loaded_kernel_latest() - repoquery_kernel_version = repoquery_version.split("\t", 1)[1] + repoquery_kernel_version = repoquery_version.split("\t")[1] uname_kernel_version = uname_version.rsplit(".", 1)[0] - assert "Latest kernel version: %s\n" % repoquery_kernel_version in caplog.records[-1].message - assert "Current loaded kernel: %s\n" % uname_kernel_version in caplog.records[-1].message + assert ( + "The version of the loaded kernel is different from the latest version in repositories defined in the %s folder" + % fake_reposdir_path + ) + assert ( + "Latest kernel version available in baseos: %s\n" % repoquery_kernel_version in caplog.records[-1].message + ) + assert "Loaded kernel version: %s\n" % uname_kernel_version in caplog.records[-1].message else: is_loaded_kernel_latest() assert "Kernel currently loaded is at the latest version." in caplog.records[-1].message +@centos8 +def test_is_loaded_kernel_latest_eus_system_no_connection(pretend_os, monkeypatch, tmpdir, caplog): + monkeypatch.setattr(checks, "get_hardcoded_repofiles_dir", value=lambda: str(tmpdir)) + system_info.has_internet_access = False + + is_loaded_kernel_latest() + assert "Skipping the check as no internet connection has been detected." in caplog.records[-1].message + + @pytest.mark.parametrize( ("repoquery_version", "return_code", "major_ver", "package_name", "unsupported_skip", "expected"), ( @@ -1062,7 +1174,7 @@ def test_is_loaded_kernel_latest_unsupported_skip( "repoquery", "--quiet", "--qf", - '"%{BUILDTIME}\\t%{VERSION}-%{RELEASE}"', + '"%{BUILDTIME}\\t%{VERSION}-%{RELEASE}\\t%{REPOID}"', package_name, ), ( diff --git a/convert2rhel/unit_tests/main_test.py b/convert2rhel/unit_tests/main_test.py index 02f2e7a5ea..eec766b217 100644 --- a/convert2rhel/unit_tests/main_test.py +++ b/convert2rhel/unit_tests/main_test.py @@ -28,7 +28,9 @@ import pytest +from convert2rhel import backup, grub from convert2rhel import logger as logger_module +from convert2rhel.breadcrumbs import breadcrumbs try: @@ -142,7 +144,7 @@ def test_show_eula_nonexisting_file(self): self.assertEqual(len(main.loggerinst.critical_msgs), 1) @unit_tests.mock( - utils.changed_pkgs_control, + backup.changed_pkgs_control, "restore_pkgs", unit_tests.CountableMockObject(), ) @@ -172,7 +174,7 @@ def test_show_eula_nonexisting_file(self): @unit_tests.mock(cert.SystemCert, "remove", unit_tests.CountableMockObject()) def test_rollback_changes(self): main.rollback_changes() - self.assertEqual(utils.changed_pkgs_control.restore_pkgs.called, 1) + self.assertEqual(backup.changed_pkgs_control.restore_pkgs.called, 1) self.assertEqual(repo.restore_yum_repos.called, 1) self.assertEqual(redhatrelease.system_release_file.restore.called, 1) self.assertEqual(redhatrelease.os_release_file.restore.called, 1) @@ -305,3 +307,34 @@ def test_initialize_logger(exception_type, exception, monkeypatch, capsys): main.initialize_logger("convert2rhel.log", "/tmp") setup_logger_handler_mock.assert_called_once() archive_old_logger_files_mock.assert_called_once() + + +def test_post_ponr_conversion(monkeypatch): + install_gpg_keys_mock = mock.Mock() + perserve_only_rhel_kernel_mock = mock.Mock() + replace_non_red_hat_pkgs_left_mock = mock.Mock() + list_non_red_hat_pkgs_left_mock = mock.Mock() + post_ponr_set_efi_configuration_mock = mock.Mock() + yum_conf_patch_mock = mock.Mock() + lock_releasever_in_rhel_repositories_mock = mock.Mock() + finish_success_mock = mock.Mock() + + monkeypatch.setattr(pkghandler, "install_gpg_keys", install_gpg_keys_mock) + monkeypatch.setattr(pkghandler, "preserve_only_rhel_kernel", perserve_only_rhel_kernel_mock) + monkeypatch.setattr(pkghandler, "replace_non_red_hat_packages", replace_non_red_hat_pkgs_left_mock) + monkeypatch.setattr(pkghandler, "list_non_red_hat_pkgs_left", list_non_red_hat_pkgs_left_mock) + monkeypatch.setattr(grub, "post_ponr_set_efi_configuration", post_ponr_set_efi_configuration_mock) + monkeypatch.setattr(redhatrelease.YumConf, "patch", yum_conf_patch_mock) + monkeypatch.setattr(subscription, "lock_releasever_in_rhel_repositories", lock_releasever_in_rhel_repositories_mock) + monkeypatch.setattr(breadcrumbs, "finish_success", finish_success_mock) + + main.post_ponr_conversion() + + assert install_gpg_keys_mock.call_count == 1 + assert perserve_only_rhel_kernel_mock.call_count == 1 + assert replace_non_red_hat_pkgs_left_mock.call_count == 1 + assert list_non_red_hat_pkgs_left_mock.call_count == 1 + assert post_ponr_set_efi_configuration_mock.call_count == 1 + assert yum_conf_patch_mock.call_count == 1 + assert lock_releasever_in_rhel_repositories_mock.call_count == 1 + assert finish_success_mock.call_count == 1 diff --git a/convert2rhel/unit_tests/pkghandler_test.py b/convert2rhel/unit_tests/pkghandler_test.py index 4f977def78..228977be02 100644 --- a/convert2rhel/unit_tests/pkghandler_test.py +++ b/convert2rhel/unit_tests/pkghandler_test.py @@ -31,8 +31,7 @@ else: from unittest import mock # pylint: disable=no-name-in-module -from convert2rhel import unit_tests # Imports unit_tests/__init__.py -from convert2rhel import pkghandler, pkgmanager, utils +from convert2rhel import backup, pkghandler, pkgmanager, unit_tests, utils # Imports unit_tests/__init__.py from convert2rhel.pkghandler import ( _get_packages_to_update_dnf, _get_packages_to_update_yum, @@ -41,7 +40,7 @@ from convert2rhel.systeminfo import system_info from convert2rhel.toolopts import tool_opts from convert2rhel.unit_tests import GetLoggerMocked, is_rpm_based_os -from convert2rhel.unit_tests.conftest import all_systems +from convert2rhel.unit_tests.conftest import all_systems, centos8 if sys.version_info[:2] <= (2, 7): @@ -170,8 +169,8 @@ def test_clear_versionlock_plugin_not_enabled(self): @unit_tests.mock(os.path, "isfile", IsFileMocked(is_file=True)) @unit_tests.mock(os.path, "getsize", GetSizeMocked(file_size=1)) @unit_tests.mock(pkghandler, "call_yum_cmd", CallYumCmdMocked()) - @unit_tests.mock(utils.RestorableFile, "backup", DumbCallableObject) - @unit_tests.mock(utils.RestorableFile, "restore", DumbCallableObject) + @unit_tests.mock(backup.RestorableFile, "backup", DumbCallableObject) + @unit_tests.mock(backup.RestorableFile, "restore", DumbCallableObject) def test_clear_versionlock_user_says_yes(self): pkghandler.clear_versionlock() self.assertEqual(pkghandler.call_yum_cmd.called, 1) @@ -313,7 +312,7 @@ def test_call_yum_cmd_w_downgrades_one_fail(self): "get_problematic_pkgs", lambda pkg: {"errors": set([pkg]), "mismatches": set()}, ) - @unit_tests.mock(utils, "remove_pkgs", RemovePkgsMocked()) + @unit_tests.mock(pkghandler, "remove_pkgs", RemovePkgsMocked()) def test_call_yum_cmd_w_downgrades_remove_problematic_pkgs(self): pkghandler.call_yum_cmd.return_code = 1 pkghandler.MAX_YUM_CMD_CALLS = 1 @@ -325,8 +324,8 @@ def test_call_yum_cmd_w_downgrades_remove_problematic_pkgs(self): ["fingerprint"], ) - self.assertIn(pkghandler.call_yum_cmd.return_string, utils.remove_pkgs.pkgs) - self.assertEqual(utils.remove_pkgs.critical, False) + self.assertIn(pkghandler.call_yum_cmd.return_string, pkghandler.remove_pkgs.pkgs) + self.assertEqual(pkghandler.remove_pkgs.critical, False) def test_get_pkgs_to_distro_sync(self): problematic_pkgs = { @@ -853,7 +852,7 @@ def __call__(self, fingerprints, name=""): @unit_tests.mock(utils, "ask_to_continue", DumbCallableObject()) @unit_tests.mock(pkghandler, "print_pkg_info", DumbCallableObject()) @unit_tests.mock(system_info, "fingerprints_rhel", ["rhel_fingerprint"]) - @unit_tests.mock(utils, "remove_pkgs", RemovePkgsMocked()) + @unit_tests.mock(pkghandler, "remove_pkgs", RemovePkgsMocked()) @unit_tests.mock( pkghandler, "get_installed_pkgs_w_different_fingerprint", @@ -862,8 +861,8 @@ def __call__(self, fingerprints, name=""): def test_remove_pkgs_with_confirm(self): pkghandler.remove_pkgs_with_confirm(["installed_pkg", "not_installed_pkg"]) - self.assertEqual(len(utils.remove_pkgs.pkgs), 1) - self.assertEqual(utils.remove_pkgs.pkgs[0], "installed_pkg-0.1-1.x86_64") + self.assertEqual(len(pkghandler.remove_pkgs.pkgs), 1) + self.assertEqual(pkghandler.remove_pkgs.pkgs[0], "installed_pkg-0.1-1.x86_64") class CallYumCmdWDowngradesMocked(unit_tests.MockFunction): def __init__(self): @@ -1115,19 +1114,23 @@ def test_handle_older_rhel_kernel_not_available(self): @unit_tests.mock(system_info, "version", namedtuple("Version", ["major", "minor"])(7, 0)) @unit_tests.mock(system_info, "releasever", None) + @unit_tests.mock(backup, "run_subprocess", RunSubprocessMocked()) @unit_tests.mock(utils, "run_subprocess", RunSubprocessMocked()) - @unit_tests.mock(utils, "remove_pkgs", RemovePkgsMocked()) + @unit_tests.mock(pkghandler, "remove_pkgs", RemovePkgsMocked()) def test_handle_older_rhel_kernel_not_available_multiple_installed(self): utils.run_subprocess.output = YUM_KERNEL_LIST_OLDER_NOT_AVAILABLE_MULTIPLE_INSTALLED pkghandler.handle_no_newer_rhel_kernel_available() - self.assertEqual(len(utils.remove_pkgs.pkgs), 1) - self.assertEqual(utils.remove_pkgs.pkgs[0], "kernel-4.7.4-200.fc24") + self.assertEqual(len(pkghandler.remove_pkgs.pkgs), 1) + self.assertEqual(pkghandler.remove_pkgs.pkgs[0], "kernel-4.7.4-200.fc24") self.assertEqual( utils.run_subprocess.cmd, ["yum", "install", "-y", "kernel-4.7.4-200.fc24"], ) + self.assertEqual(len(pkghandler.remove_pkgs.pkgs), 1) + self.assertEqual(pkghandler.remove_pkgs.pkgs[0], "kernel-4.7.4-200.fc24") + self.assertEqual(utils.run_subprocess.cmd, ["yum", "install", "-y", "kernel-4.7.4-200.fc24"]) class DownloadPkgMocked(unit_tests.MockFunction): def __init__(self): @@ -1224,7 +1227,7 @@ def test_is_rhel_kernel_installed_yes(self): GetInstalledPkgsWDifferentFingerprintMocked(), ) @unit_tests.mock(pkghandler, "print_pkg_info", DumbCallableObject()) - @unit_tests.mock(utils, "remove_pkgs", RemovePkgsMocked()) + @unit_tests.mock(pkghandler, "remove_pkgs", RemovePkgsMocked()) def test_remove_non_rhel_kernels(self): removed_pkgs = pkghandler.remove_non_rhel_kernels() @@ -1285,7 +1288,7 @@ def test_fix_invalid_grub2_entries(self): GetInstalledPkgsWDifferentFingerprintMocked(), ) @unit_tests.mock(pkghandler, "print_pkg_info", DumbCallableObject()) - @unit_tests.mock(utils, "remove_pkgs", RemovePkgsMocked()) + @unit_tests.mock(pkghandler, "remove_pkgs", RemovePkgsMocked()) @unit_tests.mock(pkghandler, "call_yum_cmd", CallYumCmdMocked()) def test_install_additional_rhel_kernel_pkgs(self): removed_pkgs = pkghandler.remove_non_rhel_kernels() @@ -1466,7 +1469,7 @@ def test_compare_package_versions(version1, version2, expected): @pytest.mark.parametrize( - ("package_manager_type", "packages", "expected"), + ("package_manager_type", "packages", "expected", "reposdir"), ( ( "yum", @@ -1478,6 +1481,7 @@ def test_compare_package_versions(version1, version2, expected): "convert2rhel.noarch-0.24-1.20211111151554764702.pr356.28.ge9ed160.el8", "convert2rhel.src-0.24-1.20211111151554764702.pr356.28.ge9ed160.el8", }, + None, ), ( "yum", @@ -1486,6 +1490,7 @@ def test_compare_package_versions(version1, version2, expected): "convert2rhel.noarch-0.24-1.20211111151554764702.pr356.28.ge9ed160.el8", ], {"convert2rhel.noarch-0.24-1.20211111151554764702.pr356.28.ge9ed160.el8"}, + None, ), ( "dnf", @@ -1499,6 +1504,21 @@ def test_compare_package_versions(version1, version2, expected): "dunst-1.7.0-1.fc35.x86_64", "java-11-openjdk-headless-1:11.0.13.0.8-2.fc35.x86_64", }, + None, + ), + ( + "dnf", + [ + "dunst-1.7.1-1.fc35.x86_64", + "dunst-1.7.0-1.fc35.x86_64", + "java-11-openjdk-headless-1:11.0.13.0.8-2.fc35.x86_64", + ], + { + "dunst-1.7.1-1.fc35.x86_64", + "dunst-1.7.0-1.fc35.x86_64", + "java-11-openjdk-headless-1:11.0.13.0.8-2.fc35.x86_64", + }, + "test/reposdir", ), ( "dnf", @@ -1511,18 +1531,33 @@ def test_compare_package_versions(version1, version2, expected): "dunst-1.7.1-1.fc35.x86_64", "java-11-openjdk-headless-1:11.0.13.0.8-2.fc35.x86_64", }, + "test/reposdir", ), ), ) -def test_get_total_packages_to_update(package_manager_type, packages, expected, monkeypatch): +@centos8 +def test_get_total_packages_to_update( + package_manager_type, + packages, + expected, + reposdir, + pretend_os, + monkeypatch, +): monkeypatch.setattr(pkgmanager, "TYPE", package_manager_type) - monkeypatch.setattr( - pkghandler, - "_get_packages_to_update_%s" % package_manager_type, - value=lambda: packages, - ) - - assert get_total_packages_to_update() == expected + if package_manager_type == "dnf": + monkeypatch.setattr( + pkghandler, + "_get_packages_to_update_%s" % package_manager_type, + value=lambda reposdir: packages, + ) + else: + monkeypatch.setattr( + pkghandler, + "_get_packages_to_update_%s" % package_manager_type, + value=lambda: packages, + ) + assert get_total_packages_to_update(reposdir=reposdir) == expected @pytest.mark.skipif( @@ -1531,7 +1566,6 @@ def test_get_total_packages_to_update(package_manager_type, packages, expected, ) @pytest.mark.parametrize(("packages"), ((["package-1", "package-2", "package-3"],))) def test_get_packages_to_update_yum(packages, monkeypatch): - PkgName = namedtuple("PkgNames", ["name"]) PkgUpdates = namedtuple("PkgUpdates", ["updates"]) transaction_pkgs = [] @@ -1549,9 +1583,21 @@ def test_get_packages_to_update_yum(packages, monkeypatch): pkgmanager.TYPE != "dnf", reason="No dnf module detected on the system, skipping it.", ) -@pytest.mark.parametrize(("packages"), ((["package-1", "package-2", "package-3"],))) +@pytest.mark.parametrize( + ("packages", "reposdir"), + ( + ( + ["package-1", "package-2", "package-i3"], + None, + ), + ( + ["package-1"], + "test/reposdir", + ), + ), +) @all_systems -def test_get_packages_to_update_dnf(packages, pretend_os, monkeypatch): +def test_get_packages_to_update_dnf(packages, reposdir, pretend_os, monkeypatch): dummy_mock = mock.Mock() PkgName = namedtuple("PkgNames", ["name"]) transaction_pkgs = [PkgName(package) for package in packages] @@ -1562,7 +1608,7 @@ def test_get_packages_to_update_dnf(packages, pretend_os, monkeypatch): monkeypatch.setattr(pkgmanager.Base, "resolve", value=dummy_mock) monkeypatch.setattr(pkgmanager.Base, "transaction", value=transaction_pkgs) - assert _get_packages_to_update_dnf() == packages + assert _get_packages_to_update_dnf(reposdir=reposdir) == packages YUM_PROTECTED_ERROR = """Error: Trying to remove "systemd", which is protected diff --git a/convert2rhel/unit_tests/repo_test.py b/convert2rhel/unit_tests/repo_test.py index c6189888d7..6a5dcb0780 100644 --- a/convert2rhel/unit_tests/repo_test.py +++ b/convert2rhel/unit_tests/repo_test.py @@ -15,14 +15,59 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from convert2rhel import unit_tests # Imports unit_tests/__init__.py +import os + +import pytest + from convert2rhel import repo from convert2rhel.systeminfo import system_info +from convert2rhel.unit_tests.conftest import centos8 + +@pytest.mark.parametrize( + ("is_eus_release", "expected"), + ( + ( + True, + [ + "rhel-8-for-x86_64-baseos-eus-rpms", + "rhel-8-for-x86_64-appstream-eus-rpms", + ], + ), + ( + False, + [ + "rhel-8-for-x86_64-baseos-rpms", + "rhel-8-for-x86_64-appstream-rpms", + ], + ), + ), +) +@centos8 +def test_get_rhel_repoids(pretend_os, is_eus_release, expected, monkeypatch): + monkeypatch.setattr(repo.system_info, "corresponds_to_rhel_eus_release", value=lambda: is_eus_release) + repos = repo.get_rhel_repoids() + assert repos == expected -class TestRepo(unit_tests.ExtendedTestCase): - @unit_tests.mock(system_info, "default_rhsm_repoids", ["rhel_server"]) - def test_get_rhel_repoids(self): - repos = repo.get_rhel_repoids() - self.assertEqual(repos, ["rhel_server"]) +@pytest.mark.parametrize( + ("path_exists", "expected"), + ( + ( + True, + "/usr/share/convert2rhel/repos/centos-8.4", + ), + ( + False, + None, + ), + ( + False, + None, + ), + ), +) +@centos8 +def test_get_hardcoded_repofiles_dir(pretend_os, path_exists, expected, monkeypatch): + monkeypatch.setattr(os.path, "exists", value=lambda _: path_exists) + assert repo.get_hardcoded_repofiles_dir() == expected diff --git a/convert2rhel/unit_tests/subscription_test.py b/convert2rhel/unit_tests/subscription_test.py index 6073983a7e..79303c85cc 100644 --- a/convert2rhel/unit_tests/subscription_test.py +++ b/convert2rhel/unit_tests/subscription_test.py @@ -25,11 +25,10 @@ import pexpect import pytest -from convert2rhel import unit_tests # Imports unit_tests/__init__.py -from convert2rhel import pkghandler, subscription, toolopts, utils +from convert2rhel import backup, pkghandler, subscription, toolopts, unit_tests, utils from convert2rhel.systeminfo import system_info -from convert2rhel.toolopts import tool_opts from convert2rhel.unit_tests import GetLoggerMocked, run_subprocess_side_effect +from convert2rhel.unit_tests.conftest import centos7, centos8 if sys.version_info[:2] <= (2, 7): @@ -256,10 +255,11 @@ def test_replace_subscription_manager_rpms_not_available(self): @unit_tests.mock(pkghandler, "get_installed_pkg_objects", lambda _: [namedtuple("Pkg", ["name"])("submgr")]) @unit_tests.mock(pkghandler, "print_pkg_info", lambda x: None) @unit_tests.mock(utils, "ask_to_continue", PromptUserMocked()) - @unit_tests.mock(utils, "remove_pkgs", DumbCallable()) + @unit_tests.mock(backup, "remove_pkgs", DumbCallable()) def test_remove_original_subscription_manager(self): subscription.remove_original_subscription_manager() - self.assertEqual(utils.remove_pkgs.called, 1) + + self.assertEqual(backup.remove_pkgs.called, 1) @unit_tests.mock( pkghandler, @@ -270,10 +270,10 @@ def test_remove_original_subscription_manager(self): @unit_tests.mock(system_info, "id", "centos") @unit_tests.mock(pkghandler, "print_pkg_info", lambda x: None) @unit_tests.mock(utils, "ask_to_continue", PromptUserMocked()) - @unit_tests.mock(utils, "remove_pkgs", DumbCallable()) + @unit_tests.mock(backup, "remove_pkgs", DumbCallable()) def test_remove_original_subscription_manager_missing_package_ol_85(self): subscription.remove_original_subscription_manager() - self.assertEqual(utils.remove_pkgs.called, 2) + self.assertEqual(backup.remove_pkgs.called, 2) @unit_tests.mock(pkghandler, "get_installed_pkg_objects", lambda _: []) @unit_tests.mock(subscription, "loggerinst", GetLoggerMocked()) @@ -295,7 +295,7 @@ def test_remove_original_subscription_manager_no_pkgs(self): ) @unit_tests.mock(pkghandler, "filter_installed_pkgs", DumbCallable()) @unit_tests.mock(pkghandler, "get_pkg_names_from_rpm_paths", DumbCallable()) - @unit_tests.mock(utils.changed_pkgs_control, "track_installed_pkgs", DumbCallable()) + @unit_tests.mock(backup.changed_pkgs_control, "track_installed_pkgs", DumbCallable()) @unit_tests.mock(subscription, "track_installed_submgr_pkgs", DumbCallable()) def test_install_rhel_subscription_manager(self): subscription.install_rhel_subscription_manager() @@ -1056,7 +1056,7 @@ def test_verify_rhsm_installed(submgr_installed, keep_rhsm, critical_string, mon ) def test_track_installed_submgr_pkgs(installed_pkgs, not_tracked_pkgs, skip_pkg_msg, expected, monkeypatch, caplog): track_installed_pkgs_mock = mock.Mock() - monkeypatch.setattr(utils.changed_pkgs_control, "track_installed_pkgs", track_installed_pkgs_mock) + monkeypatch.setattr(backup.changed_pkgs_control, "track_installed_pkgs", track_installed_pkgs_mock) subscription.track_installed_submgr_pkgs(installed_pkgs, not_tracked_pkgs) @@ -1064,3 +1064,214 @@ def test_track_installed_submgr_pkgs(installed_pkgs, not_tracked_pkgs, skip_pkg_ assert skip_pkg_msg in caplog.records[-2].message assert expected in caplog.records[-1].message assert track_installed_pkgs_mock.called == 1 + + +# ---- + + +@pytest.mark.parametrize( + ("rhel_repoids", "subprocess", "should_raise", "expected", "expected_message"), + ( + ( + ["repo-1", "repo-2"], + ("repo-1, repo-2", 0), + False, + ["repo-1", "repo-2"], + "Repositories enabled through subscription-manager", + ), + ( + ["repo-1", "repo-2"], + ("repo-1, repo-2", 1), + True, + ["repo-1", "repo-2"], + "Repos were not possible to enable through subscription-manager:\nrepo-1, repo-2", + ), + ( + ["rhel-8-for-x86_64-baseos-eus-rpms", "rhel-8-for-x86_64-appstream-eus-rpms"], + ("repo-1, repo-2", 0), + False, + ["rhel-8-for-x86_64-baseos-eus-rpms", "rhel-8-for-x86_64-appstream-eus-rpms"], + "Repositories enabled through subscription-manager", + ), + ), +) +@centos8 +def test_enable_repos_rhel_repoids( + pretend_os, rhel_repoids, subprocess, should_raise, expected, expected_message, monkeypatch, caplog +): + cmd_mock = ["subscription-manager", "repos"] + for repo in rhel_repoids: + cmd_mock.append("--enable=%s" % repo) + + run_subprocess_mock = mock.Mock( + side_effect=unit_tests.run_subprocess_side_effect( + (cmd_mock, subprocess), + ) + ) + monkeypatch.setattr( + utils, + "run_subprocess", + value=run_subprocess_mock, + ) + + if should_raise: + with pytest.raises(SystemExit): + subscription.enable_repos(rhel_repoids=rhel_repoids) + else: + subscription.enable_repos(rhel_repoids=rhel_repoids) + assert system_info.submgr_enabled_repos == expected + + assert expected_message in caplog.records[-1].message + assert run_subprocess_mock.call_count == 1 + + +@pytest.mark.parametrize( + ("rhel_repoids", "default_rhsm_repoids", "subprocess", "subprocess2", "should_raise", "expected"), + ( + ( + ["rhel-8-for-x86_64-baseos-eus-rpms", "rhel-8-for-x86_64-appstream-eus-rpms"], + ["test-repo-1", "test-repo-2"], + ("rhel-8-for-x86_64-baseos-eus-rpms, rhel-8-for-x86_64-appstream-eus-rpms", 1), + ("test-repo-1, test-repo-2", 1), + True, + "Repos were not possible to enable through subscription-manager:\ntest-repo-1, test-repo-2", + ), + ( + ["rhel-8-for-x86_64-baseos-eus-rpms", "rhel-8-for-x86_64-appstream-eus-rpms"], + ["test-repo-1", "test-repo-2"], + ("rhel-8-for-x86_64-baseos-eus-rpms, rhel-8-for-x86_64-appstream-eus-rpms", 1), + ("test-repo-1, test-repo-2", 0), + False, + "Repositories enabled through subscription-manager", + ), + ), +) +@centos8 +def test_enable_repos_rhel_repoids_fallback_default_rhsm( + pretend_os, + rhel_repoids, + default_rhsm_repoids, + subprocess, + subprocess2, + should_raise, + expected, + monkeypatch, + caplog, +): + cmd_mock = ["subscription-manager", "repos"] + for repo in rhel_repoids: + cmd_mock.append("--enable=%s" % repo) + + run_subprocess_mock = mock.Mock(side_effect=[subprocess, subprocess2]) + monkeypatch.setattr( + utils, + "run_subprocess", + value=run_subprocess_mock, + ) + monkeypatch.setattr(system_info, "default_rhsm_repoids", value=default_rhsm_repoids) + + if should_raise: + with pytest.raises(SystemExit): + subscription.enable_repos(rhel_repoids=rhel_repoids) + else: + subscription.enable_repos(rhel_repoids=rhel_repoids) + assert system_info.submgr_enabled_repos == default_rhsm_repoids + + assert expected in caplog.records[-1].message + assert run_subprocess_mock.call_count == 2 + + +@pytest.mark.parametrize( + ("toolopts_enablerepo", "subprocess", "should_raise", "expected", "expected_message"), + ( + ( + ["repo-1", "repo-2"], + ("repo-1, repo-2", 0), + False, + ["repo-1", "repo-2"], + "Repositories enabled through subscription-manager", + ), + ( + ["repo-1", "repo-2"], + ("repo-1, repo-2", 1), + True, + ["repo-1", "repo-2"], + "Repos were not possible to enable through subscription-manager:\nrepo-1, repo-2", + ), + ( + ["rhel-8-for-x86_64-baseos-eus-rpms", "rhel-8-for-x86_64-appstream-eus-rpms"], + ("repo-1, repo-2", 0), + False, + ["rhel-8-for-x86_64-baseos-eus-rpms", "rhel-8-for-x86_64-appstream-eus-rpms"], + "Repositories enabled through subscription-manager", + ), + ), +) +def test_enable_repos_toolopts_enablerepo( + toolopts_enablerepo, + subprocess, + should_raise, + expected, + expected_message, + tool_opts, + monkeypatch, + caplog, +): + cmd_mock = ["subscription-manager", "repos"] + for repo in toolopts_enablerepo: + cmd_mock.append("--enable=%s" % repo) + + run_subprocess_mock = mock.Mock( + side_effect=unit_tests.run_subprocess_side_effect( + (cmd_mock, subprocess), + ) + ) + monkeypatch.setattr( + utils, + "run_subprocess", + value=run_subprocess_mock, + ) + tool_opts.enablerepo = toolopts_enablerepo + # monkeypatch.setattr(tool_opts, "enablerepo", toolopts_enablerepo) + + if should_raise: + with pytest.raises(SystemExit): + subscription.enable_repos(rhel_repoids=None) + else: + subscription.enable_repos(rhel_repoids=None) + assert system_info.submgr_enabled_repos == expected + + assert expected_message in caplog.records[-1].message + assert run_subprocess_mock.call_count == 1 + + +@pytest.mark.parametrize( + ("subprocess", "expected"), + ( + (("output", 0), "RHEL repositories locked"), + (("output", 1), "Locking RHEL repositories failed"), + ), +) +@centos8 +def test_lock_releasever_in_rhel_repositories(pretend_os, subprocess, expected, monkeypatch, caplog): + cmd = ["subscription-manager", "release", "--set=%s" % system_info.releasever] + run_subprocess_mock = mock.Mock( + side_effect=unit_tests.run_subprocess_side_effect( + (cmd, subprocess), + ) + ) + monkeypatch.setattr( + utils, + "run_subprocess", + value=run_subprocess_mock, + ) + subscription.lock_releasever_in_rhel_repositories() + + assert expected in caplog.records[-1].message + assert run_subprocess_mock.call_count == 1 + + +@centos7 +def test_lock_releasever_in_rhel_repositories_not_eus(pretend_os, caplog): + subscription.lock_releasever_in_rhel_repositories() + assert "Skipping locking RHEL repositories to a specific EUS minor version." in caplog.records[-1].message diff --git a/convert2rhel/unit_tests/systeminfo_test.py b/convert2rhel/unit_tests/systeminfo_test.py index 0d27e7d344..1159a61e7b 100644 --- a/convert2rhel/unit_tests/systeminfo_test.py +++ b/convert2rhel/unit_tests/systeminfo_test.py @@ -19,6 +19,7 @@ import logging import os import shutil +import socket import sys import unittest @@ -162,10 +163,9 @@ def test_modified_rpm_files_diff_with_differences_after_conversion(self): @unit_tests.mock(utils, "run_subprocess", RunSubprocessMocked(("rpmva\n", 0))) def test_generate_rpm_va(self): # TODO: move class from unittest to pytest and use global tool_opts fixture - tool_opts.no_rpm_va = False # Check that rpm -Va is executed (default) and stored into the specific file. + tool_opts.no_rpm_va = False system_info.generate_rpm_va() - self.assertTrue(utils.run_subprocess.called > 0) self.assertEqual(utils.run_subprocess.used_args[0][0], ["rpm", "-Va"]) self.assertTrue(os.path.isfile(self.rpmva_output_file)) @@ -225,24 +225,28 @@ def test_get_release_ver(pretend_os): "releasever_val", "self_name", "self_version", + "has_internet", "exception", ), ( # good cases # if releasever set in config - it takes precedence - ("not_existing_release_ver_set_in_config", None, None, None), + ("not_existing_release_ver_set_in_config", None, None, True, None), # Good cases which matches supported pathes - ("", "CentOS Linux", systeminfo.Version(8, 4), None), - ("", "Oracle Linux Server", systeminfo.Version(8, 4), None), + ("", "CentOS Linux", systeminfo.Version(8, 4), True, None), + ("", "Oracle Linux Server", systeminfo.Version(8, 4), True, None), # bad cases - ("", "NextCool Linux", systeminfo.Version(8, 4), SystemExit), - ("", "CentOS Linux", systeminfo.Version(8, 10000), SystemExit), + ("", "NextCool Linux", systeminfo.Version(8, 4), False, SystemExit), + ("", "CentOS Linux", systeminfo.Version(8, 10000), False, SystemExit), ), ) # need to pretend centos8 in order to system info were resolved at module init @centos8 -def test_get_release_ver_other(pretend_os, monkeypatch, releasever_val, self_name, self_version, exception): +def test_get_release_ver_other( + pretend_os, monkeypatch, releasever_val, self_name, self_version, has_internet, exception +): monkeypatch.setattr(systeminfo.SystemInfo, "_get_cfg_opt", mock.Mock(return_value=releasever_val)) + monkeypatch.setattr(systeminfo.SystemInfo, "_check_internet_access", mock.Mock(return_value=has_internet)) if self_name: monkeypatch.setattr(systeminfo.SystemInfo, "_get_system_name", mock.Mock(return_value=self_name)) if self_version: @@ -255,3 +259,38 @@ def test_get_release_ver_other(pretend_os, monkeypatch, releasever_val, self_nam system_info.resolve_system_info() if releasever_val: assert system_info.releasever == releasever_val + if has_internet: + assert system_info.has_internet_access == has_internet + + +@pytest.mark.parametrize( + ("side_effect", "expected"), + ( + (None, True), + (socket.error, False), + ), +) +def test_check_internet_access(side_effect, expected, monkeypatch): + monkeypatch.setattr(systeminfo.socket.socket, "connect", mock.Mock(side_effect=side_effect)) + # Have to initialize the logger since we are not constructing the + # system_info object properly i.e: we are not calling `resolve_system_info()` + system_info.logger = logging.getLogger(__name__) + + assert system_info._check_internet_access() == expected + + +@pytest.mark.parametrize( + ("releasever", "expected"), + ( + ("7.9", False), + ("8.4", True), + ("8.5", False), + ("8.6", False), + ("8.7", False), + ("8.8", False), + ("8.9", False), + ), +) +def test_corresponds_to_rhel_eus_release(releasever, expected): + system_info.releasever = releasever + assert system_info.corresponds_to_rhel_eus_release() == expected diff --git a/convert2rhel/unit_tests/utils_test.py b/convert2rhel/unit_tests/utils_test.py index ab2b7fa8ed..f4152a962e 100644 --- a/convert2rhel/unit_tests/utils_test.py +++ b/convert2rhel/unit_tests/utils_test.py @@ -34,8 +34,7 @@ from collections import namedtuple -from convert2rhel import unit_tests # Imports unit_tests/__init__.py -from convert2rhel import utils +from convert2rhel import unit_tests, utils # Imports unit_tests/__init__.py from convert2rhel.systeminfo import system_info from convert2rhel.unit_tests import is_rpm_based_os @@ -83,78 +82,6 @@ def test_require_root_is_not_root(self): def test_require_root_is_root(self): self.assertEqual(utils.require_root(), None) - def test_track_installed_pkg(self): - control = utils.ChangedRPMPackagesController() - pkgs = ["pkg1", "pkg2", "pkg3"] - for pkg in pkgs: - control.track_installed_pkg(pkg) - self.assertEqual(control.installed_pkgs, pkgs) - - @unit_tests.mock(utils.RestorablePackage, "backup", DummyFuncMocked()) - def test_backup_and_track_removed_pkg(self): - control = utils.ChangedRPMPackagesController() - pkgs = ["pkg1", "pkg2", "pkg3"] - for pkg in pkgs: - control.backup_and_track_removed_pkg(pkg) - self.assertEqual(utils.RestorablePackage.backup.called, len(pkgs)) - self.assertEqual(len(control.removed_pkgs), len(pkgs)) - - @unit_tests.mock(utils, "run_subprocess", RunSubprocessMocked()) - def test_remove_pkgs_with_empty_list(self): - utils.remove_pkgs([]) - self.assertEqual(utils.run_subprocess.called, 0) - - @unit_tests.mock(utils.ChangedRPMPackagesController, "backup_and_track_removed_pkg", DummyFuncMocked()) - @unit_tests.mock(utils, "run_subprocess", RunSubprocessMocked()) - def test_remove_pkgs_without_backup(self): - pkgs = ["pkg1", "pkg2", "pkg3"] - utils.remove_pkgs(pkgs, False) - self.assertEqual(utils.ChangedRPMPackagesController.backup_and_track_removed_pkg.called, 0) - - self.assertEqual(utils.run_subprocess.called, len(pkgs)) - - rpm_remove_cmd = ["rpm", "-e", "--nodeps"] - for cmd, pkg in zip(utils.run_subprocess.cmds, pkgs): - self.assertEqual(rpm_remove_cmd + [pkg], cmd) - - @unit_tests.mock(utils.ChangedRPMPackagesController, "backup_and_track_removed_pkg", DummyFuncMocked()) - @unit_tests.mock(utils, "run_subprocess", RunSubprocessMocked()) - def test_remove_pkgs_with_backup(self): - pkgs = ["pkg1", "pkg2", "pkg3"] - utils.remove_pkgs(pkgs) - self.assertEqual(utils.ChangedRPMPackagesController.backup_and_track_removed_pkg.called, len(pkgs)) - - self.assertEqual(utils.run_subprocess.called, len(pkgs)) - - rpm_remove_cmd = ["rpm", "-e", "--nodeps"] - for cmd, pkg in zip(utils.run_subprocess.cmds, pkgs): - self.assertEqual(rpm_remove_cmd + [pkg], cmd) - - @unit_tests.mock(utils, "run_subprocess", RunSubprocessMocked()) - def test_install_local_rpms_with_empty_list(self): - utils.install_local_rpms([]) - self.assertEqual(utils.run_subprocess.called, 0) - - @unit_tests.mock(utils.ChangedRPMPackagesController, "track_installed_pkg", DummyFuncMocked()) - @unit_tests.mock(utils, "run_subprocess", RunSubprocessMocked()) - def test_install_local_rpms_without_replace(self): - pkgs = ["pkg1", "pkg2", "pkg3"] - utils.install_local_rpms(pkgs) - self.assertEqual(utils.ChangedRPMPackagesController.track_installed_pkg.called, len(pkgs)) - - self.assertEqual(utils.run_subprocess.called, 1) - self.assertEqual(["rpm", "-i", "pkg1", "pkg2", "pkg3"], utils.run_subprocess.cmd) - - @unit_tests.mock(utils.ChangedRPMPackagesController, "track_installed_pkg", DummyFuncMocked()) - @unit_tests.mock(utils, "run_subprocess", RunSubprocessMocked()) - def test_install_local_rpms_with_replace(self): - pkgs = ["pkg1", "pkg2", "pkg3"] - utils.install_local_rpms(pkgs, replace=True) - self.assertEqual(utils.ChangedRPMPackagesController.track_installed_pkg.called, len(pkgs)) - - self.assertEqual(utils.run_subprocess.called, 1) - self.assertEqual(["rpm", "-i", "--replacepkgs", "pkg1", "pkg2", "pkg3"], utils.run_subprocess.cmd) - def test_run_subprocess(self): output, code = utils.run_subprocess(["echo", "foobar"]) @@ -179,17 +106,30 @@ def test_run_subprocess(self): ] @unit_tests.mock( - utils, "download_pkg", lambda pkg, dest, reposdir, enable_repos, disable_repos, set_releasever: "/filepath/" + utils, + "download_pkg", + lambda pkg, dest, reposdir, enable_repos, disable_repos, set_releasever: "/filepath/", ) def test_download_pkgs(self): - paths = utils.download_pkgs(["pkg1", "pkg2"], "/dest/", "/reposdir/", ["repo1"], ["repo2"], False) + paths = utils.download_pkgs( + ["pkg1", "pkg2"], + "/dest/", + "/reposdir/", + ["repo1"], + ["repo2"], + False, + ) self.assertEqual(paths, ["/filepath/", "/filepath/"]) @unit_tests.mock(system_info, "version", namedtuple("Version", ["major", "minor"])(8, 0)) @unit_tests.mock(system_info, "releasever", "8") @unit_tests.mock(utils, "run_cmd_in_pty", RunSubprocessMocked(ret_code=0)) - @unit_tests.mock(utils, "get_rpm_path_from_yumdownloader_output", lambda x, y, z: "/path/test.rpm") + @unit_tests.mock( + utils, + "get_rpm_path_from_yumdownloader_output", + lambda x, y, z: "/path/test.rpm", + ) def test_download_pkg_success_with_all_params(self): dest = "/test dir/" reposdir = "/my repofiles/" @@ -416,11 +356,36 @@ def test_prompt_user(question, is_password, response, monkeypatch): ("5.14.15-300.fc35", ("0", "5.14.15", "300.fc35")), ("0.17-9.fc35", ("0", "0.17", "9.fc35")), ("2.34.1-2.fc35", ("0", "2.34.1", "2.fc35")), - ("0.9.1-2.20210420git36391559.fc35", ("0", "0.9.1", "2.20210420git36391559.fc35")), + ( + "0.9.1-2.20210420git36391559.fc35", + ("0", "0.9.1", "2.20210420git36391559.fc35"), + ), ("2:8.2.3568-1.fc35", ("2", "8.2.3568", "1.fc35")), - ("4.6~pre16262021g84ef6bd9-3.fc35", ("0", "4.6~pre16262021g84ef6bd9", "3.fc35")), + ( + "4.6~pre16262021g84ef6bd9-3.fc35", + ("0", "4.6~pre16262021g84ef6bd9", "3.fc35"), + ), ), ) def test_string_to_version(string_version, nevra): nevra_version = utils.string_to_version(string_version) assert nevra_version == nevra + + +@pytest.mark.parametrize( + ("path_exists", "list_dir", "expected"), + ( + (True, ["dir-1", "dir-2"], 0), + (True, [], 2), + (False, [], 0), + (False, ["dir-1", "dir-2"], 0), + ), +) +def test_remove_orphan_folders(path_exists, list_dir, expected, tmpdir, monkeypatch): + os_remove_mock = mock.Mock() + monkeypatch.setattr(os.path, "exists", value=lambda path: path_exists) + monkeypatch.setattr(os, "listdir", value=lambda path: list_dir) + monkeypatch.setattr(os, "rmdir", value=os_remove_mock) + + utils.remove_orphan_folders() + assert os_remove_mock.call_count == expected diff --git a/convert2rhel/utils.py b/convert2rhel/utils.py index fe0ee16720..5743767f1b 100644 --- a/convert2rhel/utils.py +++ b/convert2rhel/utils.py @@ -57,6 +57,7 @@ class Color(object): def get_executable_name(): """Get name of the executable file passed to the python interpreter.""" + return os.path.basename(inspect.stack()[-1][1]) @@ -344,127 +345,6 @@ def __getitem__(self, item): return super(DictWListValues, self).__getitem__(item) -class ChangedRPMPackagesController(object): - """Keep control of installed/removed RPM pkgs for backup/restore.""" - - def __init__(self): - self.installed_pkgs = [] - self.removed_pkgs = [] - - def track_installed_pkg(self, pkg): - """Add a installed RPM pkg to the list of installed pkgs.""" - self.installed_pkgs.append(pkg) - - def track_installed_pkgs(self, pkgs): - """Track packages installed before the PONR to be able to remove them later (roll them back) if needed.""" - self.installed_pkgs += pkgs - - def backup_and_track_removed_pkg(self, pkg): - """Add a removed RPM pkg to the list of removed pkgs.""" - restorable_pkg = RestorablePackage(pkg) - restorable_pkg.backup() - self.removed_pkgs.append(restorable_pkg) - - def _remove_installed_pkgs(self): - """For each package installed during conversion remove it.""" - loggerinst.task("Rollback: Removing installed packages") - remove_pkgs(self.installed_pkgs, backup=False, critical=False) - - def _install_removed_pkgs(self): - """For each package removed during conversion install it.""" - loggerinst.task("Rollback: Installing removed packages") - pkgs_to_install = [] - for restorable_pkg in self.removed_pkgs: - if restorable_pkg.path is None: - loggerinst.warning("Couldn't find a backup for %s package." % restorable_pkg.name) - continue - pkgs_to_install.append(restorable_pkg.path) - - install_local_rpms(pkgs_to_install, replace=True, critical=False) - - def restore_pkgs(self): - """Restore system to the original state.""" - self._remove_installed_pkgs() - remove_orphan_folders() - self._install_removed_pkgs() - - -def remove_orphan_folders(): - """Even after removing redhat-release-* package, some of its folders are - still present, are empty, and that blocks us from installing centos-release - pkg back. So, by now, we are removing them manually. - """ - rh_release_paths = [ - "/usr/share/redhat-release", - "/usr/share/doc/redhat-release", - ] - - def is_dir_empty(path): - return not os.listdir(path) - - for path in rh_release_paths: - if os.path.exists(path) and is_dir_empty(path): - os.rmdir(path) - - -def remove_pkgs(pkgs_to_remove, backup=True, critical=True): - """Remove packages not heeding to their dependencies.""" - - if backup: - # Some packages, when removed, will also remove repo files, making it - # impossible to access the repositories to download a backup. For this - # reason we first backup all packages and only after that we remove - for nvra in pkgs_to_remove: - changed_pkgs_control.backup_and_track_removed_pkg(nvra) - - if not pkgs_to_remove: - loggerinst.info("No package to remove") - return - - for nvra in pkgs_to_remove: - loggerinst.info("Removing package: %s" % nvra) - _, ret_code = run_subprocess(["rpm", "-e", "--nodeps", nvra]) - if ret_code != 0: - if critical: - loggerinst.critical("Error: Couldn't remove %s." % nvra) - else: - loggerinst.warning("Couldn't remove %s." % nvra) - - -def install_local_rpms(pkgs_to_install, replace=False, critical=True): - """Install packages locally available.""" - - if not pkgs_to_install: - loggerinst.info("No package to install") - return False - - cmd_param = ["rpm", "-i"] - if replace: - cmd_param.append("--replacepkgs") - - loggerinst.info("Installing packages:") - for pkg in pkgs_to_install: - loggerinst.info("\t%s" % pkg) - - cmd = cmd_param + pkgs_to_install - output, ret_code = run_subprocess(cmd, print_output=False) - if ret_code != 0: - pkgs_as_str = " ".join(pkgs_to_install) - loggerinst.debug(output.strip()) - if critical: - loggerinst.critical("Error: Couldn't install %s packages." % pkgs_as_str) - return False - - loggerinst.warning("Couldn't install %s packages." % pkgs_as_str) - return False - - for path in pkgs_to_install: - nvra, _ = os.path.splitext(os.path.basename(path)) - changed_pkgs_control.track_installed_pkg(nvra) - - return True - - def download_pkgs( pkgs, dest=TMP_DIR, @@ -579,58 +459,6 @@ def get_rpm_path_from_yumdownloader_output(cmd, output, dest): return path -class RestorableFile(object): - def __init__(self, filepath): - self.filepath = filepath - - def backup(self): - """Save current version of a file""" - loggerinst.info("Backing up %s." % self.filepath) - if os.path.isfile(self.filepath): - try: - loggerinst.debug("Copying %s to %s." % (self.filepath, BACKUP_DIR)) - shutil.copy2(self.filepath, BACKUP_DIR) - except (OSError, IOError) as err: - # IOError for py2 and OSError for py3 - loggerinst.critical("Error(%s): %s" % (err.errno, err.strerror)) - else: - loggerinst.info("Can't find %s.", self.filepath) - - def restore(self): - """Restore a previously backed up file""" - backup_filepath = os.path.join(BACKUP_DIR, os.path.basename(self.filepath)) - loggerinst.task("Rollback: Restoring %s from backup" % self.filepath) - - if not os.path.isfile(backup_filepath): - loggerinst.warning("%s hasn't been backed up" % self.filepath) - return - try: - shutil.copy2(backup_filepath, self.filepath) - except (OSError, IOError) as err: - # Do not call 'critical' which would halt the program. We are in - # a rollback phase now and we want to rollback as much as possible. - # IOError for py2 and OSError for py3 - loggerinst.warning("Error(%s): %s" % (err.errno, err.strerror)) - return - loggerinst.info("File %s restored" % self.filepath) - - -class RestorablePackage(object): - def __init__(self, pkgname): - self.name = pkgname - self.path = None - - def backup(self): - """Save version of RPM package""" - loggerinst.info("Backing up %s" % self.name) - if os.path.isdir(BACKUP_DIR): - # When backing up the packages, the original system repofiles are still available and for them we can't - # use the releasever for RHEL repositories - self.path = download_pkg(self.name, dest=BACKUP_DIR, set_releasever=False) - else: - loggerinst.warning("Can't access %s" % TMP_DIR) - - def get_package_name_from_rpm(rpm_path): """Return name of a package that is represented by a locally stored rpm file.""" hdr = get_rpm_header(rpm_path) @@ -678,4 +506,19 @@ def string_to_version(verstring): return (epoch, version, release) -changed_pkgs_control = ChangedRPMPackagesController() # pylint: disable=C0103 +def remove_orphan_folders(): + """Even after removing redhat-release-* package, some of its folders are + still present, are empty, and that blocks us from installing centos-release + pkg back. So, for now, we are removing them manually. + """ + rh_release_paths = [ + "/usr/share/redhat-release", + "/usr/share/doc/redhat-release", + ] + + def is_dir_empty(path): + return not os.listdir(path) + + for path in rh_release_paths: + if os.path.exists(path) and is_dir_empty(path): + os.rmdir(path) diff --git a/plans/main.fmf b/plans/main.fmf index 5cec384757..7f649e6328 100644 --- a/plans/main.fmf +++ b/plans/main.fmf @@ -14,5 +14,13 @@ prepare: copr: '@oamg/convert2rhel' package: convert2rhel missing: fail + + # We need to remove all the repositories that were used to install c2r package. + # The updated packages check may find that installed c2r is not latest and it then + # ask for one more interactive prompt to continue. This could be incosistent in some tests + # that are doing the interactive run of c2r. + - name: remove all copr repositories + how: shell + script: grep -l "copr:copr.fedorainfracloud.org:group_oamg:convert2rhel" /etc/yum.repos.d/* | xargs rm environment-file: - https://gitlab.cee.redhat.com/oamg/convert2rhel/convert2rhel-secrets/-/raw/main/.env diff --git a/plans/tier1.fmf b/plans/tier1.fmf index e641b57e3e..38bfbae845 100644 --- a/plans/tier1.fmf +++ b/plans/tier1.fmf @@ -191,7 +191,7 @@ discover+: - name: allow access to Satellite only how: shell script: pytest -svv tests/integration/tier1/convert-offline-systems/prepare_system.py - - name: run offline conversion + - name: run offline conversion using the satellite how: shell script: pytest -svv tests/integration/tier1/convert-offline-systems/run_conversion.py - name: reboot after conversion @@ -199,6 +199,13 @@ discover+: playbook: tests/ansible_collections/roles/reboot/main.yml /system_up_to_date: + # On Oracle Linux 8.4 we do not have minor version repositories so we skip the check for up-to-date system. + # The other distributions (including latest Oracle Linux 8 ) have all the necessary repositories + # to make the check possible. + adjust: + enabled: false + when: > + distro == oraclelinux-8.4 discover+: test: checks-after-conversion prepare+: @@ -238,3 +245,19 @@ discover+: - name: reboot after conversion how: ansible playbook: tests/ansible_collections/roles/reboot/main.yml + +/satellite_non_eus_repos: + adjust: + enabled: false + when: > + distro != centos-8.4 and + distro != oraclelinux-8.4 + discover+: + test: checks-after-conversion + prepare+: + - name: main conversion preparation + how: shell + script: pytest -svv tests/integration/tier1/satellite_non_eus_repos/satellite_non_eus_repos.py + - name: reboot after conversion + how: ansible + playbook: tests/ansible_collections/roles/reboot/main.yml diff --git a/tests/ansible_collections/main.yml b/tests/ansible_collections/main.yml index c344c64380..66d55b6b3b 100644 --- a/tests/ansible_collections/main.yml +++ b/tests/ansible_collections/main.yml @@ -2,6 +2,9 @@ - hosts: all roles: + - role: hardcode-minor-version-repos + when: ansible_facts['distribution_version'] == "8.4" and ansible_facts['distribution'] == "CentOS" + - role: update-system - role: oracle-linux-specific diff --git a/tests/ansible_collections/roles/add-custom-repos/main.yml b/tests/ansible_collections/roles/add-custom-repos/main.yml index ae3d502a01..8fbb5274ea 100644 --- a/tests/ansible_collections/roles/add-custom-repos/main.yml +++ b/tests/ansible_collections/roles/add-custom-repos/main.yml @@ -4,5 +4,9 @@ become: false - include: rhel7-repos.yml when: ansible_facts['distribution_major_version'] == "7" + # When Oracle Linux 8.7 is released, the "8.6" needs to change to "8.7" and the + # "8.6" is to be moved to the condition below related to enabling RHEL 8 EUS repos - include: rhel8-repos.yml - when: ansible_facts['distribution_major_version'] == "8" + when: ansible_facts['distribution_version'] == "8.5" or ansible_facts['distribution_version'] == "8.6" +- include: rhel8-eus-repos.yml + when: ansible_facts['distribution_version'] == "8.4" diff --git a/tests/ansible_collections/roles/add-custom-repos/rhel8-eus-repos.yml b/tests/ansible_collections/roles/add-custom-repos/rhel8-eus-repos.yml new file mode 100644 index 0000000000..ae552d84cd --- /dev/null +++ b/tests/ansible_collections/roles/add-custom-repos/rhel8-eus-repos.yml @@ -0,0 +1,19 @@ +- hosts: all + tasks: + - name: Add rhel8 baseos eus repo + yum_repository: + name: rhel-8-for-x86_64-baseos-eus-rpms + description: RHEL 8 BaseOS for $basearch + baseurl: http://rhsm-pulp.corp.redhat.com/content/eus/rhel8/$releasever/$basearch/baseos/os/ + gpgcheck: no + enabled: no + file: rhel8-eus + + - name: Add rhel8 appstream eus repo + yum_repository: + name: rhel-8-for-x86_64-appstream-eus-rpms + description: RHEL 8 AppStream for $basearch + baseurl: http://rhsm-pulp.corp.redhat.com/content/eus/rhel8/$releasever/$basearch/appstream/os/ + gpgcheck: no + enabled: no + file: rhel8-eus diff --git a/tests/ansible_collections/roles/hardcode-minor-version-repos/tasks/centos-repos.yml b/tests/ansible_collections/roles/hardcode-minor-version-repos/tasks/centos-repos.yml new file mode 100644 index 0000000000..cc76b52533 --- /dev/null +++ b/tests/ansible_collections/roles/hardcode-minor-version-repos/tasks/centos-repos.yml @@ -0,0 +1,32 @@ +- name: Overwrite AppStream repository (CentOS 8.4) + yum_repository: + name: appstream + description: AppStream repo + baseurl: https://vault.centos.org/$contentdir/8.4.2105/AppStream/$basearch/os/ + state: present + gpgcheck: yes + enabled: yes + gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + file: CentOS-Linux-AppStream + +- name: Overwrite BaseOS repository (CentOS 8.4) + yum_repository: + name: baseos + description: BaseOS repo + baseurl: https://vault.centos.org/$contentdir/8.4.2105/BaseOS/$basearch/os/ + state: present + gpgcheck: yes + enabled: yes + gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + file: CentOS-Linux-BaseOS + +- name: Overwrite Extras repository (CentOS 8.4) + yum_repository: + name: extras + description: Extras repo + baseurl: https://vault.centos.org/$contentdir/8.4.2105/extras/$basearch/os/ + state: present + gpgcheck: yes + enabled: yes + gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial + file: CentOS-Linux-Extras diff --git a/tests/ansible_collections/roles/hardcode-minor-version-repos/tasks/main.yml b/tests/ansible_collections/roles/hardcode-minor-version-repos/tasks/main.yml new file mode 100644 index 0000000000..79f63efc9b --- /dev/null +++ b/tests/ansible_collections/roles/hardcode-minor-version-repos/tasks/main.yml @@ -0,0 +1,2 @@ +--- +- include: centos-repos.yml diff --git a/tests/ansible_collections/roles/install-testing-deps/tasks/main.yml b/tests/ansible_collections/roles/install-testing-deps/tasks/main.yml index 96e7fe6237..5a4d56c899 100644 --- a/tests/ansible_collections/roles/install-testing-deps/tasks/main.yml +++ b/tests/ansible_collections/roles/install-testing-deps/tasks/main.yml @@ -3,9 +3,9 @@ yum: # gcc and python3-devel are needed for psutil name: - - "python3" - - "gcc" - - "python3-devel" + - python3 + - gcc + - python3-devel state: present - name: Install pip if not present diff --git a/tests/ansible_collections/roles/update-system/tasks/main.yml b/tests/ansible_collections/roles/update-system/tasks/main.yml index b954679504..f99ae08386 100644 --- a/tests/ansible_collections/roles/update-system/tasks/main.yml +++ b/tests/ansible_collections/roles/update-system/tasks/main.yml @@ -1,2 +1,7 @@ --- +# We can't update Oracle Linux 8.4 to the latest 8.4 packages because there are no public Oracle Linux 8.4 repositories available. +# The CentOS Linux 8.4 can be updated using this role because the repositories on the system image has been +# tweaked to point to the CentOS Linux 8.4 repositories in the Vault. - include: update-system.yml + when: + - not (ansible_facts['distribution_version'] == "8.4" and ansible_facts['distribution'] == "OracleLinux") diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index c6f5d60397..690093f2a9 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -87,7 +87,7 @@ def convert2rhel(shell): def factory( options: str, timeout: int = 60 * 60, - unregister: bool = True, + unregister: bool = False, ) -> ContextManager[pexpect.spawn]: c2r_runtime = pexpect.spawn( f"convert2rhel {options}", diff --git a/tests/integration/tier0/backup-release/test_backup_release.py b/tests/integration/tier0/backup-release/test_backup_release.py index e1ee4d7c81..b7b3d2127c 100644 --- a/tests/integration/tier0/backup-release/test_backup_release.py +++ b/tests/integration/tier0/backup-release/test_backup_release.py @@ -4,6 +4,9 @@ from envparse import env +system = platform.platform() + + def test_backup_os_release_no_envar(shell, convert2rhel): """ In this scenario there is no variable `CONVERT2RHEL_UNSUPPORTED_INCOMPLETE_ROLLBACK` set. @@ -22,7 +25,13 @@ def test_backup_os_release_no_envar(shell, convert2rhel): assert shell("rpm -i {}".format(pkg_dst)).returncode == 0 # Move all repos to other location, so it is not being used - assert shell("mkdir /tmp/s_backup && mv /etc/yum.repos.d/* /tmp/s_backup/").returncode == 0 + assert shell("mkdir /tmp/s_backup").returncode == 0 + assert shell("mv /etc/yum.repos.d/* /tmp/s_backup/").returncode == 0 + + # EUS version use hardoced repos from c2r as well + if "centos-8" in system or "oracle-8.4" in system: + assert shell("mkdir /tmp/s_backup_eus").returncode == 0 + assert shell("mv /usr/share/convert2rhel/repos/* /tmp/s_backup_eus/").returncode == 0 # Since we are moving all repos away, we need to bypass kernel check os.environ["CONVERT2RHEL_UNSUPPORTED_SKIP_KERNEL_CURRENCY_CHECK"] = "1" @@ -54,27 +63,25 @@ def test_backup_os_release_with_envar(shell, convert2rhel): os.environ["CONVERT2RHEL_UNSUPPORTED_INCOMPLETE_ROLLBACK"] = "1" with convert2rhel( - ("--no-rpm-va -k {} -o {} --debug --keep-rhsm").format( + ("-y --no-rpm-va -k {} -o {} --debug --keep-rhsm").format( env.str("SATELLITE_KEY"), env.str("SATELLITE_ORG"), ), ) as c2r: - c2r.expect("Continue with the system conversion?") - c2r.sendline("y") - c2r.expect("Continue with the system conversion?") - c2r.sendline("y") - # On OracleLinux8 there is one question less than on other distros - if "oracle-8" not in platform.platform(): - c2r.expect("Continue with the system conversion?") - c2r.sendline("y") - c2r.expect("The tool allows rollback of any action until this point.") - c2r.sendline("n") + c2r.expect( + "'CONVERT2RHEL_UNSUPPORTED_INCOMPLETE_ROLLBACK' environment variable detected, continuing conversion." + ) + c2r.send(chr(3)) + c2r.sendcontrol("d") assert shell("find /etc/os-release").returncode == 0 - # Restore repos + # Return repositories to their original location assert shell("mv /tmp/s_backup/* /etc/yum.repos.d/").returncode == 0 + if "centos-8" in system or "oracle-8.4" in system: + assert shell("mv /tmp/s_backup_eus/* /usr/share/convert2rhel/repos/").returncode == 0 + # Clean up del os.environ["CONVERT2RHEL_UNSUPPORTED_INCOMPLETE_ROLLBACK"] del os.environ["CONVERT2RHEL_UNSUPPORTED_SKIP_KERNEL_CURRENCY_CHECK"] diff --git a/tests/integration/tier0/check-custom-repo/test_custom_repos.py b/tests/integration/tier0/check-custom-repo/test_custom_repos.py index 80718c6192..d50e76671b 100644 --- a/tests/integration/tier0/check-custom-repo/test_custom_repos.py +++ b/tests/integration/tier0/check-custom-repo/test_custom_repos.py @@ -34,7 +34,14 @@ def test_good_convertion_without_rhsm(shell, convert2rhel): if system_version.major == 7: enable_repo_opt = "--enablerepo rhel-7-server-rpms --enablerepo rhel-7-server-optional-rpms --enablerepo rhel-7-server-extras-rpms" elif system_version.major == 8: - enable_repo_opt = "--enablerepo rhel-8-for-x86_64-baseos-rpms --enablerepo rhel-8-for-x86_64-appstream-rpms" + if system_version.minor != 4: + enable_repo_opt = ( + "--enablerepo rhel-8-for-x86_64-baseos-rpms --enablerepo rhel-8-for-x86_64-appstream-rpms" + ) + elif system_version.minor == 4: + enable_repo_opt = ( + "--enablerepo rhel-8-for-x86_64-baseos-eus-rpms --enablerepo rhel-8-for-x86_64-appstream-eus-rpms" + ) with convert2rhel("-y --no-rpm-va --disable-submgr {} --debug".format(enable_repo_opt)) as c2r: c2r.expect("The repositories passed through the --enablerepo option are all accessible.") diff --git a/tests/integration/tier0/check-user-response/test_user_response.py b/tests/integration/tier0/check-user-response/test_user_response.py index 2075edcf97..c36494a657 100644 --- a/tests/integration/tier0/check-user-response/test_user_response.py +++ b/tests/integration/tier0/check-user-response/test_user_response.py @@ -4,11 +4,7 @@ def test_check_user_response_user_and_password(convert2rhel): # Run c2r registration with no username and password provided # check for user prompt enforcing input, then continue with registration - with convert2rhel( - "-y --no-rpm-va --serverurl {}".format( - env.str("RHSM_SERVER_URL"), - ) - ) as c2r: + with convert2rhel("-y --no-rpm-va --serverurl {}".format(env.str("RHSM_SERVER_URL")), unregister=True) as c2r: c2r.expect_exact(" ... activation key not found, username and password required") c2r.expect_exact("Username") c2r.sendline() @@ -39,7 +35,8 @@ def test_check_user_response_organization(convert2rhel): "-y --no-rpm-va --serverurl {} -k {}".format( env.str("RHSM_SERVER_URL"), env.str("RHSM_KEY"), - ) + ), + unregister=True, ) as c2r: c2r.expect_exact("activation key detected") c2r.expect_exact("Organization: ") @@ -60,7 +57,8 @@ def test_auto_attach_pool_submgr(convert2rhel): env.str("RHSM_SERVER_URL"), env.str("RHSM_SINGLE_SUB_USERNAME"), env.str("RHSM_SINGLE_SUB_PASSWORD"), - ) + ), + unregister=True, ) as c2r: c2r.expect( f"{single_pool_id} is the only subscription available, it will automatically be selected for the conversion." diff --git a/tests/integration/tier0/inhibit-if-kmods-is-not-supported/test_kmods_not_supported.py b/tests/integration/tier0/inhibit-if-kmods-is-not-supported/test_kmods_not_supported.py index ec7ed52f4c..568106934d 100644 --- a/tests/integration/tier0/inhibit-if-kmods-is-not-supported/test_kmods_not_supported.py +++ b/tests/integration/tier0/inhibit-if-kmods-is-not-supported/test_kmods_not_supported.py @@ -39,6 +39,14 @@ def test_inhibit_if_custom_module_loaded(insert_custom_kmod, convert2rhel): def test_do_not_inhibit_if_module_is_not_loaded(shell, convert2rhel): assert shell("modprobe -r -v bonding").returncode == 0 + + system_version = platform.platform() + if "oracle-7" in system_version or "centos-7" in system_version: + prompt_amount = 3 + elif "oracle-8" in system_version: + prompt_amount = 2 + elif "centos-8" in system_version: + prompt_amount = 3 # If custom module is not loaded the conversion is not inhibited. with convert2rhel( ("--no-rpm-va --serverurl {} --username {} --password {} --pool {} --debug").format( @@ -48,19 +56,15 @@ def test_do_not_inhibit_if_module_is_not_loaded(shell, convert2rhel): env.str("RHSM_POOL"), ) ) as c2r: - c2r.expect("Continue with the system conversion?") - c2r.sendline("y") - c2r.expect("Continue with the system conversion?") - c2r.sendline("y") - c2r.expect("Continue with the system conversion?") - c2r.sendline("y") - if "oracle-8" not in platform.platform(): + while prompt_amount > 0: c2r.expect("Continue with the system conversion?") c2r.sendline("y") + prompt_amount -= 1 + assert c2r.expect("Kernel modules are compatible.") == 0 c2r.expect("Continue with the system conversion?") c2r.sendline("n") - assert c2r.exitstatus != 0 + assert c2r.exitstatus != 0 def test_tainted_kernel_inhibitor(shell, convert2rhel): diff --git a/tests/integration/tier0/test-check-rollback-handling/test_check_rollback_handling.py b/tests/integration/tier0/test-check-rollback-handling/test_check_rollback_handling.py index 7db88a683d..ecbb82de3b 100644 --- a/tests/integration/tier0/test-check-rollback-handling/test_check_rollback_handling.py +++ b/tests/integration/tier0/test-check-rollback-handling/test_check_rollback_handling.py @@ -5,7 +5,7 @@ booted_os = platform.platform() OL_7_PKGS = ["oracle-release-el7", "usermode", "rhn-setup", "oracle-logos"] -OL_8_PKGS = ["oracle-release-el8", "usermode", "rhn-setup", "oracle-logos"] +OL_8_PKGS = ["oraclelinux-release-el8", "usermode", "rhn-setup", "oracle-logos"] COS_7_PKGS = ["centos-release", "usermode", "rhn-setup", "python-syspurpose", "centos-logos"] COS_8_PKGS = ["centos-linux-release", "usermode", "rhn-setup", "python3-syspurpose", "centos-logos"] # The packages 'python-syspurpose' and 'python3-syspurpose' were removed in Oracle Linux 7.9 @@ -66,6 +66,12 @@ def test_proper_rhsm_clean_up(shell, convert2rhel): # Primary issue - checking for usermode, rhn-setup and os-release. # It also checks that the system has been successfully unregistered. install_pkg(shell) + if "oracle-7" in booted_os or "centos-7" in booted_os: + prompt_amount = 3 + elif "oracle-8" in booted_os: + prompt_amount = 3 + elif "centos-8" in booted_os: + prompt_amount = 3 with convert2rhel( ("--serverurl {} --username {} --password {} --pool {} --debug --no-rpm-va").format( @@ -75,14 +81,10 @@ def test_proper_rhsm_clean_up(shell, convert2rhel): env.str("RHSM_POOL"), ) ) as c2r: - c2r.expect("Continue with the system conversion?") - c2r.sendline("y") - c2r.expect("Continue with the system conversion?") - c2r.sendline("y") - c2r.expect("Continue with the system conversion?") - c2r.sendline("y") - c2r.expect("Continue with the system conversion?") - c2r.sendline("y") + while prompt_amount > 0: + c2r.expect("Continue with the system conversion?") + c2r.sendline("y") + prompt_amount -= 1 c2r.expect("The tool allows rollback of any action until this point.") c2r.sendline("n") c2r.expect("Calling command 'subscription-manager unregister'") diff --git a/tests/integration/tier1/changed-yum-conf/test_patch_yum_conf.py b/tests/integration/tier1/changed-yum-conf/test_patch_yum_conf.py index 00c324ecf6..b70a725d8d 100644 --- a/tests/integration/tier1/changed-yum-conf/test_patch_yum_conf.py +++ b/tests/integration/tier1/changed-yum-conf/test_patch_yum_conf.py @@ -21,5 +21,5 @@ def test_yum_patch(convert2rhel, shell): c2r.expect("/etc/yum.conf patched.") assert c2r.exitstatus == 0 - # When testing fedora build which is not latest this would break the test on dest distro - assert shell("yum update -y -x convert2rhel").returncode == 0 + # The tsflags will prevent updating the RHEL-8.5 versions to RHEL-8.6 + assert shell("yum update -y -x convert2rhel --setopt tsflags=test").returncode == 0 diff --git a/tests/integration/tier1/checks-after-conversion/test_enabled_repositories.py b/tests/integration/tier1/checks-after-conversion/test_enabled_repositories.py new file mode 100644 index 0000000000..8fdf424d49 --- /dev/null +++ b/tests/integration/tier1/checks-after-conversion/test_enabled_repositories.py @@ -0,0 +1,28 @@ +import platform + +from os.path import exists + + +def test_enabled_repositories(shell): + """Testing, if the EUS repostitories are enabled after conversion""" + system_version = platform.platform() + enabled_repos = shell("yum repolist").output + + # Once we will decide to use EUS 8.6 we have to add them here as well + try: + if "redhat-8.4" in system_version: + # Handle the special test case scenario where we do not use the premium account with EUS repositories + if exists("/non_eus_repos_used"): + assert "rhel-8-for-x86_64-baseos-rpms" in enabled_repos + assert "rhel-8-for-x86_64-appstream-rpms" in enabled_repos + else: + assert "rhel-8-for-x86_64-appstream-eus-rpms" in enabled_repos + assert "rhel-8-for-x86_64-baseos-eus-rpms" in enabled_repos + elif "redhat-8.5" in system_version or "redhat-8.6" in system_version: + assert "rhel-8-for-x86_64-baseos-rpms" in enabled_repos + assert "rhel-8-for-x86_64-appstream-rpms" in enabled_repos + elif "redhat-7.9" in system_version: + assert "rhel-7-server-rpms/7Server/x86_64" in enabled_repos + finally: + # We need to unregister the system after the conversion + shell("subscription-manager unregister") diff --git a/tests/integration/tier1/checks-after-conversion/test_release_version.py b/tests/integration/tier1/checks-after-conversion/test_release_version.py index fbe7068316..58ee62faee 100644 --- a/tests/integration/tier1/checks-after-conversion/test_release_version.py +++ b/tests/integration/tier1/checks-after-conversion/test_release_version.py @@ -1,3 +1,32 @@ +import json + + def test_basic_conversion(shell): os_release = shell("cat /etc/os-release").output assert "Red Hat Enterprise Linux" in os_release + + +def test_correct_distro(): + """ " + Check that we landed on the correct version + """ + with open("/etc/migration-results") as json_file: + json_data = json.load(json_file) + source_distro = json_data["activities"][0]["source_os"] + + with open("/etc/system-release", "r") as sys_release: + destination_distro = sys_release.read() + + if "Red Hat Enterprise Linux Server release 7.9 (Maipo)" in destination_distro: + assert ( + source_distro == "CentOS Linux release 7.9.2009 (Core)" + or source_distro == "Oracle Linux Server release 7.9" + ) + elif "Red Hat Enterprise Linux release 8.4 (Ootpa)" in destination_distro: + assert source_distro == "CentOS Linux release 8.4.2105" or source_distro == "Oracle Linux Server release 8.4" + elif "Red Hat Enterprise Linux release 8.5 (Ootpa)" in destination_distro: + assert source_distro == "CentOS Linux release 8.5.2111" + elif "Red Hat Enterprise Linux release 8.6 (Ootpa)" in destination_distro: + assert source_distro == "Oracle Linux Server release 8.6" + else: + assert False, "Unknown destination distro" diff --git a/tests/integration/tier1/convert-offline-systems/prepare_system.py b/tests/integration/tier1/convert-offline-systems/prepare_system.py index 5a904721e3..0758aa8dbc 100644 --- a/tests/integration/tier1/convert-offline-systems/prepare_system.py +++ b/tests/integration/tier1/convert-offline-systems/prepare_system.py @@ -1,3 +1,4 @@ +import os import re import socket @@ -34,7 +35,7 @@ def configure_connection(): def test_prepare_system(shell): - assert shell("yum install dnsmasq wget -y").returncode == 0 + assert shell("yum install dnsmasq wget iptables -y").returncode == 0 # Install katello package pkg_url = "https://dogfood.sat.engineering.redhat.com/pub/katello-ca-consumer-latest.noarch.rpm" @@ -46,4 +47,10 @@ def test_prepare_system(shell): configure_connection() + # c2r checks the internet connectivity against the 8.8.8.8 DNS server + # pinging specific IP address is still possible so we need to block this as well + assert shell("iptables -I OUTPUT -d 8.8.8.8 -j DROP").returncode == 0 + assert shell("systemctl enable dnsmasq && systemctl restart dnsmasq").returncode == 0 + + os.environ["CONVERT2RHEL_UNSUPPORTED_INCOMPLETE_ROLLBACK"] = "1" diff --git a/tests/integration/tier1/convert-offline-systems/run_conversion.py b/tests/integration/tier1/convert-offline-systems/run_conversion.py index c7286ca12e..dc45c115c1 100644 --- a/tests/integration/tier1/convert-offline-systems/run_conversion.py +++ b/tests/integration/tier1/convert-offline-systems/run_conversion.py @@ -4,20 +4,27 @@ from envparse import env -def test_convert_offline_systems(shell, convert2rhel): +def test_convert_offline_systems(convert2rhel): """Test converting systems not connected to the Internet but requiring sub-mgr (e.g. managed by Satellite).""" - # The CentOS8 Extras repo url is unreachable due to offline system setup. - # The repoquery returns an error, thus we need to disable this repository. - if "centos-8" in platform.platform(): - shell("yum-config-manager --disable extras --disable epel-modular") - os.environ["CONVERT2RHEL_UNSUPPORTED_INCOMPLETE_ROLLBACK"] = "1" - with convert2rhel( - ("-y --no-rpm-va -k {} -o {} --keep-rhsm --debug").format( - env.str("SATELLITE_KEY"), - env.str("SATELLITE_ORG"), - ) - ) as c2r: - c2r.expect("Conversion successful!") - assert c2r.exitstatus == 0 + source_distro = platform.platform() + + if "centos-8.4" in source_distro or "oracle-8.4" in source_distro: + with convert2rhel( + ("-y --no-rpm-va -k {} -o {} --keep-rhsm --debug").format( + env.str("SATELLITE_KEY_EUS"), + env.str("SATELLITE_ORG"), + ) + ) as c2r: + pass + assert c2r.exitstatus == 0 + else: + with convert2rhel( + ("-y --no-rpm-va -k {} -o {} --keep-rhsm --debug").format( + env.str("SATELLITE_KEY"), + env.str("SATELLITE_ORG"), + ) + ) as c2r: + pass + assert c2r.exitstatus == 0 diff --git a/tests/integration/tier1/method/custom_repos.py b/tests/integration/tier1/method/custom_repos.py index 841f125d09..5d59bfc562 100644 --- a/tests/integration/tier1/method/custom_repos.py +++ b/tests/integration/tier1/method/custom_repos.py @@ -28,9 +28,28 @@ def test_run_conversion_using_custom_repos(shell, convert2rhel): if system_version.major == 7: enable_repo_opt = "--enablerepo rhel-7-server-rpms --enablerepo rhel-7-server-optional-rpms --enablerepo rhel-7-server-extras-rpms" elif system_version.major == 8: - enable_repo_opt = "--enablerepo rhel-8-for-x86_64-baseos-rpms --enablerepo rhel-8-for-x86_64-appstream-rpms" + if system_version.minor != 4: + enable_repo_opt = ( + "--enablerepo rhel-8-for-x86_64-baseos-rpms --enablerepo rhel-8-for-x86_64-appstream-rpms" + ) + # for the future releases we will have to enable this also for the 8.6 versions + elif system_version.minor == 4: + enable_repo_opt = ( + "--enablerepo rhel-8-for-x86_64-baseos-eus-rpms --enablerepo rhel-8-for-x86_64-appstream-eus-rpms" + ) with convert2rhel("-y --no-rpm-va --disable-submgr {} --debug".format(enable_repo_opt)) as c2r: c2r.expect("Conversion successful!") - assert c2r.exitstatus == 0 + + # after the conversion using custom repostitories it is expected to enable repos by yourself + if system_version.major == 7: + enable_repo_opt = ( + "--enable rhel-7-server-rpms --enable rhel-7-server-optional-rpms --enable rhel-7-server-extras-rpms" + ) + elif system_version.major == 8: + if system_version.minor != 4: + enable_repo_opt = "--enable rhel-8-for-x86_64-baseos-rpms --enable rhel-8-for-x86_64-appstream-rpms" + elif system_version.minor == 4: + enable_repo_opt = "--enable rhel-8-for-x86_64-baseos-eus-rpms --enable rhel-8-for-x86_64-appstream-eus-rpms" + shell("yum-config-manager {}".format(enable_repo_opt)) diff --git a/tests/integration/tier1/method/satellite.py b/tests/integration/tier1/method/satellite.py index 1895bc25de..f7176ce842 100644 --- a/tests/integration/tier1/method/satellite.py +++ b/tests/integration/tier1/method/satellite.py @@ -1,3 +1,5 @@ +import platform + from envparse import env @@ -12,11 +14,23 @@ def test_satellite_conversion(shell, convert2rhel): pkg_dst = "/usr/share/convert2rhel/subscription-manager/katello-ca-consumer-latest.noarch.rpm" assert shell("wget --no-check-certificate --output-document {} {}".format(pkg_dst, pkg_url)).returncode == 0 - with convert2rhel( - ("-y --no-rpm-va -k {} -o {} --debug").format( - env.str("SATELLITE_KEY"), - env.str("SATELLITE_ORG"), - ) - ) as c2r: - pass - assert c2r.exitstatus == 0 + source_distro = platform.platform() + + if "centos-8.4" in source_distro or "oracle-8.4" in source_distro: + with convert2rhel( + ("-y --no-rpm-va -k {} -o {} --debug").format( + env.str("SATELLITE_KEY_EUS"), + env.str("SATELLITE_ORG"), + ) + ) as c2r: + pass + assert c2r.exitstatus == 0 + else: + with convert2rhel( + ("-y --no-rpm-va -k {} -o {} --debug").format( + env.str("SATELLITE_KEY"), + env.str("SATELLITE_ORG"), + ) + ) as c2r: + pass + assert c2r.exitstatus == 0 diff --git a/tests/integration/tier1/one-kernel-scenario/run_conversion.py b/tests/integration/tier1/one-kernel-scenario/run_conversion.py index d25a17522b..fdf31a8088 100644 --- a/tests/integration/tier1/one-kernel-scenario/run_conversion.py +++ b/tests/integration/tier1/one-kernel-scenario/run_conversion.py @@ -36,4 +36,14 @@ def test_run_conversion_using_custom_repos(shell, convert2rhel): assert c2r.exitstatus == 0 + # replace url in yum.repos.d rhel repo to the original one + original_url = "baseurl = http://rhsm-pulp.corp.redhat.com/content/dist/rhel/server/7/\$releasever/\$basearch/os/" + new_url = "baseurl=http://rhsm-pulp.corp.redhat.com/content/dist/rhel/server/7/7.9/x86_64/os/" + shell('sed -i "s+{}+{}+g" /etc/yum.repos.d/rhel7.repo'.format(new_url, original_url)) + + enable_repo_opt = ( + "--enable rhel-7-server-rpms --enable rhel-7-server-optional-rpms --enable rhel-7-server-extras-rpms" + ) + shell("yum-config-manager {}".format(enable_repo_opt)) + assert shell("yum install -y python3 --enablerepo=*").returncode == 0 diff --git a/tests/integration/tier1/remove-all-submgr-pkgs/test_no_submgr_pkg_installed.py b/tests/integration/tier1/remove-all-submgr-pkgs/test_no_submgr_pkg_installed.py index b2c907747e..cd53bd143d 100644 --- a/tests/integration/tier1/remove-all-submgr-pkgs/test_no_submgr_pkg_installed.py +++ b/tests/integration/tier1/remove-all-submgr-pkgs/test_no_submgr_pkg_installed.py @@ -10,6 +10,13 @@ def test_no_sub_manager_installed(shell, convert2rhel): """ assert shell("yum remove -y subscription-manager").returncode == 0 + system_version = platform.platform() + if "oracle-7" in system_version or "centos-7" in system_version: + prompt_amount = 2 + elif "oracle-8" in system_version: + prompt_amount = 1 + elif "centos-8" in system_version: + prompt_amount = 2 with convert2rhel( ("--no-rpm-va --serverurl {} --username {} --password {} --pool {} --debug").format( @@ -19,18 +26,12 @@ def test_no_sub_manager_installed(shell, convert2rhel): env.str("RHSM_POOL"), ) ) as c2r: - c2r.expect("Continue with the system conversion?") - c2r.sendline("y") - c2r.expect("Continue with the system conversion?") - c2r.sendline("y") - # On OracleLinux8 there is one question less than on other distros - if "oracle-8" not in platform.platform(): + while prompt_amount > 0: c2r.expect("Continue with the system conversion?") c2r.sendline("y") + prompt_amount -= 1 assert c2r.expect("The subscription-manager package is not installed.") == 0 assert c2r.expect("No packages related to subscription-manager installed.") == 0 c2r.expect("Continue with the system conversion?") - c2r.sendline("y") - c2r.expect("The tool allows rollback of any action until this point.") c2r.sendline("n") diff --git a/tests/integration/tier1/satellite_non_eus_repos/main.fmf b/tests/integration/tier1/satellite_non_eus_repos/main.fmf new file mode 100644 index 0000000000..666213048a --- /dev/null +++ b/tests/integration/tier1/satellite_non_eus_repos/main.fmf @@ -0,0 +1,6 @@ +summary: test using satellite with non eus account for the EUS distro + +tier: 1 + +test: | + pytest -svv diff --git a/tests/integration/tier1/satellite_non_eus_repos/satellite_non_eus_repos.py b/tests/integration/tier1/satellite_non_eus_repos/satellite_non_eus_repos.py new file mode 100644 index 0000000000..77e73fc5b2 --- /dev/null +++ b/tests/integration/tier1/satellite_non_eus_repos/satellite_non_eus_repos.py @@ -0,0 +1,31 @@ +from envparse import env + + +def test_missing_os_release(shell, convert2rhel): + """ + This test case verify that it's possible to do full conversion when /etc/os-release + file is not present on the system. + """ + + # Mark the system so the check for the enabled repos after the conversion handles this special case + assert shell("touch /non_eus_repos_used").returncode == 0 + + # Remove subscription manager if installed + assert shell("yum remove subscription-manager -y").returncode == 0 + + assert shell("yum install wget -y").returncode == 0 + + # Install katello package + pkg_url = "https://dogfood.sat.engineering.redhat.com/pub/katello-ca-consumer-latest.noarch.rpm" + pkg_dst = "/usr/share/convert2rhel/subscription-manager/katello-ca-consumer-latest.noarch.rpm" + assert shell("wget --no-check-certificate --output-document {} {}".format(pkg_dst, pkg_url)).returncode == 0 + + with convert2rhel( + ("-y --no-rpm-va -k {} -o {} --debug").format( + env.str("SATELLITE_KEY"), + env.str("SATELLITE_ORG"), + ) + ) as c2r: + c2r.expect("WARNING - rhel-8-for-x86_64-baseos-eus-rpms repository is not available") + c2r.expect("WARNING - rhel-8-for-x86_64-appstream-eus-rpms repository is not available") + assert c2r.exitstatus == 0 diff --git a/tests/integration/tier1/system-up-to-date/install_non_latest_kernel.py b/tests/integration/tier1/system-up-to-date/install_non_latest_kernel.py index b95ef8c630..8fe046e0d4 100644 --- a/tests/integration/tier1/system-up-to-date/install_non_latest_kernel.py +++ b/tests/integration/tier1/system-up-to-date/install_non_latest_kernel.py @@ -1,13 +1,28 @@ import platform +system_version = platform.platform() + + +def handle_centos8(shell): + """ + Install non latest kernel for each version that is available in the repository. + """ + + if "centos-8.4" in system_version: + assert shell("yum install kernel-4.18.0-305.3.1.el8 -y").returncode == 0 + shell("grub2-set-default 'CentOS Linux (4.18.0-305.3.1.el8.x86_64) 8'") + elif "centos-8.5" in system_version: + assert shell("yum install kernel-4.18.0-348.el8 -y").returncode == 0 + shell("grub2-set-default 'CentOS Stream (4.18.0-348.el8.x86_64) 8'") + + def test_install_one_kernel(shell): """ Install specific kernel version and configure the system to boot to it. The kernel version is not the latest one available in repositories. """ - system_version = platform.platform() # Set default kernel if "centos-7" in system_version: @@ -17,8 +32,8 @@ def test_install_one_kernel(shell): assert shell("yum install kernel-3.10.0-1160.el7.x86_64 -y").returncode == 0 shell("grub2-set-default 'Oracle Linux Server 7.9, with Linux 3.10.0-1160.el7.x86_64'") elif "centos-8" in system_version: - assert shell("yum install kernel-4.18.0-240.22.1.el8_3 -y").returncode == 0 - shell("grub2-set-default 'CentOS Linux (4.18.0-240.22.1.el8_3.x86_64) 8'") + handle_centos8(shell) + # Test is being run only for the latest released oracle-linux elif "oracle-8" in system_version: - assert shell("yum install kernel-4.18.0-240.22.1.el8_3 -y").returncode == 0 - shell("grub2-set-default 'Oracle Linux Server (4.18.0-240.22.1.el8_3.x86_64) 8.3'") + assert shell("yum install kernel-4.18.0-80.el8.x86_64 -y").returncode == 0 + shell("grub2-set-default 'Oracle Linux Server (4.18.0-80.el8.x86_64) 8.0'") diff --git a/tests/integration/tier1/system-up-to-date/test_non_latest_kernel_inhibitor.py b/tests/integration/tier1/system-up-to-date/test_non_latest_kernel_inhibitor.py index f1641277e9..e1bb92b0ec 100644 --- a/tests/integration/tier1/system-up-to-date/test_non_latest_kernel_inhibitor.py +++ b/tests/integration/tier1/system-up-to-date/test_non_latest_kernel_inhibitor.py @@ -39,8 +39,19 @@ def test_non_latest_kernel(shell, convert2rhel): env.str("RHSM_POOL"), ) ) as c2r: - c2r.expect("The current kernel version loaded is different from the latest version in your repos.") + if "centos-7" in system_version or "oracle-7" in system_version: + c2r.expect( + "The version of the loaded kernel is different from the latest version on the enabled system repositories." + ) + elif "oracle-8" in system_version: + c2r.expect( + "The version of the loaded kernel is different from the latest version on the enabled system repositories." + ) + else: + c2r.expect( + "The version of the loaded kernel is different from the latest version on repositories defined in the" + ) assert c2r.exitstatus != 0 - # Clean up, reboot is required after this + # Clean up, reboot is required after setting the newest kernel set_latest_kernel(shell) diff --git a/tests/integration/tier1/system-up-to-date/test_system_up_to_date.py b/tests/integration/tier1/system-up-to-date/test_system_up_to_date.py index 6b9ef1a0e8..34c701f65b 100644 --- a/tests/integration/tier1/system-up-to-date/test_system_up_to_date.py +++ b/tests/integration/tier1/system-up-to-date/test_system_up_to_date.py @@ -13,10 +13,18 @@ def test_skip_kernel_check(shell, convert2rhel): the kernel check inhibitor. One of the way to allow this is to not have any kernel packages present in repos. """ - shell("mkdir /tmp/my_tmp; mv /etc/yum.repos.d/* /tmp/my_tmp") + + # Move all repos to other location, so it is not being used + assert shell("mkdir /tmp/s_backup") + assert shell("mv /etc/yum.repos.d/* /tmp/s_backup/").returncode == 0 + + # EUS version use hardoced repos from c2r as well + if "centos-8" in system_version: + assert shell("mkdir /tmp/s_backup_eus") + assert shell("mv /usr/share/convert2rhel/repos/* /tmp/s_backup_eus/").returncode == 0 with convert2rhel( - ("--no-rpm-va --serverurl {} --username {} --password {} --pool {} --debug").format( + ("-y --no-rpm-va --serverurl {} --username {} --password {} --pool {} --debug").format( env.str("RHSM_SERVER_URL"), env.str("RHSM_USERNAME"), env.str("RHSM_PASSWORD"), @@ -25,7 +33,7 @@ def test_skip_kernel_check(shell, convert2rhel): ) as c2r: if "centos-7" in system_version or "oracle-7" in system_version: c2r.expect("Could not find any kernel from repositories to compare against the loaded kernel.") - elif "centos-8" in system_version or "oracle-8" in system_version: + else: c2r.expect("Could not find any kernel-core from repositories to compare against the loaded kernel.") assert c2r.exitstatus != 0 @@ -44,7 +52,9 @@ def test_skip_kernel_check(shell, convert2rhel): assert c2r.exitstatus != 0 # Clean up - shell("mv /tmp/my_tmp/* /etc/yum.repos.d/") + if "centos-8" in system_version in system_version: + assert shell("mv /tmp/s_backup_eus/* /usr/share/convert2rhel/repos/").returncode == 0 + assert shell("mv /tmp/s_backup/* /etc/yum.repos.d/").returncode == 0 def test_system_not_updated(shell, convert2rhel): diff --git a/tests/integration/tier1/yum-distro-sync/test_yum_distro_sync.py b/tests/integration/tier1/yum-distro-sync/test_yum_distro_sync.py index 98b479c751..974d393c9a 100644 --- a/tests/integration/tier1/yum-distro-sync/test_yum_distro_sync.py +++ b/tests/integration/tier1/yum-distro-sync/test_yum_distro_sync.py @@ -27,8 +27,7 @@ def test_yum_distro_sync(convert2rhel, shell): env.str("RHSM_USERNAME"), env.str("RHSM_PASSWORD"), env.str("RHSM_POOL"), - ), - unregister=False, + ) ) as c2r: c2r.expect("Conversion successful!") assert c2r.exitstatus == 0 @@ -40,8 +39,6 @@ def test_yum_distro_sync(convert2rhel, shell): out = shell("yum distro-sync cpaste") assert condition_test(out.output, out.returncode) - shell("subscription-manager unregister") - def condition_test(output, ret_code): """__THE SAME__ conditions as in convert2rhel/pkghandler.py are. Just small change -