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 2fdc3a370d..3728e884d7 100644 --- a/convert2rhel/checks.py +++ b/convert2rhel/checks.py @@ -29,6 +29,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 @@ -466,9 +467,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 " @@ -479,12 +497,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: @@ -495,15 +516,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: @@ -513,7 +559,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()) ] @@ -521,8 +567,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) @@ -532,13 +579,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 d4f6d017e1..d7c1401730 100644 --- a/convert2rhel/unit_tests/checks_test.py +++ b/convert2rhel/unit_tests/checks_test.py @@ -36,7 +36,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 @@ -830,15 +830,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() @@ -860,24 +872,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( @@ -886,7 +982,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, ), ( @@ -907,15 +1004,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"), ( @@ -943,7 +1055,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 -