Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement package reinstallation for DNF tasks #105

Open
wants to merge 3 commits into
base: almalinux-ng
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions etc/leapp/transaction/to_reinstall
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### List of packages (each on new line) to be reinstalled to the upgrade transaction
### Useful for packages that have identical version strings but contain binary changes between major OS versions
### Packages that aren't installed will be skipped
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,29 @@ def process(self):
to_remove = set()
to_keep = set()
to_upgrade = set()
to_reinstall = set()
modules_to_enable = {}
modules_to_reset = {}
for event in self.consume(RpmTransactionTasks, PESRpmTransactionTasks):
local_rpms.update(event.local_rpms)
to_install.update(event.to_install)
to_remove.update(installed_pkgs.intersection(event.to_remove))
to_keep.update(installed_pkgs.intersection(event.to_keep))
to_reinstall.update(installed_pkgs.intersection(event.to_reinstall))
modules_to_enable.update({'{}:{}'.format(m.name, m.stream): m for m in event.modules_to_enable})
modules_to_reset.update({'{}:{}'.format(m.name, m.stream): m for m in event.modules_to_reset})

to_remove.difference_update(to_keep)

# run upgrade for the rest of RH signed pkgs which we do not have rule for
to_upgrade = installed_pkgs - (to_install | to_remove)
to_upgrade = installed_pkgs - (to_install | to_remove | to_reinstall)

self.produce(FilteredRpmTransactionTasks(
local_rpms=list(local_rpms),
to_install=list(to_install),
to_remove=list(to_remove),
to_keep=list(to_keep),
to_upgrade=list(to_upgrade),
to_reinstall=list(to_reinstall),
modules_to_reset=list(modules_to_reset.values()),
modules_to_enable=list(modules_to_enable.values())))
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class Action(IntEnum):
MERGED = 5
MOVED = 6
RENAMED = 7
REINSTALLED = 8


def get_pes_events(pes_json_directory, pes_json_filename):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ def compute_pkg_changes_between_consequent_releases(source_installed_pkgs,
logger = api.current_logger()
# Start with the installed packages and modify the set according to release events
target_pkgs = set(source_installed_pkgs)
pkgs_to_reinstall = set()

release_events = [e for e in events if e.to_release == release]

Expand Down Expand Up @@ -165,9 +166,12 @@ def compute_pkg_changes_between_consequent_releases(source_installed_pkgs,
target_pkgs = target_pkgs.difference(event.in_pkgs)
target_pkgs = target_pkgs.union(event.out_pkgs)

if (event.action == Action.REINSTALLED and is_any_in_pkg_present):
pkgs_to_reinstall = pkgs_to_reinstall.union(event.in_pkgs)

pkgs_to_demodularize = pkgs_to_demodularize.difference(event.in_pkgs)

return (target_pkgs, pkgs_to_demodularize)
return (target_pkgs, pkgs_to_demodularize, pkgs_to_reinstall)


def remove_undesired_events(events, relevant_to_releases):
Expand Down Expand Up @@ -233,15 +237,18 @@ def compute_packages_on_target_system(source_pkgs, events, releases):
did_processing_cross_major_version = True
pkgs_to_demodularize = {pkg for pkg in target_pkgs if pkg.modulestream}

target_pkgs, pkgs_to_demodularize = compute_pkg_changes_between_consequent_releases(target_pkgs, events,
release, seen_pkgs,
pkgs_to_demodularize)
target_pkgs, pkgs_to_demodularize, pkgs_to_reinstall = compute_pkg_changes_between_consequent_releases
(
target_pkgs, events,
release, seen_pkgs,
pkgs_to_demodularize
)
seen_pkgs = seen_pkgs.union(target_pkgs)

demodularized_pkgs = {Package(pkg.name, pkg.repository, None) for pkg in pkgs_to_demodularize}
demodularized_target_pkgs = target_pkgs.difference(pkgs_to_demodularize).union(demodularized_pkgs)

return (demodularized_target_pkgs, pkgs_to_demodularize)
return (demodularized_target_pkgs, pkgs_to_demodularize, pkgs_to_reinstall)


def compute_rpm_tasks_from_pkg_set_diff(source_pkgs, target_pkgs, pkgs_to_demodularize):
Expand Down Expand Up @@ -496,7 +503,8 @@ def process():
events = remove_undesired_events(events, releases)

# Apply events - compute what packages should the target system have
target_pkgs, pkgs_to_demodularize = compute_packages_on_target_system(source_pkgs, events, releases)
# TODO: bring back the reinstallation of packages
target_pkgs, pkgs_to_demodularize, pkgs_to_reinstall = compute_packages_on_target_system(source_pkgs, events, releases)

# Packages coming out of the events have PESID as their repository, however, we need real repoid
target_pkgs = replace_pesids_with_repoids_in_packages(target_pkgs, repoids_of_source_pkgs)
Expand All @@ -512,4 +520,5 @@ def process():
# Compare the packages on source system and the computed packages on target system and determine what to install
rpm_tasks = compute_rpm_tasks_from_pkg_set_diff(source_pkgs, target_pkgs, pkgs_to_demodularize)
if rpm_tasks:
rpm_tasks.to_reinstall = pkgs_to_reinstall
api.produce(rpm_tasks)
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,37 @@ def load_tasks_file(path, logger):
return []


def filter_out(installed_rpm_names, to_filter, debug_msg):
# These are the packages that aren't installed on the system.
filtered_ok = [pkg for pkg in to_filter if pkg not in installed_rpm_names]

# And these ones are the ones that are.
filtered_out = list(set(to_filter) - set(filtered_ok))
if filtered_out:
api.current_logger().debug(
debug_msg +
'\n- ' + '\n- '.join(filtered_out)
)
# We may want to use either of the two sets.
return filtered_ok, filtered_out


def load_tasks(base_dir, logger):
# Loads configuration files to_install, to_keep, and to_remove from the given base directory
rpms = next(api.consume(InstalledRedHatSignedRPM))
rpm_names = [rpm.name for rpm in rpms.items]

to_install = load_tasks_file(os.path.join(base_dir, 'to_install'), logger)
install_debug_msg = 'The following packages from "to_install" file will be ignored as they are already installed:'
# we do not want to put into rpm transaction what is already installed (it will go to "to_upgrade" bucket)
to_install_filtered = [pkg for pkg in to_install if pkg not in rpm_names]
to_install_filtered, _ = filter_out(rpm_names, to_install, install_debug_msg)

filtered = set(to_install) - set(to_install_filtered)
if filtered:
api.current_logger().debug(
'The following packages from "to_install" file will be ignored as they are already installed:'
'\n- ' + '\n- '.join(filtered))
to_reinstall = load_tasks_file(os.path.join(base_dir, 'to_reinstall'), logger)
reinstall_debug_msg = 'The following packages from "to_reinstall" file will be ignored as they are not installed:'
_, to_reinstall_filtered = filter_out(rpm_names, to_reinstall, reinstall_debug_msg)

return RpmTransactionTasks(
to_install=to_install_filtered,
to_reinstall=to_reinstall_filtered,
to_keep=load_tasks_file(os.path.join(base_dir, 'to_keep'), logger),
to_remove=load_tasks_file(os.path.join(base_dir, 'to_remove'), logger))
4 changes: 4 additions & 0 deletions repos/system_upgrade/common/files/rhel_upgrade.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ def run(self):
to_install = self.plugin_data['pkgs_info']['to_install']
to_remove = self.plugin_data['pkgs_info']['to_remove']
to_upgrade = self.plugin_data['pkgs_info']['to_upgrade']
to_reinstall = self.plugin_data['pkgs_info']['to_reinstall']

# Modules to enable
self._process_entities(entities=[available_modules_to_enable],
Expand All @@ -196,6 +197,9 @@ def run(self):
self._process_entities(entities=to_install, op=self.base.install, entity_name='Package')
# Packages to be upgraded
self._process_entities(entities=to_upgrade, op=self.base.upgrade, entity_name='Package')
# Packages to be reinstalled
self._process_entities(entities=to_reinstall, op=self.base.reinstall, entity_name='Package')

self.base.distro_sync()

if self.opts.tid[0] == 'check':
Expand Down
1 change: 1 addition & 0 deletions repos/system_upgrade/common/libraries/dnfplugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ def build_plugin_data(target_repoids, debug, test, tasks, on_aws):
'to_install': tasks.to_install,
'to_remove': tasks.to_remove,
'to_upgrade': tasks.to_upgrade,
'to_reinstall': tasks.to_reinstall,
'modules_to_enable': ['{}:{}'.format(m.name, m.stream) for m in tasks.modules_to_enable],
},
'dnf_conf': {
Expand Down
1 change: 1 addition & 0 deletions repos/system_upgrade/common/models/rpmtransactiontasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class RpmTransactionTasks(Model):
to_keep = fields.List(fields.String(), default=[])
to_remove = fields.List(fields.String(), default=[])
to_upgrade = fields.List(fields.String(), default=[])
to_reinstall = fields.List(fields.String(), default=[])
modules_to_enable = fields.List(fields.Model(Module), default=[])
modules_to_reset = fields.List(fields.Model(Module), default=[])

Expand Down