]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/volumes: allow creation/deletion of FS subvolume groups
authorRamana Raja <rraja@redhat.com>
Mon, 29 Apr 2019 12:31:49 +0000 (18:01 +0530)
committerRamana Raja <rraja@redhat.com>
Tue, 14 May 2019 14:10:42 +0000 (19:40 +0530)
... using `ceph fs subvolumegroup create/rm` commands.
FS subvolume groups are parent directories of FS subvolumes. They
can be directly mapped to OpenStack Manila share groups.

Signed-off-by: Ramana Raja <rraja@redhat.com>
src/pybind/mgr/volumes/fs/subvolume.py
src/pybind/mgr/volumes/module.py

index fe849e2ce52fbdb9a7a3181419bb0081ae979eca..e86c169f8ed6e95af8e52ffb77487fbf5713e27b 100644 (file)
@@ -76,6 +76,19 @@ class SubvolumeClient(object):
             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)
@@ -120,6 +133,14 @@ 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)
+
+    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):
         """
         Set up metadata, pools and auth for a subvolume.
@@ -231,6 +252,14 @@ 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
+
     def get_subvolume_path(self, subvolume_path):
         path = self._subvolume_path(subvolume_path)
         try:
index f0a5024a0eabbe14cf7b7388e8f59a368f082f01..e2c8f8356b00cae9faa42c3dc56dbd7a9abc3974 100644 (file)
@@ -44,36 +44,59 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
             'desc': "Delete a CephFS volume",
             'perm': 'rw'
         },
+        {
+            'cmd': 'fs subvolumegroup create '
+                   'name=vol_name,type=CephString '
+                   'name=group_name,type=CephString ',
+            'desc': "Create a CephFS subvolume group in a volume",
+            'perm': 'rw'
+        },
+        {
+            'cmd': 'fs subvolumegroup rm '
+                   'name=vol_name,type=CephString '
+                   'name=group_name,type=CephString '
+                   'name=force,type=CephBool,req=false ',
+            'desc': "Delete a CephFS subvolume group in a volume",
+            'perm': 'rw'
+        },
         {
             'cmd': 'fs subvolume create '
                    'name=vol_name,type=CephString '
                    'name=sub_name,type=CephString '
-                   'name=size,type=CephInt,req=false ',
-            'desc': "Create a CephFS subvolume in a volume, and "
-                    "optionally with a specific size(in bytes)",
+                   'name=size,type=CephInt,req=false '
+                   'name=group_name,type=CephString,req=false ',
+            'desc': "Create a CephFS subvolume in a volume, and optionally, "
+                    "with a specific size (in bytes) and in a specific "
+                    "subvolume group",
             'perm': 'rw'
         },
         {
             'cmd': 'fs subvolume rm '
                    'name=vol_name,type=CephString '
                    'name=sub_name,type=CephString '
+                   'name=group_name,type=CephString,req=false '
                    'name=force,type=CephBool,req=false ',
-            'desc': "Delete a CephFS subvolume in a volume",
+            'desc': "Delete a CephFS subvolume in a volume, and optionally, "
+                    "in a specific subvolume group",
             'perm': 'rw'
         },
         {
             'cmd': 'fs subvolume getpath '
                    'name=vol_name,type=CephString '
-                   'name=sub_name,type=CephString ',
-            'desc': "Get the mountpath of a CephFS subvolume in a volume",
+                   'name=sub_name,type=CephString '
+                   'name=group_name,type=CephString,req=false ',
+            'desc': "Get the mountpath of a CephFS subvolume in a volume, "
+                    "and optionally, in a specific subvolume group",
             'perm': 'rw'
         },
         {
             'cmd': 'fs subvolume snapshot create '
                    'name=vol_name,type=CephString '
                    'name=sub_name,type=CephString '
-                   'name=snap_name,type=CephString ',
-            'desc': "Create a snapshot of a CephFS subvolume in a volume",
+                   'name=snap_name,type=CephString '
+                   'name=group_name,type=CephString,req=false ',
+            'desc': "Create a snapshot of a CephFS subvolume in a volume, "
+                    "and optionally, in a specific subvolume group",
             'perm': 'rw'
         },
         {
@@ -81,8 +104,10 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
                    'name=vol_name,type=CephString '
                    'name=sub_name,type=CephString '
                    'name=snap_name,type=CephString '
+                   'name=group_name,type=CephString,req=false '
                    'name=force,type=CephBool,req=false ',
-            'desc': "Delete a snapshot of a CephFS subvolume in a volume",
+            'desc': "Delete a snapshot of a CephFS subvolume in a volume, "
+                    "and optionally, in a specific subvolume group",
             'perm': 'rw'
         },
 
@@ -236,6 +261,55 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
     def _volume_exists(self, vol_name):
         return self._volume_get_fs(vol_name) is not None
 
+    def _cmd_fs_subvolumegroup_create(self, inbuf, cmd):
+        """
+        :return: a 3-tuple of return code(int), empty string(str), error message (str)
+        """
+        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, "", ""
+
+    def _cmd_fs_subvolumegroup_rm(self, inbuf, cmd):
+        """
+        :return: a 3-tuple of return code(int), empty string(str), error message (str)
+        """
+        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, "", ""
+
     def _cmd_fs_subvolume_create(self, inbuf, cmd):
         """
         :return: a 3-tuple of return code(int), empty string(str), error message (str)
@@ -244,6 +318,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
         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, "", \
@@ -253,9 +328,11 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
         # TODO: validate that subvol size fits in volume size
 
         with SubvolumeClient(self, fs_name=vol_name) as svc:
-            # TODO: support real subvolume groups rather than just
-            # always having them 1:1 with subvolumes.
-            svp = SubvolumePath(sub_name, sub_name)
+            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, "", ""
@@ -268,6 +345,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
         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:
@@ -280,9 +358,13 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
         vol_fscid = fs['id']
 
         with SubvolumeClient(self, fs_name=vol_name) as svc:
-            # TODO: support real subvolume groups rather than just
-            # always having them 1:1 with subvolumes.
-            svp = SubvolumePath(sub_name, sub_name)
+            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:
@@ -389,11 +471,16 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
         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:
-            svp = SubvolumePath(sub_name, sub_name)
+            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, "", \
@@ -405,12 +492,17 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
         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:
-            svp = SubvolumePath(sub_name, sub_name)
+            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)
@@ -424,6 +516,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
         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:
@@ -433,7 +526,13 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
                        "Volume '{0}' not found, cannot remove subvolume snapshot '{1}'".format(vol_name, snap_name)
 
         with SubvolumeClient(self, fs_name=vol_name) as svc:
-            svp = SubvolumePath(sub_name, sub_name)
+            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, "", ""