def update_grub_core(grub_dev): """ Update GRUB core after upgrade from RHEL7 to RHEL8 On legacy systems, GRUB core does not get automatically updated when GRUB packages are updated. """ cmd = ['grub2-install', grub_dev] if config.is_debug(): cmd += ['-v'] try: run(cmd) except CalledProcessError as err: reporting.create_report([ reporting.Title('GRUB core update failed'), reporting.Summary(str(err)), reporting.Tags([reporting.Tags.BOOT]), reporting.Severity(reporting.Severity.HIGH), reporting.Remediation( hint= 'Please run "grub2-install <GRUB_DEVICE>" manually after upgrade' ) ]) api.current_logger().warning( 'GRUB core update on {} failed'.format(grub_dev)) raise StopActorExecution() reporting.create_report([ reporting.Title('GRUB core successfully updated'), reporting.Summary( 'GRUB core on {} was successfully updated'.format(grub_dev)), reporting.Tags([reporting.Tags.BOOT]), reporting.Severity(reporting.Severity.INFO) ])
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()): try: context.call(cmd=[ '/usr/bin/dnf', 'rhel-upgrade', stage, DNF_PLUGIN_DATA_PATH ], 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 _logfile_logging_handler(fd_info, line): # pylint: disable=unused-argument """ Log into logfile :param fd_info: Contains File descriptor type (not used) :type fd_info: tuple :param line: data to be printed to a logfile :type line: string """ def _raise_level(handlers): for handler in handlers: handler.setLevel(handler.level + 1) def _restore_level(handlers, levels): for handler, level in zip(handlers, levels): handler.setLevel(level) if is_debug(): # raise logging level of stream handlers above DEBUG to avoid duplicated output to stdout/stderr logger_handlers = api.current_logger().root.handlers stream_handlers = [ handler for handler in logger_handlers if isinstance(handler, logging.StreamHandler) ] handler_levels = [handler.level for handler in stream_handlers] _raise_level(stream_handlers) api.current_logger().debug(line) _restore_level(stream_handlers, handler_levels) else: api.current_logger().debug(line)
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 _logging_handler(fd_info, buffer): '''Custom log handler to always show DNF stdout to console and stderr only in DEBUG mode''' (_unused, fd_type) = fd_info if fd_type == STDOUT: sys.stdout.write(buffer) else: if is_debug(): sys.stderr.write(buffer)
def backup_debug_data(context): """ Performs the backup of DNF debug data """ if config.is_debug(): # The debugdata is a folder generated by dnf when using the --debugsolver dnf option. We switch on the # debug_solver dnf config parameter in our rhel-upgrade dnf plugin when LEAPP_DEBUG env var set to 1. try: context.copytree_from('/debugdata', DNF_DEBUG_DATA_PATH) except OSError as e: api.current_logger().warning('Failed to copy debugdata. Message: {}'.format(str(e)), exc_info=True)
def test_is_debug(monkeypatch): matrix = ((('1', '1'), True), (('0', '1'), False), (('1', '0'), True), (('0', '0'), False), ((0, 1), False), ((1, 1), False), ((1, 0), False), ((0, 0), False), (('1', 0), True), ((0, '1'), False)) for (debug, verbose), expected in matrix: monkeypatch.setattr(os, 'environ', { 'LEAPP_DEBUG': debug, 'LEAPP_VERBOSE': verbose }) assert is_debug() == expected
def logging_handler(fd_info, buf): """ Custom log handler to always show stdout to console and stderr only in DEBUG mode """ (_unused, fd_type) = fd_info if fd_type == STDOUT: sys.stdout.write(buf) else: if config.is_debug(): sys.stderr.write(buf)
def logging_handler(fd_info, buf): """ Custom log handler to always show stdout to console and stderr only in DEBUG mode """ (_unused, fd_type) = fd_info if fd_type != STDOUT and not config.is_debug(): return target = sys.stdout if fd_type == STDOUT else sys.stderr if sys.version_info > (3, 0): os.writev(target.fileno(), [buf]) else: target.write(buf)
def _console_logging_handler(fd_info, a_buffer): """ Log into either STDOUT or to STDERR. Buffer Output Discrimination is based on fd_type in fd_info while in a leapp debug mode. :param fd_info: Contains File descriptor type :type fd_info: tuple :param a_buffer: buffer interface :type a_buffer: bytes array """ if is_debug(): __write_raw(fd_info, a_buffer)
def logging_handler(fd_info, buf): """ Custom log handler to always show stdout to console and stderr only in DEBUG mode """ (_unused, fd_type) = fd_info if isinstance(buf, bytes) and str is not bytes: buf = buf.decode('utf-8') if fd_type == STDOUT: sys.stdout.write(buf) else: if config.is_debug(): sys.stderr.write(buf)
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 _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)