diff --git a/drivers/linstorvolumemanager.py b/drivers/linstorvolumemanager.py index c969d0b48..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 @@ -392,7 +393,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,13 +421,14 @@ 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 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 @@ -1158,7 +1167,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 +1185,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 +1200,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 +1224,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) """ @@ -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): """