]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
cephfs-shell: add snapshot management 27467/head
authorMilind Changire <mchangir@redhat.com>
Mon, 4 Nov 2019 10:47:32 +0000 (16:17 +0530)
committerMilind Changire <mchangir@redhat.com>
Mon, 4 Nov 2019 10:47:32 +0000 (16:17 +0530)
Snapshots can be managed by:
$ snap {create|delete} snap_name dir_name

Fixes: http://tracker.ceph.com/issues/38681
Signed-off-by: Milind Changire <mchangir@redhat.com>
doc/cephfs/cephfs-shell.rst
qa/tasks/cephfs/test_cephfs_shell.py
src/tools/cephfs/cephfs-shell

index 2d4c36d5fd19b950c2f9848b7f982150a4194fd0..496a541a86669a2711841fc27aec78c5a7964f35 100644 (file)
@@ -380,3 +380,17 @@ Usage :
 
 Options :
   -h     Shows the help message
+
+snap
+----
+
+Create or Delete Snapshot
+
+Usage:
+
+     snap {create|delete} <snap_name> <dir_name>
+
+* snap_name - Snapshot name to be created or deleted
+
+* dir_name - directory under which snapshot should be created or deleted
+
index da8ceb6fed79cf5b74c3f004c7f2e78682d536c4..742433ba4bda78f40a0a52f2f9efba0285d90459 100644 (file)
@@ -48,6 +48,11 @@ class TestCephFSShell(CephFSTestCase):
         return mount_x.client_remote.run(args=args, stdout=StringIO(),
                                            stdin=stdin)
 
+    def get_cephfs_shell_cmd_error(self, cmd, mount_x=None, opts=None,
+                                    stdin=None):
+        return self.run_cephfs_shell_cmd(cmd, mount_x, opts, stdin).stderr.\
+            getvalue().strip()
+
     def get_cephfs_shell_cmd_output(self, cmd, mount_x=None, opts=None,
                                     stdin=None):
         return self.run_cephfs_shell_cmd(cmd, mount_x, opts, stdin).stdout.\
@@ -293,6 +298,71 @@ class TestGetAndPut(TestCephFSShell):
         log.info("o_hash:{}".format(o_hash))
         assert(s_hash == o_hash)
 
+class TestSnapshots(TestCephFSShell):
+    def test_snap(self):
+        """
+        Test that snapshot creation and deletion work
+        """
+        sd = self.fs.get_config('client_snapdir')
+        sdn = "data_dir/{}/snap1".format(sd)
+
+        # create a data dir and dump some files into it
+        self.get_cephfs_shell_cmd_output("mkdir data_dir")
+        s = 'A' * 10240
+        o = self.get_cephfs_shell_cmd_output("put - data_dir/data_a", stdin=s)
+        s = 'B' * 10240
+        o = self.get_cephfs_shell_cmd_output("put - data_dir/data_b", stdin=s)
+        s = 'C' * 10240
+        o = self.get_cephfs_shell_cmd_output("put - data_dir/data_c", stdin=s)
+        s = 'D' * 10240
+        o = self.get_cephfs_shell_cmd_output("put - data_dir/data_d", stdin=s)
+        s = 'E' * 10240
+        o = self.get_cephfs_shell_cmd_output("put - data_dir/data_e", stdin=s)
+
+        o = self.get_cephfs_shell_cmd_output("ls -l /data_dir")
+        log.info("cephfs-shell output:\n{}".format(o))
+
+        # create the snapshot - must pass
+        o = self.get_cephfs_shell_cmd_output("snap create snap1 /data_dir")
+        log.info("cephfs-shell output:\n{}".format(o))
+        assert(o == "")
+        o = self.mount_a.stat(sdn)
+        log.info("mount_a output:\n{}".format(o))
+        assert(('st_mode' in str(o)) == True)
+
+        # create the same snapshot again - must fail with an error message
+        o = self.get_cephfs_shell_cmd_error("snap create snap1 /data_dir")
+        log.info("cephfs-shell output:\n{}".format(o))
+        o = o.split('\n')
+        assert(o[0] == "ERROR: snapshot 'snap1' already exists")
+        o = self.mount_a.stat(sdn)
+        log.info("mount_a output:\n{}".format(o))
+        assert(('st_mode' in str(o)) == True)
+
+        # delete the snapshot - must pass
+        o = self.get_cephfs_shell_cmd_output("snap delete snap1 /data_dir")
+        log.info("cephfs-shell output:\n{}".format(o))
+        assert(o == "")
+        try:
+            o = self.mount_a.stat(sdn)
+        except:
+            # snap dir should not exist anymore
+            pass
+        log.info("mount_a output:\n{}".format(o))
+        assert(('st_mode' in str(o)) == False)
+
+        # delete the same snapshot again - must fail with an error message
+        o = self.get_cephfs_shell_cmd_error("snap delete snap1 /data_dir")
+        o = o.strip()
+        o = o.split('\n')
+        assert(o[0] == "ERROR: 'snap1': no such snapshot")
+        try:
+            o = self.mount_a.stat(sdn)
+        except:
+            pass
+        log.info("mount_a output:\n{}".format(o))
+        assert(('st_mode' in str(o)) == False)
+
 class TestCD(TestCephFSShell):
     CLIENTS_REQUIRED = 1
 
index d672f02c5385899fe9554a1a7b21716345f9f570..d74a10a0b9a958188848eb20be080e34a955b82b 100755 (executable)
@@ -172,8 +172,9 @@ def get_all_possible_paths(pattern):
     for pattern in patterns:
         for path in paths:
             paths.extend(glob(path, pattern))
-    return [path for path in paths if fnmatch.fnmatch(path,
-            os.path.join(cephfs.getcwd(), complete_pattern))]
+    if is_rel_path:
+        complete_pattern = os.path.join(cephfs.getcwd(), complete_pattern)
+    return [path for path in paths if fnmatch.fnmatch(path, complete_pattern)]
 
 
 suffixes = ['B', 'K', 'M', 'G', 'T', 'P']
@@ -822,6 +823,9 @@ sub-directories, files')
 
     @with_argparser(rmdir_parser)
     def do_rmdir(self, args):
+        self.do_rmdir_helper(args)
+
+    def do_rmdir_helper(self, args):
         """
         Remove a specific Directory
         """
@@ -1245,6 +1249,50 @@ sub-directories, files')
                 perror('max_files is not set')
                 pass
 
+    snap_parser = argparse.ArgumentParser(description='Snapshot Management')
+    snap_parser.add_argument('op', type=str,
+                             help='Snapshot operation: create or delete')
+    snap_parser.add_argument('name', type=str, action=path_to_bytes,
+                             help='Name of snapshot')
+    snap_parser.add_argument('dir', type=str, action=path_to_bytes,
+                             help='Directory for which snapshot '
+                                  'needs to be created or deleted')
+
+    @with_argparser(snap_parser)
+    def do_snap(self, args):
+        """
+        Snapshot management for the volume
+        """
+        # setting self.colors to None turns off colorizing and
+        # perror emits plain text
+        self.colors = None
+
+        snapdir = '.snap'
+        conf_snapdir = cephfs.conf_get('client_snapdir')
+        if conf_snapdir is not None:
+            snapdir = conf_snapdir
+        snapdir = to_bytes(snapdir)
+        if args.op == 'create':
+            try:
+                if is_dir_exists(args.dir):
+                    cephfs.mkdir(os.path.join(args.dir, snapdir, args.name), 0o755)
+                else:
+                    self.perror("'{}': no such directory".format(args.dir.decode('utf-8')))
+            except libcephfs.Error:
+                self.perror("snapshot '{}' already exists".format(args.name.decode('utf-8')))
+        elif args.op == 'delete':
+            snap_dir = os.path.join(args.dir, snapdir, args.name)
+            try:
+                if is_dir_exists(snap_dir):
+                    newargs = argparse.Namespace(paths=[snap_dir], parent=False)
+                    self.do_rmdir_helper(newargs)
+                else:
+                    self.perror("'{}': no such snapshot".format(args.name.decode('utf-8')))
+            except libcephfs.Error:
+                self.perror("error while deleting '{}'".format(snap_dir.decode('utf-8')))
+        else:
+            self.perror("snapshot can only be created or deleted; check - help snap")
+
     def do_help(self, line):
         """
         Get details about a command.