From 8d29816f0f3db6c7d287bbb7469db77c9de701d1 Mon Sep 17 00:00:00 2001 From: Venky Shankar Date: Fri, 17 May 2019 01:40:37 -0400 Subject: [PATCH] mgr / volumes: carve out subvolume operations as a separate class Move (and refactor) subvolume specific operations from main module source to SubVolume class in a new subvolume source. Also, provide hooks in VolumeClient to forward subvolume specific opertaions to this class. Signed-off-by: Venky Shankar --- src/pybind/mgr/volumes/fs/subvolume.py | 262 ++++++++++--------------- src/pybind/mgr/volumes/fs/volume.py | 193 ++++++++++++++++++ src/pybind/mgr/volumes/module.py | 191 +----------------- 3 files changed, 306 insertions(+), 340 deletions(-) diff --git a/src/pybind/mgr/volumes/fs/subvolume.py b/src/pybind/mgr/volumes/fs/subvolume.py index 9e476c7a7c8..01767cf331a 100644 --- a/src/pybind/mgr/volumes/fs/subvolume.py +++ b/src/pybind/mgr/volumes/fs/subvolume.py @@ -4,38 +4,16 @@ Copyright (C) 2019 Red Hat, Inc. LGPL2.1. See file COPYING. """ -import errno import logging import os import cephfs -import rados +from .subvolspec import SubvolumeSpec log = logging.getLogger(__name__) -# Reserved subvolume group name which we use in paths for subvolumes -# that are not assigned to a group (i.e. created with group=None) -NO_GROUP_NAME = "_nogroup" - - -class SubvolumePath(object): - """ - Identify a subvolume's path as group->subvolume - The Subvolume ID is a unique identifier, but this is a much more - helpful thing to pass around. - """ - def __init__(self, group_id, subvolume_id): - self.group_id = group_id - self.subvolume_id = subvolume_id - assert self.group_id != NO_GROUP_NAME - assert self.subvolume_id != "" and self.subvolume_id is not None - - def __str__(self): - return "{0}/{1}".format(self.group_id, self.subvolume_id) - - -class SubvolumeClient(object): +class SubVolume(object): """ Combine libcephfs and librados interfaces to implement a 'Subvolume' concept implemented as a cephfs directory. @@ -52,70 +30,14 @@ class SubvolumeClient(object): or cephfs.Error exceptions in unexpected situations. """ - # Where shall we create our subvolumes? - DEFAULT_SUBVOL_PREFIX = "/volumes" - DEFAULT_NS_PREFIX = "fsvolumens_" - def __init__(self, mgr, subvolume_prefix=None, pool_ns_prefix=None, fs_name=None): + def __init__(self, mgr, fs_name=None): self.fs = None self.fs_name = fs_name self.connected = False self.rados = mgr.rados - self.subvolume_prefix = subvolume_prefix if subvolume_prefix else self.DEFAULT_SUBVOL_PREFIX - self.pool_ns_prefix = pool_ns_prefix if pool_ns_prefix else self.DEFAULT_NS_PREFIX - - def _subvolume_path(self, subvolume_path): - """ - Determine the path within CephFS where this subvolume will live - :return: absolute path (string) - """ - return os.path.join( - self.subvolume_prefix, - subvolume_path.group_id if subvolume_path.group_id is not None else NO_GROUP_NAME, - subvolume_path.subvolume_id) - - def _group_path(self, group_id): - """ - Determine the path within CephFS where this subvolume group will live - :return: absolute path (string) - """ - if group_id is None: - raise ValueError("group_id may not be None") - - return os.path.join( - self.subvolume_prefix, - group_id - ) - - def connect(self): - log.debug("Connecting to cephfs...") - self.fs = cephfs.LibCephFS(rados_inst=self.rados) - log.debug("CephFS initializing...") - self.fs.init() - log.debug("CephFS mounting...") - self.fs.mount(filesystem_name=self.fs_name.encode('utf-8')) - log.debug("Connection to cephfs complete") - - def disconnect(self): - log.info("disconnect") - if self.fs: - log.debug("Disconnecting cephfs...") - self.fs.shutdown() - self.fs = None - log.debug("Disconnecting cephfs complete") - - def __enter__(self): - self.connect() - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - self.disconnect() - - def __del__(self): - self.disconnect() - def _mkdir_p(self, path, mode=0o755): try: self.fs.stat(path) @@ -133,80 +55,68 @@ class SubvolumeClient(object): except cephfs.ObjectNotFound: self.fs.mkdir(subpath, mode) - def create_group(self, group_id, mode=0o755): - path = self._group_path(group_id) - self._mkdir_p(path, mode) + ### basic subvolume operations - def delete_group(self, group_id): - path = self._group_path(group_id) - self.fs.rmdir(path) - - def create_subvolume(self, subvolume_path, size=None, namespace_isolated=True, mode=0o755): + def create_subvolume(self, spec, size=None, namespace_isolated=True, mode=0o755): """ Set up metadata, pools and auth for a subvolume. This function is idempotent. It is safe to call this again for an already-created subvolume, even if it is in use. - :param subvolume_path: SubvolumePath instance + :param spec: subvolume path specification :param size: In bytes, or None for no size limit :param namespace_isolated: If true, use separate RADOS namespace for this subvolume :return: None """ - path = self._subvolume_path(subvolume_path) - log.info("creating subvolume with path: {0}".format(path)) + subvolpath = spec.subvolume_path + log.info("creating subvolume with path: {0}".format(subvolpath)) - self._mkdir_p(path, mode) + self._mkdir_p(subvolpath, mode) if size is not None: - self.fs.setxattr(path, 'ceph.quota.max_bytes', str(size).encode('utf-8'), 0) + self.fs.setxattr(subvolpath, 'ceph.quota.max_bytes', str(size).encode('utf-8'), 0) - # enforce security isolation, use separate namespace for this subvolume + xattr_key = xattr_val = None if namespace_isolated: - namespace = "{0}{1}".format(self.pool_ns_prefix, subvolume_path.subvolume_id) - log.info("creating subvolume with path: {0}, using rados namespace {1} to isolate data.".format(subvolume_path, namespace)) - self.fs.setxattr(path, 'ceph.dir.layout.pool_namespace', - namespace.encode('utf-8'), 0) + # enforce security isolation, use separate namespace for this subvolume + xattr_key = 'ceph.dir.layout.pool_namespace' + xattr_val = spec.fs_namespace else: # If subvolume's namespace layout is not set, then the subvolume's pool # layout remains unset and will undesirably change with ancestor's # pool layout changes. - pool_name = self._get_ancestor_xattr(path, "ceph.dir.layout.pool") - self.fs.setxattr(path, 'ceph.dir.layout.pool', - pool_name.encode('utf-8'), 0) + xattr_key = 'ceph.dir.layout.pool' + xattr_val = self._get_ancestor_xattr(subvolpath, "ceph.dir.layout.pool") + # TODO: handle error... + self.fs.setxattr(subvolpath, xattr_key, xattr_val.encode('utf-8'), 0) - def delete_subvolume(self, subvolume_path): + def remove_subvolume(self, spec): """ Make a subvolume inaccessible to guests. This function is idempotent. This is the fast part of tearing down a subvolume: you must also later call purge_subvolume, which is the slow part. - :param subvolume_path: Same identifier used in create_subvolume + :param spec: subvolume path specification :return: None """ - path = self._subvolume_path(subvolume_path) - log.info("deleting subvolume with path: {0}".format(path)) - - # Create the trash folder if it doesn't already exist - trash = os.path.join(self.subvolume_prefix, "_deleting") - self._mkdir_p(trash) + subvolpath = spec.subvolume_path + log.info("deleting subvolume with path: {0}".format(subvolpath)) - # We'll move it to here - trashed_subvolume = os.path.join(trash, subvolume_path.subvolume_id) + # Create the trash directory if it doesn't already exist + trashdir = spec.trash_dir + self._mkdir_p(trashdir) - # Move the subvolume to the trash folder - self.fs.rename(path, trashed_subvolume) + trashpath = spec.trash_path + self.fs.rename(subvolpath, trashpath) - def purge_subvolume(self, subvolume_path): + def purge_subvolume(self, spec): """ Finish clearing up a subvolume that was previously passed to delete_subvolume. This function is idempotent. """ - trash = os.path.join(self.subvolume_prefix, "_deleting") - trashed_subvolume = os.path.join(trash, subvolume_path.subvolume_id) - def rmtree(root_path): log.debug("rmtree {0}".format(root_path)) try: @@ -228,11 +138,36 @@ class SubvolumeClient(object): d = self.fs.readdir(dir_handle) self.fs.closedir(dir_handle) - self.fs.rmdir(root_path) - rmtree(trashed_subvolume) + trashpath = spec.trash_path + rmtree(trashpath) + + def get_subvolume_path(self, spec): + path = spec.subvolume_path + try: + self.fs.stat(path) + except cephfs.ObjectNotFound: + return None + return path + + ### group operations + + def create_group(self, spec, mode=0o755): + path = spec.group_path + self._mkdir_p(path, mode) + + def remove_group(self, spec): + path = spec.group_path + self.fs.rmdir(path) + def get_group_path(self, spec): + path = spec.group_path + try: + self.fs.stat(path) + except cephfs.ObjectNotFound: + return None + return path def _get_ancestor_xattr(self, path, attr): """ @@ -252,56 +187,67 @@ class SubvolumeClient(object): else: return self._get_ancestor_xattr(os.path.split(path)[0], attr) - def get_group_path(self, group_id): - path = self._group_path(group_id) - try: - self.fs.stat(path) - except cephfs.ObjectNotFound: - return None - return path + ### snapshot operations - def get_subvolume_path(self, subvolume_path): - path = self._subvolume_path(subvolume_path) - try: - self.fs.stat(path) - except cephfs.ObjectNotFound: - return None - return path - - def _snapshot_path(self, dir_path, snapshot_name): - return os.path.join( - dir_path, self.rados.conf_get('client_snapdir'), snapshot_name - ) - - def _snapshot_create(self, dir_path, snapshot_name, mode=0o755): + def _snapshot_create(self, snappath, mode=0o755): """ Create a snapshot, or do nothing if it already exists. """ - snapshot_path = self._snapshot_path(dir_path, snapshot_name) try: - self.fs.stat(snapshot_path) + self.fs.stat(snappath) except cephfs.ObjectNotFound: - self.fs.mkdir(snapshot_path, mode) + self.fs.mkdir(snappath, mode) else: - log.warn("Snapshot '{0}' already exists".format(snapshot_name)) + log.warn("Snapshot '{0}' already exists".format(snappath)) - - def _snapshot_delete(self, dir_path, snapshot_name): + def _snapshot_delete(self, snappath): """ Remove a snapshot, or do nothing if it doesn't exist. """ - snapshot_path = self._snapshot_path(dir_path, snapshot_name) - self.fs.stat(snapshot_path) - self.fs.rmdir(snapshot_path) + self.fs.stat(snappath) + self.fs.rmdir(snappath) + + def create_subvolume_snapshot(self, spec, snapname, mode=0o755): + snappath = spec.make_subvol_snap_path(self.rados.conf_get('client_snapdir'), snapname) + self._snapshot_create(snappath, mode) + + def remove_subvolume_snapshot(self, spec, snapname): + snappath = spec.make_subvol_snap_path(self.rados.conf_get('client_snapdir'), snapname) + self._snapshot_delete(snappath) - def create_subvolume_snapshot(self, subvolume_path, snapshot_name, mode=0o755): - return self._snapshot_create(self._subvolume_path(subvolume_path), snapshot_name, mode) + def create_group_snapshot(self, spec, snapname, mode=0o755): + snappath = spec.make_group_snap_path(self.rados.conf_get('client_snapdir'), snapname) + self._snapshot_create(snappath, mode) - def delete_subvolume_snapshot(self, subvolume_path, snapshot_name): - return self._snapshot_delete(self._subvolume_path(subvolume_path), snapshot_name) + def remove_group_snapshot(self, spec, snapname): + snappath = spec.make_group_snap_path(self.rados.conf_get('client_snapdir'), snapname) + return self._snapshot_delete(snappath) - def create_group_snapshot(self, group_id, snapshot_name, mode=0o755): - return self._snapshot_create(self._group_path(group_id), snapshot_name, mode) + ### context manager routines - def delete_group_snapshot(self, group_id, snapshot_name): - return self._snapshot_delete(self._group_path(group_id), snapshot_name) + def connect(self): + log.debug("Connecting to cephfs...") + self.fs = cephfs.LibCephFS(rados_inst=self.rados) + log.debug("CephFS initializing...") + self.fs.init() + log.debug("CephFS mounting...") + self.fs.mount(filesystem_name=self.fs_name.encode('utf-8')) + log.debug("Connection to cephfs complete") + + def disconnect(self): + log.info("disconnect") + if self.fs: + log.debug("Disconnecting cephfs...") + self.fs.shutdown() + self.fs = None + log.debug("Disconnecting cephfs complete") + + def __enter__(self): + self.connect() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.disconnect() + + def __del__(self): + self.disconnect() diff --git a/src/pybind/mgr/volumes/fs/volume.py b/src/pybind/mgr/volumes/fs/volume.py index b9dc5f1b577..a2f4672b52d 100644 --- a/src/pybind/mgr/volumes/fs/volume.py +++ b/src/pybind/mgr/volumes/fs/volume.py @@ -2,8 +2,12 @@ import json import errno import logging +import cephfs import orchestrator +from .subvolspec import SubvolumeSpec +from .subvolume import SubVolume + log = logging.getLogger(__name__) class VolumeClient(object): @@ -152,3 +156,192 @@ class VolumeClient(object): for f in fs_map['filesystems']: result.append({'name': f['mdsmap']['fs_name']}) return 0, json.dumps(result, indent=2), "" + + def group_exists(self, sv, spec): + # default group need not be explicitly created (as it gets created + # at the time of subvolume, snapshot and other create operations). + return spec.is_default_group() or sv.get_group_path(spec) + + ### subvolume operations + + def create_subvolume(self, volname, subvolname, groupname, size): + if not self.volume_exists(volname): + return -errno.ENOENT, "", \ + "Volume '{0}' not found, create it with `ceph fs volume create` " \ + "before trying to create subvolumes".format(volname) + + # TODO: validate that subvol size fits in volume size + with SubVolume(self.mgr, fs_name=volname) as sv: + spec = SubvolumeSpec(subvolname, groupname) + if not self.group_exists(sv, spec): + return -errno.ENOENT, "", \ + "Subvolume group '{0}' not found, create it with `ceph fs subvolumegroup create` " \ + "before creating subvolumes".format(groupname) + return sv.create_subvolume(spec, size) + + def remove_subvolume(self, volname, subvolname, groupname, force): + fs = self.get_fs(volname) + if not fs: + if force: + return 0, "", "" + else: + return -errno.ENOENT, "", \ + "Volume '{0}' not found, cannot remove subvolume '{1}'".format(volname, subvolname) + + with SubVolume(self.mgr, fs_name=volname) as sv: + spec = SubvolumeSpec(subvolname, groupname) + if not self.group_exists(sv, spec): + if force: + return 0, "", "" + else: + return -errno.ENOENT, "", \ + "Subvolume group '{0}' not found, cannot remove subvolume '{1}'".format(groupname, subvolname) + try: + sv.remove_subvolume(spec) + except cephfs.ObjectNotFound: + if force: + return 0, "", "" + else: + return -errno.ENOENT, "", \ + "Subvolume '{0}' not found, cannot remove it".format(subvolname) + sv.purge_subvolume(spec) + return 0, "", "" + + def subvolume_getpath(self, volname, subvolname, groupname): + if not self.volume_exists(volname): + return -errno.ENOENT, "", "Volume '{0}' not found".format(volname) + + with SubVolume(self.mgr, fs_name=volname) as sv: + spec = SubvolumeSpec(subvolname, groupname) + if not self.group_exists(sv, spec): + return -errno.ENOENT, "", "Subvolume group '{0}' not found".format(groupname) + path = sv.get_subvolume_path(spec) + if not path: + return -errno.ENOENT, "", "Subvolume '{0}' not found".format(groupname) + return 0, path, "" + + ### subvolume snapshot + + def create_subvolume_snapshot(self, volname, subvolname, snapname, groupname): + if not self.volume_exists(volname): + return -errno.ENOENT, "", \ + "Volume '{0}' not found, cannot create snapshot '{1}'".format(volname, snapname) + + with SubVolume(self.mgr, fs_name=volname) as sv: + spec = SubvolumeSpec(subvolname, groupname) + if not self.group_exists(sv, spec): + return -errno.ENOENT, "", \ + "Subvolume group '{0}' not found, cannot create snapshot '{1}'".format(groupname, snapname) + if not sv.get_subvolume_path(spec): + return -errno.ENOENT, "", \ + "Subvolume '{0}' not found, cannot create snapshot '{1}'".format(subvolname, snapname) + sv.create_subvolume_snapshot(spec, snapname) + return 0, "", "" + + def remove_subvolume_snapshot(self, volname, subvolname, snapname, groupname, force): + if not self.volume_exists(volname): + if force: + return 0, "", "" + else: + return -errno.ENOENT, "", \ + "Volume '{0}' not found, cannot remove subvolumegroup snapshot '{1}'".format(volname, snapname) + + with SubVolume(self.mgr, fs_name=volname) as sv: + spec = SubvolumeSpec(subvolname, groupname) + if not self.group_exists(sv, spec): + if force: + return 0, "", "" + else: + return -errno.ENOENT, "", \ + "Subvolume group '{0}' already removed, cannot remove subvolume snapshot '{1}'".format(groupname, snapname) + if not sv.get_subvolume_path(spec): + if force: + return 0, "", "" + else: + return -errno.ENOENT, "", \ + "Subvolume '{0}' not found, cannot remove subvolume snapshot '{1}'".format(subvolname, snapname) + try: + sv.remove_subvolume_snapshot(spec, snapname) + except cephfs.ObjectNotFound: + if force: + return 0, "", "" + else: + return -errno.ENOENT, "", \ + "Subvolume snapshot '{0}' not found, cannot remove it".format(snapname) + return 0, "", "" + + ### group operations + + def create_subvolume_group(self, volname, groupname): + if not self.volume_exists(volname): + return -errno.ENOENT, "", \ + "Volume '{0}' not found, create it with `ceph fs volume create` " \ + "before trying to create subvolume groups".format(volname) + + # TODO: validate that subvol size fits in volume size + with SubVolume(self.mgr, fs_name=volname) as sv: + spec = SubvolumeSpec("", groupname) + sv.create_group(spec) + return 0, "", "" + + def remove_subvolume_group(self, volname, groupname, force): + if not self.volume_exists(volname): + if force: + return 0, "", "" + else: + return -errno.ENOENT, "", \ + "Volume '{0}' not found, cannot remove subvolume group '{0}'".format(volname, groupname) + + with SubVolume(self.mgr, fs_name=volname) as sv: + # TODO: check whether there are no subvolumes in the group + spec = SubvolumeSpec("", groupname) + try: + sv.remove_group(spec) + except cephfs.ObjectNotFound: + if force: + return 0, "", "" + else: + return -errno.ENOENT, "", \ + "Subvolume group '{0}' not found".format(groupname) + return 0, "", "" + + ### group snapshot + + def create_subvolume_group_snapshot(self, volname, groupname, snapname): + if not self.volume_exists(volname): + return -errno.ENOENT, "", \ + "Volume '{0}' not found, cannot create snapshot '{1}'".format(volname, snapname) + + with SubVolume(self.mgr, fs_name=volname) as sv: + spec = SubvolumeSpec("", groupname) + if not self.group_exists(sv, spec): + return -errno.ENOENT, "", \ + "Subvolume group '{0}' not found, cannot create snapshot '{1}'".format(groupname, snapname) + sv.create_group_snapshot(spec, snapname) + return 0, "", "" + + def remove_subvolume_group_snapshot(self, volname, groupname, snapname, force): + if not self.volume_exists(volname): + if force: + return 0, "", "" + else: + return -errno.ENOENT, "", \ + "Volume '{0}' not found, cannot remove subvolumegroup snapshot '{1}'".format(volname, snapname) + + with SubVolume(self.mgr, fs_name=volname) as sv: + spec = SubvolumeSpec("", groupname) + if not self.group_exists(sv, spec): + if force: + return 0, "", "" + else: + return -errno.ENOENT, "", \ + "Subvolume group '{0}' not found, cannot remove it".format(groupname) + try: + sv.remove_group_snapshot(spec, snapname) + except: + if force: + return 0, "", "" + else: + return -errno.ENOENT, "", \ + "Subvolume group snapshot '{0}' not found, cannot remove it".format(snapname) + return 0, "", "" diff --git a/src/pybind/mgr/volumes/module.py b/src/pybind/mgr/volumes/module.py index 80f4a2d7a03..214b63fb4de 100644 --- a/src/pybind/mgr/volumes/module.py +++ b/src/pybind/mgr/volumes/module.py @@ -10,7 +10,6 @@ import cephfs from mgr_module import MgrModule import orchestrator -from .fs.subvolume import SubvolumePath, SubvolumeClient from .fs.volume import VolumeClient class PurgeJob(object): @@ -24,7 +23,6 @@ class PurgeJob(object): self.fscid = volume_fscid self.subvolume_path = subvolume_path - class Module(orchestrator.OrchestratorClientMixin, MgrModule): COMMANDS = [ { @@ -200,17 +198,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): vol_name = cmd['vol_name'] group_name = cmd['group_name'] - if not self._volume_exists(vol_name): - return -errno.ENOENT, "", \ - "Volume '{0}' not found, create it with `ceph fs volume create` " \ - "before trying to create subvolume groups".format(vol_name) - - # TODO: validate that subvol size fits in volume size - - with SubvolumeClient(self, fs_name=vol_name) as svc: - svc.create_group(group_name) - - return 0, "", "" + return self.vc.create_subvolume_group(vol_name, group_name) def _cmd_fs_subvolumegroup_rm(self, inbuf, cmd): """ @@ -218,29 +206,9 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): """ vol_name = cmd['vol_name'] group_name = cmd['group_name'] - force = cmd.get('force', False) - if not self._volume_exists(vol_name): - if force: - return 0, "", "" - else: - return -errno.ENOENT, "", \ - "Volume '{0}' not found, cannot remove subvolume group '{0}'".format(vol_name, group_name) - - with SubvolumeClient(self, fs_name=vol_name) as svc: - # TODO: check whether there are no subvolumes in the group - try: - svc.delete_group(group_name) - except cephfs.ObjectNotFound: - if force: - return 0, "", "" - else: - return -errno.ENOENT, "", \ - "Subvolume group '{0}' not found, cannot remove it".format(group_name) - - - return 0, "", "" + return self.vc.remove_subvolume_group(vol_name, group_name, force) def _cmd_fs_subvolume_create(self, inbuf, cmd): """ @@ -248,26 +216,10 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): """ vol_name = cmd['vol_name'] sub_name = cmd['sub_name'] - size = cmd.get('size', None) group_name = cmd.get('group_name', None) - if not self._volume_exists(vol_name): - return -errno.ENOENT, "", \ - "Volume '{0}' not found, create it with `ceph fs volume create` " \ - "before trying to create subvolumes".format(vol_name) - - # TODO: validate that subvol size fits in volume size - - with SubvolumeClient(self, fs_name=vol_name) as svc: - if group_name and not svc.get_group_path(group_name): - return -errno.ENOENT, "", \ - "Subvolume group '{0}' not found, create it with `ceph fs subvolumegroup create` " \ - "before trying to create subvolumes".format(group_name) - svp = SubvolumePath(group_name, sub_name) - svc.create_subvolume(svp, size) - - return 0, "", "" + return self.vc.create_subvolume(vol_name, sub_name, group_name, size) def _cmd_fs_subvolume_rm(self, inbuf, cmd): """ @@ -275,171 +227,46 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule): """ vol_name = cmd['vol_name'] sub_name = cmd['sub_name'] - force = cmd.get('force', False) group_name = cmd.get('group_name', None) - fs = self._volume_get_fs(vol_name) - if fs is None: - if force: - return 0, "", "" - else: - return -errno.ENOENT, "", \ - "Volume '{0}' not found, cannot remove subvolume '{1}'".format(vol_name, sub_name) - - vol_fscid = fs['id'] - - with SubvolumeClient(self, fs_name=vol_name) as svc: - if group_name and not svc.get_group_path(group_name): - if force: - return 0, "", "" - else: - return -errno.ENOENT, "", \ - "Subvolume group '{0}' not found, cannot remove subvolume '{1}'".format(group_name, sub_name) - svp = SubvolumePath(group_name, sub_name) - try: - svc.delete_subvolume(svp) - except cephfs.ObjectNotFound: - if force: - return 0, "", "" - else: - return -errno.ENOENT, "", \ - "Subvolume '{0}' not found, cannot remove it".format(sub_name) - svc.purge_subvolume(svp) - - # TODO: purge subvolume asynchronously - # self._background_jobs.put(PurgeJob(vol_fscid, svp)) - - return 0, "", "" + return self.vc.remove_subvolume(vol_name, sub_name, group_name, force) def _cmd_fs_subvolume_getpath(self, inbuf, cmd): vol_name = cmd['vol_name'] sub_name = cmd['sub_name'] - group_name = cmd.get('group_name', None) - if not self._volume_exists(vol_name): - return -errno.ENOENT, "", "Volume '{0}' not found".format(vol_name) - - with SubvolumeClient(self, fs_name=vol_name) as svc: - if group_name and not svc.get_group_path(group_name): - return -errno.ENOENT, "", \ - "Subvolume group '{0}' not found".format(group_name) - svp = SubvolumePath(group_name, sub_name) - path = svc.get_subvolume_path(svp) - if not path: - return -errno.ENOENT, "", \ - "Subvolume '{0}' not found".format(sub_name) - return 0, path, "" + return self.vc.subvolume_getpath(vol_name, sub_name, group_name) def _cmd_fs_subvolumegroup_snapshot_create(self, inbuf, cmd): vol_name = cmd['vol_name'] group_name = cmd['group_name'] snap_name = cmd['snap_name'] - if not self._volume_exists(vol_name): - return -errno.ENOENT, "", \ - "Volume '{0}' not found, cannot create snapshot '{1}'".format(vol_name, snap_name) - - with SubvolumeClient(self, fs_name=vol_name) as svc: - if group_name and not svc.get_group_path(group_name): - return -errno.ENOENT, "", \ - "Subvolume group '{0}' not found, cannot create snapshot '{1}'".format(group_name, snap_name) - svc.create_group_snapshot(group_name, snap_name) - - return 0, "", "" + return self.vc.create_subvolume_group_snapshot(vol_name, group_name, snap_name) def _cmd_fs_subvolumegroup_snapshot_rm(self, inbuf, cmd): vol_name = cmd['vol_name'] group_name = cmd['group_name'] snap_name = cmd['snap_name'] - force = cmd.get('force', False) - if not self._volume_exists(vol_name): - if force: - return 0, "", "" - else: - return -errno.ENOENT, "", \ - "Volume '{0}' not found, cannot remove subvolumegroup snapshot '{1}'".format(vol_name, snap_name) - - with SubvolumeClient(self, fs_name=vol_name) as svc: - if group_name and not svc.get_group_path(group_name): - if force: - return 0, "", "" - else: - return -errno.ENOENT, "", \ - "Subvolume group '{0}' not found, cannot remove subvolumegroup snapshot '{1}'".format(group_name, snap_name) - try: - svc.delete_group_snapshot(group_name, snap_name) - except cephfs.ObjectNotFound: - if force: - return 0, "", "" - else: - return -errno.ENOENT, "", \ - "Subvolume group snapshot '{0}' not found, cannot remove it".format(snap_name) - - return 0, "", "" + return self.vc.remove_subvolume_group_snapshot(vol_name, group_name, snap_name, force) def _cmd_fs_subvolume_snapshot_create(self, inbuf, cmd): vol_name = cmd['vol_name'] sub_name = cmd['sub_name'] snap_name = cmd['snap_name'] - group_name = cmd.get('group_name', None) - if not self._volume_exists(vol_name): - return -errno.ENOENT, "", \ - "Volume '{0}' not found, cannot create snapshot '{1}'".format(vol_name, snap_name) - - with SubvolumeClient(self, fs_name=vol_name) as svc: - if group_name and not svc.get_group_path(group_name): - return -errno.ENOENT, "", \ - "Subvolume group '{0}' not found, cannot create snapshot '{1}'".format(group_name, snap_name) - svp = SubvolumePath(group_name, sub_name) - if not svc.get_subvolume_path(svp): - return -errno.ENOENT, "", \ - "Subvolume '{0}' not found, cannot create snapshot '{1}'".format(sub_name, snap_name) - svc.create_subvolume_snapshot(svp, snap_name) - - return 0, "", "" + return self.vc.create_subvolume_snapshot(vol_name, sub_name, snap_name, group_name) def _cmd_fs_subvolume_snapshot_rm(self, inbuf, cmd): vol_name = cmd['vol_name'] sub_name = cmd['sub_name'] snap_name = cmd['snap_name'] - force = cmd.get('force', False) group_name = cmd.get('group_name', None) - if not self._volume_exists(vol_name): - if force: - return 0, "", "" - else: - return -errno.ENOENT, "", \ - "Volume '{0}' not found, cannot remove subvolume snapshot '{1}'".format(vol_name, snap_name) - - with SubvolumeClient(self, fs_name=vol_name) as svc: - if group_name and not svc.get_group_path(group_name): - if force: - return 0, "", "" - else: - return -errno.ENOENT, "", \ - "Subvolume group '{0}' not found, cannot remove subvolume snapshot '{1}'".format(group_name, snap_name) - svp = SubvolumePath(group_name, sub_name) - if not svc.get_subvolume_path(svp): - if force: - return 0, "", "" - else: - return -errno.ENOENT, "", \ - "Subvolume '{0}' not found, cannot remove subvolume snapshot '{1}'".format(sub_name, snap_name) - try: - svc.delete_subvolume_snapshot(svp, snap_name) - except cephfs.ObjectNotFound: - if force: - return 0, "", "" - else: - return -errno.ENOENT, "", \ - "Subvolume snapshot '{0}' not found, cannot remove it".format(snap_name) - - return 0, "", "" + return self.vc.remove_subvolume_snapshot(vol_name, sub_name, snap_name, group_name, force) -- 2.39.5