Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package crmsh for openSUSE:Factory checked 
in at 2026-06-25 10:55:51
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/crmsh (Old)
 and      /work/SRC/openSUSE:Factory/.crmsh.new.2088 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "crmsh"

Thu Jun 25 10:55:51 2026 rev:413 rq:1361531 version:5.1.0+20260624.349562dd

Changes:
--------
--- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes      2026-06-15 
19:53:51.513621227 +0200
+++ /work/SRC/openSUSE:Factory/.crmsh.new.2088/crmsh.changes    2026-06-25 
10:58:30.796081890 +0200
@@ -1,0 +2,13 @@
+Wed Jun 24 04:47:36 UTC 2026 - [email protected]
+
+- Update to version 5.1.0+20260624.349562dd:
+  * Dev: storage_utils: Rename blkid UUID helper
+  * Dev: storage_utils: Refactor storage helpers out of utils.py
+
+-------------------------------------------------------------------
+Mon Jun 22 08:17:20 UTC 2026 - [email protected]
+
+- Update to version 5.1.0+20260622.f844a5ab:
+  * Chore: unittests: reduce output verbosity and stop printing coverage report
+
+-------------------------------------------------------------------

Old:
----
  crmsh-5.1.0+20260615.8409ea5a.tar.bz2

New:
----
  crmsh-5.1.0+20260624.349562dd.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ crmsh.spec ++++++
--- /var/tmp/diff_new_pack.cooZyN/_old  2026-06-25 10:58:31.560108257 +0200
+++ /var/tmp/diff_new_pack.cooZyN/_new  2026-06-25 10:58:31.560108257 +0200
@@ -41,7 +41,7 @@
 Summary:        High Availability cluster command-line interface
 License:        GPL-2.0-or-later
 Group:          %{pkg_group}
-Version:        5.1.0+20260615.8409ea5a
+Version:        5.1.0+20260624.349562dd
 Release:        0
 URL:            http://crmsh.github.io
 Source0:        %{name}-%{version}.tar.bz2

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.cooZyN/_old  2026-06-25 10:58:31.608109914 +0200
+++ /var/tmp/diff_new_pack.cooZyN/_new  2026-06-25 10:58:31.612110052 +0200
@@ -9,7 +9,7 @@
 </service>
 <service name="tar_scm">
   <param name="url">https://github.com/ClusterLabs/crmsh.git</param>
-  <param 
name="changesrevision">69bca8d37b097414990f2291b69f39f6bdb1d8a2</param>
+  <param 
name="changesrevision">349562dd6312bfaef9755ef04f626b496c66cc7e</param>
 </service>
 </servicedata>
 (No newline at EOF)

++++++ crmsh-5.1.0+20260615.8409ea5a.tar.bz2 -> 
crmsh-5.1.0+20260624.349562dd.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-5.1.0+20260615.8409ea5a/crmsh/cibconfig.py 
new/crmsh-5.1.0+20260624.349562dd/crmsh/cibconfig.py
--- old/crmsh-5.1.0+20260615.8409ea5a/crmsh/cibconfig.py        2026-06-15 
11:35:01.000000000 +0200
+++ new/crmsh-5.1.0+20260624.349562dd/crmsh/cibconfig.py        2026-06-24 
06:16:33.000000000 +0200
@@ -18,6 +18,7 @@
 from . import clidisplay
 from . import idmgmt
 from . import schema
+from . import storage_utils
 from . import utils
 from . import cibverify
 from . import parse
@@ -2679,7 +2680,7 @@
                 self.last_commit_time = t
             self.refresh()
 
-            utils.check_no_quorum_policy_with_dlm()
+            storage_utils.check_no_quorum_policy_with_dlm()
         return rc
 
     def _update_schema(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-5.1.0+20260615.8409ea5a/crmsh/cluster_fs.py 
new/crmsh-5.1.0+20260624.349562dd/crmsh/cluster_fs.py
--- old/crmsh-5.1.0+20260615.8409ea5a/crmsh/cluster_fs.py       2026-06-15 
11:35:01.000000000 +0200
+++ new/crmsh-5.1.0+20260624.349562dd/crmsh/cluster_fs.py       2026-06-24 
06:16:33.000000000 +0200
@@ -1,7 +1,7 @@
 import logging
 import re
 from contextlib import contextmanager
-from . import utils, sh
+from . import utils, sh, storage_utils
 from . import bootstrap
 from . import ra
 from . import corosync
@@ -113,7 +113,7 @@
                 raise Error("Without Cluster LVM2 (-C option), -o option only 
support one device")
             elif len(self.gfs2_devices) > 1:
                 raise Error("Without Cluster LVM2 (-C option), -g option only 
support one device")
-        if self.mount_point and utils.has_mount_point_used(self.mount_point):
+        if self.mount_point and 
storage_utils.has_mount_point_used(self.mount_point):
             raise Error(f"Mount point {self.mount_point} already mounted")
 
     def _verify_devices(self):
@@ -122,14 +122,14 @@
         """
         node_list = utils.list_cluster_nodes() if self.use_stage else 
[utils.this_node()]
         for dev in self.devices:
-            failed_nodes = utils.get_non_block_device_nodes(dev, node_list)
+            failed_nodes = storage_utils.get_non_block_device_nodes(dev, 
node_list)
             if failed_nodes:
                 raise Error(f"{dev} is not a block device on {', 
'.join(failed_nodes)}")
-            if utils.is_dev_used_for_lvm(dev) and self.use_cluster_lvm2:
+            if storage_utils.is_dev_used_for_lvm(dev) and 
self.use_cluster_lvm2:
                 raise Error(f"{dev} is a Logical Volume, cannot be used with 
the -C option")
-            if utils.has_disk_mounted(dev):
+            if storage_utils.has_disk_mounted(dev):
                 raise Error(f"{dev} is already mounted")
-            utils.MultipathInspector.check_device_under_multipath(dev)
+            storage_utils.MultipathInspector.check_device_under_multipath(dev)
 
     def _check_if_already_configured(self):
         """
@@ -176,10 +176,10 @@
         """
         for dev in self.devices:
             msg = ""
-            if utils.has_dev_partitioned(dev):
+            if storage_utils.has_dev_partitioned(dev):
                 msg = f"Found a partition table in {dev}"
             else:
-                fs_type = utils.get_dev_fs_type(dev)
+                fs_type = storage_utils.get_dev_fs_type(dev)
                 if fs_type:
                     msg = f"{dev} contains a {fs_type} file system"
             if msg and not bootstrap.confirm(f"{msg} - overwrite?"):
@@ -254,13 +254,13 @@
             shell.get_stdout_or_raise_error(f"pvcreate {disks_string} -y")
 
         # Create VG
-        self.vg_id = utils.gen_unused_id(utils.get_all_vg_name(), self.VG_ID)
+        self.vg_id = utils.gen_unused_id(storage_utils.get_all_vg_name(), 
self.VG_ID)
         with logger_utils.status_long(f"Creating VG {self.vg_id}"):
             shell.get_stdout_or_raise_error(f"vgcreate --shared {self.vg_id} 
{disks_string} -y")
 
         # Create LV
         with logger_utils.status_long(f"Creating LV {self.LV_ID} on VG 
{self.vg_id}"):
-            pe_number = utils.get_pe_number(self.vg_id)
+            pe_number = storage_utils.get_pe_number(self.vg_id)
             shell.get_stdout_or_raise_error(f"lvcreate -l {pe_number} 
{self.vg_id} -n {self.LV_ID} -y")
  
         return f"/dev/{self.vg_id}/{self.LV_ID}"
@@ -396,8 +396,8 @@
         with logger_utils.status_long(f"Verify {cluster_fs_type.upper()} 
environment on {device}"):
             use_cluster_lvm2 = 
xmlutil.CrmMonXmlParser(peer).is_resource_configured(constants.LVMLOCKD_RA)
             self._verify_packages(cluster_fs_type.upper(), use_cluster_lvm2)
-            if utils.is_dev_a_plain_raw_disk_or_partition(device, peer):
-                utils.compare_uuid_with_peer_dev([device], peer)
+            if storage_utils.is_dev_a_plain_raw_disk_or_partition(device, 
peer):
+                storage_utils.compare_uuid_with_peer_dev([device], peer)
 
     @classmethod
     def pre_verify(cls, ctx):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-5.1.0+20260615.8409ea5a/crmsh/sbd.py 
new/crmsh-5.1.0+20260624.349562dd/crmsh/sbd.py
--- old/crmsh-5.1.0+20260615.8409ea5a/crmsh/sbd.py      2026-06-15 
11:35:01.000000000 +0200
+++ new/crmsh-5.1.0+20260624.349562dd/crmsh/sbd.py      2026-06-24 
06:16:33.000000000 +0200
@@ -6,7 +6,7 @@
 import shlex
 import logging
 from enum import Enum, IntEnum, auto
-from . import utils, sh
+from . import utils, sh, storage_utils
 from . import bootstrap
 from . import log
 from . import constants
@@ -91,16 +91,16 @@
             raise ValueError(f"Maximum number of SBD device is 
{SBDManager.SBD_DEVICE_MAX}")
 
         for dev in dev_list:
-            failed_nodes = utils.get_non_block_device_nodes(dev, node_list)
+            failed_nodes = storage_utils.get_non_block_device_nodes(dev, 
node_list)
             if failed_nodes:
                 raise ValueError(f"{dev} is not a block device on {', 
'.join(failed_nodes)}")
 
-            utils.MultipathInspector.check_device_under_multipath(dev)
+            storage_utils.MultipathInspector.check_device_under_multipath(dev)
 
             if compare_uuid:
                 SBDUtils.compare_device_uuid(dev, node_list)
 
-        utils.detect_duplicate_device_path(dev_list)
+        storage_utils.detect_duplicate_device_path(dev_list)
 
     @staticmethod
     def get_sbd_value_from_config(key):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-5.1.0+20260615.8409ea5a/crmsh/storage_utils.py 
new/crmsh-5.1.0+20260624.349562dd/crmsh/storage_utils.py
--- old/crmsh-5.1.0+20260615.8409ea5a/crmsh/storage_utils.py    1970-01-01 
01:00:00.000000000 +0100
+++ new/crmsh-5.1.0+20260624.349562dd/crmsh/storage_utils.py    2026-06-24 
06:16:33.000000000 +0200
@@ -0,0 +1,249 @@
+import logging
+import os
+import re
+import shlex
+import typing
+from collections import defaultdict
+from dataclasses import dataclass
+from functools import cache
+from pathlib import Path
+
+from . import constants, sh, xmlutil, utils
+
+
+logger = logging.getLogger(__name__)
+
+
+def get_non_block_device_nodes(dev, node_list=None) -> list[str]:
+    """
+    Return a list of nodes where the device is not a block device or does not 
exist
+    """
+    shell = sh.cluster_shell()
+    cluster_nodes = node_list or [utils.this_node()]
+    failed_nodes = []
+    for node in cluster_nodes:
+        rc, _, _ = shell.get_rc_stdout_stderr_without_input(
+            node,
+            f"test -b {shlex.quote(dev)}"
+        )
+        if rc != 0:
+            failed_nodes.append(node)
+    return failed_nodes
+
+
+def detect_duplicate_device_path(device_list: typing.List[str]):
+    """
+    Resolve device path and check if there are duplicated device path
+    """
+    path_dict = defaultdict(list)
+    for dev in device_list:
+        resolved_path = Path(dev).resolve()
+        path_dict[resolved_path].append(dev)
+    for path, dev_list in path_dict.items():
+        if len(dev_list) > 1:
+            raise ValueError(f"Duplicated device path detected: 
{','.join(dev_list)}. They are all pointing to {path}")
+
+
+def has_disk_mounted(dev):
+    """
+    Check if device already mounted
+    """
+    out = sh.cluster_shell().get_stdout_or_raise_error("mount")
+    return re.search("\n{} on ".format(dev), out) is not None
+
+
+def has_mount_point_used(directory):
+    """
+    Check if mount directory already mounted
+    """
+    out = sh.cluster_shell().get_stdout_or_raise_error("mount")
+    return re.search(" on {}".format(directory), out) is not None
+
+
+def get_all_vg_name():
+    """
+    Get all available VGs
+    """
+    out = sh.cluster_shell().get_stdout_or_raise_error("vgdisplay")
+    return re.findall(r"VG Name\s+(.*)", out)
+
+
+def get_pe_number(vg_id):
+    """
+    Get pe number
+    """
+    output = sh.cluster_shell().get_stdout_or_raise_error("vgdisplay 
{}".format(vg_id))
+    res = re.search(r"Total PE\s+(\d+)", output)
+    if not res:
+        raise ValueError("Cannot find PE on VG({})".format(vg_id))
+    return int(res.group(1))
+
+
+def has_dev_partitioned(dev, peer=None):
+    """
+    Check if device has partitions
+    """
+    return len(get_dev_info(dev, "NAME", peer=peer).splitlines()) > 1
+
+
+def get_dev_uuid(dev, peer=None):
+    """
+    Get UUID of device on local or peer node
+    """
+    out = get_dev_info(dev, "UUID", peer=peer).splitlines()
+    return out[0] if out else get_dev_uuid_by_blkid(dev, peer)
+
+
+def get_dev_uuid_by_blkid(dev, peer=None):
+    """
+    Get UUID of device using blkid
+    """
+    out = sh.cluster_shell().get_stdout_or_raise_error("blkid {}".format(dev), 
peer)
+    res = re.search("UUID=\"(.*?)\"", out)
+    return res.group(1) if res else None
+
+
+def get_dev_fs_type(dev, peer=None):
+    """
+    Get filesystem type of device
+    """
+    return get_dev_info(dev, "FSTYPE", peer=peer)
+
+
+def get_dev_info(dev, *_type, peer=None):
+    """
+    Get device info using lsblk
+    """
+    cmd = "lsblk -fno {} {}".format(','.join(_type), dev)
+    return sh.cluster_shell().get_stdout_or_raise_error(cmd, peer)
+
+
+def is_dev_used_for_lvm(dev, peer=None):
+    """
+    Check if device is LV
+    """
+    return "lvm" in get_dev_info(dev, "TYPE", peer=peer)
+
+
+def is_dev_a_plain_raw_disk_or_partition(dev, peer=None):
+    """
+    Check if device is a raw disk or partition
+    """
+    out = get_dev_info(dev, "TYPE", peer=peer)
+    return re.search("(disk|part)", out) is not None
+
+
+def compare_uuid_with_peer_dev(dev_list, peer):
+    """
+    Check if device UUID is the same with peer's device
+    """
+    for dev in dev_list:
+        local_uuid = get_dev_uuid(dev)
+        if not local_uuid:
+            raise ValueError("Cannot find UUID for {} on local".format(dev))
+        peer_uuid = get_dev_uuid(dev, peer)
+        if not peer_uuid:
+            raise ValueError("Cannot find UUID for {} on {}".format(dev, peer))
+        if local_uuid != peer_uuid:
+            raise ValueError("UUID of {} not same with peer {}".format(dev, 
peer))
+
+
+def get_dlm_option_dict(peer=None):
+    """
+    Get dlm config option dictionary
+    """
+    out = sh.cluster_shell().get_stdout_or_raise_error("dlm_tool dump_config", 
peer)
+    return dict(re.findall(r"(\w+)=(\w+)", out))
+
+
+def set_dlm_option(peer=None, **kargs):
+    """
+    Set dlm option
+    """
+    shell = sh.cluster_shell()
+    dlm_option_dict = get_dlm_option_dict(peer=peer)
+    for option, value in kargs.items():
+        if option not in dlm_option_dict:
+            raise ValueError(f'"{option}" is not dlm config option')
+        if dlm_option_dict[option] != value:
+            shell.get_stdout_or_raise_error(f'dlm_tool set_config 
"{option}={value}"', peer)
+
+
+def is_dlm_running(peer=None, on_node=None):
+    """
+    Check if dlm ra controld is running
+    """
+    return 
xmlutil.CrmMonXmlParser(peer).is_resource_started(constants.DLM_CONTROLD_RA, 
node=on_node)
+
+
+def is_dlm_configured(peer=None):
+    """
+    Check if dlm configured
+    """
+    return 
xmlutil.CrmMonXmlParser(peer).is_resource_configured(constants.DLM_CONTROLD_RA)
+
+
+def check_no_quorum_policy_with_dlm():
+    """
+    Give warning when no-quorum-policy not freeze while configured DLM
+    """
+    if not is_dlm_configured():
+        return
+    from . import utils
+    res = utils.get_property("no-quorum-policy")
+    if not res or res != "freeze":
+        logger.warning("The DLM cluster best practice suggests to set the 
cluster property \"no-quorum-policy=freeze\"")
+
+
+@dataclass(frozen=True)
+class DeviceInfo:
+    device: str
+    parent_device: str|None
+    under_multipath: bool
+
+
+class MultipathInspector:
+    def __init__(self, dev):
+        self._shell = sh.cluster_shell()
+        self._device_info = self._inspect(dev)
+
+    def _get_parent_device(self, dev) -> str:
+        resolved = Path(dev).resolve()
+        cmd = f"lsblk -dn -o PKNAME {shlex.quote(str(resolved))}"
+        _, out, _ = self._shell.get_rc_stdout_stderr_without_input(None, cmd)
+        return out or resolved.name
+
+    def _get_multipath_mapping(self) -> dict[str, str]:
+        cmd = "multipathd show paths format \"%d %m\""
+        rc, out, _ = self._shell.get_rc_stdout_stderr_without_input(None, cmd)
+        mapping = dict()
+        if rc != 0:
+            return mapping
+        for line in out.splitlines():
+            parts = line.split()
+            if len(parts) < 2:
+                continue
+            dev_name, map_name = parts[0], parts[1]
+            if (dev_name, map_name) == ("dev", "multipath"):
+                continue
+            mapping[dev_name] = map_name
+        return mapping
+
+    def _inspect(self, dev: str) -> DeviceInfo:
+        parent = self._get_parent_device(dev)
+        mapping = self._get_multipath_mapping()
+        return DeviceInfo(
+            device=dev,
+            parent_device=parent,
+            under_multipath=parent in mapping
+        )
+
+    def _is_under_multipath(self) -> bool:
+        return self._device_info.under_multipath
+
+    @classmethod
+    def check_device_under_multipath(cls, dev):
+        inspector = cls(dev)
+        if inspector._is_under_multipath():
+            error_msg = f"Device {dev} is under multipath, please provide the 
multipath device instead"
+            raise ValueError(error_msg)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-5.1.0+20260615.8409ea5a/crmsh/ui_cluster.py 
new/crmsh-5.1.0+20260624.349562dd/crmsh/ui_cluster.py
--- old/crmsh-5.1.0+20260615.8409ea5a/crmsh/ui_cluster.py       2026-06-15 
11:35:01.000000000 +0200
+++ new/crmsh-5.1.0+20260624.349562dd/crmsh/ui_cluster.py       2026-06-24 
06:16:33.000000000 +0200
@@ -15,7 +15,7 @@
 from argparse import ArgumentParser, RawDescriptionHelpFormatter
 
 import crmsh.parallax
-from . import command, sh, healthcheck, migration
+from . import command, sh, healthcheck, migration, storage_utils
 from . import utils
 from . import scripts
 from . import completers as compl
@@ -247,9 +247,9 @@
         When dlm running and quorum is lost, before stop cluster service, 
should set
         enable_quorum_fencing=0, enable_quorum_lockspace=0 for dlm config 
option
         """
-        if utils.is_dlm_running(node) and not utils.cluster_with_quorum(node):
+        if storage_utils.is_dlm_running(node) and not 
utils.cluster_with_quorum(node):
             logger.debug("Quorum is lost; Set enable_quorum_fencing=0 and 
enable_quorum_lockspace=0 for dlm")
-            utils.set_dlm_option(peer=node, enable_quorum_fencing=0, 
enable_quorum_lockspace=0)
+            storage_utils.set_dlm_option(peer=node, enable_quorum_fencing=0, 
enable_quorum_lockspace=0)
 
     @command.skill_level('administrator')
     def do_stop(self, context, *args):
@@ -270,7 +270,7 @@
 
         cluster_in_maintenance = utils.is_cluster_in_maintenance_mode()
         for node in node_list[:]:
-            if cluster_in_maintenance and utils.is_dlm_running(on_node=node):
+            if cluster_in_maintenance and 
storage_utils.is_dlm_running(on_node=node):
                 logger.info("The cluster is in maintenance mode and dlm is 
running on %s", node)
                 logger.error("Stopping pacemaker/corosync will trigger 
unexpected node fencing when 'dlm_controld' is running in maintenance mode.")
                 node_list.remove(node)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-5.1.0+20260615.8409ea5a/crmsh/utils.py 
new/crmsh-5.1.0+20260624.349562dd/crmsh/utils.py
--- old/crmsh-5.1.0+20260615.8409ea5a/crmsh/utils.py    2026-06-15 
11:35:01.000000000 +0200
+++ new/crmsh-5.1.0+20260624.349562dd/crmsh/utils.py    2026-06-24 
06:16:33.000000000 +0200
@@ -29,9 +29,7 @@
 import selectors
 import shlex
 from pathlib import Path
-from collections import defaultdict
 from contextlib import contextmanager, closing
-from stat import S_ISBLK
 from lxml import etree
 from packaging import version
 from enum import IntFlag, auto
@@ -40,7 +38,7 @@
 
 import crmsh.parallax
 import crmsh.user_of_host
-from . import config, sh, corosync, cibquery
+from . import config, sh, corosync, cibquery, storage_utils
 from . import userdir
 from . import constants
 from . import options
@@ -54,6 +52,7 @@
 from .sh import ShellUtils
 from .service_manager import ServiceManager
 
+
 logger = logging.getLogger(__name__)
 logger_utils = log.LoggerUtils(logger)
 
@@ -2623,36 +2622,6 @@
     return [x for x in re.split(reg, string) if x]
 
 
-def get_non_block_device_nodes(dev, node_list=None) -> list[str]:
-    """
-    Return a list of nodes where the device is not a block device or does not 
exist
-    """
-    shell = sh.cluster_shell()
-    cluster_nodes = node_list or [this_node()]
-    failed_nodes = []
-    for node in cluster_nodes:
-        rc, _, _ = shell.get_rc_stdout_stderr_without_input(
-            node,
-            f"test -b {shlex.quote(dev)}"
-        )
-        if rc != 0:
-            failed_nodes.append(node)
-    return failed_nodes
-
-
-def detect_duplicate_device_path(device_list: typing.List[str]):
-    """
-    Resolve device path and check if there are duplicated device path
-    """
-    path_dict = defaultdict(list)
-    for dev in device_list:
-        resolved_path = Path(dev).resolve()
-        path_dict[resolved_path].append(dev)
-    for path, dev_list in path_dict.items():
-        if len(dev_list) > 1:
-            raise ValueError(f"Duplicated device path detected: 
{','.join(dev_list)}. They are all pointing to {path}")
-
-
 def has_fence_device_registered():
     """
     Check if any fence device registered
@@ -2663,22 +2632,6 @@
     return has_fence_device or using_diskless_sbd
 
 
-def has_disk_mounted(dev):
-    """
-    Check if device already mounted
-    """
-    out = sh.cluster_shell().get_stdout_or_raise_error("mount")
-    return re.search("\n{} on ".format(dev), out) is not None
-
-
-def has_mount_point_used(directory):
-    """
-    Check if mount directory already mounted
-    """
-    out = sh.cluster_shell().get_stdout_or_raise_error("mount")
-    return re.search(" on {}".format(directory), out) is not None
-
-
 def all_exist_id():
     """
     Get current exist id list
@@ -2706,94 +2659,6 @@
     return unused_id
 
 
-def get_all_vg_name():
-    """
-    Get all available VGs
-    """
-    out = sh.cluster_shell().get_stdout_or_raise_error("vgdisplay")
-    return re.findall(r"VG Name\s+(.*)", out)
-
-
-def get_pe_number(vg_id):
-    """
-    Get pe number
-    """
-    output = sh.cluster_shell().get_stdout_or_raise_error("vgdisplay 
{}".format(vg_id))
-    res = re.search(r"Total PE\s+(\d+)", output)
-    if not res:
-        raise ValueError("Cannot find PE on VG({})".format(vg_id))
-    return int(res.group(1))
-
-
-def has_dev_partitioned(dev, peer=None):
-    """
-    Check if device has partitions
-    """
-    return len(get_dev_info(dev, "NAME", peer=peer).splitlines()) > 1
-
-
-def get_dev_uuid(dev, peer=None):
-    """
-    Get UUID of device on local or peer node
-    """
-    out = get_dev_info(dev, "UUID", peer=peer).splitlines()
-    return out[0] if out else get_dev_uuid_2(dev, peer)
-
-
-def get_dev_uuid_2(dev, peer=None):
-    """
-    Get UUID of device using blkid
-    """
-    out = sh.cluster_shell().get_stdout_or_raise_error("blkid {}".format(dev), 
peer)
-    res = re.search("UUID=\"(.*?)\"", out)
-    return res.group(1) if res else None
-
-
-def get_dev_fs_type(dev, peer=None):
-    """
-    Get filesystem type of device
-    """
-    return get_dev_info(dev, "FSTYPE", peer=peer)
-
-
-def get_dev_info(dev, *_type, peer=None):
-    """
-    Get device info using lsblk
-    """
-    cmd = "lsblk -fno {} {}".format(','.join(_type), dev)
-    return sh.cluster_shell().get_stdout_or_raise_error(cmd, peer)
-
-
-def is_dev_used_for_lvm(dev, peer=None):
-    """
-    Check if device is LV
-    """
-    return "lvm" in get_dev_info(dev, "TYPE", peer=peer)
-
-
-def is_dev_a_plain_raw_disk_or_partition(dev, peer=None):
-    """
-    Check if device is a raw disk or partition
-    """
-    out = get_dev_info(dev, "TYPE", peer=peer)
-    return re.search("(disk|part)", out) is not None
-
-
-def compare_uuid_with_peer_dev(dev_list, peer):
-    """
-    Check if device UUID is the same with peer's device
-    """
-    for dev in dev_list:
-        local_uuid = get_dev_uuid(dev)
-        if not local_uuid:
-            raise ValueError("Cannot find UUID for {} on local".format(dev))
-        peer_uuid = get_dev_uuid(dev, peer)
-        if not peer_uuid:
-            raise ValueError("Cannot find UUID for {} on {}".format(dev, peer))
-        if local_uuid != peer_uuid:
-            raise ValueError("UUID of {} not same with peer {}".format(dev, 
peer))
-
-
 def append_res_to_group(group_id, res_id):
     """
     Append resource to exist group
@@ -2829,41 +2694,6 @@
     raise ValueError(error_msg)
 
 
-def get_dlm_option_dict(peer=None):
-    """
-    Get dlm config option dictionary
-    """
-    out = sh.cluster_shell().get_stdout_or_raise_error("dlm_tool dump_config", 
peer)
-    return dict(re.findall(r"(\w+)=(\w+)", out))
-
-
-def set_dlm_option(peer=None, **kargs):
-    """
-    Set dlm option
-    """
-    shell = sh.cluster_shell()
-    dlm_option_dict = get_dlm_option_dict(peer=peer)
-    for option, value in kargs.items():
-        if option not in dlm_option_dict:
-            raise ValueError(f'"{option}" is not dlm config option')
-        if dlm_option_dict[option] != value:
-            shell.get_stdout_or_raise_error(f'dlm_tool set_config 
"{option}={value}"', peer)
-
-
-def is_dlm_running(peer=None, on_node=None):
-    """
-    Check if dlm ra controld is running
-    """
-    return 
xmlutil.CrmMonXmlParser(peer).is_resource_started(constants.DLM_CONTROLD_RA, 
node=on_node)
-
-
-def is_dlm_configured(peer=None):
-    """
-    Check if dlm configured
-    """
-    return 
xmlutil.CrmMonXmlParser(peer).is_resource_configured(constants.DLM_CONTROLD_RA)
-
-
 def cluster_with_quorum(peer=None):
     """
     Check if current cluster has quorum
@@ -2994,17 +2824,6 @@
         yield False
 
 
-def check_no_quorum_policy_with_dlm():
-    """
-    Give warning when no-quorum-policy not freeze while configured DLM
-    """
-    if not is_dlm_configured():
-        return
-    res = get_property("no-quorum-policy")
-    if not res or res != "freeze":
-        logger.warning("The DLM cluster best practice suggests to set the 
cluster property \"no-quorum-policy=freeze\"")
-
-
 def set_property(property_name, property_value, property_type="crm_config", 
conditional=False):
     """
     Set property for cluster, resource and operator
@@ -3460,7 +3279,7 @@
     if not crm_mon_parser.is_non_stonith_resource_running():
         return True
     elif in_maintenance_mode:
-        if is_dlm_running():
+        if storage_utils.is_dlm_running():
             dlm_related_ids = 
crm_mon_parser.get_resource_top_parent_id_set_via_type(constants.DLM_CONTROLD_RA)
             logger.warning("Please stop DLM related resources (%s) and try 
again", ', '.join(dlm_related_ids))
             return False
@@ -3634,56 +3453,4 @@
         return not self._resolve_res.using_deprecated
 
 
-@dataclass(frozen=True)
-class DeviceInfo:
-    device: str
-    parent_device: str|None
-    under_multipath: bool
-
-
-class MultipathInspector:
-    def __init__(self, dev):
-        self._shell = sh.cluster_shell()
-        self._device_info = self._inspect(dev)
-
-    def _get_parent_device(self, dev) -> str:
-        resolved = Path(dev).resolve()
-        cmd = f"lsblk -dn -o PKNAME {shlex.quote(str(resolved))}"
-        _, out, _ = self._shell.get_rc_stdout_stderr_without_input(None, cmd)
-        return out or resolved.name
-
-    def _get_multipath_mapping(self) -> dict[str, str]:
-        cmd = "multipathd show paths format \"%d %m\""
-        rc, out, _ = self._shell.get_rc_stdout_stderr_without_input(None, cmd)
-        mapping = dict()
-        if rc != 0:
-            return mapping
-        for line in out.splitlines():
-            parts = line.split()
-            if len(parts) < 2:
-                continue
-            dev_name, map_name = parts[0], parts[1]
-            if (dev_name, map_name) == ("dev", "multipath"):
-                continue
-            mapping[dev_name] = map_name
-        return mapping
-
-    def _inspect(self, dev: str) -> DeviceInfo:
-        parent = self._get_parent_device(dev)
-        mapping = self._get_multipath_mapping()
-        return DeviceInfo(
-            device=dev,
-            parent_device=parent,
-            under_multipath=parent in mapping
-        )
-
-    def _is_under_multipath(self) -> bool:
-        return self._device_info.under_multipath
-
-    @classmethod
-    def check_device_under_multipath(cls, dev):
-        inspector = cls(dev)
-        if inspector._is_under_multipath():
-            error_msg = f"Device {dev} is under multipath, please provide the 
multipath device instead"
-            raise ValueError(error_msg)
 # vim:ts=4:sw=4:et:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/crmsh-5.1.0+20260615.8409ea5a/test/unittests/test_cluster_fs.py 
new/crmsh-5.1.0+20260624.349562dd/test/unittests/test_cluster_fs.py
--- old/crmsh-5.1.0+20260615.8409ea5a/test/unittests/test_cluster_fs.py 
2026-06-15 11:35:01.000000000 +0200
+++ new/crmsh-5.1.0+20260624.349562dd/test/unittests/test_cluster_fs.py 
2026-06-24 06:16:33.000000000 +0200
@@ -81,7 +81,7 @@
             self.multi_gfs2_devices_without_clvm2._verify_options()
         self.assertIn("Without Cluster LVM2 (-C option), -g option only 
support one device", str(context.exception))
 
-    @mock.patch("crmsh.utils.has_mount_point_used")
+    @mock.patch("crmsh.cluster_fs.storage_utils.has_mount_point_used")
     def test_verify_options_mount_point(self, mock_has_mount_point_used):
         mock_has_mount_point_used.return_value = True
         with self.assertRaises(cluster_fs.Error) as context:
@@ -89,7 +89,7 @@
         self.assertIn("Mount point /mnt/gfs2 already mounted", 
str(context.exception))
 
     @mock.patch("crmsh.utils.list_cluster_nodes")
-    @mock.patch("crmsh.utils.get_non_block_device_nodes")
+    @mock.patch("crmsh.cluster_fs.storage_utils.get_non_block_device_nodes")
     def test_verify_devices_not_block_device(self, 
mock_get_non_block_device_nodes, mock_list_cluster_nodes):
         mock_list_cluster_nodes.return_value = ["node1", "node2"]
         mock_get_non_block_device_nodes.return_value = ["node1"]
@@ -97,8 +97,8 @@
             self.ocfs2_instance_one_device._verify_devices()
         self.assertIn("/dev/sda1 is not a block device on node1", 
str(context.exception))
 
-    @mock.patch("crmsh.utils.is_dev_used_for_lvm")
-    @mock.patch("crmsh.utils.get_non_block_device_nodes")
+    @mock.patch("crmsh.cluster_fs.storage_utils.is_dev_used_for_lvm")
+    @mock.patch("crmsh.cluster_fs.storage_utils.get_non_block_device_nodes")
     def test_verify_devices_clvm2_with_lv(self, 
mock_get_non_block_device_nodes, mock_is_dev_used_for_lvm):
         mock_get_non_block_device_nodes.return_value = []
         mock_is_dev_used_for_lvm.return_value = True
@@ -106,9 +106,9 @@
             self.gfs2_instance_one_device_clvm2._verify_devices()
         self.assertIn("/dev/sda1 is a Logical Volume, cannot be used with the 
-C option", str(context.exception))
 
-    @mock.patch("crmsh.utils.has_disk_mounted")
-    @mock.patch("crmsh.utils.is_dev_used_for_lvm")
-    @mock.patch("crmsh.utils.get_non_block_device_nodes")
+    @mock.patch("crmsh.cluster_fs.storage_utils.has_disk_mounted")
+    @mock.patch("crmsh.cluster_fs.storage_utils.is_dev_used_for_lvm")
+    @mock.patch("crmsh.cluster_fs.storage_utils.get_non_block_device_nodes")
     def test_verify_devices_already_mounted(self, 
mock_get_non_block_device_nodes, mock_is_dev_used_for_lvm, 
mock_has_disk_mounted):
         mock_get_non_block_device_nodes.return_value = []
         mock_is_dev_used_for_lvm.return_value = False
@@ -156,7 +156,7 @@
         self.assertEqual(str(context.exception), '/dev/sda1 cannot be the same 
with SBD device')
 
     @mock.patch("crmsh.bootstrap.confirm")
-    @mock.patch("crmsh.utils.has_dev_partitioned")
+    @mock.patch("crmsh.cluster_fs.storage_utils.has_dev_partitioned")
     def test_confirm_to_overwrite_device_no_overwrite(self, 
mock_has_dev_partitioned, mock_confirm):
         mock_has_dev_partitioned.return_value = True
         mock_confirm.return_value = False
@@ -166,8 +166,8 @@
 
     @mock.patch("crmsh.sh.cluster_shell")
     @mock.patch("crmsh.bootstrap.confirm")
-    @mock.patch("crmsh.utils.get_dev_fs_type")
-    @mock.patch("crmsh.utils.has_dev_partitioned")
+    @mock.patch("crmsh.cluster_fs.storage_utils.get_dev_fs_type")
+    @mock.patch("crmsh.cluster_fs.storage_utils.has_dev_partitioned")
     def test_confirm_to_overwrite_device(self, mock_has_dev_partitioned, 
mock_get_dev_fs_type, mock_confirm, mock_cluster_shell):
         mock_has_dev_partitioned.return_value = False
         mock_get_dev_fs_type.return_value = "ext4"
@@ -296,8 +296,8 @@
         self.ocfs2_instance_one_device.join("node1")
         mock_status_long.assert_not_called()
 
-    @mock.patch("crmsh.utils.compare_uuid_with_peer_dev")
-    @mock.patch("crmsh.utils.is_dev_a_plain_raw_disk_or_partition")
+    @mock.patch("crmsh.cluster_fs.storage_utils.compare_uuid_with_peer_dev")
+    
@mock.patch("crmsh.cluster_fs.storage_utils.is_dev_a_plain_raw_disk_or_partition")
     @mock.patch("crmsh.xmlutil.CrmMonXmlParser")
     @mock.patch("crmsh.log.LoggerUtils.status_long")
     def test_join(self, mock_status_long, mock_crmmonxmlparser, 
mock_is_dev_a_plain_raw_disk_or_partition, mock_compare_uuid_with_peer_dev):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/crmsh-5.1.0+20260615.8409ea5a/test/unittests/test_sbd.py 
new/crmsh-5.1.0+20260624.349562dd/test/unittests/test_sbd.py
--- old/crmsh-5.1.0+20260615.8409ea5a/test/unittests/test_sbd.py        
2026-06-15 11:35:01.000000000 +0200
+++ new/crmsh-5.1.0+20260624.349562dd/test/unittests/test_sbd.py        
2026-06-24 06:16:33.000000000 +0200
@@ -59,7 +59,7 @@
         with self.assertRaises(ValueError):
             SBDUtils.compare_device_uuid("/dev/sbd_device", ["node1"])
 
-    @patch('crmsh.utils.get_non_block_device_nodes')
+    @patch('crmsh.sbd.storage_utils.get_non_block_device_nodes')
     @patch('crmsh.sbd.SBDUtils.compare_device_uuid')
     def test_verify_sbd_device_exceeds_max(self, mock_compare_device_uuid, 
mock_get_non_block_device_nodes):
         dev_list = [f"/dev/sbd_device_{i}" for i in 
range(SBDManager.SBD_DEVICE_MAX + 1)]
@@ -67,7 +67,7 @@
             SBDUtils.verify_sbd_device(dev_list)
         self.assertTrue(f"Maximum number of SBD device is 
{SBDManager.SBD_DEVICE_MAX}" in str(context.exception))
 
-    @patch('crmsh.utils.get_non_block_device_nodes')
+    @patch('crmsh.sbd.storage_utils.get_non_block_device_nodes')
     @patch('crmsh.sbd.SBDUtils.compare_device_uuid')
     def test_verify_sbd_device_non_block(self, mock_compare_device_uuid, 
mock_get_non_block_device_nodes):
         mock_get_non_block_device_nodes.return_value = ["node1"]
@@ -75,7 +75,7 @@
             SBDUtils.verify_sbd_device(["/dev/not_a_block_device"])
         self.assertTrue(f"/dev/not_a_block_device is not a block device on 
node1" in str(context.exception))
 
-    @patch('crmsh.utils.get_non_block_device_nodes')
+    @patch('crmsh.sbd.storage_utils.get_non_block_device_nodes')
     @patch('crmsh.sbd.SBDUtils.compare_device_uuid')
     def test_verify_sbd_device_valid(self, mock_compare_device_uuid, 
mock_get_non_block_device_nodes):
         mock_get_non_block_device_nodes.return_value = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/crmsh-5.1.0+20260615.8409ea5a/test/unittests/test_utils.py 
new/crmsh-5.1.0+20260624.349562dd/test/unittests/test_utils.py
--- old/crmsh-5.1.0+20260615.8409ea5a/test/unittests/test_utils.py      
2026-06-15 11:35:01.000000000 +0200
+++ new/crmsh-5.1.0+20260624.349562dd/test/unittests/test_utils.py      
2026-06-24 06:16:33.000000000 +0200
@@ -13,7 +13,7 @@
 from itertools import chain
 
 import crmsh.utils
-from crmsh import utils, config, tmpfiles, constants, options
+from crmsh import utils, storage_utils, config, tmpfiles, constants, options
 
 logging.basicConfig(level=logging.DEBUG)
 
@@ -756,31 +756,31 @@
     assert utils.re_split_string('[; ]', "/dev/sda1 ") == ["/dev/sda1"]
 
 
[email protected]('crmsh.utils.get_dev_info')
[email protected]('crmsh.storage_utils.get_dev_info')
 def test_has_dev_partitioned(mock_get_dev_info):
     mock_get_dev_info.return_value = """
 disk
 part
     """
-    res = utils.has_dev_partitioned("/dev/sda1")
+    res = storage_utils.has_dev_partitioned("/dev/sda1")
     assert res is True
     mock_get_dev_info.assert_called_once_with("/dev/sda1", "NAME", peer=None)
 
 
[email protected]('crmsh.utils.get_dev_uuid')
[email protected]('crmsh.storage_utils.get_dev_uuid')
 def test_compare_uuid_with_peer_dev_cannot_find_local(mock_get_dev_uuid):
     mock_get_dev_uuid.return_value = ""
     with pytest.raises(ValueError) as err:
-        utils.compare_uuid_with_peer_dev(["/dev/sdb1"], "node2")
+        storage_utils.compare_uuid_with_peer_dev(["/dev/sdb1"], "node2")
     assert str(err.value) == "Cannot find UUID for /dev/sdb1 on local"
     mock_get_dev_uuid.assert_called_once_with("/dev/sdb1")
 
 
[email protected]('crmsh.utils.get_dev_uuid')
[email protected]('crmsh.storage_utils.get_dev_uuid')
 def test_compare_uuid_with_peer_dev_cannot_find_peer(mock_get_dev_uuid):
     mock_get_dev_uuid.side_effect = ["1234", ""]
     with pytest.raises(ValueError) as err:
-        utils.compare_uuid_with_peer_dev(["/dev/sdb1"], "node2")
+        storage_utils.compare_uuid_with_peer_dev(["/dev/sdb1"], "node2")
     assert str(err.value) == "Cannot find UUID for /dev/sdb1 on node2"
     mock_get_dev_uuid.assert_has_calls([
         mock.call("/dev/sdb1"),
@@ -788,11 +788,11 @@
         ])
 
 
[email protected]('crmsh.utils.get_dev_uuid')
[email protected]('crmsh.storage_utils.get_dev_uuid')
 def test_compare_uuid_with_peer_dev(mock_get_dev_uuid):
     mock_get_dev_uuid.side_effect = ["1234", "5678"]
     with pytest.raises(ValueError) as err:
-        utils.compare_uuid_with_peer_dev(["/dev/sdb1"], "node2")
+        storage_utils.compare_uuid_with_peer_dev(["/dev/sdb1"], "node2")
     assert str(err.value) == "UUID of /dev/sdb1 not same with peer node2"
     mock_get_dev_uuid.assert_has_calls([
         mock.call("/dev/sdb1"),
@@ -800,18 +800,18 @@
         ])
 
 
[email protected]('crmsh.utils.get_dev_info')
[email protected]('crmsh.storage_utils.get_dev_info')
 def test_is_dev_used_for_lvm(mock_dev_info):
     mock_dev_info.return_value = "lvm"
-    res = utils.is_dev_used_for_lvm("/dev/sda1")
+    res = storage_utils.is_dev_used_for_lvm("/dev/sda1")
     assert res is True
     mock_dev_info.assert_called_once_with("/dev/sda1", "TYPE", peer=None)
 
 
[email protected]('crmsh.utils.get_dev_info')
[email protected]('crmsh.storage_utils.get_dev_info')
 def test_is_dev_a_plain_raw_disk_or_partition(mock_dev_info):
     mock_dev_info.return_value = "raid1\nlvm"
-    res = utils.is_dev_a_plain_raw_disk_or_partition("/dev/md127")
+    res = storage_utils.is_dev_a_plain_raw_disk_or_partition("/dev/md127")
     assert res is False
     mock_dev_info.assert_called_once_with("/dev/md127", "TYPE", peer=None)
 
@@ -819,23 +819,23 @@
 @mock.patch('crmsh.sh.ClusterShell.get_stdout_or_raise_error')
 def test_get_dev_info(mock_run):
     mock_run.return_value = "data"
-    res = utils.get_dev_info("/dev/sda1", "TYPE")
+    res = storage_utils.get_dev_info("/dev/sda1", "TYPE")
     assert res == "data"
     mock_run.assert_called_once_with("lsblk -fno TYPE /dev/sda1", None)
 
 
[email protected]('crmsh.utils.get_dev_info')
[email protected]('crmsh.storage_utils.get_dev_info')
 def test_get_dev_fs_type(mock_get_info):
     mock_get_info.return_value = "data"
-    res = utils.get_dev_fs_type("/dev/sda1")
+    res = storage_utils.get_dev_fs_type("/dev/sda1")
     assert res == "data"
     mock_get_info.assert_called_once_with("/dev/sda1", "FSTYPE", peer=None)
 
 
[email protected]('crmsh.utils.get_dev_info')
[email protected]('crmsh.storage_utils.get_dev_info')
 def test_get_dev_uuid(mock_get_info):
     mock_get_info.return_value = "uuid"
-    res = utils.get_dev_uuid("/dev/sda1")
+    res = storage_utils.get_dev_uuid("/dev/sda1")
     assert res == "uuid"
     mock_get_info.assert_called_once_with("/dev/sda1", "UUID", peer=None)
 
@@ -844,7 +844,7 @@
 def test_get_pe_number_except(mock_run):
     mock_run.return_value = "data"
     with pytest.raises(ValueError) as err:
-        utils.get_pe_number("vg1")
+        storage_utils.get_pe_number("vg1")
     assert str(err.value) == "Cannot find PE on VG(vg1)"
     mock_run.assert_called_once_with("vgdisplay vg1")
 
@@ -856,7 +856,7 @@
 Total PE              1534
 Alloc PE / Size       1534 / 5.99 GiB
     """
-    res = utils.get_pe_number("vg1")
+    res = storage_utils.get_pe_number("vg1")
     assert res == 1534
     mock_run.assert_called_once_with("vgdisplay vg1")
 
@@ -868,7 +868,7 @@
   VG Name               ocfs2-vg
   System ID
     """
-    res = utils.get_all_vg_name()
+    res = storage_utils.get_all_vg_name()
     assert res == ["ocfs2-vg"]
     mock_run.assert_called_once_with("vgdisplay")
 
@@ -908,7 +908,7 @@
 /dev/vda2 on /opt type btrfs 
(rw,relatime,space_cache,subvolid=263,subvol=/@/opt)
 /dev/vda2 on /var/lib/docker/btrfs type btrfs 
(rw,relatime,space_cache,subvolid=258,subvol=/@/var)
     """
-    res = utils.has_mount_point_used("/opt")
+    res = storage_utils.has_mount_point_used("/opt")
     assert res is True
     mock_run.assert_called_once_with("mount")
 
@@ -920,7 +920,7 @@
 /dev/vda2 on /opt type btrfs 
(rw,relatime,space_cache,subvolid=263,subvol=/@/opt)
 /dev/vda2 on /var/lib/docker/btrfs type btrfs 
(rw,relatime,space_cache,subvolid=258,subvol=/@/var)
     """
-    res = utils.has_disk_mounted("/dev/vda2")
+    res = storage_utils.has_disk_mounted("/dev/vda2")
     assert res is True
     mock_run.assert_called_once_with("mount")
 
@@ -944,7 +944,7 @@
     mock_cluster_shell_inst = mock.Mock()
     mock_cluster_shell.return_value = mock_cluster_shell_inst
     mock_cluster_shell_inst.get_rc_stdout_stderr_without_input.return_value = 
(1, None, None)
-    res = utils.get_non_block_device_nodes("/dev/sda1", ["node1"])
+    res = storage_utils.get_non_block_device_nodes("/dev/sda1", ["node1"])
     assert res == ["node1"]
     
mock_cluster_shell_inst.get_rc_stdout_stderr_without_input.assert_called_once_with("node1",
 "test -b /dev/sda1")    
 
@@ -995,7 +995,7 @@
 key1=value1
 key2=value2
     """
-    res_dict = utils.get_dlm_option_dict()
+    res_dict = storage_utils.get_dlm_option_dict()
     assert res_dict == {
             "key1": "value1",
             "key2": "value2"
@@ -1003,19 +1003,19 @@
     mock_run_inst.get_stdout_or_raise_error.assert_called_once_with("dlm_tool 
dump_config", None)
 
 
[email protected]('crmsh.utils.get_dlm_option_dict')
[email protected]('crmsh.storage_utils.get_dlm_option_dict')
 def test_set_dlm_option_exception(mock_get_dict):
     mock_get_dict.return_value = {
             "key1": "value1",
             "key2": "value2"
             }
     with pytest.raises(ValueError) as err:
-        utils.set_dlm_option(name="xin")
+        storage_utils.set_dlm_option(name="xin")
     assert str(err.value) == '"name" is not dlm config option'
 
 
 @mock.patch('crmsh.sh.cluster_shell')
[email protected]('crmsh.utils.get_dlm_option_dict')
[email protected]('crmsh.storage_utils.get_dlm_option_dict')
 def test_set_dlm_option(mock_get_dict, mock_run):
     mock_run_inst = mock.Mock()
     mock_run.return_value = mock_run_inst
@@ -1023,7 +1023,7 @@
             "key1": "value1",
             "key2": "value2"
             }
-    utils.set_dlm_option(key2="test")
+    storage_utils.set_dlm_option(key2="test")
     mock_run_inst.get_stdout_or_raise_error.assert_called_once_with('dlm_tool 
set_config "key2=test"', None)
 
 
@@ -1032,7 +1032,7 @@
     mock_crmmon_inst = mock.Mock()
     mock_crmmon.return_value = mock_crmmon_inst
     mock_crmmon_inst.is_resource_configured.return_value = True
-    assert utils.is_dlm_configured() is True
+    assert storage_utils.is_dlm_configured() is True
     
mock_crmmon_inst.is_resource_configured.assert_called_once_with(constants.DLM_CONTROLD_RA)
 
 
@@ -1150,20 +1150,20 @@
     mock_msec.assert_has_calls([mock.call("10s"), mock.call("10")])
 
 
[email protected]('crmsh.utils.is_dlm_configured')
[email protected]('crmsh.storage_utils.is_dlm_configured')
 def test_check_no_quorum_policy_with_dlm_return(mock_dlm):
     mock_dlm.return_value = False
-    utils.check_no_quorum_policy_with_dlm()
+    storage_utils.check_no_quorum_policy_with_dlm()
     mock_dlm.assert_called_once_with()
 
 
 @mock.patch('logging.Logger.warning')
 @mock.patch('crmsh.utils.get_property')
[email protected]('crmsh.utils.is_dlm_configured')
[email protected]('crmsh.storage_utils.is_dlm_configured')
 def test_check_no_quorum_policy_with_dlm(mock_dlm, mock_get_property, 
mock_warn):
     mock_dlm.return_value = True
     mock_get_property.return_value = "stop"
-    utils.check_no_quorum_policy_with_dlm()
+    storage_utils.check_no_quorum_policy_with_dlm()
     mock_dlm.assert_called_once_with()
     mock_get_property.assert_called_once_with("no-quorum-policy")
     mock_warn.assert_called_once_with('The DLM cluster best practice suggests 
to set the cluster property "no-quorum-policy=freeze"')
@@ -1492,7 +1492,7 @@
             (0, "dev multipath\nsda mpatha", "")  # multipathd show paths 
output
         ]
 
-        inspector = utils.MultipathInspector("/dev/sda1")
+        inspector = storage_utils.MultipathInspector("/dev/sda1")
 
         assert inspector._shell == mock_shell_inst
         assert inspector._device_info.device == "/dev/sda1"
@@ -1510,7 +1510,7 @@
             (0, "sda", "")  # lsblk output for test call
         ]
 
-        inspector = utils.MultipathInspector("/dev/sda1")
+        inspector = storage_utils.MultipathInspector("/dev/sda1")
         parent = inspector._get_parent_device("/dev/sda1")
 
         assert parent == "sda"
@@ -1530,7 +1530,7 @@
             (0, multipathd_output, "")  # multipathd for test call
         ]
 
-        inspector = utils.MultipathInspector("/dev/sda1")
+        inspector = storage_utils.MultipathInspector("/dev/sda1")
         mapping = inspector._get_multipath_mapping()
 
         assert mapping == {"sda": "mpatha", "sdb": "mpatha", "sdc": "mpathb"}
@@ -1545,7 +1545,7 @@
             (0, "dev multipath\nsda mpatha", "")
         ]
 
-        inspector = utils.MultipathInspector("/dev/sda1")
+        inspector = storage_utils.MultipathInspector("/dev/sda1")
         device_info = inspector._device_info
 
         assert device_info.device == "/dev/sda1"
@@ -1562,7 +1562,7 @@
             (0, "dev multipath\nsda mpatha", "")
         ]
 
-        inspector = utils.MultipathInspector("/dev/sda1")
+        inspector = storage_utils.MultipathInspector("/dev/sda1")
 
         assert inspector._is_under_multipath() is True
 
@@ -1577,6 +1577,6 @@
         ]
 
         with pytest.raises(ValueError) as exc_info:
-            utils.MultipathInspector.check_device_under_multipath("/dev/sda1")
+            
storage_utils.MultipathInspector.check_device_under_multipath("/dev/sda1")
 
         assert str(exc_info.value) == "Device /dev/sda1 is under multipath, 
please provide the multipath device instead"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-5.1.0+20260615.8409ea5a/tox.ini 
new/crmsh-5.1.0+20260624.349562dd/tox.ini
--- old/crmsh-5.1.0+20260615.8409ea5a/tox.ini   2026-06-15 11:35:01.000000000 
+0200
+++ new/crmsh-5.1.0+20260624.349562dd/tox.ini   2026-06-24 06:16:33.000000000 
+0200
@@ -8,7 +8,7 @@
 deps =
     pytest
     pytest-cov
-commands = pytest -vv --cov=crmsh --cov-config .coveragerc --cov-report term 
--cov-report xml {posargs}
+commands = pytest --cov=crmsh --cov-config .coveragerc --cov-report xml 
{posargs}
 
 [testenv]
 changedir = {[base]changedir}

Reply via email to