From 6ad596104346b1816cf51db1f8fbbc40161019a7 Mon Sep 17 00:00:00 2001 From: Dan Mick Date: Mon, 9 Jul 2012 15:43:36 -0700 Subject: [PATCH] rbd, librbd: add tests for cloning Signed-off-by: Dan Mick --- src/test/pybind/test_rbd.py | 47 ++++++++++++++++-- src/test/test_librbd.cc | 97 ++++++++++++++++++++++++++++++++++--- 2 files changed, 134 insertions(+), 10 deletions(-) diff --git a/src/test/pybind/test_rbd.py b/src/test/pybind/test_rbd.py index 6d250e0153f73..891dd4a7a65d0 100644 --- a/src/test/pybind/test_rbd.py +++ b/src/test/pybind/test_rbd.py @@ -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') diff --git a/src/test/test_librbd.cc b/src/test/test_librbd.cc index 1b6ac07f66a5f..6c84cbff05b35 100644 --- a/src/test/test_librbd.cc +++ b/src/test/test_librbd.cc @@ -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)); +} -- 2.39.5