]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/volumes: list FS subvolumes, subvolume groups and their snapshots
authorJos Collin <jcollin@redhat.com>
Tue, 17 Sep 2019 09:31:04 +0000 (15:01 +0530)
committerJos Collin <jcollin@redhat.com>
Wed, 9 Oct 2019 23:35:58 +0000 (05:05 +0530)
Fixes: https://tracker.ceph.com/issues/41842
Signed-off-by: Jos Collin <jcollin@redhat.com>
(cherry picked from commit 1de980020d546f1f80cb3b60f199d578dc321825)

src/pybind/mgr/volumes/fs/subvolspec.py
src/pybind/mgr/volumes/fs/subvolume.py
src/pybind/mgr/volumes/fs/volume.py
src/pybind/mgr/volumes/module.py

index 60fb6d06af00921861ec3dbe425c6fb3052c685e..d00c1e4b1352b77feb87e1be599356cc6638118a 100644 (file)
@@ -92,11 +92,23 @@ class SubvolumeSpec(object):
         """
         return os.path.join(self.subvolume_path, snapdir, snapname)
 
+    def make_subvol_snapdir_path(self, snapdir):
+        """
+        return the subvolume snapdir path
+        """
+        return os.path.join(self.subvolume_path, snapdir.encode('utf-8'))
+
     def make_group_snap_path(self, snapdir, snapname):
         """
         return the group snapshot path for a given snapshot name
         """
         return os.path.join(self.group_path, snapdir, snapname)
 
+    def make_group_snapdir_path(self, snapdir):
+        """
+        return the group's snapdir path
+        """
+        return os.path.join(self.group_path, snapdir.encode('utf-8'))
+
     def __str__(self):
         return "{0}/{1}".format(self.groupid, self.subvolumeid)
index ed3314ac5257c82c417993d651e438562842ddae..8f3c2b1ab5ef4c50428d92b0e9b7ab155acac160 100644 (file)
@@ -189,6 +189,27 @@ class SubVolume(object):
             raise VolumeException(-e.args[0], e.args[1])
         return path
 
+    def get_dir_entries(self, path):
+        """
+        Get the directory names in a given path
+        :param path: the given path
+        :return: the list of directory names
+        """
+        dirs = []
+        try:
+            with self.fs.opendir(path) as dir_handle:
+                d = self.fs.readdir(dir_handle)
+                while d:
+                    if (d.d_name not in (b".", b"..")) and d.is_dir():
+                        dirs.append(d.d_name)
+                    d = self.fs.readdir(dir_handle)
+        except cephfs.ObjectNotFound:
+            # When the given path is not found, we just return an empty list
+            return []
+        except cephfs.Error as e:
+            raise VolumeException(-e.args[0], e.args[1])
+        return dirs
+
     ### group operations
 
     def create_group(self, spec, mode=0o755, pool=None):
index 5a7af604eb71b03238c88e41bb9000947d8f8cc0..fd3874ef22ac8f2ac0370aff1156465c4f6991e7 100644 (file)
@@ -359,6 +359,16 @@ class VolumeClient(object):
             return result
         return conn_wrapper
 
+    def nametojson(self, names):
+        """
+        convert the list of names to json
+        """
+
+        namedict = []
+        for i in range(len(names)):
+            namedict.append({'name': names[i].decode('utf-8')})
+        return json.dumps(namedict, indent=2)
+
     ### subvolume operations
 
     @connection_pool_wrap
@@ -425,6 +435,28 @@ class VolumeClient(object):
             ret = self.volume_exception_to_retval(ve)
         return ret
 
+    @connection_pool_wrap
+    def list_subvolumes(self, fs_handle, **kwargs):
+        ret        = 0, "", ""
+        groupname  = kwargs['group_name']
+
+        try:
+            with SubVolume(self.mgr, fs_handle) as sv:
+                spec = SubvolumeSpec(None, groupname)
+                if not self.group_exists(sv, spec):
+                    raise VolumeException(
+                        -errno.ENOENT, "Subvolume group '{0}' not found".format(groupname))
+                path = sv.get_group_path(spec)
+                # When default subvolume group is not yet created we just return an empty list.
+                if path is None:
+                    ret = 0, '[]', ""
+                else:
+                    subvolumes = sv.get_dir_entries(path)
+                    ret = 0, self.nametojson(subvolumes), ""
+        except VolumeException as ve:
+            ret = self.volume_exception_to_retval(ve)
+        return ret
+
     ### subvolume snapshot
 
     @connection_pool_wrap
@@ -477,6 +509,31 @@ class VolumeClient(object):
             ret = self.volume_exception_to_retval(ve)
         return ret
 
+    @connection_pool_wrap
+    def list_subvolume_snapshots(self, fs_handle, **kwargs):
+        ret        = 0, "", ""
+        subvolname = kwargs['sub_name']
+        groupname  = kwargs['group_name']
+
+        try:
+            with SubVolume(self.mgr, fs_handle) as sv:
+                spec = SubvolumeSpec(subvolname, groupname)
+                if not self.group_exists(sv, spec):
+                    raise VolumeException(
+                        -errno.ENOENT, "Subvolume group '{0}' not found".format(groupname))
+
+                if sv.get_subvolume_path(spec) == None:
+                    raise VolumeException(-errno.ENOENT,
+                                          "Subvolume '{0}' not found".format(subvolname))
+
+                path = spec.make_subvol_snapdir_path(self.mgr.rados.conf_get('client_snapdir'))
+                snapshots = sv.get_dir_entries(path)
+                ret = 0, self.nametojson(snapshots), ""
+        except VolumeException as ve:
+            ret = self.volume_exception_to_retval(ve)
+        return ret
+
+
     ### group operations
 
     @connection_pool_wrap
@@ -525,6 +582,18 @@ class VolumeClient(object):
         except VolumeException as ve:
             return self.volume_exception_to_retval(ve)
 
+    @connection_pool_wrap
+    def list_subvolume_groups(self, fs_handle, **kwargs):
+        ret = 0, "", ""
+
+        try:
+            with SubVolume(self.mgr, fs_handle) as sv:
+                subvolumegroups = sv.get_dir_entries(SubvolumeSpec.DEFAULT_SUBVOL_PREFIX)
+                ret = 0, self.nametojson(subvolumegroups), ""
+        except VolumeException as ve:
+            ret = self.volume_exception_to_retval(ve)
+        return ret
+
     ### group snapshot
 
     @connection_pool_wrap
@@ -565,6 +634,25 @@ class VolumeClient(object):
             ret = self.volume_exception_to_retval(ve)
         return ret
 
+    @connection_pool_wrap
+    def list_subvolume_group_snapshots(self, fs_handle, **kwargs):
+        ret        = 0, "", ""
+        groupname  = kwargs['group_name']
+
+        try:
+            with SubVolume(self.mgr, fs_handle) as sv:
+                spec = SubvolumeSpec(None, groupname)
+                if not self.group_exists(sv, spec):
+                    raise VolumeException(
+                        -errno.ENOENT, "Subvolume group '{0}' not found".format(groupname))
+
+                path = spec.make_group_snapdir_path(self.mgr.rados.conf_get('client_snapdir'))
+                snapshots = sv.get_dir_entries(path)
+                ret = 0, self.nametojson(snapshots), ""
+        except VolumeException as ve:
+            ret = self.volume_exception_to_retval(ve)
+        return ret
+
     @connection_pool_wrap
     def get_subvolume_trash_entry(self, fs_handle, **kwargs):
         ret = None
index 3d7260577f5968265776bb25ddc777dffacfbe33..e44574c85773df09469f7c8bcec2f8d32a03beb7 100644 (file)
@@ -41,6 +41,12 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
             'desc': "Delete a CephFS volume",
             'perm': 'rw'
         },
+        {
+            'cmd': 'fs subvolumegroup ls '
+            'name=vol_name,type=CephString ',
+            'desc': "List subvolumegroups",
+            'perm': 'r'
+        },
         {
             'cmd': 'fs subvolumegroup create '
                    'name=vol_name,type=CephString '
@@ -59,6 +65,13 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
             'desc': "Delete a CephFS subvolume group in a volume",
             'perm': 'rw'
         },
+        {
+            'cmd': 'fs subvolume ls '
+                   'name=vol_name,type=CephString '
+                   'name=group_name,type=CephString,req=false ',
+            'desc': "List subvolumes",
+            'perm': 'r'
+        },
         {
             'cmd': 'fs subvolume create '
                    'name=vol_name,type=CephString '
@@ -98,6 +111,13 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
                     "and optionally, in a specific subvolume group",
             'perm': 'rw'
         },
+        {
+            'cmd': 'fs subvolumegroup snapshot ls '
+                   'name=vol_name,type=CephString '
+                   'name=group_name,type=CephString ',
+            'desc': "List subvolumegroup snapshots",
+            'perm': 'r'
+        },
         {
             'cmd': 'fs subvolumegroup snapshot create '
                    'name=vol_name,type=CephString '
@@ -115,6 +135,14 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
                    'desc': "Delete a snapshot of a CephFS subvolume group in a volume",
             'perm': 'rw'
         },
+        {
+            'cmd': 'fs subvolume snapshot ls '
+                   'name=vol_name,type=CephString '
+                   'name=sub_name,type=CephString '
+                   'name=group_name,type=CephString,req=false ',
+            'desc': "List subvolume snapshots",
+            'perm': 'r'
+        },
         {
             'cmd': 'fs subvolume snapshot create '
                    'name=vol_name,type=CephString '
@@ -215,6 +243,10 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
                                               group_name=cmd['group_name'],
                                               force=cmd.get('force', False))
 
+    def _cmd_fs_subvolumegroup_ls(self, inbuf, cmd):
+        vol_name = cmd['vol_name']
+        return self.vc.list_subvolume_groups(None, vol_name=cmd['vol_name'])
+
     def _cmd_fs_subvolume_create(self, inbuf, cmd):
         """
         :return: a 3-tuple of return code(int), empty string(str), error message (str)
@@ -235,6 +267,10 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
                                         group_name=cmd.get('group_name', None),
                                         force=cmd.get('force', False))
 
+    def _cmd_fs_subvolume_ls(self, inbuf, cmd):
+        return self.vc.list_subvolumes(None, vol_name=cmd['vol_name'],
+                                       group_name=cmd.get('group_name', None))
+
     def _cmd_fs_subvolumegroup_getpath(self, inbuf, cmd):
         return self.vc.getpath_subvolume_group(
                 None, vol_name=cmd['vol_name'], group_name=cmd['group_name'])
@@ -255,6 +291,10 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
                                                        snap_name=cmd['snap_name'],
                                                        force=cmd.get('force', False))
 
+    def _cmd_fs_subvolumegroup_snapshot_ls(self, inbuf, cmd):
+        return self.vc.list_subvolume_group_snapshots(None, vol_name=cmd['vol_name'],
+                                                      group_name=cmd['group_name'])
+
     def _cmd_fs_subvolume_snapshot_create(self, inbuf, cmd):
         return self.vc.create_subvolume_snapshot(None, vol_name=cmd['vol_name'],
                                                  sub_name=cmd['sub_name'],
@@ -267,3 +307,8 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
                                                  snap_name=cmd['snap_name'],
                                                  group_name=cmd.get('group_name', None),
                                                  force=cmd.get('force', False))
+
+    def _cmd_fs_subvolume_snapshot_ls(self, inbuf, cmd):
+        return self.vc.list_subvolume_snapshots(None, vol_name=cmd['vol_name'],
+                                                sub_name=cmd['sub_name'],
+                                                group_name=cmd.get('group_name', None))