From 58b750a8c9ee10bfbbe526db92aeb313741b119e Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Tue, 8 Dec 2020 14:30:31 +0100 Subject: [PATCH] Add support for removing Stratis devices using DBus API We are ignoring a lot of stratis private device mapper devices now so we can no longer use libblockdev DM plugin to remove Stratis storage stack and we need to use Stratis DBus API instead. --- blivet/devicelibs/stratis.py | 70 ++++++++++++++++++++++++++++++ blivet/devices/stratis.py | 13 +++++- blivet/errors.py | 5 +++ blivet/static_data/stratis_info.py | 23 ++++------ 4 files changed, 96 insertions(+), 15 deletions(-) diff --git a/blivet/devicelibs/stratis.py b/blivet/devicelibs/stratis.py index 983073235..507fd31ed 100644 --- a/blivet/devicelibs/stratis.py +++ b/blivet/devicelibs/stratis.py @@ -20,7 +20,77 @@ # Author(s): Vojtech Trefny # +import gi +gi.require_version("GLib", "2.0") + +from gi.repository import GLib + +from ..errors import StratisError from ..size import Size +from ..static_data import stratis_info +from .. import safe_dbus + + +STRATIS_SERVICE = "org.storage.stratis2" +STRATIS_PATH = "/org/storage/stratis2" +STRATIS_POOL_INTF = STRATIS_SERVICE + ".pool" +STRATIS_FILESYSTEM_INTF = STRATIS_SERVICE + ".filesystem" +STRATIS_BLOCKDEV_INTF = STRATIS_SERVICE + ".blockdev" +STRATIS_PROPS_INTF = STRATIS_SERVICE + ".FetchProperties" +STRATIS_MANAGER_INTF = STRATIS_SERVICE + ".Manager" STRATIS_FS_SIZE = Size("1 TiB") + + +def remove_pool(pool_uuid): + if not safe_dbus.check_object_available(STRATIS_SERVICE, STRATIS_PATH): + raise StratisError("Stratis DBus service not available") + + # repopulate the stratis info cache just to be sure all values are still valid + stratis_info.drop_cache() + + if pool_uuid not in stratis_info.pools.keys(): + raise StratisError("Stratis pool with UUID %s not found" % pool_uuid) + + pool_info = stratis_info.pools[pool_uuid] + + try: + (succ, _uuid), rc, err = safe_dbus.call_sync(STRATIS_SERVICE, + STRATIS_PATH, + STRATIS_MANAGER_INTF, + "DestroyPool", + GLib.Variant("(o)", (pool_info.object_path,))) + except safe_dbus.DBusCallError as e: + raise StratisError("Failed to remove stratis pool: %s" % str(e)) + else: + if not succ: + raise StratisError("Failed to remove stratis pool: %s (%d)" % (err, rc)) + + +def remove_filesystem(pool_uuid, fs_uuid): + if not safe_dbus.check_object_available(STRATIS_SERVICE, STRATIS_PATH): + raise StratisError("Stratis DBus service not available") + + # repopulate the stratis info cache just to be sure all values are still valid + stratis_info.drop_cache() + + if pool_uuid not in stratis_info.pools.keys(): + raise StratisError("Stratis pool with UUID %s not found" % pool_uuid) + if fs_uuid not in stratis_info.filesystems.keys(): + raise StratisError("Stratis filesystem with UUID %s not found" % fs_uuid) + + pool_info = stratis_info.pools[pool_uuid] + fs_info = stratis_info.filesystems[fs_uuid] + + try: + (succ, _uuid), rc, err = safe_dbus.call_sync(STRATIS_SERVICE, + pool_info.object_path, + STRATIS_POOL_INTF, + "DestroyFilesystems", + GLib.Variant("(ao)", ([fs_info.object_path],))) + except safe_dbus.DBusCallError as e: + raise StratisError("Failed to remove stratis filesystem: %s" % str(e)) + else: + if not succ: + raise StratisError("Failed to remove stratis filesystem: %s (%d)" % (err, rc)) diff --git a/blivet/devices/stratis.py b/blivet/devices/stratis.py index 06253437e..df6d1711e 100644 --- a/blivet/devices/stratis.py +++ b/blivet/devices/stratis.py @@ -25,6 +25,8 @@ from .storage import StorageDevice from ..static_data import stratis_info from ..size import Size +from ..storage_log import log_method_call +from .. import devicelibs class StratisPoolDevice(StorageDevice): @@ -39,9 +41,13 @@ def read_current_size(self): size = Size(0) if self.exists and self.uuid in stratis_info.pools.keys(): size = stratis_info.pools[self.uuid].physical_size - return size + def _destroy(self): + """ Destroy the device. """ + log_method_call(self, self.name, status=self.status) + devicelibs.stratis.remove_pool(self.uuid) + class StratisFilesystemDevice(StorageDevice): """ A stratis pool device """ @@ -74,3 +80,8 @@ def pool(self): @property def path(self): return "%s/%s/%s" % (self._dev_dir, self.pool.name, self.fsname) + + def _destroy(self): + """ Destroy the device. """ + log_method_call(self, self.name, status=self.status) + devicelibs.stratis.remove_filesystem(self.pool.uuid, self.uuid) diff --git a/blivet/errors.py b/blivet/errors.py index 1832fbdd5..b281c2c66 100644 --- a/blivet/errors.py +++ b/blivet/errors.py @@ -181,6 +181,11 @@ class BTRFSError(StorageError): class BTRFSValueError(BTRFSError, ValueError): pass + +class StratisError(StorageError): + pass + + # DeviceTree diff --git a/blivet/static_data/stratis_info.py b/blivet/static_data/stratis_info.py index bff8053f6..ec6d61327 100644 --- a/blivet/static_data/stratis_info.py +++ b/blivet/static_data/stratis_info.py @@ -24,22 +24,15 @@ from .. import safe_dbus from ..size import Size +from ..devicelibs.stratis import STRATIS_SERVICE, STRATIS_PATH, STRATIS_POOL_INTF, STRATIS_FILESYSTEM_INTF, STRATIS_BLOCKDEV_INTF, STRATIS_PROPS_INTF import logging log = logging.getLogger("blivet") -STRATIS_SERVICE = "org.storage.stratis2" -STRATIS_PATH = "/org/storage/stratis2" -STRATIS_POOL_INTF = STRATIS_SERVICE + ".pool" -STRATIS_FILESYSTEM_INTF = STRATIS_SERVICE + ".filesystem" -STRATIS_BLOCKDEV_INTF = STRATIS_SERVICE + ".blockdev" -STRATIS_PROPS_INTF = STRATIS_SERVICE + ".FetchProperties" - - -StratisPoolInfo = namedtuple("StratisPoolInfo", ["name", "uuid", "physical_size"]) -StratisFilesystemInfo = namedtuple("StratisFilesystemInfo", ["name", "uuid", "pool_name", "pool_uuid"]) -StratisBlockdevInfo = namedtuple("StratisBlockdevInfo", ["path", "uuid", "pool_name", "pool_uuid"]) +StratisPoolInfo = namedtuple("StratisPoolInfo", ["name", "uuid", "physical_size", "object_path"]) +StratisFilesystemInfo = namedtuple("StratisFilesystemInfo", ["name", "uuid", "pool_name", "pool_uuid", "object_path"]) +StratisBlockdevInfo = namedtuple("StratisBlockdevInfo", ["path", "uuid", "pool_name", "pool_uuid", "object_path"]) class StratisInfo(object): @@ -77,7 +70,7 @@ def _get_pool_info(self, pool_path): pool_size = 0 return StratisPoolInfo(name=properties["Name"], uuid=properties["Uuid"], - physical_size=Size(pool_size)) + physical_size=Size(pool_size), object_path=pool_path) def _get_filesystem_info(self, filesystem_path): try: @@ -97,7 +90,8 @@ def _get_filesystem_info(self, filesystem_path): return None return StratisFilesystemInfo(name=properties["Name"], uuid=properties["Uuid"], - pool_name=pool_info.name, pool_uuid=pool_info.uuid) + pool_name=pool_info.name, pool_uuid=pool_info.uuid, + object_path=filesystem_path) def _get_blockdev_info(self, blockdev_path): try: @@ -122,7 +116,8 @@ def _get_blockdev_info(self, blockdev_path): pool_name = pool_info.name return StratisBlockdevInfo(path=properties["Devnode"], uuid=properties["Uuid"], - pool_name=pool_name, pool_uuid=pool_info.uuid) + pool_name=pool_name, pool_uuid=pool_info.uuid, + object_path=blockdev_path) def _get_stratis_info(self): self._info_cache = dict()