Update ELevate patch

This commit is contained in:
Andrew Lukoshko 2023-06-14 15:08:36 +02:00
parent bf6d221b4f
commit 81d6380127
2 changed files with 531 additions and 44 deletions

View File

@ -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 diff --git a/README.md b/README.md
index 4de458b..c82651d 100644 index 4de458b..c82651d 100644
--- a/README.md --- a/README.md
@ -778,10 +791,69 @@ index da62c50..f062f78 100644
def get_upgrade_paths_config(): 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 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 --- a/commands/upgrade/__init__.py
+++ b/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 @@ -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.') @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('reboot', is_flag=True, help='Automatically performs reboot when requested.')
@command_opt('whitelist-experimental', action='append', metavar='ActorName', help='Enable experimental actors') @command_opt('whitelist-experimental', action='append', metavar='ActorName', help='Enable experimental actors')
@command_opt('debug', is_flag=True, help='Enable debug mode', inherit=False) @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) workflow = repositories.lookup_workflow('IPUWorkflow')(auto_reboot=args.reboot)
util.process_whitelist_experimental(repositories, workflow, configuration, logger) util.process_whitelist_experimental(repositories, workflow, configuration, logger)
util.warn_if_unsupported(configuration) util.warn_if_unsupported(configuration)
@ -801,20 +890,23 @@ index c9c2741..911d11d 100644
+ logger.info("Upgrade cancelled by user") + logger.info("Upgrade cancelled by user")
+ sys.exit(1) + 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) logger.info("Using answerfile at %s", answerfile_path)
workflow.load_answers(answerfile_path, userchoices_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) logger.info("Answerfile will be created at %s", answerfile_path)
workflow.save_answers(answerfile_path, userchoices_path) workflow.save_answers(answerfile_path, userchoices_path)
+
+ util.log_errors(workflow.errors, logger) + util.log_errors(workflow.errors, logger)
+ util.log_inhibitors(context, logger) + util.log_inhibitors(context, logger, sentry_client)
report_errors(workflow.errors) report_errors(workflow.errors)
report_inhibitors(context) report_inhibitors(context)
+
util.generate_report_files(context, report_schema) 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) report_info(report_files, log_files, answerfile_path, fail=workflow.failure)
if 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 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 --- a/commands/upgrade/util.py
+++ b/commands/upgrade/util.py +++ b/commands/upgrade/util.py
@@ -2,18 +2,25 @@ import functools @@ -2,18 +2,23 @@ import functools
import itertools import itertools
import json import json
import os 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.output import report_unsupported, pretty_block_text, pretty_block, Color
from leapp.utils.report import fetch_upgrade_report_messages, generate_report_file from leapp.utils.report import fetch_upgrade_report_messages, generate_report_file
+from leapp.models import ErrorModel +from leapp.models import ErrorModel
+
+
def disable_database_sync(): 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"]) report_unsupported(devel_vars, configuration["whitelist_experimental"])
@ -899,7 +989,7 @@ index 75ffa6a..de021a5 100644
def handle_output_level(args): def handle_output_level(args):
""" """
Set environment variables following command line arguments. 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 ' raise CommandError('--report-schema version can not be greater that the '
'actual {} one.'.format(default_report_schema)) 'actual {} one.'.format(default_report_schema))
return args.report_schema or default_report_schema return args.report_schema or default_report_schema
@ -915,20 +1005,18 @@ index 75ffa6a..de021a5 100644
+ +
+ +
+@contextmanager +@contextmanager
+def format_actor_exceptions(logger): +def format_actor_exceptions(logger, sentry):
+ try: + try:
+ try: + try:
+ yield + yield
+ except LeappRuntimeError as e: + except LeappRuntimeError as err:
+ # TODO: This only reports the actor that raised an exception + msg = f'{err.message} - Please check the above details'
+ # 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)
+ sys.stderr.write("\n") + sys.stderr.write("\n")
+ sys.stderr.write(pretty_block_text(msg, color="", width=len(msg))) + 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: + finally:
+ pass + pass
+ +
@ -955,7 +1043,7 @@ index 75ffa6a..de021a5 100644
+ v=details[detail].rstrip().replace('\n', '\n' + ' ' * (6 + len(detail))))) + 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 + from leapp.reporting import Flags # pylint: disable=import-outside-toplevel
+ reports = fetch_upgrade_report_messages(context_id) + reports = fetch_upgrade_report_messages(context_id)
+ inhibitors = [report for report in reports if Flags.INHIBITOR in report.get('flags', [])] + 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): + for position, report in enumerate(inhibitors, start=1):
+ logger.error('{idx:5}. Inhibitor: {title}'.format(idx=position, title=report['title'])) + logger.error('{idx:5}. Inhibitor: {title}'.format(idx=position, title=report['title']))
+ logger.info('Consult the pre-upgrade report for details and possible remediation.') + 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 diff --git a/etc/leapp/transaction/to_reinstall b/etc/leapp/transaction/to_reinstall
new file mode 100644 new file mode 100644
index 0000000..c6694a8 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 +### Useful for packages that have identical version strings but contain binary changes between major OS versions
+### Packages that aren't installed will be skipped +### Packages that aren't installed will be skipped
diff --git a/packaging/leapp-repository.spec b/packaging/leapp-repository.spec 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 --- a/packaging/leapp-repository.spec
+++ b/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 rm -rf %{buildroot}%{repositorydir}/system_upgrade/el8toel9
%else %else
rm -rf %{buildroot}%{repositorydir}/system_upgrade/el7toel8 rm -rf %{buildroot}%{repositorydir}/system_upgrade/el7toel8
@ -2323,10 +2442,10 @@ index 0000000..202e5f7
+ scanrolloutrepositories.process() + scanrolloutrepositories.process()
diff --git a/repos/system_upgrade/cloudlinux/actors/scanrolloutrepositories/libraries/scanrolloutrepositories.py b/repos/system_upgrade/cloudlinux/actors/scanrolloutrepositories/libraries/scanrolloutrepositories.py 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 new file mode 100644
index 0000000..0a059f1 index 0000000..cc2d1e9
--- /dev/null --- /dev/null
+++ b/repos/system_upgrade/cloudlinux/actors/scanrolloutrepositories/libraries/scanrolloutrepositories.py +++ b/repos/system_upgrade/cloudlinux/actors/scanrolloutrepositories/libraries/scanrolloutrepositories.py
@@ -0,0 +1,49 @@ @@ -0,0 +1,46 @@
+import os +import os
+ +
+from leapp.models import ( +from leapp.models import (
@ -2365,15 +2484,12 @@ index 0000000..0a059f1
+ api.current_logger().debug("Rollout file {} has used repositories, adding".format(reponame)) + api.current_logger().debug("Rollout file {} has used repositories, adding".format(reponame))
+ +
+ for repo in repofile.data: + for repo in repofile.data:
+ # Don't enable all the rollout repositories wholesale, some might + api.produce(CustomTargetRepository(
+ # be disabled and we want to keep that configuration. + repoid=repo.repoid,
+ if repo.enabled: + name=repo.name,
+ api.produce(CustomTargetRepository( + baseurl=repo.baseurl,
+ repoid=repo.repoid, + enabled=repo.enabled,
+ name=repo.name, + ))
+ baseurl=repo.baseurl,
+ enabled=repo.enabled,
+ ))
+ +
+ api.produce(CustomTargetRepositoryFile(file=full_repo_path)) + 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 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=data.get('VARIANT', '').strip('"') or None,
variant_id=data.get('VARIANT_ID', '').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 diff --git a/repos/system_upgrade/common/actors/peseventsscanner/actor.py b/repos/system_upgrade/common/actors/peseventsscanner/actor.py
index fadf76b..7ef2664 100644 index fadf76b..7ef2664 100644
--- a/repos/system_upgrade/common/actors/peseventsscanner/actor.py --- a/repos/system_upgrade/common/actors/peseventsscanner/actor.py
@ -4457,7 +4591,7 @@ index 00de073..95cedcd 100644
tags = (IPUWorkflowTag, FactsPhaseTag) 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 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 --- a/repos/system_upgrade/common/actors/setuptargetrepos/libraries/setuptargetrepos.py
+++ b/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 ( @@ -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'..? # TODO(pstodulk): what about skip this completely and keep the default 'ga'..?
default_channels = setuptargetrepos_repomap.get_default_repository_channels(repomap, src_repoids) default_channels = setuptargetrepos_repomap.get_default_repository_channels(repomap, src_repoids)
repomap.set_default_channels(default_channels) 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 return mapped_repoids
@ -4563,11 +4697,12 @@ index 3f34aed..9428ef6 100644
- repomap = _setup_repomap_handler(enabled_repoids) - repomap = _setup_repomap_handler(enabled_repoids)
+ repomap = _setup_repomap_handler(enabled_repoids, mapping_list) + repomap = _setup_repomap_handler(enabled_repoids, mapping_list)
mapped_repoids = _get_mapped_repoids(repomap, enabled_repoids) 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 skipped_repoids = enabled_repoids & set(used_repoids_dict.keys()) - mapped_repoids
# Now get the info what should be the target RHEL repositories # Now get the info what should be the target RHEL repositories
expected_repos = repomap.get_expected_target_pesid_repos(enabled_repoids) 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() target_rhel_repoids = set()
for target_pesid, target_pesidrepo in expected_repos.items(): for target_pesid, target_pesidrepo in expected_repos.items():
if not target_pesidrepo: if not target_pesidrepo:
@ -5192,11 +5327,34 @@ index b7e4b21..dc038bf 100644
def with_rhsm(f): def with_rhsm(f):
diff --git a/repos/system_upgrade/common/libraries/rpms.py b/repos/system_upgrade/common/libraries/rpms.py 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 --- a/repos/system_upgrade/common/libraries/rpms.py
+++ b/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): @@ -21,7 +21,10 @@ def get_installed_rpms():
return set()
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): -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. Expects a model InstalledRedHatSignedRPM or InstalledUnsignedRPM.
Can be useful in cases like a quick item presence check, ex. check in actor that 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 model: model class
:param package_name: package to be checked :param package_name: package to be checked
:param arch: filter by architecture. None means all arches. :param arch: filter by architecture. None means all arches.
@ -5222,12 +5381,32 @@ index 86767c7..1bc93ca 100644
+ keys.append('version') + keys.append('version')
+ if release: + if release:
+ keys.append('release') + keys.append('release')
+
+ attributes = [package_name] + attributes = [package_name]
+ attributes += [attr for attr in (arch, version, release) if attr is not None] + attributes += [attr for attr in (arch, version, release) if attr is not None]
rpm_lookup = create_lookup(model, field='items', keys=keys, context=context) 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 (package_name, arch) in rpm_lookup if arch else (package_name,) in rpm_lookup
+ return tuple(attributes) 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 diff --git a/repos/system_upgrade/common/libraries/utils.py b/repos/system_upgrade/common/libraries/utils.py
index 6793de6..d201677 100644 index 6793de6..d201677 100644
--- a/repos/system_upgrade/common/libraries/utils.py --- a/repos/system_upgrade/common/libraries/utils.py
@ -5781,3 +5960,311 @@ index 0000000..b77f784
+ with open(varfile_path, 'w') as varfile: + with open(varfile_path, 'w') as varfile:
+ # Overwrite the value from outdated "7". + # Overwrite the value from outdated "7".
+ varfile.write('8') + 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. <http://bugzilla.redhat.com/bugzilla>'
+
+
+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'

View File

@ -43,7 +43,7 @@ py2_byte_compile "%1" "%2"}
Epoch: 1 Epoch: 1
Name: leapp-repository Name: leapp-repository
Version: 0.16.0 Version: 0.16.0
Release: 6%{?dist}.elevate.13 Release: 6%{?dist}.elevate.14
Summary: Repositories for leapp Summary: Repositories for leapp
License: ASL 2.0 License: ASL 2.0