def report(args): if os.getuid(): raise CommandError('This command has to be run under the root user.') id = args.id or fetch_last_upgrade_context()[0] if not id: raise CommandError( 'No previous Leapp upgrade run found. This command can only be run after "leapp upgrade" has been executed' ) # FIXME: add proper default and choices parameters for the format option if args.format not in ('html', 'plaintext'): print( 'No / not supported renderer provided as --format (available renderers: "html", "plaintext"). ' 'Defaulting to "plaintext"', file=sys.stdout, end='\n\n') renderer = 'plaintext' else: renderer = args.format messages = fetch_upgrade_report_messages(id, renderer) if not messages: raise CommandError( 'No upgrade report messages found for context {}'.format(id)) print(messages, file=sys.stdout)
def upgrade(args): skip_phases_until = None context = str(uuid.uuid4()) cfg = get_config() configuration = prepare_configuration(args) answerfile_path = cfg.get('report', 'answerfile') userchoices_path = cfg.get('report', 'userchoices') if os.getuid(): raise CommandError('This command has to be run under the root user.') handle_output_level(args) if args.resume: context, configuration = fetch_last_upgrade_context() if not context: raise CommandError('No previous upgrade run to continue, remove `--resume` from leapp invocation to' 'start a new upgrade flow') os.environ['LEAPP_DEBUG'] = '1' if check_env_and_conf('LEAPP_DEBUG', 'debug', configuration) else '0' if os.environ['LEAPP_DEBUG'] == '1' or check_env_and_conf('LEAPP_VERBOSE', 'verbose', configuration): os.environ['LEAPP_VERBOSE'] = '1' else: os.environ['LEAPP_VERBOSE'] = '0' skip_phases_until = get_last_phase(context) logger = configure_logger() else: e = Execution(context=context, kind='upgrade', configuration=configuration) e.store() archive_logfiles() logger = configure_logger('leapp-upgrade.log') os.environ['LEAPP_EXECUTION_ID'] = context if args.resume: logger.info("Resuming execution after phase: %s", skip_phases_until) try: repositories = load_repositories() except LeappError as exc: raise CommandError(exc.message) workflow = repositories.lookup_workflow('IPUWorkflow')(auto_reboot=args.reboot) process_whitelist_experimental(repositories, workflow, configuration, logger) warn_if_unsupported(configuration) with beautify_actor_exception(): logger.info("Using answerfile at %s", answerfile_path) workflow.load_answers(answerfile_path, userchoices_path) workflow.run(context=context, skip_phases_until=skip_phases_until, skip_dialogs=True) logger.info("Answerfile will be created at %s", answerfile_path) workflow.save_answers(answerfile_path, userchoices_path) report_errors(workflow.errors) report_inhibitors(context) generate_report_files(context) report_files = get_cfg_files('report', cfg) log_files = get_cfg_files('logs', cfg) report_info(report_files, log_files, answerfile_path, fail=workflow.failure) if workflow.failure: sys.exit(1)
def preupgrade(args): if os.getuid(): raise CommandError('This command has to be run under the root user.') if args.whitelist_experimental: args.whitelist_experimental = list( itertools.chain( *[i.split(',') for i in args.whitelist_experimental])) context = str(uuid.uuid4()) configuration = { 'debug': os.getenv('LEAPP_DEBUG', '0'), 'verbose': os.getenv('LEAPP_VERBOSE', '0'), 'whitelist_experimental': args.whitelist_experimental or () } e = Execution(context=context, kind='preupgrade', configuration=configuration) e.store() archive_logfiles() logger = configure_logger('leapp-preupgrade.log') os.environ['LEAPP_EXECUTION_ID'] = context try: repositories = load_repositories() except LeappError as exc: raise CommandError(exc.message) workflow = repositories.lookup_workflow('IPUWorkflow')() for actor_name in configuration.get('whitelist_experimental', ()): actor = repositories.lookup_actor(actor_name) if actor: workflow.whitelist_experimental_actor(actor) else: msg = 'No such Actor: {}'.format(actor_name) logger.error(msg) raise CommandError(msg) with beautify_actor_exception(): until_phase = 'ReportsPhase' logger.info('Executing workflow until phase: %s', until_phase) workflow.run(context=context, until_phase=until_phase, skip_dialogs=True) cfg = get_config() answerfile = args.save_answerfile or cfg.get('report', 'answerfile') logger.info("Answerfile will be created at %s", answerfile) workflow._answer_store.generate_for_workflow(workflow, answerfile) generate_report_files(context) report_errors(workflow.errors) report_files = [ os.path.join(cfg.get('report', 'dir'), r) for r in cfg.get('report', 'files').split(',') ] report_info([rf for rf in report_files if os.path.isfile(rf)], fail=workflow.failure) if workflow.failure: sys.exit(1)
def upgrade(args): if os.getuid(): raise CommandError('This command has to be run under the root user.') if args.whitelist_experimental: args.whitelist_experimental = list(itertools.chain(*[i.split(',') for i in args.whitelist_experimental])) skip_phases_until = None context = str(uuid.uuid4()) configuration = { 'debug': os.getenv('LEAPP_DEBUG', '0'), 'verbose': os.getenv('LEAPP_VERBOSE', '0'), 'whitelist_experimental': args.whitelist_experimental or () } if args.resume: context, configuration = fetch_last_upgrade_context() if not context: raise CommandError('No previous upgrade run to continue, remove `--resume` from leapp invocation to' 'start a new upgrade flow') os.environ['LEAPP_DEBUG'] = '1' if check_env_and_conf('LEAPP_DEBUG', 'debug', configuration) else '0' if os.environ['LEAPP_DEBUG'] == '1' or check_env_and_conf('LEAPP_VERBOSE', 'verbose', configuration): os.environ['LEAPP_VERBOSE'] = '1' else: os.environ['LEAPP_VERBOSE'] = '0' skip_phases_until = get_last_phase(context) logger = configure_logger() else: e = Execution(context=context, kind='upgrade', configuration=configuration) e.store() archive_logfiles() logger = configure_logger('leapp-upgrade.log') os.environ['LEAPP_EXECUTION_ID'] = context if args.resume: logger.info("Resuming execution after phase: %s", skip_phases_until) try: repositories = load_repositories() except LeappError as exc: raise CommandError(exc.message) workflow = repositories.lookup_workflow('IPUWorkflow')(auto_reboot=args.reboot) for actor_name in configuration.get('whitelist_experimental', ()): actor = repositories.lookup_actor(actor_name) if actor: workflow.whitelist_experimental_actor(actor) else: msg = 'No such Actor: {}'.format(actor_name) logger.error(msg) raise CommandError(msg) with beautify_actor_exception(): workflow.run(context=context, skip_phases_until=skip_phases_until) report_errors(workflow.errors) if workflow.failure: sys.exit(1)
def rerun(args): if os.environ.get('LEAPP_UNSUPPORTED') != '1': raise CommandError('This command requires the environment variable LEAPP_UNSUPPORTED="1" to be set!') if args.from_phase not in RERUN_SUPPORTED_PHASES: raise CommandError('This command is only supported for {}'.format(', '.join(RERUN_SUPPORTED_PHASES))) context = str(uuid.uuid4()) last_context, configuration = util.fetch_last_upgrade_context() phases = [chkpt['phase'] for chkpt in util.get_checkpoints(context=last_context)] if args.from_phase not in set(phases): raise CommandError('Phase {} has not been executed in the last leapp upgrade execution. ' 'Cannot rerun not executed phase'.format(args.from_phase)) if not last_context: raise CommandError('No previous upgrade run to rerun - ' 'leapp upgrade has to be run before leapp rerun can be used') with get_connection(None) as db: e = Execution(context=context, kind='rerun', configuration=configuration) e.store(db) clone_context(last_context, context, db) db.execute(''' DELETE FROM audit WHERE id IN ( SELECT audit.id AS id FROM audit JOIN data_source ON data_source.id = audit.data_source_id WHERE audit.context = ? AND audit.event = 'checkpoint' AND data_source.phase LIKE 'FirstBoot%' ); ''', (context,)) db.execute('''DELETE FROM message WHERE context = ? and type = 'ErrorModel';''', (context,)) util.archive_logfiles() upgrade(Namespace( # pylint: disable=no-value-for-parameter resume=True, resume_context=context, only_with_tags=args.only_actors_with_tag or [], debug=args.debug, verbose=args.verbose, reboot=False, no_rhsm=False, channel=None, whitelist_experimental=[], enablerepo=[]))
def preupgrade(args, breadcrumbs): context = str(uuid.uuid4()) cfg = get_config() util.handle_output_level(args) configuration = util.prepare_configuration(args) answerfile_path = cfg.get('report', 'answerfile') userchoices_path = cfg.get('report', 'userchoices') if os.getuid(): raise CommandError('This command has to be run under the root user.') e = Execution(context=context, kind='preupgrade', configuration=configuration) e.store() util.archive_logfiles() logger = configure_logger('leapp-preupgrade.log') os.environ['LEAPP_EXECUTION_ID'] = context try: repositories = util.load_repositories() except LeappError as exc: raise CommandError(exc.message) workflow = repositories.lookup_workflow('IPUWorkflow')() util.warn_if_unsupported(configuration) util.process_whitelist_experimental(repositories, workflow, configuration, logger) with beautify_actor_exception(): workflow.load_answers(answerfile_path, userchoices_path) until_phase = 'ReportsPhase' logger.info('Executing workflow until phase: %s', until_phase) # Set the locale, so that the actors parsing command outputs that might be localized will not fail os.environ['LC_ALL'] = 'en_US.UTF-8' os.environ['LANG'] = 'en_US.UTF-8' workflow.run(context=context, until_phase=until_phase, skip_dialogs=True) logger.info("Answerfile will be created at %s", answerfile_path) workflow.save_answers(answerfile_path, userchoices_path) util.generate_report_files(context) report_errors(workflow.errors) report_inhibitors(context) report_files = util.get_cfg_files('report', cfg) log_files = util.get_cfg_files('logs', cfg) report_info(report_files, log_files, answerfile_path, fail=workflow.failure) if workflow.failure: sys.exit(1)
def cli(args): model_name = args.model_name basedir = find_repository_basedir('.') basedir = os.path.join(basedir, 'models') if not os.path.isdir(basedir): os.mkdir(basedir) model_path = os.path.join(basedir, model_name.lower() + '.py') if os.path.exists(model_path): raise CommandError("File already exists: {}".format(model_path)) topic_usage = 'None # TODO: import appropriate topic and set it here' topic_import = '' if args.topic: topic_usage = args.topic topic_import = 'from leapp.topics import {}\n'.format(args.topic) with open(model_path, 'w') as f: f.write('''from leapp.models import Model, fields {topic_import} class {model_name}(Model): topic = {topic_usage} '''.format(model_name=make_class_name(model_name), topic_import=topic_import, topic_usage=topic_usage)) sys.stdout.write("New model {} has been created in {}\n".format(make_class_name(model_name), os.path.realpath(model_path)))
def impl(context=None): configure_logger() repository = find_and_scan_repositories(find_repository_basedir('.'), include_locals=True) try: repository.load() except LeappError as exc: sys.stderr.write(exc.message) sys.stderr.write('\n') sys.exit(1) wf = repository.lookup_workflow(params.name) if not wf: raise CommandError('Could not find any workflow named "{}"'.format( params.name)) instance = wf() for actor_name in params.whitelist_experimental or (): actor = repository.lookup_actor(actor_name) if actor: instance.whitelist_experimental_actor(actor) with beautify_actor_exception(): instance.run(context=context, until_phase=params.until_phase, until_actor=params.until_actor) report_errors(instance.errors)
def cli(args): log = configure_logger() basedir = find_repository_basedir('.') repository = find_and_scan_repositories(basedir, include_locals=True) try: repository.load() except LeappError as exc: sys.stderr.write(exc.message) sys.stderr.write('\n') sys.exit(1) actor_logger = log.getChild('actors') actor = repository.lookup_actor(args.actor_name) if not actor: raise CommandError('Actor "{}" not found!'.format(args.actor_name)) messaging = InProcessMessaging(stored=args.save_output) messaging.load(actor.consumes) failure = False with beautify_actor_exception(): try: actor(messaging=messaging, logger=actor_logger).run() except BaseException: failure = True raise report_errors(messaging.errors()) if failure or messaging.errors(): sys.exit(1) if args.print_output: json.dump(messaging.messages(), sys.stdout, indent=2) sys.stdout.write('\n')
def cli(args): topic_name = args.topic_name basedir = find_repository_basedir('.') basedir = os.path.join(basedir, 'topics') if not os.path.isdir(basedir): os.mkdir(basedir) topic_path = os.path.join(basedir, topic_name.lower() + '.py') if os.path.exists(topic_path): raise CommandError("File already exists: {}".format(topic_path)) topic_path = os.path.join(basedir, topic_name.lower() + '.py') topic_class_name = make_class_name(topic_name) if not topic_class_name.endswith('Topic'): topic_class_name += 'Topic' with open(topic_path, 'w') as f: f.write('''from leapp.topics import Topic class {topic_name}(Topic): name = '{topic}' '''.format(topic_name=topic_class_name, topic=make_name(topic_name))) sys.stdout.write("New topic {} has been created in {}\n".format(topic_class_name, os.path.realpath(topic_path)))
def process_report_schema(args, configuration): default_report_schema = configuration.get('report', 'schema') if args.report_schema and args.report_schema > default_report_schema: raise CommandError( '--report-schema version can not be greater that the ' 'actual {} one.'.format(default_report_schema)) return args.report_schema or default_report_schema
def preupgrade(args): if os.getuid(): raise CommandError('This command has to be run under the root user.') if args.whitelist_experimental: args.whitelist_experimental = list(itertools.chain(*[i.split(',') for i in args.whitelist_experimental])) context = str(uuid.uuid4()) configuration = { 'debug': os.getenv('LEAPP_DEBUG', '0'), 'verbose': os.getenv('LEAPP_VERBOSE', '0'), 'whitelist_experimental': args.whitelist_experimental or () } e = Execution(context=context, kind='preupgrade', configuration=configuration) e.store() archive_logfiles() logger = configure_logger('leapp-preupgrade.log') os.environ['LEAPP_EXECUTION_ID'] = context try: repositories = load_repositories() except LeappError as exc: raise CommandError(exc.message) workflow = repositories.lookup_workflow('IPUWorkflow')() for actor_name in configuration.get('whitelist_experimental', ()): actor = repositories.lookup_actor(actor_name) if actor: workflow.whitelist_experimental_actor(actor) else: msg = 'No such Actor: {}'.format(actor_name) logger.error(msg) raise CommandError(msg) with beautify_actor_exception(): until_phase = 'ReportsPhase' logger.info('Executing workflow until phase: %s', until_phase) workflow.run(context=context, until_phase=until_phase) report_errors(workflow.errors) report_txt, report_json = [os.path.join(get_config().get('report', 'dir'), 'leapp-report.{}'.format(f)) for f in ['txt', 'json']] report_info([report_txt, report_json], fail=workflow.errors) # fetch all report messages as a list of dicts messages = fetch_upgrade_report_raw(context, renderers=False) with open(report_json, 'w+') as f: json.dump({'entries': messages}, f, indent=2) if workflow.failure: sys.exit(1)
def list_runs(args): # noqa; pylint: disable=unused-argument contexts = fetch_all_upgrade_contexts() if contexts: for context in contexts: print('Context ID: {} - time: {} - details: {}'.format(context[0], context[1], json.loads(context[2])), file=sys.stdout) else: raise CommandError('No previous run found!')
def cli(args): actor_name = args.actor_name basedir = find_repository_basedir('.') tag_imports = '' model_imports = '' if args.tag: tag_imports = '\nfrom leapp.tags import {}'.format(', '.join( tuple(map(lambda x: x.split('.')[0], args.tag)))) if args.consumes or args.produces: models = set((args.produces or []) + (args.consumes or [])) model_imports = '\nfrom leapp.models import {}'.format( ', '.join(models)) tags_content = '({})'.format(as_quoted_tuple(args.tag)) consumes_content = '({})'.format(as_quoted_tuple(args.consumes)) produces_content = '({})'.format(as_quoted_tuple(args.produces)) actors_dir = os.path.join(basedir, 'actors') if not os.path.isdir(actors_dir): os.mkdir(actors_dir) actor_dir = os.path.join(actors_dir, actor_name.lower()) if not os.path.isdir(actor_dir): os.mkdir(actor_dir) actor_test_dir = os.path.join(actor_dir, 'tests') if not os.path.isdir(actor_test_dir): os.mkdir(actor_test_dir) actor_path = os.path.join(actor_dir, 'actor.py') if os.path.exists(actor_path): raise CommandError("File already exists: {}".format(actor_path)) with open(actor_path, 'w') as f: f.write('''from leapp.actors import Actor{model_imports}{tag_imports} class {actor_class}(Actor): name = '{actor_name}' description = 'No description has been provided for the {actor_name} actor.' consumes = {consumes_content} produces = {produces_content} tags = {tags_content} def process(self): pass '''.format(actor_class=make_class_name(actor_name), actor_name=make_name(actor_name), tags_content=tags_content, produces_content=produces_content, consumes_content=consumes_content, model_imports=model_imports, tag_imports=tag_imports)) sys.stdout.write("New actor {} has been created at {}\n".format( make_class_name(actor_name), os.path.realpath(actor_path))) return os.path.dirname(os.path.realpath(actor_path))
def process_whitelist_experimental(repositories, workflow, configuration, logger=None): for actor_name in configuration.get('whitelist_experimental', ()): actor = repositories.lookup_actor(actor_name) if actor: workflow.whitelist_experimental_actor(actor) else: msg = 'No such Actor: {}'.format(actor_name) if logger: logger.error(msg) raise CommandError(msg)
def check_version(version): """ Versioning schema: MAJOR.MINOR In case version contains an invalid version string, an CommandError will be raised. :raises: CommandError :return: release tuple """ if not re.match(VERSION_REGEX, version): raise CommandError('Unexpected format of target version: {}'.format(version)) return version.split('.')[0]
def cli(params): configure_logger() repository = find_and_scan_repositories(find_repository_basedir('.'), include_locals=True) try: repository.load() except LeappError as exc: sys.stderr.write(exc.message) sys.exit(1) wf = repository.lookup_workflow(params.name) if not wf: raise CommandError('Could not find any workflow named "{}"'.format(params.name)) instance = wf() instance.run(until_phase=params.until_phase, until_actor=params.until_actor) report_errors(instance.errors)
def _load_ini(cls, inifile): """ Loads an ini config file from the given location. :param inifile: Path to the answer file to load. :return: configparser.SafeConfigParser object :raises CommandError if any of the values are not in key=value format """ conf = configparser.SafeConfigParser(allow_no_value=False) try: conf.read(inifile) return conf except configparser.ParsingError as exc: # Some of the sections were not in key = value format raise CommandError('Failed to load answer file {inifile} with the following errors: {errors}'.format( inifile=inifile, errors=exc.message))
def new_repository(args): name = args.name basedir = os.path.join('.', name) if os.path.isdir(basedir): raise CommandError("Directory already exists: {}".format(basedir)) os.mkdir(basedir) repository_dir = os.path.join(basedir, '.leapp') os.mkdir(repository_dir) with open(os.path.join(repository_dir, 'info'), 'w') as f: json.dump({'name': name}, f) with open(os.path.join(repository_dir, 'leapp.conf'), 'w') as f: f.write(_REPOSITORY_CONFIG) register_path(basedir) sys.stdout.write("New repository {} has been created in {}\n".format( name, os.path.realpath(name)))
def cli(args): basedir = os.path.join(find_repository_basedir('.'), 'tags') if not os.path.isdir(basedir): os.mkdir(basedir) tag_path = os.path.join(basedir, args.tag_name.lower() + '.py') if os.path.exists(tag_path): raise CommandError("File already exists: {}".format(tag_path)) with open(tag_path, 'w') as f: f.write('''from leapp.tags import Tag class {tag_name}Tag(Tag): name = '{tag}' '''.format(tag_name=make_class_name(args.tag_name), tag=make_name(args.tag_name))) sys.stdout.write("New tag {} has been created in {}\n".format( make_class_name(args.tag_name), os.path.realpath(tag_path)))
def cli(args): start = datetime.datetime.utcnow() log = configure_logger() basedir = find_repository_basedir('.') repository = find_and_scan_repositories(basedir, include_locals=True) try: repository.load() except LeappError as exc: sys.stderr.write(exc.message) sys.stderr.write('\n') sys.exit(1) actor_logger = log.getChild('actors') actor = repository.lookup_actor(args.actor_name) if not actor: raise CommandError('Actor "{}" not found!'.format(args.actor_name)) config_model = getattr(import_module('leapp.models'), args.actor_config) if args.actor_config else None messaging = InProcessMessaging(stored=args.save_output, config_model=config_model) messaging.load(actor.consumes) failure = False with beautify_actor_exception(): try: actor(messaging=messaging, logger=actor_logger, config_model=config_model).run() except BaseException: failure = True raise report_errors(messaging.errors()) report_deprecations(os.getenv('LEAPP_EXECUTION_ID'), start=start) if failure or messaging.errors(): sys.exit(1) if args.print_output: json.dump(messaging.messages(), sys.stdout, indent=2) sys.stdout.write('\n')
def vet_upgrade_path(args): """ Make sure the user requested upgrade_path is a supported one. If LEAPP_DEVEL_TARGET_RELEASE is set then it's value is not vetted against upgrade_paths_map but used as is. :raises: `CommandError` if the specified upgrade_path is not supported :return: `tuple` (target_release, flavor) """ flavor = get_upgrade_flavour() env_version_override = os.getenv('LEAPP_DEVEL_TARGET_RELEASE') if env_version_override: check_version(env_version_override) return (env_version_override, flavor) target_release = args.target or get_target_version(flavor) supported_target_versions = get_supported_target_versions(flavor) if target_release not in supported_target_versions: raise CommandError( "Upgrade to {to} for {flavor} upgrade path is not supported, possible choices are {choices}" .format(to=target_release, flavor=flavor, choices=','.join(supported_target_versions))) return (target_release, flavor)
def cli(params): configure_logger() repository = find_and_scan_repositories(find_repository_basedir('.'), include_locals=True) try: repository.load() except LeappError as exc: sys.stderr.write(exc.message) sys.stderr.write('\n') sys.exit(1) wf = repository.lookup_workflow(params.name) if not wf: raise CommandError('Could not find any workflow named "{}"'.format( params.name)) instance = wf() produced_late = set(instance.initial).intersection(set(instance.produces)) if produced_late: print_fail( _DESCRIPTION.format(' '.join([m.__name__ for m in produced_late]))) sys.exit(1)
def run(self, context=None, until_phase=None, until_actor=None, skip_phases_until=None): """ Executes the workflow :param context: Custom execution ID to be used instead of a randomly generated UUIDv4 :type context: str :param until_phase: Specify until including which phase the execution should run - phase.stage can be used to control it even more granularly. `phase` is any phase name where `stage` refers to `main`, `before` or `after`. If no stage is defined, `after` is assumed to be the default value. The execution ends when this phase (and stage, if specified) has been executed. :type until_phase: str :param until_actor: The execution finishes when this actor has been executed. :type until_actor: str :param skip_phases_until: Skips all phases until including the phase specified, and then continues the execution. :type skip_phases_until: str or None """ context = context or str(uuid.uuid4()) os.environ['LEAPP_EXECUTION_ID'] = context if not os.environ.get('LEAPP_HOSTNAME', None): os.environ['LEAPP_HOSTNAME'] = socket.getfqdn() self.log.info('Starting workflow execution: {name} - ID: {id}'.format( name=self.name, id=os.environ['LEAPP_EXECUTION_ID'])) skip_phases_until = (skip_phases_until or '').lower() needle_phase = until_phase or '' needle_stage = None if '.' in needle_phase: needle_phase, needle_stage = needle_phase.split('.', 1) needle_phase = needle_phase.lower() needle_stage = (needle_stage or '').lower() needle_actor = (until_actor or '').lower() self._errors = get_errors(context) config_model = type(self).configuration for phase in skip_phases_until, needle_phase: if phase and not self.is_valid_phase(phase): raise CommandError( 'Phase {phase} does not exist in the workflow'.format( phase=phase)) for phase in self._phase_actors: os.environ['LEAPP_CURRENT_PHASE'] = phase[0].name if skip_phases_until: if skip_phases_until in phase_names(phase): skip_phases_until = '' self.log.info( 'Skipping phase {name}'.format(name=phase[0].name)) continue self.log.info('Starting phase {name}'.format(name=phase[0].name)) current_logger = self.log.getChild(phase[0].name) early_finish = False for stage in phase[1:]: if early_finish: return current_logger.info( "Starting stage {stage} of phase {phase}".format( phase=phase[0].name, stage=stage.stage)) for actor in stage.actors: if early_finish: return designation = '' if ExperimentalTag in actor.tags: designation = '[EXPERIMENTAL]' if actor not in self.experimental_whitelist: current_logger.info( "Skipping experimental actor {actor}".format( actor=actor.name)) continue current_logger.info( "Executing actor {actor} {designation}".format( designation=designation, actor=actor.name)) messaging = InProcessMessaging(config_model=config_model) messaging.load(actor.consumes) instance = actor(logger=current_logger, messaging=messaging, config_model=config_model) try: instance.run() except BaseException: self._unhandled_exception = True raise # Collect errors if messaging.errors(): self._errors.extend(messaging.errors()) if phase[ 0].policies.error is Policies.Errors.FailImmediately: self.log.info( 'Workflow interrupted due to FailImmediately error policy' ) early_finish = True break checkpoint(actor=actor.name, phase=phase[0].name, context=context, hostname=os.environ['LEAPP_HOSTNAME']) if needle_actor in actor_names(actor): self.log.info( 'Workflow finished due to the until-actor flag') early_finish = True break if not stage.actors: checkpoint(actor='', phase=phase[0].name + '.' + stage.stage, context=context, hostname=os.environ['LEAPP_HOSTNAME']) if needle_phase in phase_names( phase) and needle_stage == stage.stage.lower(): self.log.info( 'Workflow finished due to the until-phase flag') early_finish = True break checkpoint(actor='', phase=phase[0].name, context=context, hostname=os.environ['LEAPP_HOSTNAME']) if self._errors and phase[ 0].policies.error is Policies.Errors.FailPhase: self.log.info( 'Workflow interrupted due to the FailPhase error policy') early_finish = True elif needle_phase in phase_names(phase): self.log.info('Workflow finished due to the until-phase flag') early_finish = True elif phase[0].flags.request_restart_after_phase or phase[ 0].flags.restart_after_phase: reboot = True if phase[ 0].flags.request_restart_after_phase and not self._auto_reboot: reboot = False messaging.request_answers( RawMessageDialog( message= 'A reboot is required to continue. Please reboot your system.' )) if reboot: self.log.info( 'Initiating system reboot due to the restart_after_reboot flag' ) reboot_system() early_finish = True elif phase[0].flags.is_checkpoint: self.log.info( 'Stopping the workflow execution due to the is_checkpoint flag' ) early_finish = True if early_finish: return
def run(self, context=None, until_phase=None, until_actor=None, skip_phases_until=None, skip_dialogs=False, only_with_tags=None): """ Executes the workflow :param context: Custom execution ID to be used instead of a randomly generated UUIDv4 :type context: str :param until_phase: Specify until including which phase the execution should run - phase.stage can be used to control it even more granularly. `phase` is any phase name where `stage` refers to `main`, `before` or `after`. If no stage is defined, `after` is assumed to be the default value. The execution ends when this phase (and stage, if specified) has been executed. :type until_phase: str :param until_actor: The execution finishes when this actor has been executed. :type until_actor: str :param skip_phases_until: Skips all phases until including the phase specified, and then continues the execution. :type skip_phases_until: str or None :param skip_dialogs: Inform actors about the mode of dialogs processing. If skip_dialogs is set to True it means that dialogs can't be processed in the current workflow run interactively and every attempted call of get_answers api method will be non-blocking, returning an empty dict if no user choice was found in answerfile or a selected option otherwise. If skip_dialogs is set to False then in case of absent recorded answer the dialog will be rendered in a blocking user input requiring way. The value of skip_dialogs will be passed to the actors that can theoretically use it for their purposes. :type skip_dialogs: bool :param only_with_tags: Executes only actors with the given tag, any other actor is going to get skipped. :type only_with_tags: List[str] """ context = context or str(uuid.uuid4()) os.environ['LEAPP_EXECUTION_ID'] = context if not os.environ.get('LEAPP_HOSTNAME', None): os.environ['LEAPP_HOSTNAME'] = socket.getfqdn() self.log.info('Starting workflow execution: {name} - ID: {id}'.format( name=self.name, id=os.environ['LEAPP_EXECUTION_ID'])) skip_phases_until = (skip_phases_until or '').lower() needle_phase = until_phase or '' needle_stage = None if '.' in needle_phase: needle_phase, needle_stage = needle_phase.split('.', 1) needle_phase = needle_phase.lower() needle_stage = (needle_stage or '').lower() needle_actor = (until_actor or '').lower() self._errors = get_errors(context) config_model = type(self).configuration for phase in skip_phases_until, needle_phase: if phase and not self.is_valid_phase(phase): raise CommandError( 'Phase {phase} does not exist in the workflow'.format( phase=phase)) self._stop_after_phase_requested = False for phase in self._phase_actors: os.environ['LEAPP_CURRENT_PHASE'] = phase[0].name if skip_phases_until: if skip_phases_until in phase_names(phase): skip_phases_until = '' self.log.info( 'Skipping phase {name}'.format(name=phase[0].name)) continue display_status_current_phase(phase) self.log.info('Starting phase {name}'.format(name=phase[0].name)) current_logger = self.log.getChild(phase[0].name) early_finish = False for stage in phase[1:]: if early_finish: return current_logger.info( "Starting stage {stage} of phase {phase}".format( phase=phase[0].name, stage=stage.stage)) for actor in stage.actors: if early_finish: return designation = '' if ExperimentalTag in actor.tags: designation = '[EXPERIMENTAL]' if actor not in self.experimental_whitelist: current_logger.info( "Skipping experimental actor {actor}".format( actor=actor.name)) continue if only_with_tags and not contains_tag( only_with_tags, actor.tags): current_logger.info( "Actor {actor} does not contain any required tag. Skipping." .format(actor=actor.name)) continue display_status_current_actor(actor, designation=designation) current_logger.info( "Executing actor {actor} {designation}".format( designation=designation, actor=actor.name)) messaging = InProcessMessaging( config_model=config_model, answer_store=self._answer_store) messaging.load(actor.consumes) instance = actor(logger=current_logger, messaging=messaging, config_model=config_model, skip_dialogs=skip_dialogs) try: instance.run() except BaseException: self._unhandled_exception = True raise self._stop_after_phase_requested = messaging.stop_after_phase or self._stop_after_phase_requested # Collect dialogs self._dialogs.extend(messaging.dialogs()) # Collect errors if messaging.errors(): self._errors.extend(messaging.errors()) if phase[ 0].policies.error is Policies.Errors.FailImmediately: self.log.info( 'Workflow interrupted due to FailImmediately error policy' ) early_finish = True break for command in messaging.commands: if command[ 'command'] == SkipPhasesUntilCommand.COMMAND: skip_phases_until = command['arguments'][ 'until_phase'] self.log.info( 'SkipPhasesUntilCommand received. Skipping phases until {}' .format(skip_phases_until)) checkpoint(actor=actor.name, phase=phase[0].name, context=context, hostname=os.environ['LEAPP_HOSTNAME']) if needle_actor in actor_names(actor): self.log.info( 'Workflow finished due to the until-actor flag') early_finish = True break if not stage.actors: checkpoint(actor='', phase=phase[0].name + '.' + stage.stage, context=context, hostname=os.environ['LEAPP_HOSTNAME']) if needle_phase in phase_names( phase) and needle_stage == stage.stage.lower(): self.log.info( 'Workflow finished due to the until-phase flag') early_finish = True break checkpoint(actor='', phase=phase[0].name, context=context, hostname=os.environ['LEAPP_HOSTNAME']) if self._errors and phase[ 0].policies.error is Policies.Errors.FailPhase: self.log.info( 'Workflow interrupted due to the FailPhase error policy') early_finish = True elif needle_phase in phase_names(phase): self.log.info('Workflow finished due to the until-phase flag') early_finish = True elif self._stop_after_phase_requested: self.log.info('Workflow received request to stop after phase.') early_finish = True elif phase[0].flags.request_restart_after_phase or phase[ 0].flags.restart_after_phase: reboot = True if phase[ 0].flags.request_restart_after_phase and not self._auto_reboot: reboot = False messaging.request_answers( RawMessageDialog( message= 'A reboot is required to continue. Please reboot your system.' )) if reboot: self.log.info( 'Initiating system reboot due to the restart_after_reboot flag' ) reboot_system() early_finish = True elif phase[0].flags.is_checkpoint: self.log.info( 'Stopping the workflow execution due to the is_checkpoint flag' ) early_finish = True if early_finish: return
def upgrade(args, breadcrumbs): skip_phases_until = None context = str(uuid.uuid4()) cfg = get_config() util.handle_output_level(args) answerfile_path = cfg.get('report', 'answerfile') userchoices_path = cfg.get('report', 'userchoices') # Processing of parameters passed by the rerun call, these aren't actually command line arguments # therefore we have to assume that they aren't even in `args` as they are added only by rerun. only_with_tags = args.only_with_tags if 'only_with_tags' in args else None resume_context = args.resume_context if 'resume_context' in args else None report_schema = util.process_report_schema(args, cfg) if os.getuid(): raise CommandError('This command has to be run under the root user.') if args.resume: context, configuration = util.fetch_last_upgrade_context(resume_context) if not context: raise CommandError('No previous upgrade run to continue, remove `--resume` from leapp invocation to' ' start a new upgrade flow') os.environ['LEAPP_DEBUG'] = '1' if util.check_env_and_conf('LEAPP_DEBUG', 'debug', configuration) else '0' if os.environ['LEAPP_DEBUG'] == '1' or util.check_env_and_conf('LEAPP_VERBOSE', 'verbose', configuration): os.environ['LEAPP_VERBOSE'] = '1' else: os.environ['LEAPP_VERBOSE'] = '0' util.restore_leapp_env_vars(context) skip_phases_until = util.get_last_phase(context) else: util.disable_database_sync() configuration = util.prepare_configuration(args) e = Execution(context=context, kind='upgrade', configuration=configuration) e.store() util.archive_logfiles() logger = configure_logger('leapp-upgrade.log') os.environ['LEAPP_EXECUTION_ID'] = context if args.resume: logger.info("Resuming execution after phase: %s", skip_phases_until) try: repositories = util.load_repositories() except LeappError as exc: raise CommandError(exc.message) workflow = repositories.lookup_workflow('IPUWorkflow')(auto_reboot=args.reboot) util.process_whitelist_experimental(repositories, workflow, configuration, logger) util.warn_if_unsupported(configuration) with beautify_actor_exception(): logger.info("Using answerfile at %s", answerfile_path) workflow.load_answers(answerfile_path, userchoices_path) # Set the locale, so that the actors parsing command outputs that might be localized will not fail os.environ['LC_ALL'] = 'en_US.UTF-8' os.environ['LANG'] = 'en_US.UTF-8' workflow.run(context=context, skip_phases_until=skip_phases_until, skip_dialogs=True, only_with_tags=only_with_tags) logger.info("Answerfile will be created at %s", answerfile_path) workflow.save_answers(answerfile_path, userchoices_path) report_errors(workflow.errors) report_inhibitors(context) util.generate_report_files(context, report_schema) report_files = util.get_cfg_files('report', cfg) log_files = util.get_cfg_files('logs', cfg) report_info(report_files, log_files, answerfile_path, fail=workflow.failure) if workflow.failure: sys.exit(1)
def checker(*args, **kwargs): if not find_repository_basedir('.'): raise CommandError( 'This command must be executed from the repository directory.') return f(*args, **kwargs)