- Requires leapp-framework 6.6+ - Initial implementation of upgrades on systems with configured Software RAID - Handle multipath device identification in upgrade environment - Fix upgrade incorrectly resuming during SELinux relabeling - Fix upgrades on systems with multiple LUKS devices - Fix upgrades for systems with /boot/efi on a Software RAID - Fix mount failures for FSTAB entries with the `nofail` option specified - Fix AVC errors triggered by registration to insight-client during the upgrade - Install the correct kernel for the source system kernel page size on ARM systems - Inhibit the upgrade when network devices configured with ifcfg files could depend on NM - Introduce rhui.obsolete_gpg_keys configuration option for the removal of obsoleted RPM GPG keys of RHUI Cloud providers - LiveMode: Fix upgrade getting stuck when the `.leapp_upgrade_failed` file exists - LiveMode: Fix system version determination in the upgrade environment on CentOS Stream - Fix target system initramfs containing outdated configuration files in some circumstances - Ensure SELinux is set to permissive mode during the upgrade even when enforcing=1 is set on the kernel cmdline - Fix source and target distribution names in /etc/migration-results - Fix upgrades with the RealTime kernel on CentOS Stream - Detect misconfigured kernel & systemd API mountpoints in FSTAB - Detect misconfigured /var/run on the source system - Unify behaviour of upgrades on systems with enabled CRB repositories and explicitly required CRB repositories by user during the upgrade - Drop the inconsistent report about the use of CRB (unsupported by Red Hat) repositories - Fix upgrade crashing when dnf repofiles contain URL encoded characters - Resolves: RHEL-3289, RHEL-17842, RHEL-36249, RHEL-56040, RHEL-56176, RHEL-60060, RHEL-76846, RHEL-104384, RHEL-145136, RHEL-148631, RHEL-162192, RHEL-185508
660 lines
29 KiB
Diff
660 lines
29 KiB
Diff
From beffa9b5decef2639af93adf014ca63071900e3e Mon Sep 17 00:00:00 2001
|
|
From: Benjamin Marzinski <bmarzins@redhat.com>
|
|
Date: Mon, 30 Mar 2026 18:39:57 -0400
|
|
Subject: [PATCH 057/108] multipath: Add MultipathUpgradeConfUpdate9to10
|
|
mpath_upgrade_conf_patcher actor
|
|
|
|
Removes deprecated defaults section options (config_dir, bindings_file,
|
|
wwids_file, prkeys_file) from multipath configuration files during the
|
|
RHEL 9 to RHEL 10 upgrade. Relocates secondary configs to
|
|
/etc/multipath/conf.d/ when config_dir is non-default, and creates
|
|
entries to move bindings, wwids, and prkeys files to their default
|
|
RHEL-10 locations.
|
|
|
|
Also make multipath_system_config_patcher create directories if they
|
|
don't already exist when copying files, to deal with the case where
|
|
config files need to be copied to /etc/multipath/conf.d, but it doesn't
|
|
exist.
|
|
|
|
Jira: RHEL-151509
|
|
|
|
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
---
|
|
.../libraries/system_config_patcher.py | 5 +
|
|
.../mpath_upgrade_conf_patcher/actor.py | 29 ++
|
|
.../libraries/mpathconfupdate.py | 143 ++++++++++
|
|
.../tests/files/after/all_deprecated.conf | 7 +
|
|
.../tests/files/after/has_config_dir.conf | 4 +
|
|
.../tests/files/after/has_files.conf | 6 +
|
|
.../after/secondary_with_deprecated.conf | 9 +
|
|
.../tests/files/before/all_deprecated.conf | 7 +
|
|
.../tests/files/before/empty.conf | 1 +
|
|
.../tests/files/before/has_config_dir.conf | 4 +
|
|
.../tests/files/before/has_files.conf | 6 +
|
|
.../tests/files/before/no_defaults.conf | 3 +
|
|
.../tests/files/before/no_deprecated.conf | 3 +
|
|
.../tests/files/before/secondary_simple.conf | 6 +
|
|
.../before/secondary_with_deprecated.conf | 9 +
|
|
.../tests/test_mpath_conf_update_9to10.py | 256 ++++++++++++++++++
|
|
16 files changed, 498 insertions(+)
|
|
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/actor.py
|
|
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/libraries/mpathconfupdate.py
|
|
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/after/all_deprecated.conf
|
|
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/after/has_config_dir.conf
|
|
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/after/has_files.conf
|
|
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/after/secondary_with_deprecated.conf
|
|
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/all_deprecated.conf
|
|
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/empty.conf
|
|
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/has_config_dir.conf
|
|
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/has_files.conf
|
|
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/no_defaults.conf
|
|
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/no_deprecated.conf
|
|
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/secondary_simple.conf
|
|
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/secondary_with_deprecated.conf
|
|
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/test_mpath_conf_update_9to10.py
|
|
|
|
diff --git a/repos/system_upgrade/common/actors/multipath/system_conf_patcher/libraries/system_config_patcher.py b/repos/system_upgrade/common/actors/multipath/system_conf_patcher/libraries/system_config_patcher.py
|
|
index 0d873322..0d1fd070 100644
|
|
--- a/repos/system_upgrade/common/actors/multipath/system_conf_patcher/libraries/system_config_patcher.py
|
|
+++ b/repos/system_upgrade/common/actors/multipath/system_conf_patcher/libraries/system_config_patcher.py
|
|
@@ -1,3 +1,4 @@
|
|
+import os
|
|
import shutil
|
|
|
|
from leapp.libraries.stdlib import api
|
|
@@ -14,4 +15,8 @@ def patch_system_configs():
|
|
)
|
|
)
|
|
|
|
+ os.makedirs(
|
|
+ os.path.dirname(modified_config.target_path),
|
|
+ exist_ok=True
|
|
+ )
|
|
shutil.copy(modified_config.updated_config_location, modified_config.target_path)
|
|
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/actor.py b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/actor.py
|
|
new file mode 100644
|
|
index 00000000..f72d2936
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/actor.py
|
|
@@ -0,0 +1,29 @@
|
|
+from leapp.actors import Actor
|
|
+from leapp.libraries.actor import mpathconfupdate
|
|
+from leapp.models import MultipathConfFacts9to10, MultipathConfigUpdatesInfo
|
|
+from leapp.tags import IPUWorkflowTag, TargetTransactionChecksPhaseTag
|
|
+
|
|
+
|
|
+class MultipathUpgradeConfUpdate9to10(Actor):
|
|
+ """
|
|
+ Modifies multipath configuration files for the RHEL-10 upgrade.
|
|
+
|
|
+ Removes deprecated options (config_dir, bindings_file, wwids_file,
|
|
+ prkeys_file) from multipath configuration files. If config_dir is
|
|
+ set to a non-default directory, ensures all secondary configs are
|
|
+ moved to /etc/multipath/conf.d/. Creates entries to relocate
|
|
+ bindings, wwids, and prkeys files to their default RHEL-10
|
|
+ locations if necessary.
|
|
+ """
|
|
+
|
|
+ name = 'multipath_upgrade_conf_update_9to10'
|
|
+ consumes = (MultipathConfFacts9to10,)
|
|
+ produces = (MultipathConfigUpdatesInfo,)
|
|
+ tags = (TargetTransactionChecksPhaseTag, IPUWorkflowTag)
|
|
+
|
|
+ def process(self):
|
|
+ facts = next(self.consume(MultipathConfFacts9to10), None)
|
|
+ if facts is None:
|
|
+ self.log.debug('Skipping execution. No MultipathConfFacts9to10 has been produced')
|
|
+ return
|
|
+ mpathconfupdate.update_configs(facts)
|
|
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/libraries/mpathconfupdate.py b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/libraries/mpathconfupdate.py
|
|
new file mode 100644
|
|
index 00000000..a2e3bafc
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/libraries/mpathconfupdate.py
|
|
@@ -0,0 +1,143 @@
|
|
+import os
|
|
+import shutil
|
|
+
|
|
+from leapp.libraries.common import multipathutil
|
|
+from leapp.libraries.stdlib import api
|
|
+from leapp.models import MultipathConfigUpdatesInfo, UpdatedMultipathConfig
|
|
+
|
|
+MODIFICATIONS_STORE_PATH = '/var/lib/leapp/proposed_modifications'
|
|
+
|
|
+_DEFAULT_CONFIG_DIR = '/etc/multipath/conf.d'
|
|
+_DEFAULT_BINDINGS_FILE = '/etc/multipath/bindings'
|
|
+_DEFAULT_WWIDS_FILE = '/etc/multipath/wwids'
|
|
+_DEFAULT_PRKEYS_FILE = '/etc/multipath/prkeys'
|
|
+
|
|
+_deprecated_options = ('config_dir', 'bindings_file', 'wwids_file', 'prkeys_file')
|
|
+
|
|
+
|
|
+def _update_config(config):
|
|
+ contents = multipathutil.read_config(config.pathname)
|
|
+ if contents is None:
|
|
+ return None
|
|
+ lines = contents.split('\n')
|
|
+
|
|
+ section = None
|
|
+ in_subsection = False
|
|
+ updated_file = False
|
|
+ comment_lines = []
|
|
+ for i, line in enumerate(lines):
|
|
+ try:
|
|
+ data = multipathutil.LineData(line, section, in_subsection)
|
|
+ except ValueError:
|
|
+ continue
|
|
+ if data.type == data.TYPE_SECTION_END:
|
|
+ if in_subsection:
|
|
+ in_subsection = False
|
|
+ elif section is not None:
|
|
+ section = None
|
|
+ elif data.type == data.TYPE_SECTION_START:
|
|
+ if section is None:
|
|
+ section = data.section
|
|
+ elif not in_subsection:
|
|
+ in_subsection = True
|
|
+ elif data.type == data.TYPE_OPTION:
|
|
+ if section == 'defaults' and data.option in _deprecated_options:
|
|
+ comment_lines.append(i)
|
|
+ updated_file = True
|
|
+
|
|
+ if not updated_file:
|
|
+ return None
|
|
+
|
|
+ for i in reversed(comment_lines):
|
|
+ lines[i] = '#{} # line commented out by leapp'.format(lines[i])
|
|
+
|
|
+ return '\n'.join(lines)
|
|
+
|
|
+
|
|
+def _get_file_locations(facts):
|
|
+ bindings_file = None
|
|
+ wwids_file = None
|
|
+ prkeys_file = None
|
|
+ for conf in facts.configs:
|
|
+ if conf.bindings_file is not None:
|
|
+ bindings_file = os.path.normpath(conf.bindings_file)
|
|
+ if conf.wwids_file is not None:
|
|
+ wwids_file = os.path.normpath(conf.wwids_file)
|
|
+ if conf.prkeys_file is not None:
|
|
+ prkeys_file = os.path.normpath(conf.prkeys_file)
|
|
+
|
|
+ file_updates = []
|
|
+ if bindings_file is not None and bindings_file != _DEFAULT_BINDINGS_FILE:
|
|
+ file_updates.append((bindings_file, _DEFAULT_BINDINGS_FILE))
|
|
+ if wwids_file is not None and wwids_file != _DEFAULT_WWIDS_FILE:
|
|
+ file_updates.append((wwids_file, _DEFAULT_WWIDS_FILE))
|
|
+ if prkeys_file is not None and prkeys_file != _DEFAULT_PRKEYS_FILE:
|
|
+ file_updates.append((prkeys_file, _DEFAULT_PRKEYS_FILE))
|
|
+ return file_updates
|
|
+
|
|
+
|
|
+def prepare_destination_for_file(file_path):
|
|
+ dirname = os.path.dirname(file_path)
|
|
+ os.makedirs(dirname, exist_ok=True)
|
|
+
|
|
+
|
|
+def prepare_place_for_config_modifications(workspace_path=MODIFICATIONS_STORE_PATH):
|
|
+ if os.path.exists(workspace_path):
|
|
+ shutil.rmtree(workspace_path)
|
|
+ os.mkdir(workspace_path)
|
|
+
|
|
+
|
|
+def update_configs(facts):
|
|
+ if not facts.configs:
|
|
+ return
|
|
+
|
|
+ config_updates = []
|
|
+ prepare_place_for_config_modifications()
|
|
+
|
|
+ primary = facts.configs[0]
|
|
+ non_default_config_dir = (
|
|
+ primary.config_dir is not None
|
|
+ and os.path.normpath(primary.config_dir) != _DEFAULT_CONFIG_DIR
|
|
+ )
|
|
+
|
|
+ for idx, config in enumerate(facts.configs):
|
|
+ is_secondary = idx > 0
|
|
+
|
|
+ if is_secondary:
|
|
+ target_path = os.path.join(
|
|
+ _DEFAULT_CONFIG_DIR, os.path.basename(config.pathname)
|
|
+ )
|
|
+ else:
|
|
+ target_path = config.pathname
|
|
+
|
|
+ contents = _update_config(config)
|
|
+
|
|
+ if contents is not None:
|
|
+ rootless_path = config.pathname.lstrip('/')
|
|
+ updated_config_location = os.path.join(
|
|
+ MODIFICATIONS_STORE_PATH, rootless_path
|
|
+ )
|
|
+ api.current_logger().debug(
|
|
+ 'Instead of modifying {}, preparing modified config at {}'.format(
|
|
+ config.pathname, updated_config_location
|
|
+ )
|
|
+ )
|
|
+ prepare_destination_for_file(updated_config_location)
|
|
+ multipathutil.write_config(updated_config_location, contents)
|
|
+ config_updates.append(UpdatedMultipathConfig(
|
|
+ updated_config_location=updated_config_location,
|
|
+ target_path=target_path
|
|
+ ))
|
|
+ elif is_secondary and non_default_config_dir:
|
|
+ config_updates.append(UpdatedMultipathConfig(
|
|
+ updated_config_location=config.pathname,
|
|
+ target_path=target_path
|
|
+ ))
|
|
+
|
|
+ for source_path, default_path in _get_file_locations(facts):
|
|
+ config_updates.append(UpdatedMultipathConfig(
|
|
+ updated_config_location=source_path,
|
|
+ target_path=default_path
|
|
+ ))
|
|
+
|
|
+ api.produce(MultipathConfigUpdatesInfo(updates=config_updates))
|
|
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/after/all_deprecated.conf b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/after/all_deprecated.conf
|
|
new file mode 100644
|
|
index 00000000..7489ed9e
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/after/all_deprecated.conf
|
|
@@ -0,0 +1,7 @@
|
|
+defaults {
|
|
+ polling_interval 5
|
|
+# config_dir "/etc/multipath/custom.d" # line commented out by leapp
|
|
+# bindings_file "/tmp/bindings" # line commented out by leapp
|
|
+# wwids_file "/tmp/wwids" # line commented out by leapp
|
|
+# prkeys_file "/tmp/prkeys" # line commented out by leapp
|
|
+}
|
|
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/after/has_config_dir.conf b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/after/has_config_dir.conf
|
|
new file mode 100644
|
|
index 00000000..94c54ded
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/after/has_config_dir.conf
|
|
@@ -0,0 +1,4 @@
|
|
+defaults {
|
|
+ polling_interval 5
|
|
+# config_dir "/etc/multipath/custom.d" # line commented out by leapp
|
|
+}
|
|
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/after/has_files.conf b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/after/has_files.conf
|
|
new file mode 100644
|
|
index 00000000..fb74a86e
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/after/has_files.conf
|
|
@@ -0,0 +1,6 @@
|
|
+defaults {
|
|
+ polling_interval 5
|
|
+# bindings_file "/tmp/bindings" # line commented out by leapp
|
|
+# wwids_file "/tmp/wwids" # line commented out by leapp
|
|
+# prkeys_file "/tmp/prkeys" # line commented out by leapp
|
|
+}
|
|
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/after/secondary_with_deprecated.conf b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/after/secondary_with_deprecated.conf
|
|
new file mode 100644
|
|
index 00000000..68bfcfca
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/after/secondary_with_deprecated.conf
|
|
@@ -0,0 +1,9 @@
|
|
+defaults {
|
|
+# bindings_file "/tmp/bindings" # line commented out by leapp
|
|
+}
|
|
+devices {
|
|
+ device {
|
|
+ vendor "VENDOR"
|
|
+ product "PRODUCT"
|
|
+ }
|
|
+}
|
|
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/all_deprecated.conf b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/all_deprecated.conf
|
|
new file mode 100644
|
|
index 00000000..15e39d34
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/all_deprecated.conf
|
|
@@ -0,0 +1,7 @@
|
|
+defaults {
|
|
+ polling_interval 5
|
|
+ config_dir "/etc/multipath/custom.d"
|
|
+ bindings_file "/tmp/bindings"
|
|
+ wwids_file "/tmp/wwids"
|
|
+ prkeys_file "/tmp/prkeys"
|
|
+}
|
|
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/empty.conf b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/empty.conf
|
|
new file mode 100644
|
|
index 00000000..8b137891
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/empty.conf
|
|
@@ -0,0 +1 @@
|
|
+
|
|
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/has_config_dir.conf b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/has_config_dir.conf
|
|
new file mode 100644
|
|
index 00000000..7e8295ee
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/has_config_dir.conf
|
|
@@ -0,0 +1,4 @@
|
|
+defaults {
|
|
+ polling_interval 5
|
|
+ config_dir "/etc/multipath/custom.d"
|
|
+}
|
|
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/has_files.conf b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/has_files.conf
|
|
new file mode 100644
|
|
index 00000000..9404312b
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/has_files.conf
|
|
@@ -0,0 +1,6 @@
|
|
+defaults {
|
|
+ polling_interval 5
|
|
+ bindings_file "/tmp/bindings"
|
|
+ wwids_file "/tmp/wwids"
|
|
+ prkeys_file "/tmp/prkeys"
|
|
+}
|
|
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/no_defaults.conf b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/no_defaults.conf
|
|
new file mode 100644
|
|
index 00000000..dfc28f43
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/no_defaults.conf
|
|
@@ -0,0 +1,3 @@
|
|
+blacklist {
|
|
+ devnode "^sd[a-z]"
|
|
+}
|
|
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/no_deprecated.conf b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/no_deprecated.conf
|
|
new file mode 100644
|
|
index 00000000..8c0e1510
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/no_deprecated.conf
|
|
@@ -0,0 +1,3 @@
|
|
+defaults {
|
|
+ polling_interval 5
|
|
+}
|
|
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/secondary_simple.conf b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/secondary_simple.conf
|
|
new file mode 100644
|
|
index 00000000..092e7cdc
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/secondary_simple.conf
|
|
@@ -0,0 +1,6 @@
|
|
+devices {
|
|
+ device {
|
|
+ vendor "VENDOR"
|
|
+ product "PRODUCT"
|
|
+ }
|
|
+}
|
|
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/secondary_with_deprecated.conf b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/secondary_with_deprecated.conf
|
|
new file mode 100644
|
|
index 00000000..534c6f07
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/files/before/secondary_with_deprecated.conf
|
|
@@ -0,0 +1,9 @@
|
|
+defaults {
|
|
+ bindings_file "/tmp/bindings"
|
|
+}
|
|
+devices {
|
|
+ device {
|
|
+ vendor "VENDOR"
|
|
+ product "PRODUCT"
|
|
+ }
|
|
+}
|
|
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/test_mpath_conf_update_9to10.py b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/test_mpath_conf_update_9to10.py
|
|
new file mode 100644
|
|
index 00000000..ad6668b9
|
|
--- /dev/null
|
|
+++ b/repos/system_upgrade/el9toel10/actors/multipath/mpath_upgrade_conf_patcher/tests/test_mpath_conf_update_9to10.py
|
|
@@ -0,0 +1,256 @@
|
|
+import os
|
|
+
|
|
+import pytest
|
|
+
|
|
+from leapp.libraries.actor import mpathconfupdate
|
|
+from leapp.libraries.common import multipathutil
|
|
+from leapp.libraries.common.testutils import CurrentActorMocked, produce_mocked
|
|
+from leapp.libraries.stdlib import api
|
|
+from leapp.models import MultipathConfFacts9to10, MultipathConfig9to10
|
|
+
|
|
+BEFORE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files/before')
|
|
+AFTER_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files/after')
|
|
+
|
|
+
|
|
+def build_config(pathname, config_dir=None, bindings_file=None,
|
|
+ wwids_file=None, prkeys_file=None):
|
|
+ return MultipathConfig9to10(
|
|
+ pathname=pathname,
|
|
+ config_dir=config_dir,
|
|
+ bindings_file=bindings_file,
|
|
+ wwids_file=wwids_file,
|
|
+ prkeys_file=prkeys_file,
|
|
+ )
|
|
+
|
|
+
|
|
+def build_facts(confs):
|
|
+ return MultipathConfFacts9to10(configs=confs)
|
|
+
|
|
+
|
|
+def mock_read_config(path):
|
|
+ return multipathutil.read_config_orig(os.path.join(BEFORE_DIR, path))
|
|
+
|
|
+
|
|
+# Configs with no changes needed
|
|
+no_deprecated_conf = build_config('no_deprecated.conf')
|
|
+empty_conf = build_config('empty.conf')
|
|
+no_defaults_conf = build_config('no_defaults.conf')
|
|
+
|
|
+# Configs with deprecated options
|
|
+has_config_dir_conf = build_config(
|
|
+ 'has_config_dir.conf', config_dir='/etc/multipath/custom.d')
|
|
+has_files_conf = build_config(
|
|
+ 'has_files.conf', bindings_file='/tmp/bindings',
|
|
+ wwids_file='/tmp/wwids', prkeys_file='/tmp/prkeys')
|
|
+all_deprecated_conf = build_config(
|
|
+ 'all_deprecated.conf', config_dir='/etc/multipath/custom.d',
|
|
+ bindings_file='/tmp/bindings', wwids_file='/tmp/wwids',
|
|
+ prkeys_file='/tmp/prkeys')
|
|
+
|
|
+# Secondary configs
|
|
+secondary_simple_conf = build_config('secondary_simple.conf')
|
|
+secondary_with_deprecated_conf = build_config(
|
|
+ 'secondary_with_deprecated.conf', bindings_file='/tmp/bindings')
|
|
+
|
|
+
|
|
+@pytest.mark.parametrize(
|
|
+ 'config_facts',
|
|
+ [
|
|
+ build_facts([no_deprecated_conf]),
|
|
+ build_facts([empty_conf]),
|
|
+ build_facts([no_defaults_conf]),
|
|
+ build_facts([has_config_dir_conf]),
|
|
+ build_facts([has_files_conf]),
|
|
+ build_facts([all_deprecated_conf]),
|
|
+ build_facts([has_config_dir_conf, secondary_simple_conf]),
|
|
+ build_facts([has_config_dir_conf, secondary_with_deprecated_conf]),
|
|
+ build_facts([no_deprecated_conf, secondary_simple_conf]),
|
|
+ build_facts([no_deprecated_conf, secondary_with_deprecated_conf]),
|
|
+ ]
|
|
+)
|
|
+def test_all_facts(monkeypatch, config_facts):
|
|
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked())
|
|
+
|
|
+ produce_mock = produce_mocked()
|
|
+ monkeypatch.setattr(api, 'produce', produce_mock)
|
|
+
|
|
+ config_writes = {}
|
|
+
|
|
+ def write_config_mock(location, contents):
|
|
+ config_writes[location] = contents
|
|
+
|
|
+ monkeypatch.setattr(multipathutil, 'read_config_orig', multipathutil.read_config, raising=False)
|
|
+ monkeypatch.setattr(multipathutil, 'read_config', mock_read_config)
|
|
+ monkeypatch.setattr(multipathutil, 'write_config', write_config_mock)
|
|
+ monkeypatch.setattr(mpathconfupdate, 'prepare_destination_for_file', lambda file_path: None)
|
|
+ monkeypatch.setattr(mpathconfupdate, 'prepare_place_for_config_modifications', lambda: None)
|
|
+
|
|
+ mpathconfupdate.update_configs(config_facts)
|
|
+
|
|
+ config_updates = {}
|
|
+ for config_updates_msg in produce_mock.model_instances:
|
|
+ for update in config_updates_msg.updates:
|
|
+ config_updates[update.target_path] = update.updated_config_location
|
|
+
|
|
+ primary = config_facts.configs[0]
|
|
+ non_default_config_dir = (
|
|
+ primary.config_dir is not None
|
|
+ and os.path.normpath(primary.config_dir) != '/etc/multipath/conf.d'
|
|
+ )
|
|
+
|
|
+ for idx, config in enumerate(config_facts.configs):
|
|
+ is_secondary = idx > 0
|
|
+
|
|
+ if is_secondary:
|
|
+ target_path = os.path.join(
|
|
+ '/etc/multipath/conf.d', os.path.basename(config.pathname)
|
|
+ )
|
|
+ else:
|
|
+ target_path = config.pathname
|
|
+
|
|
+ expected_conf_location = os.path.join(AFTER_DIR, config.pathname)
|
|
+
|
|
+ if target_path not in config_updates:
|
|
+ # No update for this config - verify no expected after file exists
|
|
+ # and it's not a secondary that should have been relocated
|
|
+ assert not os.path.exists(expected_conf_location)
|
|
+ assert not (is_secondary and non_default_config_dir)
|
|
+ continue
|
|
+
|
|
+ updated_config_location = config_updates[target_path]
|
|
+
|
|
+ if os.path.exists(expected_conf_location):
|
|
+ # Config was modified - check contents
|
|
+ assert updated_config_location in config_writes
|
|
+ actual_contents = config_writes[updated_config_location]
|
|
+
|
|
+ updated_config_expected_location = os.path.join(
|
|
+ mpathconfupdate.MODIFICATIONS_STORE_PATH,
|
|
+ config.pathname.lstrip('/')
|
|
+ )
|
|
+ assert updated_config_location == updated_config_expected_location
|
|
+
|
|
+ expected_contents = multipathutil.read_config_orig(expected_conf_location)
|
|
+ assert actual_contents == expected_contents
|
|
+ else:
|
|
+ # Unmodified secondary relocated - source is original path
|
|
+ assert updated_config_location == config.pathname
|
|
+
|
|
+
|
|
+def test_file_relocation(monkeypatch):
|
|
+ """Check that non-default file locations produce UpdatedMultipathConfig entries."""
|
|
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked())
|
|
+
|
|
+ produce_mock = produce_mocked()
|
|
+ monkeypatch.setattr(api, 'produce', produce_mock)
|
|
+
|
|
+ monkeypatch.setattr(multipathutil, 'read_config_orig', multipathutil.read_config, raising=False)
|
|
+ monkeypatch.setattr(multipathutil, 'read_config', mock_read_config)
|
|
+ monkeypatch.setattr(multipathutil, 'write_config', lambda loc, contents: None)
|
|
+ monkeypatch.setattr(mpathconfupdate, 'prepare_destination_for_file', lambda file_path: None)
|
|
+ monkeypatch.setattr(mpathconfupdate, 'prepare_place_for_config_modifications', lambda: None)
|
|
+
|
|
+ facts = build_facts([has_files_conf])
|
|
+ mpathconfupdate.update_configs(facts)
|
|
+
|
|
+ file_updates = {}
|
|
+ for config_updates_msg in produce_mock.model_instances:
|
|
+ for update in config_updates_msg.updates:
|
|
+ file_updates[update.target_path] = update.updated_config_location
|
|
+
|
|
+ assert file_updates['/etc/multipath/bindings'] == '/tmp/bindings'
|
|
+ assert file_updates['/etc/multipath/wwids'] == '/tmp/wwids'
|
|
+ assert file_updates['/etc/multipath/prkeys'] == '/tmp/prkeys'
|
|
+
|
|
+
|
|
+def test_default_file_locations_no_relocation(monkeypatch):
|
|
+ """Check that default file locations don't produce relocation entries."""
|
|
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked())
|
|
+
|
|
+ produce_mock = produce_mocked()
|
|
+ monkeypatch.setattr(api, 'produce', produce_mock)
|
|
+
|
|
+ conf = build_config(
|
|
+ 'has_files.conf',
|
|
+ bindings_file='/etc/multipath/bindings',
|
|
+ wwids_file='/etc/multipath/wwids',
|
|
+ prkeys_file='/etc/multipath/prkeys',
|
|
+ )
|
|
+
|
|
+ monkeypatch.setattr(multipathutil, 'read_config_orig', multipathutil.read_config, raising=False)
|
|
+ monkeypatch.setattr(multipathutil, 'read_config', mock_read_config)
|
|
+ monkeypatch.setattr(multipathutil, 'write_config', lambda loc, contents: None)
|
|
+ monkeypatch.setattr(mpathconfupdate, 'prepare_destination_for_file', lambda file_path: None)
|
|
+ monkeypatch.setattr(mpathconfupdate, 'prepare_place_for_config_modifications', lambda: None)
|
|
+
|
|
+ facts = build_facts([conf])
|
|
+ mpathconfupdate.update_configs(facts)
|
|
+
|
|
+ file_targets = set()
|
|
+ for config_updates_msg in produce_mock.model_instances:
|
|
+ for update in config_updates_msg.updates:
|
|
+ file_targets.add(update.target_path)
|
|
+
|
|
+ # Config itself is modified (has deprecated options in before file), but no file relocations
|
|
+ assert '/etc/multipath/bindings' not in file_targets
|
|
+ assert '/etc/multipath/wwids' not in file_targets
|
|
+ assert '/etc/multipath/prkeys' not in file_targets
|
|
+
|
|
+
|
|
+def test_last_value_wins_for_files(monkeypatch):
|
|
+ """Check that the last non-None value wins for file locations."""
|
|
+ monkeypatch.setattr(api, 'current_actor', CurrentActorMocked())
|
|
+
|
|
+ produce_mock = produce_mocked()
|
|
+ monkeypatch.setattr(api, 'produce', produce_mock)
|
|
+
|
|
+ primary = build_config(
|
|
+ 'no_deprecated.conf', bindings_file='/first/bindings')
|
|
+ secondary = build_config(
|
|
+ 'secondary_simple.conf', bindings_file='/second/bindings')
|
|
+
|
|
+ monkeypatch.setattr(multipathutil, 'read_config_orig', multipathutil.read_config, raising=False)
|
|
+ monkeypatch.setattr(multipathutil, 'read_config', mock_read_config)
|
|
+ monkeypatch.setattr(multipathutil, 'write_config', lambda loc, contents: None)
|
|
+ monkeypatch.setattr(mpathconfupdate, 'prepare_destination_for_file', lambda file_path: None)
|
|
+ monkeypatch.setattr(mpathconfupdate, 'prepare_place_for_config_modifications', lambda: None)
|
|
+
|
|
+ facts = build_facts([primary, secondary])
|
|
+ mpathconfupdate.update_configs(facts)
|
|
+
|
|
+ file_updates = {}
|
|
+ for config_updates_msg in produce_mock.model_instances:
|
|
+ for update in config_updates_msg.updates:
|
|
+ file_updates[update.target_path] = update.updated_config_location
|
|
+
|
|
+ # Last value (/second/bindings) should win
|
|
+ assert file_updates['/etc/multipath/bindings'] == '/second/bindings'
|
|
+
|
|
+
|
|
+def test_proposed_config_updates_store(monkeypatch):
|
|
+ """Check whether configs are being stored in the expected path."""
|
|
+ config = MultipathConfig9to10(
|
|
+ pathname='/etc/multipath.conf.d/xy.conf',
|
|
+ config_dir='',
|
|
+ )
|
|
+
|
|
+ produce_mock = produce_mocked()
|
|
+ monkeypatch.setattr(api, 'produce', produce_mock)
|
|
+
|
|
+ monkeypatch.setattr(multipathutil, 'write_config', lambda loc, contents: None)
|
|
+ monkeypatch.setattr(mpathconfupdate, '_update_config', lambda *args: 'new config content')
|
|
+ monkeypatch.setattr(mpathconfupdate, 'prepare_destination_for_file', lambda file_path: None)
|
|
+ monkeypatch.setattr(mpathconfupdate, 'prepare_place_for_config_modifications', lambda: None)
|
|
+
|
|
+ mpathconfupdate.update_configs(MultipathConfFacts9to10(configs=[config]))
|
|
+
|
|
+ expected_updated_config_path = os.path.join(
|
|
+ mpathconfupdate.MODIFICATIONS_STORE_PATH,
|
|
+ 'etc/multipath.conf.d/xy.conf'
|
|
+ )
|
|
+ found = False
|
|
+ for config_updates_msg in produce_mock.model_instances:
|
|
+ for update in config_updates_msg.updates:
|
|
+ if update.updated_config_location == expected_updated_config_path:
|
|
+ found = True
|
|
+ assert found
|
|
--
|
|
2.54.0
|
|
|