leapp-repository/0055-multipath-Add-MultipathConfRead9to10-config_reader-a.patch
karolinku dc04575ed7 IPU 9.9 -> 10.3: CTC2 candidate 1
- Requires leapp-framework 6.6+
- Initial implementation of upgrades on systems with configured Software RAID
- Include multipath related configuration in the upgrade environment
- Fix upgrades on systems with multiple LUKS devices
- Fix upgrades for systems with /boot/efi on a Software RAID
- Fix upgrade crashing when dnf repofiles contain URL encoded characters
- Fix mount failures for FSTAB entries with the `nofail` option specified
- Fix upgrade incorrectly resuming during SELinux relabeling
- Fix AVC SELinux warnings
- 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
- Inhibit the upgrade when network devices configured with ifcfg files could depend on NM
- 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
- Install the correct kernel for the source system kernel page size on ARM systems
- Introduce rhui.obsolete_gpg_keys configuration option for the removal of obsoleted RPM GPG keys of RHUI Cloud providers
- 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
- Check and migrate the multipath configuration when possible
- Fix unwanted suspend mode after 15min of inactivity after the upgrade on systems with graphical environment
- Resolves: RHEL-111860, RHEL-115867, RHEL-121205, RHEL-147438, RHEL-148697, RHEL-151509,
 RHEL-154369, RHEL-154370, RHEL-156580, RHEL-161560, RHEL-161684, RHEL-174874
2026-06-25 18:48:05 +02:00

1898 lines
54 KiB
Diff

From 7ff626243366a4ffaaf972f12e8a4d7708c06040 Mon Sep 17 00:00:00 2001
From: Benjamin Marzinski <bmarzins@redhat.com>
Date: Wed, 18 Mar 2026 20:51:05 -0400
Subject: [PATCH 055/105] multipath: Add MultipathConfRead9to10 config_reader
actor
Add the el9toel10 config_reader actor that scans multipath configuration
and produces MultipathInfo and MultipathConfFacts9to10 messages. The actor
detects getuid_callout usage, socket activation, DM NVMe multipathing,
and tracks config_dir/bindings_file/wwids_file/prkeys_file settings.
Also keep target_uspace_configs from automatically copying the old
config_dir, if it isn't in the default location in an el9toel10 upgrade.
the old config_dir will always be copied in an el8toel9 upgrade.
Jira: RHEL-151509
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
.../target_uspace_multipath_configs.py | 2 +-
.../actors/multipath/config_reader/actor.py | 25 +
.../libraries/multipathconfread.py | 138 ++
.../tests/files/all_options.conf | 9 +
.../tests/files/all_set_in_dir.conf | 5 +
.../tests/files/complicated.conf | 1136 +++++++++++++++++
.../tests/files/conf1.d/bindings_set.conf | 3 +
.../tests/files/conf1.d/empty.conf | 1 +
.../tests/files/conf2.d/getuid_set.conf | 11 +
.../tests/files/conf2.d/set_files.conf | 5 +
.../config_reader/tests/files/conf3.d/README | 1 +
.../config_reader/tests/files/config_dir.conf | 5 +
.../tests/files/default_rhel9.conf | 21 +
.../config_reader/tests/files/empty.conf | 1 +
.../config_reader/tests/files/empty_dir.conf | 5 +
.../tests/files/extra_slash.conf | 5 +
.../tests/files/getuid_defaults.conf | 5 +
.../tests/files/getuid_devices.conf | 12 +
.../tests/files/getuid_overrides.conf | 8 +
.../tests/files/missing_dir.conf | 5 +
.../tests/files/no_defaults.conf | 7 +
.../tests/test_multipath_conf_read_9to10.py | 283 ++++
22 files changed, 1692 insertions(+), 1 deletion(-)
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/actor.py
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/libraries/multipathconfread.py
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/all_options.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/all_set_in_dir.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/complicated.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf1.d/bindings_set.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf1.d/empty.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf2.d/getuid_set.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf2.d/set_files.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf3.d/README
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/config_dir.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/default_rhel9.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/empty.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/empty_dir.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/extra_slash.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/getuid_defaults.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/getuid_devices.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/getuid_overrides.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/missing_dir.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/no_defaults.conf
create mode 100644 repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/test_multipath_conf_read_9to10.py
diff --git a/repos/system_upgrade/common/actors/multipath/target_uspace_configs/libraries/target_uspace_multipath_configs.py b/repos/system_upgrade/common/actors/multipath/target_uspace_configs/libraries/target_uspace_multipath_configs.py
index 72afc477..bc685fa2 100644
--- a/repos/system_upgrade/common/actors/multipath/target_uspace_configs/libraries/target_uspace_multipath_configs.py
+++ b/repos/system_upgrade/common/actors/multipath/target_uspace_configs/libraries/target_uspace_multipath_configs.py
@@ -22,7 +22,7 @@ def request_mpath_confs(multipath_info):
'/etc/multipath.conf': '/etc/multipath.conf' # default config
}
- if os.path.exists(multipath_info.config_dir):
+ if multipath_info.config_dir and os.path.exists(multipath_info.config_dir):
for filename in os.listdir(multipath_info.config_dir):
config_path = os.path.join(multipath_info.config_dir, filename)
if not config_path.endswith('.conf'):
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/actor.py b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/actor.py
new file mode 100644
index 00000000..2b122fdd
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/actor.py
@@ -0,0 +1,25 @@
+from leapp.actors import Actor
+from leapp.libraries.actor import multipathconfread
+from leapp.models import DistributionSignedRPM, MultipathConfFacts9to10, MultipathInfo
+from leapp.tags import FactsPhaseTag, IPUWorkflowTag
+
+
+class MultipathConfRead9to10(Actor):
+ """
+ Read multipath configuration files and extract the necessary information
+
+ Related files:
+ - /etc/multipath.conf
+ - /etc/multipath/ - any files inside the directory
+
+ Produces MultipathInfo with general information about multipath, and
+ MultipathConfFacts9to10 with details needed for the 9 to 10 upgrade.
+ """
+
+ name = 'multipath_conf_read_9to10'
+ consumes = (DistributionSignedRPM,)
+ produces = (MultipathInfo, MultipathConfFacts9to10)
+ tags = (FactsPhaseTag, IPUWorkflowTag)
+
+ def process(self):
+ multipathconfread.scan_and_emit_multipath_info()
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/libraries/multipathconfread.py b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/libraries/multipathconfread.py
new file mode 100644
index 00000000..50c87d86
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/libraries/multipathconfread.py
@@ -0,0 +1,138 @@
+import errno
+import os
+
+from leapp.libraries.common import multipathutil
+from leapp.libraries.common.rpms import has_package
+from leapp.libraries.stdlib import api
+from leapp.models import DistributionSignedRPM, MultipathConfFacts9to10, MultipathConfig9to10, MultipathInfo
+
+
+def _parse_config(path):
+ contents = multipathutil.read_config(path)
+ if contents is None:
+ return None
+ conf = MultipathConfig9to10(pathname=path)
+ section = None
+ in_subsection = False
+ for line in contents.split('\n'):
+ try:
+ data = multipathutil.LineData(line, section, in_subsection)
+ except ValueError:
+ continue
+ if data.type == data.TYPE_BLANK:
+ continue
+ if data.type == data.TYPE_SECTION_END:
+ if in_subsection:
+ in_subsection = False
+ elif section:
+ section = None
+ continue
+ if data.type == data.TYPE_SECTION_START:
+ if not section:
+ section = data.section
+ elif not in_subsection:
+ in_subsection = True
+ continue
+ if data.type != data.TYPE_OPTION:
+ continue
+ if section == 'defaults':
+ if data.option == 'config_dir':
+ conf.config_dir = data.value
+ elif data.option == 'bindings_file':
+ conf.bindings_file = data.value
+ elif data.option == 'wwids_file':
+ conf.wwids_file = data.value
+ elif data.option == 'prkeys_file':
+ conf.prkeys_file = data.value
+ if data.option == 'getuid_callout':
+ conf.has_getuid = True
+ return conf
+
+
+def _parse_config_dir(config_dir):
+ res = []
+ try:
+ for config_file in sorted(os.listdir(config_dir)):
+ path = os.path.join(config_dir, config_file)
+ if not path.endswith('.conf'):
+ continue
+ conf = _parse_config(path)
+ if conf:
+ res.append(conf)
+ except OSError as e:
+ if e.errno == errno.ENOENT:
+ api.current_logger().debug(
+ 'Multipath conf directory "%s" doesn\'t exist',
+ config_dir
+ )
+ else:
+ api.current_logger().warning(
+ 'Failed to read multipath config directory "%s": %s',
+ config_dir,
+ e
+ )
+ return res
+
+
+def _check_socket_activation():
+ return os.path.exists(
+ '/etc/systemd/system/sockets.target.wants/multipathd.socket'
+ )
+
+
+def _check_dm_nvme_multipathing():
+ if not os.path.isdir('/sys/module/nvme_core'):
+ return False
+ try:
+ with open('/sys/module/nvme_core/parameters/multipath', 'r') as f:
+ content = f.read().strip()
+ except IOError:
+ return False
+ return content == 'N'
+
+
+def is_processable():
+ res = has_package(DistributionSignedRPM, 'device-mapper-multipath')
+ if not res:
+ api.current_logger().debug('device-mapper-multipath is not installed.')
+ return res
+
+
+def scan_and_emit_multipath_info(default_config_path='/etc/multipath.conf'):
+ if not is_processable():
+ return
+
+ primary_config = _parse_config(default_config_path)
+ if not primary_config:
+ api.current_logger().debug(
+ 'Primary multipath config /etc/multipath.conf is not present - multipath '
+ 'is not used.'
+ )
+ mpath_info = MultipathInfo(is_configured=False)
+ api.produce(mpath_info)
+ return
+
+ multipath_info = MultipathInfo(is_configured=True)
+ # Do not set multipath_info.config_dir to a non-default directory,
+ # otherwise any files that exist there will be copied to that directory
+ # during the upgrade. Also don't set it to the default directory if you
+ # aren't reading config files from there. The directory may exist and have
+ # config files which are not used in the existing config, and should not
+ # be copied.
+ if (
+ not primary_config.config_dir or
+ os.path.normpath(primary_config.config_dir) == '/etc/multipath/conf.d'
+ ):
+ multipath_info.config_dir = '/etc/multipath/conf.d'
+ api.produce(multipath_info)
+
+ primary_config.has_socket_activation = _check_socket_activation()
+ primary_config.has_dm_nvme_multipathing = _check_dm_nvme_multipathing()
+
+ secondary_configs = _parse_config_dir(
+ primary_config.config_dir or '/etc/multipath/conf.d'
+ )
+ all_configs = [primary_config] + secondary_configs
+
+ config_facts_for_9to10 = MultipathConfFacts9to10(configs=all_configs)
+ api.produce(config_facts_for_9to10)
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/all_options.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/all_options.conf
new file mode 100644
index 00000000..cf72bf24
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/all_options.conf
@@ -0,0 +1,9 @@
+defaults {
+ user_friendly_names yes
+ find_multipaths yes
+ config_dir "/etc/multipath/conf.d"
+ bindings_file "/etc/multipath/bindings"
+ wwids_file "/etc/multipath/wwids"
+ prkeys_file "/etc/multipath/prkeys"
+ getuid_callout "/lib/udev/scsi_id --whitelisted --device=/dev/%n"
+}
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/all_set_in_dir.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/all_set_in_dir.conf
new file mode 100644
index 00000000..d9698c0a
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/all_set_in_dir.conf
@@ -0,0 +1,5 @@
+defaults {
+ user_friendly_names yes
+ find_multipaths yes
+ config_dir "conf2.d"
+}
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/complicated.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/complicated.conf
new file mode 100644
index 00000000..368e7d91
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/complicated.conf
@@ -0,0 +1,1136 @@
+defaults {
+ verbosity 2
+ polling_interval 5
+ max_polling_interval 20
+ reassign_maps "no"
+ multipath_dir "/lib64/multipath"
+ path_selector "service-time 0"
+ path_grouping_policy "failover"
+ uid_attribute "ID_SERIAL"
+ prio "const"
+ prio_args ""
+ features "0"
+ path_checker "tur"
+ alias_prefix "mpath"
+ failback "manual"
+ rr_min_io 1000
+ rr_min_io_rq 1
+ max_fds "max"
+ rr_weight "uniform"
+ queue_without_daemon "no"
+ allow_usb_devices "no"
+ flush_on_last_del "unused"
+ user_friendly_names "yes"
+ fast_io_fail_tmo 5
+ bindings_file "/etc/multipath/bindings"
+ wwids_file "/etc/multipath/wwids"
+ prkeys_file "/etc/multipath/prkeys"
+ log_checker_err "always"
+ reservation_key "file"
+ all_tg_pt "no"
+ retain_attached_hw_handler "yes"
+ detect_prio "yes"
+ detect_checker "yes"
+ force_sync "yes"
+ strict_timing "no"
+ deferred_remove "no"
+ config_dir "/etc/multipath/conf.d"
+ delay_watch_checks "no"
+ delay_wait_checks "no"
+ san_path_err_threshold "no"
+ san_path_err_forget_rate "no"
+ san_path_err_recovery_time "no"
+ marginal_path_err_sample_time "no"
+ marginal_path_err_rate_threshold "no"
+ marginal_path_err_recheck_gap_time "no"
+ marginal_path_double_failed_time "no"
+ find_multipaths "on"
+ uxsock_timeout 4000
+ retrigger_tries 0
+ retrigger_delay 10
+ missing_uev_wait_timeout 30
+ skip_kpartx "no"
+ purge_disconnected "no"
+ disable_changed_wwids "ignored"
+ remove_retries 0
+ ghost_delay "no"
+ auto_resize "never"
+ find_multipaths_timeout -10
+ enable_foreign "NONE"
+ marginal_pathgroups "off"
+ recheck_wwid "no"
+}
+blacklist {
+ devnode ".*"
+ device {
+ vendor "SGI"
+ product "Universal Xport"
+ }
+ device {
+ vendor "^DGC"
+ product "LUNZ"
+ }
+ device {
+ vendor "EMC"
+ product "LUNZ"
+ }
+ device {
+ vendor "DELL"
+ product "Universal Xport"
+ }
+ device {
+ vendor "FUJITSU"
+ product "Universal Xport"
+ }
+ device {
+ vendor "IBM"
+ product "Universal Xport"
+ }
+ device {
+ vendor "IBM"
+ product "S/390"
+ }
+ device {
+ vendor "LENOVO"
+ product "Universal Xport"
+ }
+ device {
+ vendor "(NETAPP|LSI|ENGENIO)"
+ product "Universal Xport"
+ }
+ device {
+ vendor "STK"
+ product "Universal Xport"
+ }
+ device {
+ vendor "SUN"
+ product "Universal Xport"
+ }
+ wwid ".*"
+ device {
+ vendor "(Intel|INTEL)"
+ product "VTrak V-LUN"
+ }
+ device {
+ vendor "Promise"
+ product "VTrak V-LUN"
+ }
+ device {
+ vendor "Promise"
+ product "Vess V-LUN"
+ }
+ protocol ".*"
+}
+blacklist_exceptions {
+ devnode "^sd[a-z]"
+ wwid "^3"
+ protocol "scsi"
+}
+devices {
+ device {
+ vendor "NVME"
+ product ".*"
+ uid_attribute "ID_WWN"
+ path_checker "none"
+ retain_attached_hw_handler "no"
+ }
+ device {
+ vendor "APPLE"
+ product "Xserve RAID"
+ path_grouping_policy "multibus"
+ }
+ device {
+ vendor "3PARdata"
+ product "VV"
+ path_grouping_policy "group_by_prio"
+ hardware_handler "1 alua"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 18
+ fast_io_fail_tmo 10
+ dev_loss_tmo "infinity"
+ vpd_vendor "hp3par"
+ }
+ device {
+ vendor "NVME"
+ product "HPE Alletra"
+ path_grouping_policy "group_by_prio"
+ failback "immediate"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "DEC"
+ product "HSG80"
+ path_grouping_policy "group_by_prio"
+ path_checker "hp_sw"
+ hardware_handler "1 hp_sw"
+ prio "hp_sw"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "HP"
+ product "A6189A"
+ path_grouping_policy "multibus"
+ no_path_retry 12
+ }
+ device {
+ vendor "(COMPAQ|HP)"
+ product "(MSA|HSV)1[01]0"
+ path_grouping_policy "group_by_prio"
+ path_checker "hp_sw"
+ hardware_handler "1 hp_sw"
+ prio "hp_sw"
+ no_path_retry 12
+ }
+ device {
+ vendor "(COMPAQ|HP)"
+ product "MSA VOLUME"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 12
+ }
+ device {
+ vendor "(COMPAQ|HP)"
+ product "(HSV1[01]1|HSV2[01]0|HSV3[046]0|HSV4[05]0)"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 12
+ }
+ device {
+ vendor "HP"
+ product "(MSA2[02]12fc|MSA2012i)"
+ path_grouping_policy "multibus"
+ no_path_retry 18
+ }
+ device {
+ vendor "HP"
+ product "(MSA2012sa|MSA23(12|24)(fc|i|sa)|MSA2000s VOLUME)"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 18
+ }
+ device {
+ vendor "(HP|HPE)"
+ product "MSA [12]0[4567]0 (SAN|SAS|FC|iSCSI)"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 18
+ }
+ device {
+ vendor "HP"
+ product "(HSVX700|HSVX740)"
+ path_grouping_policy "group_by_prio"
+ hardware_handler "1 alua"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 12
+ }
+ device {
+ vendor "HP"
+ product "LOGICAL VOLUME"
+ path_grouping_policy "multibus"
+ no_path_retry 12
+ }
+ device {
+ vendor "HP"
+ product "(P2000 G3 FC|P2000G3 FC/iSCSI|P2000 G3 SAS|P2000 G3 iSCSI)"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 18
+ }
+ device {
+ vendor "LEFTHAND"
+ product "(P4000|iSCSIDisk|FCDISK)"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 18
+ }
+ device {
+ vendor "Nimble"
+ product "Server"
+ path_grouping_policy "group_by_prio"
+ hardware_handler "1 alua"
+ prio "alua"
+ failback "immediate"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "SGI"
+ product "TP9100"
+ path_grouping_policy "multibus"
+ }
+ device {
+ vendor "SGI"
+ product "TP9[3457]00"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "SGI"
+ product "IS"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "SGI"
+ product "^DD[46]A-"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "DDN"
+ product "SAN DataDirector"
+ path_grouping_policy "multibus"
+ }
+ device {
+ vendor "DDN"
+ product "^EF3010"
+ path_grouping_policy "multibus"
+ no_path_retry 30
+ }
+ device {
+ vendor "DDN"
+ product "^(EF3015|S2A|SFA)"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "NEXENTA"
+ product "COMSTAR"
+ path_grouping_policy "group_by_serial"
+ no_path_retry 30
+ }
+ device {
+ vendor "TEGILE"
+ product "(ZEBI-(FC|ISCSI)|INTELLIFLASH)"
+ path_grouping_policy "group_by_prio"
+ hardware_handler "1 alua"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 10
+ }
+ device {
+ vendor "EMC"
+ product "SYMMETRIX"
+ path_grouping_policy "multibus"
+ no_path_retry 6
+ }
+ device {
+ vendor "^DGC"
+ product "^(RAID|DISK|VRAID)"
+ product_blacklist "LUNZ"
+ path_grouping_policy "group_by_prio"
+ path_checker "emc_clariion"
+ hardware_handler "1 emc"
+ prio "emc"
+ failback "immediate"
+ no_path_retry 60
+ detect_checker "no"
+ }
+ device {
+ vendor "EMC"
+ product "Invista"
+ product_blacklist "LUNZ"
+ path_grouping_policy "multibus"
+ no_path_retry 5
+ }
+ device {
+ vendor "XtremIO"
+ product "XtremApp"
+ path_grouping_policy "multibus"
+ }
+ device {
+ vendor "COMPELNT"
+ product "Compellent Vol"
+ path_grouping_policy "group_by_prio"
+ failback "immediate"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "DELL"
+ product "^MD3"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "NVME"
+ product "^EMC PowerMax_"
+ path_grouping_policy "multibus"
+ }
+ device {
+ vendor "DellEMC"
+ product "PowerStore"
+ path_grouping_policy "group_by_prio"
+ hardware_handler "1 alua"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 3
+ fast_io_fail_tmo 15
+ }
+ device {
+ vendor "DellEMC"
+ product "^ME"
+ path_grouping_policy "group_by_prio"
+ hardware_handler "1 alua"
+ prio "alua"
+ failback "immediate"
+ }
+ device {
+ vendor "FSC"
+ product "CentricStor"
+ path_grouping_policy "group_by_serial"
+ }
+ device {
+ vendor "FUJITSU"
+ product "ETERNUS_DX(H|L|M|400|8000)"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 10
+ }
+ device {
+ vendor "(EUROLOGC|EuroLogc)"
+ product "FC2502"
+ path_grouping_policy "multibus"
+ }
+ device {
+ vendor "FUJITSU"
+ product "E[234]000"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 10
+ }
+ device {
+ vendor "FUJITSU"
+ product "E[68]000"
+ path_grouping_policy "multibus"
+ no_path_retry 10
+ }
+ device {
+ vendor "FUJITSU"
+ product "ETERNUS_AHB"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "(HITACHI|HP|HPE)"
+ product "^OPEN-"
+ path_grouping_policy "multibus"
+ }
+ device {
+ vendor "HITACHI"
+ product "^DF"
+ path_grouping_policy "group_by_prio"
+ prio "hds"
+ failback "immediate"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "HITACHI"
+ product "^DF600F"
+ path_grouping_policy "multibus"
+ }
+ device {
+ vendor "IBM"
+ product "ProFibre 4000R"
+ path_grouping_policy "multibus"
+ }
+ device {
+ vendor "IBM"
+ product "^1722-600"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "IBM"
+ product "^1724"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "IBM"
+ product "^1726"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "IBM"
+ product "^1742"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "IBM"
+ product "^1746"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "IBM"
+ product "^1813"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "IBM"
+ product "^1814"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "IBM"
+ product "^1815"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "IBM"
+ product "^1818"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "IBM"
+ product "^3526"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "IBM"
+ product "^(3542|3552)"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "IBM"
+ product "^2105"
+ path_grouping_policy "multibus"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "IBM"
+ product "^1750500"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "IBM"
+ product "^2107900"
+ path_grouping_policy "group_by_prio"
+ failback "immediate"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "IBM"
+ product "^2145"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "IBM"
+ product "S/390 DASD ECKD"
+ product_blacklist "S/390"
+ path_grouping_policy "multibus"
+ uid_attribute "ID_UID"
+ path_checker "directio"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "IBM"
+ product "S/390 DASD FBA"
+ product_blacklist "S/390"
+ path_grouping_policy "multibus"
+ uid_attribute "ID_UID"
+ path_checker "directio"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "IBM"
+ product "^IPR"
+ path_grouping_policy "group_by_prio"
+ hardware_handler "1 alua"
+ prio "alua"
+ failback "immediate"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "IBM"
+ product "1820N00"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "(XIV|IBM)"
+ product "(NEXTRA|2810XIV)"
+ path_grouping_policy "group_by_prio"
+ failback 15
+ no_path_retry "queue"
+ }
+ device {
+ vendor "(TMS|IBM)"
+ product "(RamSan|FlashSystem)"
+ path_grouping_policy "multibus"
+ }
+ device {
+ vendor "IBM"
+ product "^(DCS9900|2851)"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "AIX"
+ product "VDASD"
+ path_grouping_policy "multibus"
+ no_path_retry 60
+ }
+ device {
+ vendor "IBM"
+ product "3303[ ]+NVDISK"
+ no_path_retry 60
+ }
+ device {
+ vendor "AIX"
+ product "NVDISK"
+ path_grouping_policy "group_by_prio"
+ hardware_handler "1 alua"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 60
+ }
+ device {
+ vendor "LENOVO"
+ product "DE_Series"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "NETAPP"
+ product "LUN"
+ path_grouping_policy "group_by_prio"
+ features "2 pg_init_retries 50"
+ prio "ontap"
+ failback "immediate"
+ no_path_retry "queue"
+ flush_on_last_del "always"
+ dev_loss_tmo "infinity"
+ user_friendly_names "no"
+ }
+ device {
+ vendor "(NETAPP|LSI|ENGENIO)"
+ product "INF-01-00"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "SolidFir"
+ product "SSD SAN"
+ path_grouping_policy "multibus"
+ no_path_retry 24
+ }
+ device {
+ vendor "NVME"
+ product "^NetApp ONTAP Controller"
+ path_grouping_policy "multibus"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "NEC"
+ product "DISK ARRAY"
+ path_grouping_policy "group_by_prio"
+ hardware_handler "1 alua"
+ prio "alua"
+ failback "immediate"
+ }
+ device {
+ vendor "^Pillar"
+ product "^Axiom"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ }
+ device {
+ vendor "^Oracle"
+ product "^Oracle FS"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ }
+ device {
+ vendor "STK"
+ product "BladeCtlr"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "STK"
+ product "OPENstorage"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "STK"
+ product "FLEXLINE 380"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "SUN"
+ product "StorEdge 3"
+ path_grouping_policy "multibus"
+ }
+ device {
+ vendor "SUN"
+ product "STK6580_6780"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "SUN"
+ product "CSM[12]00_R"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "SUN"
+ product "LCSM100_[IEFS]"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "SUN"
+ product "SUN_6180"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "SUN"
+ product "ArrayStorage"
+ product_blacklist "Universal Xport"
+ path_grouping_policy "group_by_prio"
+ path_checker "rdac"
+ features "2 pg_init_retries 50"
+ hardware_handler "1 rdac"
+ prio "rdac"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "SUN"
+ product "(Sun Storage|ZFS Storage|COMSTAR)"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "PIVOT3"
+ product "RAIGE VOLUME"
+ path_grouping_policy "multibus"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "(NexGen|Pivot3)"
+ product "(TierStore|vSTAC)"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "(Intel|INTEL)"
+ product "Multi-Flex"
+ product_blacklist "VTrak V-LUN"
+ path_grouping_policy "group_by_prio"
+ hardware_handler "1 alua"
+ prio "alua"
+ failback "immediate"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "(LIO-ORG|SUSE)"
+ product "RBD"
+ path_grouping_policy "group_by_prio"
+ hardware_handler "1 alua"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 12
+ }
+ device {
+ vendor "DataCore"
+ product "SANmelody"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "DataCore"
+ product "Virtual Disk"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry "queue"
+ }
+ device {
+ vendor "PURE"
+ product "FlashArray"
+ path_grouping_policy "group_by_prio"
+ hardware_handler "1 alua"
+ prio "alua"
+ failback "immediate"
+ fast_io_fail_tmo 10
+ }
+ device {
+ vendor "HUAWEI"
+ product "XSG1"
+ path_grouping_policy "group_by_prio"
+ failback "immediate"
+ no_path_retry 15
+ }
+ device {
+ vendor "KOVE"
+ product "XPD"
+ path_grouping_policy "multibus"
+ }
+ device {
+ vendor "NFINIDAT"
+ product "InfiniBox"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry "queue"
+ flush_on_last_del "always"
+ fast_io_fail_tmo 15
+ dev_loss_tmo "infinity"
+ detect_prio "no"
+ }
+ device {
+ vendor "KMNRIO"
+ product "K2"
+ path_grouping_policy "multibus"
+ }
+ device {
+ vendor "NEXSAN"
+ product "NXS-B0"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 15
+ }
+ device {
+ vendor "NEXSAN"
+ product "SATAB"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 15
+ }
+ device {
+ vendor "Nexsan"
+ product "(NestOS|NST5000)"
+ path_grouping_policy "group_by_prio"
+ hardware_handler "1 alua"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "VIOLIN"
+ product "SAN ARRAY$"
+ path_grouping_policy "group_by_serial"
+ no_path_retry 30
+ }
+ device {
+ vendor "VIOLIN"
+ product "SAN ARRAY ALUA"
+ path_grouping_policy "group_by_prio"
+ hardware_handler "1 alua"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "VIOLIN"
+ product "CONCERTO ARRAY"
+ path_grouping_policy "multibus"
+ no_path_retry 30
+ }
+ device {
+ vendor "(XIOTECH|XIOtech)"
+ product "ISE"
+ path_grouping_policy "multibus"
+ no_path_retry 12
+ }
+ device {
+ vendor "(XIOTECH|XIOtech)"
+ product "IGLU DISK"
+ path_grouping_policy "multibus"
+ no_path_retry 30
+ }
+ device {
+ vendor "(XIOTECH|XIOtech)"
+ product "Magnitude"
+ path_grouping_policy "multibus"
+ no_path_retry 30
+ }
+ device {
+ vendor "Vexata"
+ product "VX"
+ path_grouping_policy "multibus"
+ no_path_retry 30
+ }
+ device {
+ vendor "Promise"
+ product "VTrak"
+ product_blacklist "VTrak V-LUN"
+ path_grouping_policy "group_by_prio"
+ hardware_handler "1 alua"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "Promise"
+ product "Vess"
+ product_blacklist "Vess V-LUN"
+ path_grouping_policy "group_by_prio"
+ hardware_handler "1 alua"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "^IFT"
+ product ".*"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "DotHill"
+ product "SANnet"
+ path_grouping_policy "multibus"
+ no_path_retry 30
+ }
+ device {
+ vendor "DotHill"
+ product "R/Evo"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "DotHill"
+ product "^DH"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 30
+ }
+ device {
+ vendor "AStor"
+ product "NeoSapphire"
+ path_grouping_policy "multibus"
+ no_path_retry 30
+ }
+ device {
+ vendor "INSPUR"
+ product "MCS"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ }
+ device {
+ vendor "MacroSAN"
+ product "LU"
+ path_grouping_policy "group_by_prio"
+ prio "alua"
+ failback "immediate"
+ no_path_retry 30
+ }
+}
+
+overrides {
+ path_grouping_policy "multibus"
+ protocol {
+ type scsi:fcp
+ fast_io_fail_tmo 5
+ }
+}
+
+multipaths {
+ multipath {
+ wwid "333333330000007d0"
+ alias "test"
+ }
+ multipath {
+ wwid "33333333000001388"
+ alias "foo"
+ }
+}
+
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf1.d/bindings_set.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf1.d/bindings_set.conf
new file mode 100644
index 00000000..9b5120f9
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf1.d/bindings_set.conf
@@ -0,0 +1,3 @@
+defaults {
+ bindings_file "/etc/multipath/bindings"
+}
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf1.d/empty.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf1.d/empty.conf
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf1.d/empty.conf
@@ -0,0 +1 @@
+
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf2.d/getuid_set.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf2.d/getuid_set.conf
new file mode 100644
index 00000000..da0f9677
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf2.d/getuid_set.conf
@@ -0,0 +1,11 @@
+defaults {
+ user_friendly_names yes
+}
+
+devices {
+ device {
+ vendor "foo"
+ product "bar"
+ getuid_callout "/lib/udev/scsi_id --whitelisted --device=/dev/%n"
+ }
+}
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf2.d/set_files.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf2.d/set_files.conf
new file mode 100644
index 00000000..26c250b0
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf2.d/set_files.conf
@@ -0,0 +1,5 @@
+defaults {
+ bindings_file "/etc/multipath/bindings"
+ wwids_file "/etc/multipath/wwids"
+ prkeys_file "/etc/multipath/prkeys"
+}
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf3.d/README b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf3.d/README
new file mode 100644
index 00000000..d846e286
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/conf3.d/README
@@ -0,0 +1 @@
+This directory is intentionally left without .conf files.
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/config_dir.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/config_dir.conf
new file mode 100644
index 00000000..6b56d7f6
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/config_dir.conf
@@ -0,0 +1,5 @@
+defaults {
+ user_friendly_names yes
+ find_multipaths yes
+ config_dir "conf1.d"
+}
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/default_rhel9.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/default_rhel9.conf
new file mode 100644
index 00000000..c1076198
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/default_rhel9.conf
@@ -0,0 +1,21 @@
+# device-mapper-multipath configuration file
+
+# For a complete list of the default configuration values, run either:
+# # multipath -t
+# or
+# # multipathd show config
+
+# For a list of configuration options with descriptions, see the
+# multipath.conf man page.
+
+defaults {
+ user_friendly_names yes
+ find_multipaths yes
+}
+
+blacklist_exceptions {
+ property "(SCSI_IDENT_|ID_WWN)"
+}
+
+blacklist {
+}
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/empty.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/empty.conf
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/empty.conf
@@ -0,0 +1 @@
+
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/empty_dir.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/empty_dir.conf
new file mode 100644
index 00000000..a163ed7e
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/empty_dir.conf
@@ -0,0 +1,5 @@
+defaults {
+ user_friendly_names yes
+ find_multipaths yes
+ config_dir "conf3.d"
+}
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/extra_slash.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/extra_slash.conf
new file mode 100644
index 00000000..ce7ea02a
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/extra_slash.conf
@@ -0,0 +1,5 @@
+defaults {
+ user_friendly_names yes
+ find_multipaths yes
+ config_dir "/etc/multipath/conf.d/"
+}
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/getuid_defaults.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/getuid_defaults.conf
new file mode 100644
index 00000000..326d677a
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/getuid_defaults.conf
@@ -0,0 +1,5 @@
+defaults {
+ user_friendly_names yes
+ find_multipaths yes
+ getuid_callout "/lib/udev/scsi_id --whitelisted --device=/dev/%n"
+}
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/getuid_devices.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/getuid_devices.conf
new file mode 100644
index 00000000..75abb4cb
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/getuid_devices.conf
@@ -0,0 +1,12 @@
+defaults {
+ user_friendly_names yes
+ find_multipaths yes
+}
+
+devices {
+ device {
+ vendor "foo"
+ product "bar"
+ getuid_callout "/lib/udev/scsi_id --whitelisted --device=/dev/%n"
+ }
+}
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/getuid_overrides.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/getuid_overrides.conf
new file mode 100644
index 00000000..8861a2d7
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/getuid_overrides.conf
@@ -0,0 +1,8 @@
+defaults {
+ user_friendly_names yes
+ find_multipaths yes
+}
+
+overrides {
+ getuid_callout "/lib/udev/scsi_id --whitelisted --device=/dev/%n"
+}
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/missing_dir.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/missing_dir.conf
new file mode 100644
index 00000000..6a4bf49f
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/missing_dir.conf
@@ -0,0 +1,5 @@
+defaults {
+ user_friendly_names yes
+ find_multipaths yes
+ config_dir "missing"
+}
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/no_defaults.conf b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/no_defaults.conf
new file mode 100644
index 00000000..f8d54d09
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/files/no_defaults.conf
@@ -0,0 +1,7 @@
+devices {
+ device {
+ vendor "foo"
+ product "bar"
+ getuid_callout "/lib/udev/scsi_id --whitelisted --device=/dev/%n"
+ }
+}
diff --git a/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/test_multipath_conf_read_9to10.py b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/test_multipath_conf_read_9to10.py
new file mode 100644
index 00000000..cb90fcc3
--- /dev/null
+++ b/repos/system_upgrade/el9toel10/actors/multipath/config_reader/tests/test_multipath_conf_read_9to10.py
@@ -0,0 +1,283 @@
+import os
+
+import pytest
+
+from leapp.libraries.actor import multipathconfread
+from leapp.libraries.common.testutils import CurrentActorMocked, produce_mocked
+from leapp.libraries.stdlib import api
+from leapp.models import MultipathConfFacts9to10, MultipathConfig9to10, MultipathInfo
+
+TEST_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'files')
+
+
+def build_config(pathname, config_dir=None, bindings_file=None, wwids_file=None,
+ prkeys_file=None, has_getuid=False):
+ return MultipathConfig9to10(
+ pathname=pathname,
+ config_dir=config_dir,
+ bindings_file=bindings_file,
+ wwids_file=wwids_file,
+ prkeys_file=prkeys_file,
+ has_getuid=has_getuid,
+ )
+
+
+def assert_config(config, expected):
+ assert config.pathname == expected.pathname
+ assert config.config_dir == expected.config_dir
+ assert config.bindings_file == expected.bindings_file
+ assert config.wwids_file == expected.wwids_file
+ assert config.prkeys_file == expected.prkeys_file
+ assert config.has_getuid == expected.has_getuid
+
+
+default_rhel9_conf = build_config(
+ os.path.join(TEST_DIR, 'default_rhel9.conf'))
+
+empty_conf = build_config(
+ os.path.join(TEST_DIR, 'empty.conf'))
+
+getuid_defaults_conf = build_config(
+ os.path.join(TEST_DIR, 'getuid_defaults.conf'), has_getuid=True)
+
+getuid_devices_conf = build_config(
+ os.path.join(TEST_DIR, 'getuid_devices.conf'), has_getuid=True)
+
+getuid_overrides_conf = build_config(
+ os.path.join(TEST_DIR, 'getuid_overrides.conf'), has_getuid=True)
+
+all_options_conf = build_config(
+ os.path.join(TEST_DIR, 'all_options.conf'),
+ config_dir='/etc/multipath/conf.d',
+ bindings_file='/etc/multipath/bindings',
+ wwids_file='/etc/multipath/wwids',
+ prkeys_file='/etc/multipath/prkeys',
+ has_getuid=True)
+
+no_defaults_conf = build_config(
+ os.path.join(TEST_DIR, 'no_defaults.conf'), has_getuid=True)
+
+complicated_conf = build_config(
+ os.path.join(TEST_DIR, 'complicated.conf'),
+ config_dir='/etc/multipath/conf.d',
+ bindings_file='/etc/multipath/bindings',
+ wwids_file='/etc/multipath/wwids',
+ prkeys_file='/etc/multipath/prkeys')
+
+
+def test_parse_config():
+ test_map = {'default_rhel9.conf': default_rhel9_conf,
+ 'empty.conf': empty_conf,
+ 'getuid_defaults.conf': getuid_defaults_conf,
+ 'getuid_devices.conf': getuid_devices_conf,
+ 'getuid_overrides.conf': getuid_overrides_conf,
+ 'all_options.conf': all_options_conf,
+ 'no_defaults.conf': no_defaults_conf,
+ 'complicated.conf': complicated_conf}
+ for config_name, expected_data in test_map.items():
+ config = multipathconfread._parse_config(os.path.join(TEST_DIR, config_name))
+ assert config
+ assert_config(config, expected_data)
+
+
+extra_slash_conf = build_config(
+ os.path.join(TEST_DIR, 'extra_slash.conf'),
+ config_dir=os.path.join(TEST_DIR, '/etc/multipath/conf.d/'))
+
+missing_dir_conf = build_config(
+ os.path.join(TEST_DIR, 'missing_dir.conf'),
+ config_dir=os.path.join(TEST_DIR, 'missing'))
+
+empty_dir_conf = build_config(
+ os.path.join(TEST_DIR, 'empty_dir.conf'),
+ config_dir=os.path.join(TEST_DIR, 'conf3.d'))
+
+config_dir_conf = build_config(
+ os.path.join(TEST_DIR, 'config_dir.conf'),
+ config_dir=os.path.join(TEST_DIR, 'conf1.d'))
+
+bindings_set_conf = build_config(
+ os.path.join(TEST_DIR, 'conf1.d/bindings_set.conf'),
+ bindings_file='/etc/multipath/bindings')
+
+empty1_conf = build_config(
+ os.path.join(TEST_DIR, 'conf1.d/empty.conf'))
+
+all_set_in_dir_conf = build_config(
+ os.path.join(TEST_DIR, 'all_set_in_dir.conf'),
+ config_dir=os.path.join(TEST_DIR, 'conf2.d'))
+
+getuid_set_conf = build_config(
+ os.path.join(TEST_DIR, 'conf2.d/getuid_set.conf'),
+ has_getuid=True)
+
+set_files_conf = build_config(
+ os.path.join(TEST_DIR, 'conf2.d/set_files.conf'),
+ bindings_file='/etc/multipath/bindings',
+ wwids_file='/etc/multipath/wwids',
+ prkeys_file='/etc/multipath/prkeys')
+
+
+def mock_parse_config(path):
+ """Convert config_dir into full pathname"""
+ conf = multipathconfread._parse_config_orig(path)
+ if not conf:
+ return None
+ if conf.config_dir:
+ conf.config_dir = os.path.join(TEST_DIR, conf.config_dir)
+ return conf
+
+
+def mock_parse_config_dir(path):
+ assert os.path.normpath(path) == '/etc/multipath/conf.d'
+ return []
+
+
+@pytest.mark.parametrize(
+ ('primary_config', 'expected_config'),
+ [
+ ('all_options.conf', all_options_conf),
+ ('default_rhel9.conf', default_rhel9_conf),
+ ('extra_slash.conf', extra_slash_conf),
+ ]
+)
+def test_get_primary_facts_default_config_dir(monkeypatch, primary_config, expected_config):
+ monkeypatch.setattr(multipathconfread, 'is_processable', lambda: True)
+ monkeypatch.setattr(multipathconfread, '_check_socket_activation', lambda: True)
+ monkeypatch.setattr(multipathconfread, '_check_dm_nvme_multipathing', lambda: True)
+ monkeypatch.setattr(multipathconfread, '_parse_config_dir', mock_parse_config_dir)
+
+ produce_mock = produce_mocked()
+ monkeypatch.setattr(api, 'produce', produce_mock)
+
+ actor_mock = CurrentActorMocked(src_ver='9.6', dst_ver='10.0')
+ monkeypatch.setattr(api, 'current_actor', actor_mock)
+
+ config_to_use = os.path.join(TEST_DIR, primary_config)
+ multipathconfread.scan_and_emit_multipath_info(config_to_use)
+
+ assert produce_mock.called
+
+ general_info = [msg for msg in produce_mock.model_instances if isinstance(msg, MultipathInfo)]
+ assert len(general_info) == 1
+ assert general_info[0].is_configured
+ assert general_info[0].config_dir == '/etc/multipath/conf.d'
+
+ msgs = [msg for msg in produce_mock.model_instances if isinstance(msg, MultipathConfFacts9to10)]
+ assert len(msgs) == 1
+
+ actual_configs = msgs[0].configs
+ assert len(actual_configs) == 1
+
+ assert_config(actual_configs[0], expected_config)
+
+
+@pytest.mark.parametrize(
+ ('primary_config', 'expected_configs'),
+ [
+ ('missing_dir.conf', [missing_dir_conf]),
+ ('empty_dir.conf', [empty_dir_conf]),
+ ('config_dir.conf', [config_dir_conf, bindings_set_conf, empty1_conf]),
+ ('all_set_in_dir.conf', [all_set_in_dir_conf, getuid_set_conf, set_files_conf]),
+ ]
+)
+def test_get_facts_with_config_dir(monkeypatch, primary_config, expected_configs):
+ monkeypatch.setattr(multipathconfread, '_parse_config_orig', multipathconfread._parse_config, raising=False)
+ monkeypatch.setattr(multipathconfread, '_parse_config', mock_parse_config)
+ monkeypatch.setattr(multipathconfread, 'is_processable', lambda: True)
+ monkeypatch.setattr(multipathconfread, '_check_socket_activation', lambda: True)
+ monkeypatch.setattr(multipathconfread, '_check_dm_nvme_multipathing', lambda: False)
+
+ produce_mock = produce_mocked()
+ monkeypatch.setattr(api, 'produce', produce_mock)
+
+ actor_mock = CurrentActorMocked(src_ver='9.6', dst_ver='10.0')
+ monkeypatch.setattr(api, 'current_actor', actor_mock)
+
+ config_to_use = os.path.join(TEST_DIR, primary_config)
+ multipathconfread.scan_and_emit_multipath_info(config_to_use)
+
+ assert produce_mock.called
+
+ general_info = [msg for msg in produce_mock.model_instances if isinstance(msg, MultipathInfo)]
+ assert len(general_info) == 1
+ assert general_info[0].is_configured
+ assert not general_info[0].config_dir
+
+ msgs = [msg for msg in produce_mock.model_instances if isinstance(msg, MultipathConfFacts9to10)]
+ assert len(msgs) == 1
+
+ actual_configs = msgs[0].configs
+ assert len(actual_configs) == len(expected_configs)
+
+ for actual_config, expected_config in zip(actual_configs, expected_configs):
+ assert_config(actual_config, expected_config)
+
+
+def test_check_socket_activation(monkeypatch):
+ monkeypatch.setattr(os.path, 'exists', lambda path: True)
+ assert multipathconfread._check_socket_activation() is True
+
+ monkeypatch.setattr(os.path, 'exists', lambda path: False)
+ assert multipathconfread._check_socket_activation() is False
+
+
+def test_check_dm_nvme_multipathing_no_module(monkeypatch):
+ monkeypatch.setattr(os.path, 'isdir', lambda path: False)
+ assert multipathconfread._check_dm_nvme_multipathing() is False
+
+
+def test_check_dm_nvme_multipathing_disabled(monkeypatch):
+ monkeypatch.setattr(os.path, 'isdir', lambda path: True)
+ monkeypatch.setattr(multipathconfread, 'open',
+ lambda path, mode='r': _mock_open('N'), raising=False)
+ assert multipathconfread._check_dm_nvme_multipathing() is True
+
+
+def test_check_dm_nvme_multipathing_enabled(monkeypatch):
+ monkeypatch.setattr(os.path, 'isdir', lambda path: True)
+ monkeypatch.setattr(multipathconfread, 'open',
+ lambda path, mode='r': _mock_open('Y'), raising=False)
+ assert multipathconfread._check_dm_nvme_multipathing() is False
+
+
+class _mock_open:
+ def __init__(self, content):
+ self._content = content
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ pass
+
+ def read(self):
+ return self._content
+
+
+def test_system_fields_on_primary(monkeypatch):
+ monkeypatch.setattr(multipathconfread, 'is_processable', lambda: True)
+ monkeypatch.setattr(multipathconfread, '_check_socket_activation', lambda: True)
+ monkeypatch.setattr(multipathconfread, '_check_dm_nvme_multipathing', lambda: True)
+ monkeypatch.setattr(multipathconfread, '_parse_config_dir', lambda config_dir: [])
+
+ produce_mock = produce_mocked()
+ monkeypatch.setattr(api, 'produce', produce_mock)
+
+ actor_mock = CurrentActorMocked(src_ver='9.6', dst_ver='10.0')
+ monkeypatch.setattr(api, 'current_actor', actor_mock)
+
+ config_to_use = os.path.join(TEST_DIR, 'default_rhel9.conf')
+ multipathconfread.scan_and_emit_multipath_info(config_to_use)
+
+ assert produce_mock.called
+
+ msgs = [msg for msg in produce_mock.model_instances if isinstance(msg, MultipathConfFacts9to10)]
+ assert len(msgs) == 1
+
+ configs = msgs[0].configs
+ assert len(configs) == 1
+
+ primary = configs[0]
+ assert primary.has_socket_activation is True
+ assert primary.has_dm_nvme_multipathing is True
--
2.54.0