def prepare_target_userspace(context, userspace_dir, enabled_repos, packages): """ Implements the creation of the target userspace. """ run(['rm', '-rf', userspace_dir]) _create_target_userspace_directories(userspace_dir) with mounting.BindMount(source=userspace_dir, target=os.path.join(context.base_dir, 'el8target')): repos_opt = [['--enablerepo', repo] for repo in enabled_repos] repos_opt = list(itertools.chain(*repos_opt)) cmd = [ 'dnf', 'install', '-y', '--nogpgcheck', '--setopt=module_platform_id=platform:el8', '--setopt=keepcache=1', '--releasever', api.current_actor().configuration.version.target, '--installroot', '/el8target', '--disablerepo', '*' ] + repos_opt + packages if config.is_verbose(): cmd.append('-v') try: context.call(cmd, callback_raw=utils.logging_handler) except CalledProcessError as exc: raise StopActorExecutionError( message='Unable to install RHEL 8 userspace packages.', details={ 'details': str(exc), 'stderr': exc.stderr })
def _transaction(context, stage, target_repoids, tasks, test=False): """ Perform the actual DNF rpm download via our DNF plugin """ create_config(context=context, target_repoids=target_repoids, debug=config.is_debug(), test=test, tasks=tasks) backup_config(context=context) with guards.guarded_execution(guards.connection_guard(), guards.space_guard()): cmd = ['/usr/bin/dnf', 'rhel-upgrade', stage, DNF_PLUGIN_DATA_PATH] if config.is_verbose(): cmd.append('-v') try: context.call(cmd=cmd, callback_raw=utils.logging_handler) except OSError as e: api.current_logger().error( 'Could not call dnf command: Message: %s', str(e), exc_info=True) raise StopActorExecutionError( message='Failed to execute dnf. Reason: {}'.format(str(e))) except CalledProcessError as e: api.current_logger().error('DNF execution failed: ') raise StopActorExecutionError( message= 'DNF execution failed with non zero exit code.\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}' .format(stdout=e.stdout, stderr=e.stderr)) finally: if stage == 'check': backup_debug_data(context=context)
def process(self): repos = set() packages = set() for message in self.consume(SkippedRepositories): repos.update(message.repos) packages.update(message.packages) if repos: title = 'Some enabled RPM repositories are unknown to Leapp' summary_data = [] summary_data.append('The following repositories with Red Hat-signed packages are unknown to Leapp:') summary_data.extend(['- {}'.format(r) for r in repos]) summary_data.append('And the following packages installed from those repositories may not be upgraded:') summary_data.extend(['- {}'.format(p) for p in packages]) summary = '\n'.join(summary_data) reporting.report_with_remediation( title=title, summary=summary, remediation='You can file a request to add this repository to the scope of in-place upgrades ' 'by filing a support ticket', severity='low') if config.is_verbose(): self.log.info('\n'.join([title, summary]))
def report_skipped_packages(title, message, package_repo_pairs, remediation=None): """Generate report message about skipped packages""" package_repo_pairs = sorted(package_repo_pairs) summary = '{} {}\n{}'.format( len(package_repo_pairs), message, '\n'.join([ '- {pkg} (repoid: {repo})'.format(pkg=pkg, repo=repo) for pkg, repo in package_repo_pairs ])) report_content = [ reporting.Title(title), reporting.Summary(summary), reporting.Severity(reporting.Severity.HIGH), reporting.Tags([reporting.Tags.REPOSITORY]), ] if remediation: report_content += [reporting.Remediation(hint=remediation)] report_content += [ reporting.RelatedResource('package', p) for p, _ in package_repo_pairs ] reporting.create_report(report_content) if is_verbose(): api.current_logger().info(summary)
def install_initramdisk_requirements(packages, target_userspace_info, used_repos): """ Performs the installation of packages into the initram disk """ with _prepare_transaction(used_repos=used_repos, target_userspace_info=target_userspace_info) as (context, target_repoids, _unused): if get_target_major_version() == '9': _rebuild_rpm_db(context) repos_opt = [['--enablerepo', repo] for repo in target_repoids] repos_opt = list(itertools.chain(*repos_opt)) cmd = [ 'dnf', 'install', '-y', '--nogpgcheck', '--setopt=module_platform_id=platform:el{}'.format(get_target_major_version()), '--setopt=keepcache=1', '--releasever', api.current_actor().configuration.version.target, '--disablerepo', '*' ] + repos_opt + list(packages) if config.is_verbose(): cmd.append('-v') if rhsm.skip_rhsm(): cmd += ['--disableplugin', 'subscription-manager'] env = {} if get_target_major_version() == '9': # allow handling new RHEL 9 syscalls by systemd-nspawn env = {'SYSTEMD_SECCOMP': '0'} context.call(cmd, env=env)
def report_skipped_packages(message, packages): """Generate report message about skipped packages""" title = 'Packages will not be installed' summary = '{} {}\n{}'.format(len(packages), message, '\n'.join(['- ' + p for p in packages])) reporting.report_generic(title=title, summary=summary, severity='high') if is_verbose(): api.show_message(summary)
def _transaction(context, stage, target_repoids, tasks, plugin_info, test=False, cmd_prefix=None, on_aws=False): """ Perform the actual DNF rpm download via our DNF plugin """ # we do not want if stage != 'upgrade': create_config( context=context, target_repoids=target_repoids, debug=config.is_debug(), test=test, tasks=tasks, on_aws=on_aws ) backup_config(context=context) # FIXME: rhsm with guards.guarded_execution(guards.connection_guard(), guards.space_guard()): cmd = [ '/usr/bin/dnf', 'rhel-upgrade', stage, DNF_PLUGIN_DATA_PATH ] if config.is_verbose(): cmd.append('-v') if rhsm.skip_rhsm(): cmd += ['--disableplugin', 'subscription-manager'] if plugin_info: for info in plugin_info: if stage in info.disable_in: cmd += ['--disableplugin', info.name] if cmd_prefix: cmd = cmd_prefix + cmd env = {} if get_target_major_version() == '9': # allow handling new RHEL 9 syscalls by systemd-nspawn env = {'SYSTEMD_SECCOMP': '0'} try: context.call( cmd=cmd, callback_raw=utils.logging_handler, env=env ) except OSError as e: api.current_logger().error('Could not call dnf command: Message: %s', str(e), exc_info=True) raise StopActorExecutionError( message='Failed to execute dnf. Reason: {}'.format(str(e)) ) except CalledProcessError as e: api.current_logger().error('DNF execution failed: ') raise StopActorExecutionError( message='DNF execution failed with non zero exit code.\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}'.format( stdout=e.stdout, stderr=e.stderr) ) finally: if stage == 'check': backup_debug_data(context=context)
def test_is_verbose(monkeypatch): matrix = ((('1', '1'), True), (('0', '1'), True), (('1', '0'), True), (('0', '0'), False), ((0, 1), False), ((1, 1), False), ((1, 0), False), ((0, 0), False), (('1', 0), True), ((0, '1'), True)) for (debug, verbose), expected in matrix: monkeypatch.setattr(os, 'environ', { 'LEAPP_DEBUG': debug, 'LEAPP_VERBOSE': verbose }) assert is_verbose() == expected
def report_skipped_packages(message, packages): """Generate report message about skipped packages""" title = 'Packages will not be installed' summary = '{} {}\n{}'.format(len(packages), message, '\n'.join(['- ' + p for p in packages])) reporting.create_report([ reporting.Title(title), reporting.Summary(summary), reporting.Severity(reporting.Severity.HIGH), reporting.Tags([reporting.Tags.REPOSITORY]), ] + [reporting.RelatedResource('package', p) for p in packages]) if is_verbose(): api.show_message(summary)
def generate_report(packages): """ Generate a report if exists packages unsigned in the system """ if not packages: return unsigned_packages_new_line = '\n'.join(['- ' + p for p in packages]) unsigned_packages = ' '.join(packages) remediation = 'yum remove {}'.format(unsigned_packages) summary = 'The following packages have not been signed by Red Hat ' \ 'and may be removed in the upgrade process:\n{}'.format(unsigned_packages_new_line) reporting.report_with_remediation( title='Packages not signed by Red Hat found in the system', summary=summary, remediation=remediation, severity='high', ) if is_verbose(): api.show_message(summary)
def configure_logger(log_file=None): global _logger if not _logger: log_format = '%(asctime)s.%(msecs)-3d %(levelname)-8s PID: %(process)d %(name)s: %(message)s' log_date_format = '%Y-%m-%d %H:%M:%S' path = os.getenv('LEAPP_LOGGER_CONFIG', '/etc/leapp/logger.conf') if path and os.path.isfile(path): logging.config.fileConfig(path) else: # Fall back logging configuration logging.Formatter.converter = time.gmtime logging.basicConfig( level=logging.DEBUG, format=log_format, datefmt=log_date_format, stream=sys.stderr, ) logging.getLogger('urllib3').setLevel(logging.WARN) handler = LeappAuditHandler() handler.setFormatter( logging.Formatter(fmt=log_format, datefmt=log_date_format)) logging.getLogger('leapp').addHandler(handler) logging.StreamHandler().setLevel(logging.ERROR) if log_file: file_handler = logging.FileHandler( os.path.join('/var/log/leapp/', log_file)) file_handler.setFormatter( logging.Formatter(fmt=log_format, datefmt=log_date_format)) file_handler.setLevel(logging.DEBUG) logging.getLogger('leapp').addHandler(file_handler) if is_verbose(): for handler in logging.getLogger().handlers: if isinstance(handler, logging.StreamHandler): handler.setLevel( logging.DEBUG if is_debug() else logging.INFO) _logger = logging.getLogger('leapp') _logger.info('Logging has been initialized') return _logger
def install_initramdisk_requirements(packages, target_userspace_info, used_repos): """ Performs the installation of packages into the initram disk """ with _prepare_transaction( used_repos=used_repos, target_userspace_info=target_userspace_info) as (context, target_repoids, _unused): repos_opt = [['--enablerepo', repo] for repo in target_repoids] repos_opt = list(itertools.chain(*repos_opt)) cmd = [ 'dnf', 'install', '-y', '--nogpgcheck', '--setopt=module_platform_id=platform:el8', '--setopt=keepcache=1', '--disablerepo', '*' ] + repos_opt + list(packages) if config.is_verbose(): cmd.append('-v') context.call(cmd)
def generate_report(packages): """ Generate a report if there are unsigned packages installed on the system """ if not packages: return unsigned_packages_new_line = '\n'.join(['- ' + p for p in packages]) title = 'Packages not signed by Red Hat found on the system' summary = ( 'The following packages have not been signed by Red Hat' ' and may be removed during the upgrade process in case Red Hat-signed' ' packages to be removed during the upgrade depend on them:\n{}'. format(unsigned_packages_new_line)) reporting.create_report([ reporting.Title(title), reporting.Summary(summary), reporting.Severity(reporting.Severity.HIGH), reporting.Tags(COMMON_REPORT_TAGS) ]) if is_verbose(): api.show_message(summary)
def generate_report(packages): """ Generate a report if exists packages unsigned in the system """ if not packages: return unsigned_packages_new_line = '\n'.join(['- ' + p for p in packages]) unsigned_packages = ' '.join(packages) remediation = ['yum', 'remove', '{}'.format(unsigned_packages)] title = 'Packages not signed by Red Hat found in the system' summary = 'The following packages have not been signed by Red Hat ' \ 'and may be removed in the upgrade process:\n{}'.format(unsigned_packages_new_line) reporting.create_report([ reporting.Title(title), reporting.Summary(summary), reporting.Severity(reporting.Severity.HIGH), reporting.Tags(COMMON_REPORT_TAGS), reporting.Remediation(commands=[remediation]), ] + [reporting.RelatedResource('package', p) for p in packages]) if is_verbose(): api.show_message(summary)
def process(self): repos = set() packages = set() for message in self.consume(SkippedRepositories): repos.update(message.repos) packages.update(message.packages) if repos: title = 'Some enabled RPM repositories are unknown to Leapp' summary_data = [] summary_data.append( 'The following repositories with Red Hat-signed packages are unknown to Leapp:' ) summary_data.extend(['- {}'.format(r) for r in repos]) summary_data.append( 'And the following packages installed from those repositories may not be upgraded:' ) summary_data.extend(['- {}'.format(p) for p in packages]) summary = '\n'.join(summary_data) packages_related = [ reporting.RelatedResource('package', str(p)) for p in packages ] repos_related = [ reporting.RelatedResource('repository', str(r)) for r in repos ] create_report([ reporting.Title(title), reporting.Summary(summary), reporting.Severity(reporting.Severity.LOW), reporting.Tags([reporting.Tags.REPOSITORY]), reporting.Remediation( hint= 'You can file a request to add this repository to the scope of in-place upgrades ' 'by filing a support ticket') ] + packages_related + repos_related) if config.is_verbose(): self.log.info('\n'.join([title, summary]))
def report_skipped_repos(self, repos, pkgs): title = 'Some enabled RPM repositories are unknown to Leapp' summary_data = [] summary_data.append( 'The following repositories with Red Hat-signed packages are unknown to Leapp:' ) summary_data.extend(['- ' + r for r in repos]) summary_data.append( 'And the following packages installed from those repositories may not be upgraded:' ) summary_data.extend(['- ' + p for p in pkgs]) summary = '\n'.join(summary_data) reporting.report_with_remediation( title=title, summary=summary, remediation= 'You can file a request to add this repository to the scope of in-place upgrades by filing a support ticket', severity='low') if is_verbose(): self.log.info('\n'.join([title, summary]))
def prepare_target_userspace(context, userspace_dir, enabled_repos, packages): """ Implement the creation of the target userspace. """ _backup_to_persistent_package_cache(userspace_dir) target_major_version = get_target_major_version() run(['rm', '-rf', userspace_dir]) _create_target_userspace_directories(userspace_dir) with mounting.BindMount(source=userspace_dir, target=os.path.join( context.base_dir, 'el{}target'.format(target_major_version))): _restore_persistent_package_cache(userspace_dir) repos_opt = [['--enablerepo', repo] for repo in enabled_repos] repos_opt = list(itertools.chain(*repos_opt)) cmd = [ 'dnf', 'install', '-y', '--nogpgcheck', '--setopt=module_platform_id=platform:el{}'.format( target_major_version), '--setopt=keepcache=1', '--releasever', api.current_actor().configuration.version.target, '--installroot', '/el{}target'.format(target_major_version), '--disablerepo', '*' ] + repos_opt + packages if config.is_verbose(): cmd.append('-v') if rhsm.skip_rhsm(): cmd += ['--disableplugin', 'subscription-manager'] try: context.call(cmd, callback_raw=utils.logging_handler) except CalledProcessError as exc: raise StopActorExecutionError( message='Unable to install RHEL {} userspace packages.'.format( target_major_version), details={ 'details': str(exc), 'stderr': exc.stderr })
def install_initramdisk_requirements(packages, target_userspace_info, used_repos): """ Performs the installation of packages into the initram disk """ with _prepare_transaction( used_repos=used_repos, target_userspace_info=target_userspace_info) as (context, target_repoids, _unused): repos_opt = [['--enablerepo', repo] for repo in target_repoids] repos_opt = list(itertools.chain(*repos_opt)) cmd = [ 'dnf', 'install', '-y', '--nogpgcheck', '--setopt=module_platform_id=platform:el8', '--setopt=keepcache=1', '--releasever', api.current_actor().configuration.version.target, '--disablerepo', '*' ] + repos_opt + list(packages) if config.is_verbose(): cmd.append('-v') if rhsm.skip_rhsm(): cmd += ['--disableplugin', 'subscription-manager'] context.call(cmd)
def _transaction(context, stage, target_repoids, tasks, plugin_info, test=False, cmd_prefix=None, on_aws=False): """ Perform the actual DNF rpm download via our DNF plugin """ # we do not want if stage not in ['dry-run', 'upgrade']: create_config( context=context, target_repoids=target_repoids, debug=config.is_debug(), test=test, tasks=tasks, on_aws=on_aws ) backup_config(context=context) # FIXME: rhsm with guards.guarded_execution(guards.connection_guard(), guards.space_guard()): cmd_prefix = cmd_prefix or [] common_params = [] if config.is_verbose(): common_params.append('-v') if rhsm.skip_rhsm(): common_params += ['--disableplugin', 'subscription-manager'] if plugin_info: for info in plugin_info: if stage in info.disable_in: common_params += ['--disableplugin', info.name] env = {} if get_target_major_version() == '9': # allow handling new RHEL 9 syscalls by systemd-nspawn env = {'SYSTEMD_SECCOMP': '0'} # We need to reset modules twice, once before we check, and the second time before we actually perform # the upgrade. Not more often as the modules will be reset already. if stage in ('check', 'upgrade') and tasks.modules_to_reset: # We shall only reset modules that are not going to be enabled # This will make sure it is so modules_to_reset = {(module.name, module.stream) for module in tasks.modules_to_reset} modules_to_enable = {(module.name, module.stream) for module in tasks.modules_to_enable} module_reset_list = [module[0] for module in modules_to_reset - modules_to_enable] # Perform module reset cmd = ['/usr/bin/dnf', 'module', 'reset', '--enabled', ] + module_reset_list cmd += ['--disablerepo', '*', '-y', '--installroot', '/installroot'] try: context.call( cmd=cmd_prefix + cmd + common_params, callback_raw=utils.logging_handler, env=env ) except (CalledProcessError, OSError): api.current_logger().debug('Failed to reset modules via dnf with an error. Ignoring.', exc_info=True) cmd = [ '/usr/bin/dnf', 'rhel-upgrade', stage, DNF_PLUGIN_DATA_PATH ] try: context.call( cmd=cmd_prefix + cmd + common_params, callback_raw=utils.logging_handler, env=env ) except OSError as e: api.current_logger().error('Could not call dnf command: Message: %s', str(e), exc_info=True) raise StopActorExecutionError( message='Failed to execute dnf. Reason: {}'.format(str(e)) ) except CalledProcessError as e: api.current_logger().error('DNF execution failed: ') raise StopActorExecutionError( message='DNF execution failed with non zero exit code.\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}'.format( stdout=e.stdout, stderr=e.stderr) ) finally: if stage == 'check': backup_debug_data(context=context)