diff --git a/SOURCES/leapp-repository-0.16.0-elevate.patch b/SOURCES/leapp-repository-0.16.0-elevate.patch index b2bb482..c915ede 100644 --- a/SOURCES/leapp-repository-0.16.0-elevate.patch +++ b/SOURCES/leapp-repository-0.16.0-elevate.patch @@ -1,3 +1,16 @@ +diff --git a/Makefile b/Makefile +index 3e51e3c..b931920 100644 +--- a/Makefile ++++ b/Makefile +@@ -209,7 +209,7 @@ install-deps: + case $(_PYTHON_VENV) in python3*) yum install -y ${shell echo $(_PYTHON_VENV) | tr -d .}; esac + @# in centos:7 python dependencies required gcc + case $(_PYTHON_VENV) in python3*) yum install gcc -y; esac +- virtualenv --system-site-packages -p /usr/bin/$(_PYTHON_VENV) $(VENVNAME); \ ++ virtualenv -p /usr/bin/$(_PYTHON_VENV) $(VENVNAME); \ + . $(VENVNAME)/bin/activate; \ + pip install -U pip; \ + pip install --upgrade setuptools; \ diff --git a/README.md b/README.md index 4de458b..c82651d 100644 --- a/README.md @@ -778,10 +791,69 @@ index da62c50..f062f78 100644 def get_upgrade_paths_config(): +diff --git a/commands/preupgrade/__init__.py b/commands/preupgrade/__init__.py +index 92038bb..8dd8966 100644 +--- a/commands/preupgrade/__init__.py ++++ b/commands/preupgrade/__init__.py +@@ -48,6 +48,16 @@ def preupgrade(args, breadcrumbs): + logger = configure_logger('leapp-preupgrade.log') + os.environ['LEAPP_EXECUTION_ID'] = context + ++ sentry_client = None ++ sentry_dsn = cfg.get('sentry', 'dsn') ++ if sentry_dsn: ++ try: ++ from raven import Client ++ from raven.transport.http import HTTPTransport ++ sentry_client = Client(sentry_dsn, transport=HTTPTransport) ++ except ImportError: ++ logger.warn("Cannot import the Raven library - remote error logging not functional") ++ + try: + repositories = util.load_repositories() + except LeappError as exc: +@@ -56,7 +66,8 @@ def preupgrade(args, breadcrumbs): + workflow = repositories.lookup_workflow('IPUWorkflow')() + util.warn_if_unsupported(configuration) + util.process_whitelist_experimental(repositories, workflow, configuration, logger) +- with beautify_actor_exception(): ++ ++ with util.format_actor_exceptions(logger, sentry_client): + workflow.load_answers(answerfile_path, userchoices_path) + until_phase = 'ReportsPhase' + logger.info('Executing workflow until phase: %s', until_phase) +@@ -68,12 +79,17 @@ def preupgrade(args, breadcrumbs): + + logger.info("Answerfile will be created at %s", answerfile_path) + workflow.save_answers(answerfile_path, userchoices_path) +- util.generate_report_files(context, report_schema) ++ ++ util.log_errors(workflow.errors, logger) ++ util.log_inhibitors(context, logger, sentry_client) + 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) + diff --git a/commands/upgrade/__init__.py b/commands/upgrade/__init__.py -index c9c2741..911d11d 100644 +index c9c2741..f773a5f 100644 --- a/commands/upgrade/__init__.py +++ b/commands/upgrade/__init__.py +@@ -9,7 +9,7 @@ from leapp.exceptions import CommandError, LeappError + from leapp.logger import configure_logger + from leapp.utils.audit import Execution + from leapp.utils.clicmd import command, command_opt +-from leapp.utils.output import beautify_actor_exception, report_errors, report_info, report_inhibitors ++from leapp.utils.output import report_errors, report_info, report_inhibitors + + # NOTE: + # If you are adding new parameters please ensure that they are set in the upgrade function invocation in `rerun` @@ -18,6 +18,7 @@ from leapp.utils.output import beautify_actor_exception, report_errors, report_i @command('upgrade', help='Upgrade the current system to the next available major version.') @@ -790,7 +862,24 @@ index c9c2741..911d11d 100644 @command_opt('reboot', is_flag=True, help='Automatically performs reboot when requested.') @command_opt('whitelist-experimental', action='append', metavar='ActorName', help='Enable experimental actors') @command_opt('debug', is_flag=True, help='Enable debug mode', inherit=False) -@@ -86,7 +87,13 @@ def upgrade(args, breadcrumbs): +@@ -77,6 +78,16 @@ def upgrade(args, breadcrumbs): + logger = configure_logger('leapp-upgrade.log') + os.environ['LEAPP_EXECUTION_ID'] = context + ++ sentry_client = None ++ sentry_dsn = cfg.get('sentry', 'dsn') ++ if sentry_dsn: ++ try: ++ from raven import Client ++ from raven.transport.http import HTTPTransport ++ sentry_client = Client(sentry_dsn, transport=HTTPTransport) ++ except ImportError: ++ logger.warn("Cannot import the Raven library - remote error logging not functional") ++ + if args.resume: + logger.info("Resuming execution after phase: %s", skip_phases_until) + try: +@@ -86,7 +97,13 @@ def upgrade(args, breadcrumbs): workflow = repositories.lookup_workflow('IPUWorkflow')(auto_reboot=args.reboot) util.process_whitelist_experimental(repositories, workflow, configuration, logger) util.warn_if_unsupported(configuration) @@ -801,20 +890,23 @@ index c9c2741..911d11d 100644 + logger.info("Upgrade cancelled by user") + sys.exit(1) + -+ with util.format_actor_exceptions(logger): ++ with util.format_actor_exceptions(logger, sentry_client): logger.info("Using answerfile at %s", answerfile_path) workflow.load_answers(answerfile_path, userchoices_path) -@@ -98,6 +105,8 @@ def upgrade(args, breadcrumbs): +@@ -98,14 +115,19 @@ def upgrade(args, breadcrumbs): logger.info("Answerfile will be created at %s", answerfile_path) workflow.save_answers(answerfile_path, userchoices_path) ++ + util.log_errors(workflow.errors, logger) -+ util.log_inhibitors(context, logger) ++ util.log_inhibitors(context, logger, sentry_client) report_errors(workflow.errors) report_inhibitors(context) ++ util.generate_report_files(context, report_schema) -@@ -106,6 +115,7 @@ def upgrade(args, breadcrumbs): + 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: @@ -823,10 +915,10 @@ index c9c2741..911d11d 100644 diff --git a/commands/upgrade/util.py b/commands/upgrade/util.py -index 75ffa6a..de021a5 100644 +index 75ffa6a..be5da73 100644 --- a/commands/upgrade/util.py +++ b/commands/upgrade/util.py -@@ -2,18 +2,25 @@ import functools +@@ -2,18 +2,23 @@ import functools import itertools import json import os @@ -849,12 +941,10 @@ index 75ffa6a..de021a5 100644 +from leapp.utils.output import report_unsupported, pretty_block_text, pretty_block, Color from leapp.utils.report import fetch_upgrade_report_messages, generate_report_file +from leapp.models import ErrorModel -+ -+ def disable_database_sync(): -@@ -167,6 +174,44 @@ def warn_if_unsupported(configuration): +@@ -167,6 +172,44 @@ def warn_if_unsupported(configuration): report_unsupported(devel_vars, configuration["whitelist_experimental"]) @@ -899,7 +989,7 @@ index 75ffa6a..de021a5 100644 def handle_output_level(args): """ Set environment variables following command line arguments. -@@ -236,3 +281,65 @@ def process_report_schema(args, configuration): +@@ -236,3 +279,76 @@ def process_report_schema(args, configuration): 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 @@ -915,20 +1005,18 @@ index 75ffa6a..de021a5 100644 + + +@contextmanager -+def format_actor_exceptions(logger): ++def format_actor_exceptions(logger, sentry): + try: + try: + yield -+ except LeappRuntimeError as e: -+ # TODO: This only reports the actor that raised an exception -+ # and the return code. -+ # The traceback gets eaten on the framework level, and is only -+ # seen in stderr. Changing that will require modifying the framework -+ # code itself. -+ msg = '{} - Please check the above details'.format(e.message) ++ except LeappRuntimeError as err: ++ msg = f'{err.message} - Please check the above details' + sys.stderr.write("\n") + sys.stderr.write(pretty_block_text(msg, color="", width=len(msg))) -+ logger.error(e.message) ++ logger.error(err.message) ++ if sentry: ++ sent_code = sentry.captureException() ++ logger.info("Error \"{}\" sent to Sentry with code {}".format(err, sent_code)) + finally: + pass + @@ -955,7 +1043,7 @@ index 75ffa6a..de021a5 100644 + v=details[detail].rstrip().replace('\n', '\n' + ' ' * (6 + len(detail))))) + + -+def log_inhibitors(context_id, logger): ++def log_inhibitors(context_id, logger, sentry): + from leapp.reporting import Flags # pylint: disable=import-outside-toplevel + reports = fetch_upgrade_report_messages(context_id) + inhibitors = [report for report in reports if Flags.INHIBITOR in report.get('flags', [])] @@ -965,6 +1053,19 @@ index 75ffa6a..de021a5 100644 + for position, report in enumerate(inhibitors, start=1): + logger.error('{idx:5}. Inhibitor: {title}'.format(idx=position, title=report['title'])) + logger.info('Consult the pre-upgrade report for details and possible remediation.') ++ ++ if sentry: ++ for inhibitor in inhibitors: ++ sentry.captureMessage( ++ "Inhibitor: {}\n" ++ "Severity: {}\n" ++ "{}".format( ++ inhibitor['title'], ++ inhibitor['severity'], ++ inhibitor['summary'] ++ ) ++ ) ++ logger.info("Inhibitor \"{}\" sent to Sentry".format(inhibitor['title'])) diff --git a/etc/leapp/transaction/to_reinstall b/etc/leapp/transaction/to_reinstall new file mode 100644 index 0000000..c6694a8 @@ -975,10 +1076,28 @@ index 0000000..c6694a8 +### Useful for packages that have identical version strings but contain binary changes between major OS versions +### Packages that aren't installed will be skipped diff --git a/packaging/leapp-repository.spec b/packaging/leapp-repository.spec -index af4b31d..0d8f6c8 100644 +index af4b31d..b9e88a9 100644 --- a/packaging/leapp-repository.spec +++ b/packaging/leapp-repository.spec -@@ -196,6 +196,8 @@ rm -rf %{buildroot}%{leapp_python_sitelib}/leapp/cli/commands/tests +@@ -137,6 +137,8 @@ Requires: pciutils + # Required to gather system facts about SELinux + Requires: libselinux-python + Requires: python-pyudev ++# Required to gather data about actor exceptions or inhibitors ++Requires: python-raven + # required by SELinux actors + Requires: policycoreutils-python + # Required to fetch leapp data +@@ -147,6 +149,8 @@ Requires: python-requests + # systemd-nspawn utility + Requires: systemd-container + Requires: python3-pyudev ++# Required to gather data about actor exceptions or inhibitors ++Requires: python3-raven + # Required to fetch leapp data + Requires: python3-requests + # Required because the code is kept Py2 & Py3 compatible +@@ -196,6 +200,8 @@ rm -rf %{buildroot}%{leapp_python_sitelib}/leapp/cli/commands/tests rm -rf %{buildroot}%{repositorydir}/system_upgrade/el8toel9 %else rm -rf %{buildroot}%{repositorydir}/system_upgrade/el7toel8 @@ -2323,10 +2442,10 @@ index 0000000..202e5f7 + scanrolloutrepositories.process() diff --git a/repos/system_upgrade/cloudlinux/actors/scanrolloutrepositories/libraries/scanrolloutrepositories.py b/repos/system_upgrade/cloudlinux/actors/scanrolloutrepositories/libraries/scanrolloutrepositories.py new file mode 100644 -index 0000000..0a059f1 +index 0000000..cc2d1e9 --- /dev/null +++ b/repos/system_upgrade/cloudlinux/actors/scanrolloutrepositories/libraries/scanrolloutrepositories.py -@@ -0,0 +1,49 @@ +@@ -0,0 +1,46 @@ +import os + +from leapp.models import ( @@ -2365,15 +2484,12 @@ index 0000000..0a059f1 + api.current_logger().debug("Rollout file {} has used repositories, adding".format(reponame)) + + for repo in repofile.data: -+ # Don't enable all the rollout repositories wholesale, some might -+ # be disabled and we want to keep that configuration. -+ if repo.enabled: -+ api.produce(CustomTargetRepository( -+ repoid=repo.repoid, -+ name=repo.name, -+ baseurl=repo.baseurl, -+ enabled=repo.enabled, -+ )) ++ api.produce(CustomTargetRepository( ++ repoid=repo.repoid, ++ name=repo.name, ++ baseurl=repo.baseurl, ++ enabled=repo.enabled, ++ )) + + api.produce(CustomTargetRepositoryFile(file=full_repo_path)) diff --git a/repos/system_upgrade/cloudlinux/actors/switchclnchannel/actor.py b/repos/system_upgrade/cloudlinux/actors/switchclnchannel/actor.py @@ -3202,6 +3318,24 @@ index edf978f..7fea4ec 100644 variant=data.get('VARIANT', '').strip('"') or None, variant_id=data.get('VARIANT_ID', '').strip('"') or None ) +diff --git a/repos/system_upgrade/common/actors/kernel/checkinstalledkernels/libraries/checkinstalledkernels.py b/repos/system_upgrade/common/actors/kernel/checkinstalledkernels/libraries/checkinstalledkernels.py +index 134d1aa..c4d9931 100644 +--- a/repos/system_upgrade/common/actors/kernel/checkinstalledkernels/libraries/checkinstalledkernels.py ++++ b/repos/system_upgrade/common/actors/kernel/checkinstalledkernels/libraries/checkinstalledkernels.py +@@ -125,7 +125,12 @@ def process(): + api.current_logger().debug('Current kernel EVR: {}'.format(current_evr)) + api.current_logger().debug('Newest kernel EVR: {}'.format(newest_evr)) + +- if current_evr != newest_evr: ++ # LVE kernels can be installed over newer kernels and be older ++ # than the most current avalable ones - that's not an inhibitor, it's expected ++ # They're marked with 'lve' in the release string ++ lve_kernel = "lve" in current_evr[2] ++ ++ if current_evr != newest_evr and not lve_kernel: + title = 'Newest installed kernel not in use' + summary = ('To ensure a stable upgrade, the machine needs to be' + ' booted into the latest installed kernel.') diff --git a/repos/system_upgrade/common/actors/peseventsscanner/actor.py b/repos/system_upgrade/common/actors/peseventsscanner/actor.py index fadf76b..7ef2664 100644 --- a/repos/system_upgrade/common/actors/peseventsscanner/actor.py @@ -4457,7 +4591,7 @@ index 00de073..95cedcd 100644 tags = (IPUWorkflowTag, FactsPhaseTag) diff --git a/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos.py b/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos.py -index 3f34aed..9428ef6 100644 +index 3f34aed..9c1e360 100644 --- a/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos.py +++ b/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos.py @@ -12,7 +12,8 @@ from leapp.models import ( @@ -4495,7 +4629,7 @@ index 3f34aed..9428ef6 100644 # TODO(pstodulk): what about skip this completely and keep the default 'ga'..? default_channels = setuptargetrepos_repomap.get_default_repository_channels(repomap, src_repoids) repomap.set_default_channels(default_channels) -@@ -77,22 +89,74 @@ def _get_mapped_repoids(repomap, src_repoids): +@@ -77,22 +89,75 @@ def _get_mapped_repoids(repomap, src_repoids): return mapped_repoids @@ -4563,11 +4697,12 @@ index 3f34aed..9428ef6 100644 - repomap = _setup_repomap_handler(enabled_repoids) + repomap = _setup_repomap_handler(enabled_repoids, mapping_list) mapped_repoids = _get_mapped_repoids(repomap, enabled_repoids) ++ api.current_logger().debug('Mapped repos: {}'.format(mapped_repoids)) skipped_repoids = enabled_repoids & set(used_repoids_dict.keys()) - mapped_repoids # Now get the info what should be the target RHEL repositories expected_repos = repomap.get_expected_target_pesid_repos(enabled_repoids) -+ api.current_logger().debug('Expected repos: {}'.format(expected_repos)) ++ api.current_logger().debug('Expected repos: {}'.format(expected_repos.keys())) target_rhel_repoids = set() for target_pesid, target_pesidrepo in expected_repos.items(): if not target_pesidrepo: @@ -5192,11 +5327,34 @@ index b7e4b21..dc038bf 100644 def with_rhsm(f): diff --git a/repos/system_upgrade/common/libraries/rpms.py b/repos/system_upgrade/common/libraries/rpms.py -index 86767c7..1bc93ca 100644 +index 86767c7..18fd63b 100644 --- a/repos/system_upgrade/common/libraries/rpms.py +++ b/repos/system_upgrade/common/libraries/rpms.py -@@ -39,18 +39,28 @@ def create_lookup(model, field, keys, context=stdlib.api): - return set() +@@ -21,7 +21,10 @@ def get_installed_rpms(): + + def create_lookup(model, field, keys, context=stdlib.api): + """ +- Create a lookup set from one of the model fields. ++ Create a lookup list from one of the model fields. ++ Returns a list of keys instead of a set, as you might want to ++ access this data at some point later in some form of structured ++ manner. See package_data_for + + :param model: model class + :param field: model field, its value will be taken for lookup data +@@ -30,27 +33,57 @@ def create_lookup(model, field, keys, context=stdlib.api): + """ + data = getattr(next((m for m in context.consume(model)), model()), field) + try: +- return {tuple(getattr(obj, key) for key in keys) for obj in data} if data else set() ++ return [tuple(getattr(obj, key) for key in keys) for obj in data] if data else list() + except TypeError: + # data is not iterable, not lookup can be built + stdlib.api.current_logger().error( + "{model}.{field}.{keys} is not iterable, can't build lookup".format( + model=model, field=field, keys=keys)) +- return set() ++ return list() -def has_package(model, package_name, arch=None, context=stdlib.api): @@ -5204,8 +5362,9 @@ index 86767c7..1bc93ca 100644 """ Expects a model InstalledRedHatSignedRPM or InstalledUnsignedRPM. Can be useful in cases like a quick item presence check, ex. check in actor that - a certain package is installed. +- a certain package is installed. - ++ a certain package is installed. Returns BOOL :param model: model class :param package_name: package to be checked :param arch: filter by architecture. None means all arches. @@ -5222,12 +5381,32 @@ index 86767c7..1bc93ca 100644 + keys.append('version') + if release: + keys.append('release') -+ + attributes = [package_name] + attributes += [attr for attr in (arch, version, release) if attr is not None] rpm_lookup = create_lookup(model, field='items', keys=keys, context=context) - return (package_name, arch) in rpm_lookup if arch else (package_name,) in rpm_lookup + return tuple(attributes) in rpm_lookup ++ ++ ++def package_data_for(model, package_name, context=stdlib.api): ++ """ ++ Expects a model InstalledRedHatSignedRPM or InstalledUnsignedRPM. ++ Useful for where we want to know a thing is installed ++ THEN do something based on the data. ++ Returns list( name, arch, version, release ) for given RPM. ++ :param model: model class ++ :param package_name: package to be checked ++ :param arch: filter by architecture. None means all arches. ++ :param version: filter by version. None means all versions. ++ :param release: filter by release. None means all releases. ++ """ ++ if not (isinstance(model, type) and issubclass(model, InstalledRPM)): ++ return list() ++ ++ lookup_keys = ['name', 'arch', 'version', 'release'] ++ for (rpmName,rpmArch,rpmVersion,rpmRelease) in create_lookup(model, field='items', keys=lookup_keys, context=context): ++ if package_name == rpmName: ++ return {'name': rpmName,'arch': rpmArch, 'version': rpmVersion, 'release': rpmRelease} diff --git a/repos/system_upgrade/common/libraries/utils.py b/repos/system_upgrade/common/libraries/utils.py index 6793de6..d201677 100644 --- a/repos/system_upgrade/common/libraries/utils.py @@ -5781,3 +5960,311 @@ index 0000000..b77f784 + with open(varfile_path, 'w') as varfile: + # Overwrite the value from outdated "7". + varfile.write('8') +diff --git a/repos/system_upgrade/wp-toolkit/.leapp/info b/repos/system_upgrade/wp-toolkit/.leapp/info +new file mode 100644 +index 0000000..e4059e3 +--- /dev/null ++++ b/repos/system_upgrade/wp-toolkit/.leapp/info +@@ -0,0 +1 @@ ++{"name": "wp-toolkit", "id": "ae31666a-37b8-435c-a071-a3d28342099b", "repos": ["644900a5-c347-43a3-bfab-f448f46d9647"]} +\ No newline at end of file +diff --git a/repos/system_upgrade/wp-toolkit/.leapp/leapp.conf b/repos/system_upgrade/wp-toolkit/.leapp/leapp.conf +new file mode 100644 +index 0000000..b459134 +--- /dev/null ++++ b/repos/system_upgrade/wp-toolkit/.leapp/leapp.conf +@@ -0,0 +1,6 @@ ++ ++[repositories] ++repo_path=${repository:root_dir} ++ ++[database] ++path=${repository:state_dir}/leapp.db +diff --git a/repos/system_upgrade/wp-toolkit/actors/setwptoolkityumvariable/actor.py b/repos/system_upgrade/wp-toolkit/actors/setwptoolkityumvariable/actor.py +new file mode 100644 +index 0000000..f386358 +--- /dev/null ++++ b/repos/system_upgrade/wp-toolkit/actors/setwptoolkityumvariable/actor.py +@@ -0,0 +1,65 @@ ++from leapp.actors import Actor ++from leapp.models import ActiveVendorList, CopyFile, TargetUserSpacePreupgradeTasks, WpToolkit ++from leapp.libraries.stdlib import api ++from leapp.tags import TargetTransactionFactsPhaseTag, IPUWorkflowTag ++ ++VENDOR_NAME = 'wp-toolkit' ++SUPPORTED_VARIANTS = ['cpanel', ] ++ ++# Is the vendors.d path the best place to create this file? ++src_path = '/etc/leapp/files/vendors.d/wp-toolkit.var' ++dst_path = '/etc/dnf/vars/wptkversion' ++ ++ ++class SetWpToolkitYumVariable(Actor): ++ """ ++ Records the current WP Toolkit version into a DNF variable file so that the ++ precise version requested is reinstalled, and forwards the request to copy ++ this data into the upgrading environment using a ++ :class:`TargetUserSpacePreupgradeTasks`. ++ """ ++ ++ name = 'set_wp_toolkit_yum_variable' ++ consumes = (ActiveVendorList, WpToolkit) ++ produces = (TargetUserSpacePreupgradeTasks,) ++ tags = (TargetTransactionFactsPhaseTag.Before, IPUWorkflowTag) ++ ++ def _do_cpanel(self, version): ++ ++ files_to_copy = [] ++ if version is None: ++ version = 'latest' ++ ++ try: ++ with open(src_path, 'w') as var_file: ++ var_file.write(version) ++ ++ files_to_copy.append(CopyFile(src=src_path, dst=dst_path)) ++ msg = 'Requesting leapp to copy {} into the upgrade environment as {}'.format(src_path, dst_path) ++ api.current_logger().debug(msg) ++ ++ except OSError as e: ++ api.current_logger().error('Cannot write to {}: {}'.format(e.filename, e.strerror)) ++ ++ return TargetUserSpacePreupgradeTasks(copy_files=files_to_copy) ++ ++ def process(self): ++ ++ active_vendors = [] ++ for vendor_list in api.consume(ActiveVendorList): ++ active_vendors.extend(vendor_list.data) ++ ++ if VENDOR_NAME in active_vendors: ++ wptk_data = next(api.consume(WpToolkit), WpToolkit()) ++ ++ preupgrade_task = None ++ if wptk_data.variant == 'cpanel': ++ preupgrade_task = self._do_cpanel(wptk_data.version) ++ else: ++ api.current_logger().warn('Could not recognize a supported environment for WP Toolkit.') ++ ++ if preupgrade_task is not None: ++ api.produce(preupgrade_task) ++ ++ else: ++ api.current_logger().info('{} not an active vendor: skipping actor'.format(VENDOR_NAME)) +diff --git a/repos/system_upgrade/wp-toolkit/actors/updatewptoolkitrepos/actor.py b/repos/system_upgrade/wp-toolkit/actors/updatewptoolkitrepos/actor.py +new file mode 100644 +index 0000000..f1c6839 +--- /dev/null ++++ b/repos/system_upgrade/wp-toolkit/actors/updatewptoolkitrepos/actor.py +@@ -0,0 +1,49 @@ ++import os ++import shutil ++ ++from leapp.actors import Actor ++from leapp.libraries.stdlib import api, run ++from leapp.models import ActiveVendorList, WpToolkit ++from leapp.tags import IPUWorkflowTag, FirstBootPhaseTag ++ ++VENDOR_NAME = 'wp-toolkit' ++ ++VENDORS_DIR = '/etc/leapp/files/vendors.d' ++REPO_DIR = '/etc/yum.repos.d' ++ ++class UpdateWpToolkitRepos(Actor): ++ """ ++ Replaces the WP Toolkit's old repo file from the CentOS 7 version with one appropriate for the new OS. ++ """ ++ ++ name = 'update_wp_toolkit_repos' ++ consumes = (ActiveVendorList, WpToolkit) ++ produces = () ++ tags = (IPUWorkflowTag, FirstBootPhaseTag) ++ ++ def process(self): ++ ++ active_vendors = [] ++ for vendor_list in api.consume(ActiveVendorList): ++ active_vendors.extend(vendor_list.data) ++ ++ if VENDOR_NAME in active_vendors: ++ ++ wptk_data = next(api.consume(WpToolkit), WpToolkit()) ++ ++ src_file = api.get_file_path('{}-{}.el8.repo'. format(VENDOR_NAME, wptk_data.variant)) ++ dst_file = '{}/{}-{}.repo'.format(REPO_DIR, VENDOR_NAME, wptk_data.variant) ++ ++ try: ++ os.rename(dst_file, dst_file + '.bak') ++ except OSError as e: ++ api.current_logger().warn('Could not rename {} to {}: {}'.format(e.filename, e.filename2, e.strerror)) ++ ++ api.current_logger().info('Updating WPTK package repository file at {} using {}'.format(dst_file, src_file)) ++ ++ try: ++ shutil.copy(src_file, dst_file) ++ except OSError as e: ++ api.current_logger().error('Could not update WPTK package repository file {}: {}'.format(e.filename2, e.strerror)) ++ else: ++ api.current_logger().info('{} not an active vendor: skipping actor'.format(VENDOR_NAME)) +diff --git a/repos/system_upgrade/wp-toolkit/actors/wptoolkitfacts/actor.py b/repos/system_upgrade/wp-toolkit/actors/wptoolkitfacts/actor.py +new file mode 100644 +index 0000000..a2925dd +--- /dev/null ++++ b/repos/system_upgrade/wp-toolkit/actors/wptoolkitfacts/actor.py +@@ -0,0 +1,55 @@ ++from leapp.actors import Actor ++from leapp.libraries.stdlib import api ++from leapp.models import ActiveVendorList, WpToolkit, VendorSourceRepos, InstalledRPM ++from leapp.tags import IPUWorkflowTag, FactsPhaseTag ++from leapp.libraries.common.rpms import package_data_for ++ ++VENDOR_NAME = 'wp-toolkit' ++SUPPORTED_VARIANTS = ['cpanel', ] ++ ++ ++class WpToolkitFacts(Actor): ++ """ ++ Find out whether a supported WP Toolkit repository is present and whether the appropriate package is installed. ++ """ ++ ++ name = 'wp_toolkit_facts' ++ consumes = (ActiveVendorList, VendorSourceRepos, InstalledRPM) ++ produces = (WpToolkit,) ++ tags = (IPUWorkflowTag, FactsPhaseTag) ++ ++ def process(self): ++ ++ active_vendors = [] ++ for vendor_list in api.consume(ActiveVendorList): ++ active_vendors.extend(vendor_list.data) ++ ++ if VENDOR_NAME in active_vendors: ++ api.current_logger().info('Vendor {} is active. Looking for information...'.format(VENDOR_NAME)) ++ ++ repo_list = [] ++ for src_info in api.consume(VendorSourceRepos): ++ if src_info.vendor == VENDOR_NAME: ++ repo_list = src_info.source_repoids ++ break ++ ++ variant = None ++ version = None ++ for maybe_variant in SUPPORTED_VARIANTS: ++ if '{}-{}'.format(VENDOR_NAME, maybe_variant) in repo_list: ++ variant = maybe_variant ++ api.current_logger().info('Found WP Toolkit variant {}'.format(variant)) ++ ++ pkgData = package_data_for(InstalledRPM, u'wp-toolkit-{}'.format(variant)) ++ # name, arch, version, release ++ if pkgData: ++ version = pkgData['version'] ++ ++ break ++ ++ api.current_logger().debug('Did not find WP Toolkit variant {}'.format(maybe_variant)) ++ ++ api.produce(WpToolkit(variant=variant, version=version)) ++ ++ else: ++ api.current_logger().info('{} not an active vendor: skipping actor'.format(VENDOR_NAME)) +diff --git a/repos/system_upgrade/wp-toolkit/actors/wptoolkitfacts/tests/test_wptoolkitfacts.py b/repos/system_upgrade/wp-toolkit/actors/wptoolkitfacts/tests/test_wptoolkitfacts.py +new file mode 100644 +index 0000000..551c2af +--- /dev/null ++++ b/repos/system_upgrade/wp-toolkit/actors/wptoolkitfacts/tests/test_wptoolkitfacts.py +@@ -0,0 +1,38 @@ ++# XXX TODO this copies a lot from satellite_upgrade_facts.py, should probably make a fixture ++# for fake_package at the least? ++ ++from leapp.models import InstalledRPM, RPM, ActiveVendorList, VendorSourceRepos, WpToolkit ++ ++RH_PACKAGER = 'Red Hat, Inc. ' ++ ++ ++def fake_package(pkg_name,version): ++ return RPM(name=pkg_name, version=version, release='1.sm01', epoch='1', packager=RH_PACKAGER, arch='noarch', ++ pgpsig='RSA/SHA256, Mon 01 Jan 1970 00:00:00 AM -03, Key ID 199e2f91fd431d51') ++ ++ ++BOGUS_RPM = fake_package('bogus-bogus', '1.0') ++WPTOOLKIT_RPM = fake_package('wp-toolkit-cpanel', '0.1') ++ ++ ++def test_no_wptoolkit_vendor_present(current_actor_context): ++ current_actor_context.feed(ActiveVendorList(data=list(["jello"])), InstalledRPM(items=[])) ++ current_actor_context.run() ++ message = current_actor_context.consume(WpToolkit) ++ assert not message ++ ++ ++def test_no_wptoolkit_rpm_present(current_actor_context): ++ current_actor_context.feed(ActiveVendorList(data=list(['wp-toolkit'])), InstalledRPM(items=[])) ++ current_actor_context.run() ++ message = current_actor_context.consume(WpToolkit) ++ assert not hasattr(message, 'variant') ++ assert not hasattr(message, 'version') ++ ++ ++def test_wptoolkit_rpm_present(current_actor_context): ++ current_actor_context.feed(ActiveVendorList(data=list(['wp-toolkit'])), VendorSourceRepos(vendor='wp-toolkit',source_repoids=list(['wp-toolkit-cpanel'])), InstalledRPM(items=[BOGUS_RPM,WPTOOLKIT_RPM])) ++ current_actor_context.run() ++ message = current_actor_context.consume(WpToolkit)[0] ++ assert message.variant == 'cpanel' ++ assert message.version == '0.1' +diff --git a/repos/system_upgrade/wp-toolkit/files/wp-toolkit-cpanel.el8.repo b/repos/system_upgrade/wp-toolkit/files/wp-toolkit-cpanel.el8.repo +new file mode 100644 +index 0000000..adfd7b6 +--- /dev/null ++++ b/repos/system_upgrade/wp-toolkit/files/wp-toolkit-cpanel.el8.repo +@@ -0,0 +1,11 @@ ++[wp-toolkit-cpanel] ++name=WP Toolkit for cPanel ++baseurl=https://wp-toolkit.plesk.com/cPanel/CentOS-8-x86_64/latest/wp-toolkit/ ++enabled=1 ++gpgcheck=1 ++ ++[wp-toolkit-thirdparties] ++name=WP Toolkit third parties ++baseurl=https://wp-toolkit.plesk.com/cPanel/CentOS-8-x86_64/latest/thirdparty/ ++enabled=1 ++gpgcheck=1 +diff --git a/repos/system_upgrade/wp-toolkit/models/wptoolkit.py b/repos/system_upgrade/wp-toolkit/models/wptoolkit.py +new file mode 100644 +index 0000000..9df3c0d +--- /dev/null ++++ b/repos/system_upgrade/wp-toolkit/models/wptoolkit.py +@@ -0,0 +1,23 @@ ++from leapp.models import Model, fields ++from leapp.topics import SystemFactsTopic ++ ++ ++class WpToolkit(Model): ++ """ ++ Records information about presence and versioning of WP Toolkit package management resources on the source system. ++ """ ++ topic = SystemFactsTopic ++ ++ """ ++ States which supported "variant" of WP Toolkit seems available to the package manager. ++ ++ Currently, only `cpanel` is supported. ++ """ ++ variant = fields.Nullable(fields.String()) ++ ++ """ ++ States which version of the WP Toolkit package for the given variant is installed. ++ ++ If no package is installed, this will be `None`. ++ """ ++ version = fields.Nullable(fields.String()) +diff --git a/requirements.txt b/requirements.txt +index ac6bf9b..f69f981 100644 +--- a/requirements.txt ++++ b/requirements.txt +@@ -11,5 +11,6 @@ distro==1.5.0 + ipaddress==1.0.23 + git+https://github.com/oamg/leapp + requests ++raven + # pinning a py27 troublemaking transitive dependency + lazy-object-proxy==1.5.2; python_version < '3' diff --git a/SPECS/leapp-repository.spec b/SPECS/leapp-repository.spec index 6f15539..97dc5ed 100644 --- a/SPECS/leapp-repository.spec +++ b/SPECS/leapp-repository.spec @@ -43,7 +43,7 @@ py2_byte_compile "%1" "%2"} Epoch: 1 Name: leapp-repository Version: 0.16.0 -Release: 6%{?dist}.elevate.13 +Release: 6%{?dist}.elevate.14 Summary: Repositories for leapp License: ASL 2.0