]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd, librbd: add tests for cloning
authorDan Mick <dan.mick@inktank.com>
Mon, 9 Jul 2012 22:43:36 +0000 (15:43 -0700)
committerDan Mick <dan.mick@inktank.com>
Tue, 10 Jul 2012 20:59:34 +0000 (13:59 -0700)
Signed-off-by: Dan Mick <dan.mick@inktank.com>
src/test/pybind/test_rbd.py
src/test/test_librbd.cc

index 6d250e0153f7366b38681c8182c7a75830a6bdec..891dd4a7a65d01084b7c357a3af8bf2846f89fdb 100644 (file)
@@ -6,7 +6,7 @@ from nose import with_setup
 from nose.tools import eq_ as eq, assert_raises
 from rados import Rados
 from rbd import (RBD, Image, ImageNotFound, InvalidArgument, ImageExists,
-                 ImageBusy, ImageHasSnapshots)
+                 ImageBusy, ImageHasSnapshots, RBD_FEATURE_LAYERING)
 
 
 rados = None
@@ -30,8 +30,10 @@ def tearDown():
     rados.shutdown()
 
 def create_image():
+    global features
     features = os.getenv("RBD_FEATURES")
     if features is not None:
+        features = int(features)
         RBD().create(ioctx, IMG_NAME, IMG_SIZE, IMG_ORDER, old_format=False,
                      features=int(features))
     else:
@@ -86,8 +88,6 @@ def check_stat(info, size, order):
     eq(info['order'], order)
     eq(info['num_objs'], size / (1 << order))
     eq(info['obj_size'], 1 << order)
-    eq(info['parent_pool'], -1)
-    eq(info['parent_name'], '')
 
 class TestImage(object):
 
@@ -349,3 +349,44 @@ class TestImage(object):
         read = self.image.read(0, 256)
         eq(read, data)
         self.image.remove_snap('snap1')
+
+    def test_clone(self):
+        if features is None or (features & RBD_FEATURE_LAYERING) == 0:
+            return 0
+        self.image.create_snap('snap1')
+        RBD().clone(ioctx, IMG_NAME, 'snap1', ioctx, 'clone', features)
+        with Image(ioctx, 'clone') as clone:
+            image_info = self.image.stat()
+            clone_info = clone.stat()
+            eq(clone_info['size'], image_info['size'])
+            eq(clone_info['size'], clone.overlap())
+        RBD().remove(ioctx, 'clone')
+        self.image.remove_snap('snap1')
+
+    def test_clone_resize(self):
+        if features is None or (features & RBD_FEATURE_LAYERING) == 0:
+            return 0
+        self.image.create_snap('snap1')
+        RBD().clone(ioctx, IMG_NAME, 'snap1', ioctx, 'clone', features)
+        with Image(ioctx, 'clone') as clone:
+            image_info = self.image.stat()
+            clone_info = clone.stat()
+            eq(clone_info['size'], image_info['size'])
+            eq(clone_info['size'], clone.overlap())
+
+            clone.resize(IMG_SIZE / 2)
+            image_info = self.image.stat()
+            clone_info = clone.stat()
+            eq(clone_info['size'], IMG_SIZE / 2)
+            eq(image_info['size'], IMG_SIZE)
+            eq(clone.overlap(), IMG_SIZE / 2)
+
+            clone.resize(IMG_SIZE * 2)
+            image_info = self.image.stat()
+            clone_info = clone.stat()
+            eq(clone_info['size'], IMG_SIZE * 2)
+            eq(image_info['size'], IMG_SIZE)
+            eq(clone.overlap(), IMG_SIZE / 2)
+
+        RBD().remove(ioctx, 'clone')
+        self.image.remove_snap('snap1')
index 1b6ac07f66a5ffbc8b119d38b829d403c3870074..6c84cbff05b359432aa5f0ccaa199a6a0c7272df 100644 (file)
@@ -13,6 +13,7 @@
  */
 
 #include "include/rados/librados.h"
+#include "include/rbd_types.h"
 #include "include/rbd/librbd.h"
 #include "include/rbd/librbd.hpp"
 
@@ -54,20 +55,27 @@ static int get_features(bool *old_format, uint64_t *features)
   return 0;
 }
 
+static int create_image_full(rados_ioctx_t ioctx, const char *name,
+                             uint64_t size, int *order, int old_format,
+                             uint64_t features)
+{
+  if (old_format) {
+    return rbd_create(ioctx, name, size, order);
+  } else {
+    return rbd_create2(ioctx, name, size, features, order);
+  }
+}
+
 static int create_image(rados_ioctx_t ioctx, const char *name,
                        uint64_t size, int *order)
 {
   bool old_format;
   uint64_t features;
+
   int r = get_features(&old_format, &features);
   if (r < 0)
     return r;
-
-  if (old_format) {
-    return rbd_create(ioctx, name, size, order);
-  } else {
-    return rbd_create2(ioctx, name, size, features, order);
-  }
+  return create_image_full(ioctx, name, size, order, old_format, features);
 }
 
 static int create_image_pp(librbd::RBD &rbd,
@@ -79,7 +87,6 @@ static int create_image_pp(librbd::RBD &rbd,
   int r = get_features(&old_format, &features);
   if (r < 0)
     return r;
-
   if (old_format) {
     return rbd.create(ioctx, name, size, order);
   } else {
@@ -963,3 +970,79 @@ TEST(LibRBD, TestIOToSnapshot)
   rados_ioctx_destroy(ioctx);
   ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster));
 }
+
+TEST(LibRBD, TestClone)
+{
+  rados_t cluster;
+  rados_ioctx_t ioctx;
+  rbd_image_info_t pinfo, cinfo;
+  string pool_name = get_temp_pool_name();
+  ASSERT_EQ("", create_one_pool(pool_name, &cluster));
+  rados_ioctx_create(cluster, pool_name.c_str(), &ioctx);
+
+  int features = RBD_FEATURE_LAYERING;
+  rbd_image_t parent, child;
+  int order = 0;
+
+  // make a parent to clone from
+  ASSERT_EQ(0, create_image_full(ioctx, "parent", 4<<20, &order, false, features));
+  ASSERT_EQ(0, rbd_open(ioctx, "parent", &parent, NULL));
+  printf("made parent image \"parent\"\n");
+
+  // can't clone a non-snapshot, expect failure
+  EXPECT_NE(0, rbd_clone(ioctx, "parent", NULL, ioctx, "child", features, &order));
+
+  // create a snapshot, reopen as the parent we're interested in
+  ASSERT_EQ(0, rbd_snap_create(parent, "parent_snap"));
+  ASSERT_EQ(0, rbd_close(parent));
+  ASSERT_EQ(0, rbd_open(ioctx, "parent", &parent, "parent_snap"));
+  printf("made snapshot \"parent@parent_snap\"\n");
+
+  // - validate "no clone if not preserved" when preserved is available
+
+  // This clone and open should work
+  ASSERT_EQ(0, rbd_clone(ioctx, "parent", "parent_snap", ioctx, "child", features,
+           &order));
+  ASSERT_EQ(0, rbd_open(ioctx, "child", &child, NULL));
+  printf("made and opened clone \"child\"\n"); 
+
+  // check attributes
+  ASSERT_EQ(0, rbd_stat(parent, &pinfo, sizeof(pinfo)));
+  ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
+  EXPECT_EQ(cinfo.size, pinfo.size);
+  uint64_t overlap;
+  rbd_get_overlap(child, &overlap);
+  EXPECT_EQ(overlap, pinfo.size);
+  EXPECT_EQ(cinfo.obj_size, pinfo.obj_size);
+  EXPECT_EQ(cinfo.order, pinfo.order);
+  printf("sizes and overlaps are good between parent and child\n");
+
+  // sizing down child results in changing overlap and size, not parent size
+  ASSERT_EQ(0, rbd_resize(child, 2UL<<20));
+  ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
+  rbd_get_overlap(child, &overlap);
+  ASSERT_EQ(overlap, 2UL<<20);
+  ASSERT_EQ(cinfo.size, 2UL<<20);
+  ASSERT_EQ(0, rbd_resize(child, 4UL<<20));
+  ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
+  rbd_get_overlap(child, &overlap);
+  ASSERT_EQ(overlap, 2UL<<20);
+  ASSERT_EQ(cinfo.size, 4UL<<20);
+  printf("sized down clone, changed overlap\n");
+
+  // sizing back up doesn't change that
+  ASSERT_EQ(0, rbd_resize(child, 5UL<<20));
+  ASSERT_EQ(0, rbd_stat(child, &cinfo, sizeof(cinfo)));
+  rbd_get_overlap(child, &overlap);
+  ASSERT_EQ(overlap, 2UL<<20);
+  ASSERT_EQ(cinfo.size, 5UL<<20);
+  ASSERT_EQ(0, rbd_stat(parent, &pinfo, sizeof(pinfo)));
+  printf("parent info: size %ld obj_size %ld parent_pool %ld\n", pinfo.size, pinfo.obj_size, pinfo.parent_pool);
+  ASSERT_EQ(pinfo.size, 4UL<<20);
+  printf("sized up clone, changed size but not overlap or parent's size\n");
+  
+  ASSERT_EQ(0, rbd_close(child));
+  ASSERT_EQ(0, rbd_close(parent));
+  rados_ioctx_destroy(ioctx);
+  ASSERT_EQ(0, destroy_one_pool(pool_name, &cluster));
+}