From 5ea82e18254e0130e1d17355a4b44bce7a7a8212 Mon Sep 17 00:00:00 2001 From: Antoine Bartuccio Date: Fri, 14 Nov 2025 14:17:36 +0100 Subject: [PATCH 1/2] fix(linstorvolumemanager): fix typo Fix some typo in docstring Signed-off-by: Antoine Bartuccio --- drivers/linstorvolumemanager.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/linstorvolumemanager.py b/drivers/linstorvolumemanager.py index c969d0b48..da2d0e380 100755 --- a/drivers/linstorvolumemanager.py +++ b/drivers/linstorvolumemanager.py @@ -392,7 +392,7 @@ def __init__( """ Create a new LinstorVolumeManager object. :param str uri: URI to communicate with the LINSTOR controller. - :param str group_name: The SR goup name to use. + :param str group_name: The SR group name to use. :param bool repair: If true we try to remove bad volumes due to a crash or unexpected behavior. :param function logger: Function to log messages. @@ -420,7 +420,7 @@ def __init__( self._volumes = set() self._storage_pools_time = 0 - # To increate performance and limit request count to LINSTOR services, + # To increase performance and limit request count to LINSTOR services, # we use caches. self._kv_cache = self._create_kv_cache() self._resource_cache = None @@ -1158,7 +1158,7 @@ def get_usage_states(self, volume_uuid): """ Check if a volume is currently used. :param str volume_uuid: The volume uuid to check. - :return: A dictionnary that contains states. + :return: A dictionary that contains states. :rtype: dict(str, bool or None) """ @@ -1176,14 +1176,14 @@ def get_volume_openers(self, volume_uuid): """ Get openers of a volume. :param str volume_uuid: The volume uuid to monitor. - :return: A dictionnary that contains openers. + :return: A dictionary that contains openers. :rtype: dict(str, obj) """ return get_all_volume_openers(self.get_volume_name(volume_uuid), '0') def get_volumes_with_name(self): """ - Give a volume dictionnary that contains names actually owned. + Give a volume dictionary that contains names actually owned. :return: A volume/name dict. :rtype: dict(str, str) """ @@ -1191,7 +1191,7 @@ def get_volumes_with_name(self): def get_volumes_with_info(self): """ - Give a volume dictionnary that contains VolumeInfos. + Give a volume dictionary that contains VolumeInfos. :return: A volume/VolumeInfo dict. :rtype: dict(str, VolumeInfo) """ @@ -1215,7 +1215,7 @@ def get_volumes_with_info(self): def get_volumes_with_metadata(self): """ - Give a volume dictionnary that contains metadata. + Give a volume dictionary that contains metadata. :return: A volume/metadata dict. :rtype: dict(str, dict) """ From e85e3e9fed2e1e9376a875a3fcccac012bb03056 Mon Sep 17 00:00:00 2001 From: Antoine Bartuccio Date: Fri, 31 Oct 2025 13:00:42 +0100 Subject: [PATCH 2/2] fix(linstorvolumemanager): don't allow InUse volumes to be deleted Check for usage status before deleting a linstor volume and raise an appropriate error if this happens Signed-off-by: Antoine Bartuccio --- drivers/linstorvolumemanager.py | 34 ++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/drivers/linstorvolumemanager.py b/drivers/linstorvolumemanager.py index da2d0e380..c053cc506 100755 --- a/drivers/linstorvolumemanager.py +++ b/drivers/linstorvolumemanager.py @@ -15,7 +15,7 @@ # along with this program. If not, see . # -from sm_typing import override +from sm_typing import Any, Dict, override import errno import json @@ -302,7 +302,8 @@ class LinstorVolumeManager(object): '_base_group_name', '_group_name', '_ha_group_name', '_volumes', '_storage_pools', '_storage_pools_time', '_kv_cache', '_resource_cache', '_volume_info_cache', - '_kv_cache_dirty', '_resource_cache_dirty', '_volume_info_cache_dirty' + '_kv_cache_dirty', '_resource_cache_dirty', '_volume_info_cache_dirty', + '_resources_info_cache', ) DEV_ROOT_PATH = DRBD_BY_RES_PATH @@ -427,6 +428,7 @@ def __init__( self._resource_cache_dirty = True self._volume_info_cache = None self._volume_info_cache_dirty = True + self._resources_info_cache = None self._build_volumes(repair=repair) @property @@ -686,6 +688,13 @@ def destroy_volume(self, volume_uuid): self._ensure_volume_exists(volume_uuid) self.ensure_volume_is_not_locked(volume_uuid) + is_volume_in_use = any(node["in-use"] for node in self.get_resource_info(volume_uuid)["nodes"].values()) + if is_volume_in_use: + raise LinstorVolumeManagerError( + f"Could not destroy volume `{volume_uuid}` as it is currently in use", + LinstorVolumeManagerError.ERR_VOLUME_DESTROY + ) + # Mark volume as destroyed. volume_properties = self._get_volume_properties(volume_uuid) volume_properties[self.PROP_NOT_EXISTS] = self.STATE_NOT_EXISTS @@ -1683,6 +1692,9 @@ def get_resources_info(self): Give all resources of current group name. :rtype: dict(str, list) """ + if self._resources_info_cache and not self._resource_cache_dirty: + return self._resources_info_cache + resources = {} resource_list = self._get_resource_cache() volume_names = self.get_volumes_with_name() @@ -1739,7 +1751,23 @@ def get_resources_info(self): if resource: resource['uuid'] = volume_uuid - return resources + self._resources_info_cache = resources + return self._resources_info_cache + + def get_resource_info(self, volume_uuid: str) -> Dict[str, Any]: + """ + Give all resource info related to provided UUID in the current group. + :param volume_uuid str: volume uuid to search for + :rtype: dict(str, any) + """ + for volume in self.get_resources_info().values(): + if volume["uuid"] == volume_uuid: + return volume + + raise LinstorVolumeManagerError( + f"Could not find info about volume `{volume_uuid}`", + LinstorVolumeManagerError.ERR_VOLUME_NOT_EXISTS + ) def get_database_path(self): """