def modified_rpm_files_diff(self): """Get a list of modified rpm files after the conversion and compare it to the one from before the conversion. """ self.generate_rpm_va(log_filename=POST_RPM_VA_LOG_FILENAME) pre_rpm_va_log_path = os.path.join(logger.LOG_DIR, PRE_RPM_VA_LOG_FILENAME) if not os.path.exists(pre_rpm_va_log_path): self.logger.info( "Skipping comparison of the 'rpm -Va' output from before and after the conversion." ) return pre_rpm_va = utils.get_file_content(pre_rpm_va_log_path, True) post_rpm_va_log_path = os.path.join(logger.LOG_DIR, POST_RPM_VA_LOG_FILENAME) post_rpm_va = utils.get_file_content(post_rpm_va_log_path, True) modified_rpm_files_diff = "\n".join( difflib.unified_diff(pre_rpm_va, post_rpm_va, fromfile=pre_rpm_va_log_path, tofile=post_rpm_va_log_path, n=0, lineterm="")) if modified_rpm_files_diff: self.logger.info( "Comparison of modified rpm files from before and after the conversion:\n%s" % modified_rpm_files_diff)
def check_readonly_mounts(): """ Mounting directly to /mnt/ is not in line with Unix FS (https://en.wikipedia.org/wiki/Unix_filesystem). Having /mnt/ and /sys/ read-only causes the installation of the filesystem package to fail (https://bugzilla.redhat.com/show_bug.cgi?id=1887513, https://github.com/oamg/convert2rhel/issues/123). """ logger.task("Prepare: Checking /mnt and /sys are read-write") mounts = get_file_content("/proc/mounts", as_list=True) for line in mounts: _, mount_point, _, flags, _, _ = line.split() flags = flags.split(",") if mount_point not in ("/mnt", "/sys"): continue if "ro" in flags: if mount_point == "/mnt": logger.critical( "Stopping conversion due to read-only mount to /mnt directory.\n" "Mount at a subdirectory of /mnt to have /mnt writeable.") else: # /sys logger.critical( "Stopping conversion due to read-only mount to /sys directory.\n" "Ensure mount point is writable before executing convert2rhel." ) logger.debug("%s mount point is not read-only." % mount_point) logger.info("Read-only /mnt or /sys mount points not detected.")
def fix_default_kernel(): """ Systems converted from Oracle Linux or CentOS Linux may have leftover kernel-uek or kernel-plus in /etc/sysconfig/kernel as DEFAULTKERNEL. This function fixes that by replacing the DEFAULTKERNEL setting from kernel-uek or kernel-plus to kernel for RHEL 6,7 and kernel-core for RHEL 8 """ loggerinst = logging.getLogger(__name__) loggerinst.info("Checking for incorrect boot kernel") kernel_sys_cfg = utils.get_file_content("/etc/sysconfig/kernel") possible_kernels = ["kernel-uek", "kernel-plus"] kernel_to_change = next( iter(kernel for kernel in possible_kernels if kernel in kernel_sys_cfg), None) if kernel_to_change: loggerinst.warning( "Detected leftover boot kernel, changing to RHEL kernel") # need to change to "kernel" in rhel6, 7 and "kernel-core" in rhel8 new_kernel_str = "DEFAULTKERNEL=" + ( "kernel" if system_info.version.major in [6, 7] else "kernel-core") kernel_sys_cfg = kernel_sys_cfg.replace( "DEFAULTKERNEL=" + kernel_to_change, new_kernel_str) utils.store_content_to_file("/etc/sysconfig/kernel", kernel_sys_cfg) loggerinst.info("Boot kernel %s was changed to %s" % (kernel_to_change, new_kernel_str)) else: loggerinst.debug("Boot kernel validated.")
def get_supported_repos(): """Get a dictionary with RHEL repositories supported by dark matrix. Note: Mapping of the installed packages to RHEL repositories is possible only for the RHEL repositories processed by dark matrix - these are captured in the repo_minimap file. """ loggerinst = logging.getLogger(__name__) loggerinst.info("Getting supported %s repositories ... " % tool_opts.variant) minimap_path = os.path.join(utils.data_dir, "repo-mapping", "repo_minimap") minimap = utils.get_file_content(minimap_path, as_list=True) repos = {} for line in minimap: if tool_opts.variant not in line: # Skip the variants different from the chosen one continue # Save into a dictionary in format 'repo name':'repo ID' repos[re.match("(.+?);", line).group(1)] = re.search(";.*?;(.+?);", line).group(1) if not repos: # If there is no repos, add the default one. repos['Server'] = system_info.default_repository_id print_supported_repos(repos) return repos
def test_generate_rpm_va(self): # Check that rpm -Va is executed (default) and stored into the specific file. 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)) self.assertEqual(utils.get_file_content(self.rpmva_output_file), "rpmva\n")
def test_generate_rpm_va(self): # TODO: move class from unittest to pytest and use global tool_opts fixture # 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)) self.assertEqual(utils.get_file_content(self.rpmva_output_file), "rpmva\n")
def get_system_release_content(): """Return content of the file containing name of the operating system and its version. """ filepath = get_system_release_filepath() try: return utils.get_file_content(filepath) except EnvironmentError as err: loggerinst.critical("%s\n%s file is essential for running this tool." % (err, filepath))
def show_eula(): """Print out the content of the Red Hat End User License Agreement.""" eula_filepath = os.path.join(utils.DATA_DIR, "GLOBAL_EULA_RHEL") eula_text = utils.get_file_content(eula_filepath) if eula_text: loggerinst.info(eula_text) else: loggerinst.critical('EULA file not found.') return
def _process_cli_options(self): """Process command line options used with the tool.""" loggerinst = logging.getLogger(__name__) parsed_opts, _ = self._parser.parse_args() global tool_opts if parsed_opts.debug: tool_opts.debug = True if parsed_opts.no_rpm_va: tool_opts.no_rpm_va = True if parsed_opts.username: tool_opts.username = parsed_opts.username if parsed_opts.password: tool_opts.password = parsed_opts.password if parsed_opts.password_from_file: tool_opts.password_file = parsed_opts.password_from_file tool_opts.password = utils.get_file_content( parsed_opts.password_from_file) if parsed_opts.disable_submgr: tool_opts.disable_submgr = True if parsed_opts.enablerepo: tool_opts.enablerepo = parsed_opts.enablerepo if parsed_opts.disablerepo: tool_opts.disablerepo = parsed_opts.disablerepo if parsed_opts.pool: tool_opts.pool = parsed_opts.pool if parsed_opts.variant: if not rhelvariant.is_variant_supported(parsed_opts.variant): loggerinst.critical("Error: Incorrect RHEL variant has been " " passed through command line.\nSupported" " variants are: %s." % ", ".join( rhelvariant.get_supported_variants())) tool_opts.variant = parsed_opts.variant tool_opts.autoaccept = parsed_opts.y tool_opts.auto_attach = parsed_opts.auto_attach tool_opts.restart = parsed_opts.restart if parsed_opts.activationkey: tool_opts.activation_key = parsed_opts.activationkey if parsed_opts.org: tool_opts.org = parsed_opts.org if tool_opts.username and tool_opts.password: tool_opts.credentials_thru_cli = True return
def read_repo_files(repo_data_files): """Read content of the single RHEL variant-related dark matrix-generated static repository files which hold information about moved, removed and kept packages. """ rhel_repos_content = {} rhel_repos_content["removed"] = [] rhel_repos_content["kept"] = [] rhel_repos_content["moved"] = utils.DictWListValues() for repo_file in repo_data_files: if "_kept" in repo_file: # The repository names on the original system do not # match those on RHEL, except the base repo (that has no suffix, # like -optional). Therefore all kept packages are put into just # one list, basically representing just the RHEL base repo. The # list will serve just to complete the picture, which packages are # available in RHEL repos. # TODO: This may not be true -> implement logic to cope with repos # different from base repo in which the packages are 'kept' for pkg in utils.get_file_content(repo_file, True): rhel_repos_content["kept"].append(pkg.split(' kept')[0]) if "_removed" in repo_file: # Put all removed packages into one list, no matter in which repo # they are missing. This list will be used to determine which # packages are not available in the RHEL repos. for pkg in utils.get_file_content(repo_file, True): rhel_repos_content["removed"].append(pkg.split(' removed')[0]) if "_moved" in repo_file: # The moved packages are stored into separate dictionaries to # distinguish in which repository is each 'moved' package # available. moved_to = repo_file.rsplit('moved_', 1)[1] for pkg in utils.get_file_content(repo_file, True): rhel_repos_content["moved"][moved_to].append( pkg.split(' moved')[0]) return rhel_repos_content
def _load_supported_variants_from_file(): """The repo_minimap contains all the available repos whose name are prepended by a variant. """ minimap_path = os.path.join(utils.DATA_DIR, "repo-mapping", "repo_minimap") minimap = utils.get_file_content(minimap_path, as_list=True) supported_variants = [] for line in minimap: variant_found = re.match("(.+?)(-.*?)?;", line).group(1) if variant_found not in supported_variants: supported_variants.append(variant_found) if not supported_variants: supported_variants.append('Server') return supported_variants
def user_to_accept_eula(): """Request user to accept EULA license agreement. This is required otherwise the conversion process stops and fails with error. """ loggerinst = logging.getLogger(__name__) eula_filename = "GLOBAL_EULA_RHEL" eula_filepath = os.path.join(utils.data_dir, eula_filename) eula_text = utils.get_file_content(eula_filepath) if eula_text: loggerinst.info(eula_text) loggerinst.warning("By continuing you accept this EULA.") utils.ask_to_continue() else: loggerinst.critical('EULA file not found.') return
def fix_invalid_grub2_entries(): """ On systems derived from RHEL 8 and later, /etc/machine-id is being used to identify grub2 boot loader entries per the Boot Loader Specification. However, at the time of executing convert2rhel, the current machine-id can be different from the machine-id from the time when the kernels were installed. If that happens: - convert2rhel installs the RHEL kernel, but it's not set as default - convert2rhel removes the original OS kernels, but for these the boot entries are not removed The solution handled by this function is to remove the non-functioning boot entries upon the removal of the original OS kernels, and setting the RHEL kernel as default. """ if system_info.version.major < 8 or system_info.arch == "s390x": # Applicable only on systems derived from RHEL 8 and later, and systems using GRUB2 (s390x uses zipl) return loggerinst = logging.getLogger(__name__) loggerinst.info("Fixing GRUB boot loader entries.") machine_id = utils.get_file_content("/etc/machine-id") boot_entries = glob.glob("/boot/loader/entries/*.conf") for entry in boot_entries: # The boot loader entries in /boot/loader/entries/<machine-id>-<kernel-version>.conf if machine_id.strip() not in os.path.basename(entry): loggerinst.debug("Removing boot entry %s" % entry) os.remove(entry) # Removing a boot entry that used to be the default makes grubby to choose a different entry as default, but we will # call grub --set-default to set the new default on all the proper places, e.g. for grub2-editenv output, ret_code = utils.run_subprocess( "/usr/sbin/grubby --default-kernel", print_output=False) if ret_code: # Not setting the default entry shouldn't be a deal breaker and the reason to stop the conversions, grub should # pick one entry in any case. loggerinst.warning( "Couldn't get the default GRUB2 boot loader entry:\n%s" % output) return loggerinst.debug( "Setting RHEL kernel %s as the default boot loader entry." % output.strip()) output, ret_code = utils.run_subprocess( "/usr/sbin/grubby --set-default %s" % output.strip()) if ret_code: loggerinst.warning( "Couldn't set the default GRUB2 boot loader entry:\n%s" % output)
def _process_cli_options(self): """Process command line options used with the tool.""" loggerinst = logging.getLogger(__name__) parsed_opts, _ = self._parser.parse_args() global tool_opts # pylint: disable=C0103 if parsed_opts.debug: tool_opts.debug = True if parsed_opts.no_rpm_va: tool_opts.no_rpm_va = True if parsed_opts.username: tool_opts.username = parsed_opts.username if parsed_opts.password: tool_opts.password = parsed_opts.password if parsed_opts.password_from_file: tool_opts.password_file = parsed_opts.password_from_file tool_opts.password = utils.get_file_content( parsed_opts.password_from_file) if parsed_opts.enablerepo: tool_opts.enablerepo = parsed_opts.enablerepo if parsed_opts.disablerepo: tool_opts.disablerepo = parsed_opts.disablerepo if parsed_opts.disable_submgr: tool_opts.disable_submgr = True if not tool_opts.enablerepo: loggerinst.critical( "Error: --enablerepo is required if --disable-submgr is passed " ) if not tool_opts.disablerepo: tool_opts.disablerepo = "*" # Default to disable everything if parsed_opts.pool: tool_opts.pool = parsed_opts.pool if parsed_opts.variant: if not rhelvariant.is_variant_supported(parsed_opts.variant): loggerinst.critical( "Error: Incorrect RHEL variant has been " " passed through command line.\nSupported" " variants are: %s." % ", ".join(rhelvariant.get_supported_variants())) tool_opts.variant = parsed_opts.variant if parsed_opts.serverurl: if parsed_opts.disable_submgr: loggerinst.warn( "Ignoring the --serverurl option. It has no effect when --disable-submgr is used." ) else: tool_opts.serverurl = parsed_opts.serverurl tool_opts.autoaccept = parsed_opts.y tool_opts.auto_attach = parsed_opts.auto_attach tool_opts.restart = parsed_opts.restart if parsed_opts.activationkey: tool_opts.activation_key = parsed_opts.activationkey if parsed_opts.org: tool_opts.org = parsed_opts.org if tool_opts.username and tool_opts.password: tool_opts.credentials_thru_cli = True return
def __init__(self): self._yum_conf_content = utils.get_file_content(self._yum_conf_path) self.loggerinst = logging.getLogger(__name__)
def _process_cli_options(self): """Process command line options used with the tool.""" warn_on_unsupported_options() parsed_opts, _ = self._parser.parse_args() global tool_opts # pylint: disable=C0103 if parsed_opts.debug: tool_opts.debug = True if parsed_opts.disable_colors: tool_opts.disable_colors = True if parsed_opts.no_rpm_va: tool_opts.no_rpm_va = True if parsed_opts.username: tool_opts.username = parsed_opts.username if parsed_opts.password: tool_opts.password = parsed_opts.password if parsed_opts.password_from_file: tool_opts.password_file = parsed_opts.password_from_file tool_opts.password = utils.get_file_content(parsed_opts.password_from_file) if parsed_opts.enablerepo: tool_opts.enablerepo = parsed_opts.enablerepo if parsed_opts.disablerepo: tool_opts.disablerepo = parsed_opts.disablerepo if parsed_opts.no_rhsm or parsed_opts.disable_submgr: tool_opts.no_rhsm = True if not tool_opts.enablerepo: loggerinst.critical("The --enablerepo option is required when --disable-submgr or --no-rhsm is used.") if not tool_opts.disablerepo: # Default to disable every repo except: # - the ones passed through --enablerepo # - the ones enabled through subscription-manager based on convert2rhel config files tool_opts.disablerepo = ["*"] if parsed_opts.pool: tool_opts.pool = parsed_opts.pool if parsed_opts.serverurl: if tool_opts.no_rhsm: loggerinst.warning( "Ignoring the --serverurl option. It has no effect when --disable-submgr or --no-rhsm is used." ) else: tool_opts.serverurl = parsed_opts.serverurl if parsed_opts.keep_rhsm: if tool_opts.no_rhsm: loggerinst.warning( "Ignoring the --keep-rhsm option. It has no effect when --disable-submgr or --no-rhsm is used." ) else: tool_opts.keep_rhsm = parsed_opts.keep_rhsm tool_opts.autoaccept = parsed_opts.y tool_opts.auto_attach = parsed_opts.auto_attach tool_opts.restart = parsed_opts.restart if parsed_opts.activationkey: tool_opts.activation_key = parsed_opts.activationkey if parsed_opts.org: tool_opts.org = parsed_opts.org if tool_opts.username and tool_opts.password: tool_opts.credentials_thru_cli = True
def __init__(self): self._yum_conf_content = utils.get_file_content(self._yum_conf_path)
def _process_cli_options(self): """Process command line options used with the tool.""" loggerinst = logging.getLogger(__name__) parsed_opts, _ = self._parser.parse_args() global tool_opts # pylint: disable=C0103 if parsed_opts.debug: tool_opts.debug = True if parsed_opts.disable_colors: tool_opts.disable_colors = True if parsed_opts.no_rpm_va: tool_opts.no_rpm_va = True if parsed_opts.username: tool_opts.username = parsed_opts.username if parsed_opts.password: tool_opts.password = parsed_opts.password if parsed_opts.password_from_file: tool_opts.password_file = parsed_opts.password_from_file tool_opts.password = utils.get_file_content( parsed_opts.password_from_file) if parsed_opts.enablerepo: tool_opts.enablerepo = parsed_opts.enablerepo if parsed_opts.disablerepo: tool_opts.disablerepo = parsed_opts.disablerepo if parsed_opts.disable_submgr: tool_opts.disable_submgr = True if not tool_opts.enablerepo: loggerinst.critical( "Error: --enablerepo is required if --disable-submgr is passed " ) if not tool_opts.disablerepo: # Default to disable every repo except: # - the ones passed through --enablerepo # - the ones enabled through subscription-manager based on convert2rhel config files tool_opts.disablerepo = ["*"] if parsed_opts.pool: tool_opts.pool = parsed_opts.pool if '--variant' in sys.argv[1:]: loggerinst.warning( "The --variant option is not supported anymore.") if parsed_opts.disable_submgr: loggerinst.warning( "The system will be converted to the RHEL variant provided by the repositories you" " have enabled through the --enablerepo option.") else: loggerinst.warning( "The system will be converted to the Server variant of RHEL." ) utils.ask_to_continue() if parsed_opts.serverurl: if parsed_opts.disable_submgr: loggerinst.warn( "Ignoring the --serverurl option. It has no effect when --disable-submgr is used." ) else: tool_opts.serverurl = parsed_opts.serverurl tool_opts.autoaccept = parsed_opts.y tool_opts.auto_attach = parsed_opts.auto_attach tool_opts.restart = parsed_opts.restart if parsed_opts.activationkey: tool_opts.activation_key = parsed_opts.activationkey if parsed_opts.org: tool_opts.org = parsed_opts.org if tool_opts.username and tool_opts.password: tool_opts.credentials_thru_cli = True