From 7ff626243366a4ffaaf972f12e8a4d7708c06040 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Wed, 18 Mar 2026 20:51:05 -0400 Subject: [PATCH 055/108] 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 --- .../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