mirror of
https://github.com/ceph/ceph
synced 2025-02-21 09:57:26 +00:00
Merge pull request #18483 from Songweibin/wip-list-children2
rbd: fix rbd children listing when child is in trash Reviewed-by: Jason Dillaman <dillaman@redhat.com>
This commit is contained in:
commit
16715eccdc
@ -57,7 +57,6 @@ extern "C" {
|
||||
#define RBD_FLAG_OBJECT_MAP_INVALID (1<<0)
|
||||
#define RBD_FLAG_FAST_DIFF_INVALID (1<<1)
|
||||
|
||||
typedef void *rbd_snap_t;
|
||||
typedef void *rbd_image_t;
|
||||
typedef void *rbd_image_options_t;
|
||||
|
||||
@ -74,6 +73,13 @@ typedef struct {
|
||||
const char *name;
|
||||
} rbd_snap_info_t;
|
||||
|
||||
typedef struct {
|
||||
const char *pool_name;
|
||||
const char *image_name;
|
||||
const char *image_id;
|
||||
bool trash;
|
||||
} rbd_child_info_t;
|
||||
|
||||
#define RBD_MAX_IMAGE_NAME_SIZE 96
|
||||
#define RBD_MAX_BLOCK_NAME_SIZE 24
|
||||
|
||||
@ -541,6 +547,12 @@ CEPH_RBD_API int rbd_flatten_with_progress(rbd_image_t image,
|
||||
CEPH_RBD_API ssize_t rbd_list_children(rbd_image_t image, char *pools,
|
||||
size_t *pools_len, char *images,
|
||||
size_t *images_len);
|
||||
CEPH_RBD_API int rbd_list_children2(rbd_image_t image,
|
||||
rbd_child_info_t *children,
|
||||
int *max_children);
|
||||
CEPH_RBD_API void rbd_list_child_cleanup(rbd_child_info_t *child);
|
||||
CEPH_RBD_API void rbd_list_children_cleanup(rbd_child_info_t *children,
|
||||
size_t num_children);
|
||||
|
||||
/**
|
||||
* @defgroup librbd_h_locking Advisory Locking
|
||||
|
@ -101,6 +101,13 @@ namespace librbd {
|
||||
time_t deferment_end_time;
|
||||
} trash_image_info_t;
|
||||
|
||||
typedef struct {
|
||||
std::string pool_name;
|
||||
std::string image_name;
|
||||
std::string image_id;
|
||||
bool trash;
|
||||
} child_info_t;
|
||||
|
||||
class CEPH_RBD_API RBD
|
||||
{
|
||||
public:
|
||||
@ -311,6 +318,11 @@ public:
|
||||
* of this image at the currently set snapshot.
|
||||
*/
|
||||
int list_children(std::set<std::pair<std::string, std::string> > *children);
|
||||
/**
|
||||
* Returns a structure of poolname, imagename, imageid and trash flag
|
||||
* for each clone of this image at the currently set snapshot.
|
||||
*/
|
||||
int list_children2(std::vector<librbd::child_info_t> *children);
|
||||
|
||||
/* advisory locking (see librbd.h for details) */
|
||||
int list_lockers(std::list<locker_t> *lockers,
|
||||
|
@ -109,6 +109,15 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool compare_by_name(const child_info_t& c1, const child_info_t& c2)
|
||||
{
|
||||
if (c1.pool_name != c2.pool_name)
|
||||
return c1.pool_name < c2.pool_name;
|
||||
else if (c1.image_name != c2.image_name)
|
||||
return c1.image_name < c2.image_name;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
@ -620,7 +629,8 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int list_children(ImageCtx *ictx, set<pair<string, string> >& names)
|
||||
int list_children(ImageCtx *ictx,
|
||||
vector<child_info_t> *names)
|
||||
{
|
||||
CephContext *cct = ictx->cct;
|
||||
ldout(cct, 20) << "children list " << ictx->name << dendl;
|
||||
@ -640,7 +650,7 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
|
||||
}
|
||||
|
||||
Rados rados(ictx->md_ctx);
|
||||
for ( auto &info : image_info){
|
||||
for (auto &info : image_info) {
|
||||
IoCtx ioctx;
|
||||
r = rados.ioctx_create2(info.first.first, ioctx);
|
||||
if (r < 0) {
|
||||
@ -650,17 +660,38 @@ int validate_pool(IoCtx &io_ctx, CephContext *cct) {
|
||||
}
|
||||
|
||||
for (auto &id_it : info.second) {
|
||||
string name;
|
||||
r = cls_client::dir_get_name(&ioctx, RBD_DIRECTORY, id_it, &name);
|
||||
if (r < 0) {
|
||||
lderr(cct) << "Error looking up name for image id " << id_it
|
||||
<< " in pool " << info.first.second << dendl;
|
||||
return r;
|
||||
}
|
||||
names.insert(make_pair(info.first.second, name));
|
||||
string name;
|
||||
bool trash = false;
|
||||
r = cls_client::dir_get_name(&ioctx, RBD_DIRECTORY, id_it, &name);
|
||||
if (r == -ENOENT) {
|
||||
cls::rbd::TrashImageSpec trash_spec;
|
||||
r = cls_client::trash_get(&ioctx, id_it, &trash_spec);
|
||||
if (r < 0) {
|
||||
if (r != -EOPNOTSUPP && r != -ENOENT) {
|
||||
lderr(cct) << "Error looking up name for image id " << id_it
|
||||
<< " in rbd trash" << dendl;
|
||||
return r;
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
name = trash_spec.name;
|
||||
trash = true;
|
||||
} else if (r < 0 && r != -ENOENT) {
|
||||
lderr(cct) << "Error looking up name for image id " << id_it
|
||||
<< " in pool " << info.first.second << dendl;
|
||||
return r;
|
||||
}
|
||||
names->push_back(
|
||||
child_info_t {
|
||||
info.first.second,
|
||||
name,
|
||||
id_it,
|
||||
trash
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(names->begin(), names->end(), compare_by_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ namespace librbd {
|
||||
|
||||
int list(librados::IoCtx& io_ctx, std::vector<std::string>& names);
|
||||
int list_children(ImageCtx *ictx,
|
||||
std::set<std::pair<std::string, std::string> > & names);
|
||||
std::vector<child_info_t> *names);
|
||||
int create(librados::IoCtx& io_ctx, const char *imgname, uint64_t size,
|
||||
int *order);
|
||||
int create(librados::IoCtx& io_ctx, const char *imgname, uint64_t size,
|
||||
|
@ -1292,11 +1292,30 @@ namespace librbd {
|
||||
{
|
||||
ImageCtx *ictx = (ImageCtx *)ctx;
|
||||
tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
|
||||
int r = librbd::list_children(ictx, *children);
|
||||
vector<librbd::child_info_t> children2;
|
||||
int r = librbd::list_children(ictx, &children2);
|
||||
if (r >= 0) {
|
||||
for (set<pair<string, string> >::const_iterator it = children->begin();
|
||||
it != children->end(); ++it) {
|
||||
tracepoint(librbd, list_children_entry, it->first.c_str(), it->second.c_str());
|
||||
for (std::vector<librbd::child_info_t>::iterator it = children2.begin();
|
||||
it != children2.end(); ++it) {
|
||||
if (!it->trash) {
|
||||
children->insert(make_pair(it->pool_name, it->image_name));
|
||||
tracepoint(librbd, list_children_entry, it->pool_name.c_str(), it->image_name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
tracepoint(librbd, list_children_exit, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
int Image::list_children2(vector<librbd::child_info_t> *children)
|
||||
{
|
||||
ImageCtx *ictx = (ImageCtx *)ctx;
|
||||
tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
|
||||
int r = librbd::list_children(ictx, children);
|
||||
if (r >= 0) {
|
||||
for (std::vector<librbd::child_info_t>::iterator it = children->begin();
|
||||
it != children->end(); ++it) {
|
||||
tracepoint(librbd, list_children_entry, it->pool_name.c_str(), it->image_name.c_str());
|
||||
}
|
||||
}
|
||||
tracepoint(librbd, list_children_exit, r);
|
||||
@ -3364,13 +3383,21 @@ extern "C" ssize_t rbd_list_children(rbd_image_t image, char *pools,
|
||||
librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
|
||||
tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
|
||||
set<pair<string, string> > image_set;
|
||||
vector<librbd::child_info_t> children;
|
||||
|
||||
int r = librbd::list_children(ictx, image_set);
|
||||
int r = librbd::list_children(ictx, &children);
|
||||
if (r < 0) {
|
||||
tracepoint(librbd, list_children_exit, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
for (std::vector<librbd::child_info_t>::iterator it = children.begin();
|
||||
it != children.end(); ++it) {
|
||||
if (!it->trash) {
|
||||
image_set.insert(make_pair(it->pool_name, it->image_name));
|
||||
}
|
||||
}
|
||||
|
||||
size_t pools_total = 0;
|
||||
size_t images_total = 0;
|
||||
for (set<pair<string, string> >::const_iterator it = image_set.begin();
|
||||
@ -3409,6 +3436,72 @@ extern "C" ssize_t rbd_list_children(rbd_image_t image, char *pools,
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C" int rbd_list_children2(rbd_image_t image,
|
||||
rbd_child_info_t *children,
|
||||
int *max_children)
|
||||
{
|
||||
vector<librbd::child_info_t> cpp_children;
|
||||
librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
|
||||
tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
|
||||
|
||||
if (!max_children) {
|
||||
tracepoint(librbd, list_children_exit, -EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int r = librbd::list_children(ictx, &cpp_children);
|
||||
if (r == -ENOENT) {
|
||||
tracepoint(librbd, list_children_exit, *max_children);
|
||||
r = 0;
|
||||
}
|
||||
if (r < 0) {
|
||||
tracepoint(librbd, list_children_exit, *max_children);
|
||||
return r;
|
||||
}
|
||||
if (*max_children < (int)cpp_children.size() + 1) {
|
||||
*max_children = (int)cpp_children.size() + 1;
|
||||
tracepoint(librbd, list_children_exit, *max_children);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < (int)cpp_children.size(); i++) {
|
||||
children[i].pool_name = strdup(cpp_children[i].pool_name.c_str());
|
||||
children[i].image_name = strdup(cpp_children[i].image_name.c_str());
|
||||
children[i].image_id = strdup(cpp_children[i].image_id.c_str());
|
||||
children[i].trash = cpp_children[i].trash;
|
||||
if (!children[i].pool_name || !children[i].image_name ||
|
||||
!children[i].image_id) {
|
||||
rbd_list_children_cleanup(&children[i], i);
|
||||
tracepoint(librbd, list_children_exit, *max_children);
|
||||
return -ENOMEM;
|
||||
}
|
||||
tracepoint(librbd, list_children_entry, children[i].pool_name, children[i].image_name);
|
||||
}
|
||||
children[i].pool_name = NULL;
|
||||
children[i].image_name = NULL;
|
||||
children[i].image_id = NULL;
|
||||
|
||||
r = (int)cpp_children.size();
|
||||
tracepoint(librbd, list_children_exit, *max_children);
|
||||
return r;
|
||||
}
|
||||
|
||||
extern "C" void rbd_list_child_cleanup(rbd_child_info_t *child)
|
||||
{
|
||||
free((void *)child->pool_name);
|
||||
free((void *)child->image_name);
|
||||
free((void *)child->image_id);
|
||||
}
|
||||
|
||||
extern "C" void rbd_list_children_cleanup(rbd_child_info_t *children,
|
||||
size_t num_children)
|
||||
{
|
||||
for (size_t i=0; i < num_children; i++) {
|
||||
rbd_list_child_cleanup(&children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" ssize_t rbd_list_lockers(rbd_image_t image, int *exclusive,
|
||||
char *tag, size_t *tag_len,
|
||||
char *clients, size_t *clients_len,
|
||||
|
@ -96,6 +96,12 @@ cdef extern from "rbd/librbd.h" nogil:
|
||||
uint64_t size
|
||||
char *name
|
||||
|
||||
ctypedef struct rbd_child_info_t:
|
||||
char *pool_name
|
||||
char *image_name
|
||||
char *image_id
|
||||
bint trash
|
||||
|
||||
ctypedef enum rbd_mirror_mode_t:
|
||||
_RBD_MIRROR_MODE_DISABLED "RBD_MIRROR_MODE_DISABLED"
|
||||
_RBD_MIRROR_MODE_IMAGE "RBD_MIRROR_MODE_IMAGE"
|
||||
@ -269,6 +275,10 @@ cdef extern from "rbd/librbd.h" nogil:
|
||||
void *cbdata)
|
||||
ssize_t rbd_list_children(rbd_image_t image, char *pools, size_t *pools_len,
|
||||
char *images, size_t *images_len)
|
||||
int rbd_list_children2(rbd_image_t image, rbd_child_info_t *children,
|
||||
int *max_children)
|
||||
void rbd_list_children_cleanup(rbd_child_info_t *children,
|
||||
size_t num_children)
|
||||
ssize_t rbd_list_lockers(rbd_image_t image, int *exclusive,
|
||||
char *tag, size_t *tag_len,
|
||||
char *clients, size_t *clients_len,
|
||||
@ -2232,6 +2242,14 @@ written." % (self.name, ret, length))
|
||||
free(c_pools)
|
||||
free(c_images)
|
||||
|
||||
def list_children2(self):
|
||||
"""
|
||||
Iterate over the children of a snapshot.
|
||||
|
||||
:returns: :class:`ChildIterator`
|
||||
"""
|
||||
return ChildIterator(self)
|
||||
|
||||
def list_lockers(self):
|
||||
"""
|
||||
List clients that have locked the image and information
|
||||
@ -2958,3 +2976,53 @@ cdef class TrashIterator(object):
|
||||
if self.entries:
|
||||
free(self.entries)
|
||||
|
||||
cdef class ChildIterator(object):
|
||||
"""
|
||||
Iterator over child info for a snapshot.
|
||||
|
||||
Yields a dictionary containing information about a child.
|
||||
|
||||
Keys are:
|
||||
|
||||
* ``pool`` (str) - name of the pool
|
||||
|
||||
* ``image`` (str) - name of the child
|
||||
|
||||
* ``id`` (str) - id of the child
|
||||
|
||||
* ``trash`` (bool) - True if child is in trash bin
|
||||
"""
|
||||
|
||||
cdef rbd_child_info_t *children
|
||||
cdef int num_children
|
||||
cdef object image
|
||||
|
||||
def __init__(self, Image image):
|
||||
self.image = image
|
||||
self.children = NULL
|
||||
self.num_children = 10
|
||||
while True:
|
||||
self.children = <rbd_child_info_t*>realloc_chk(self.children,
|
||||
self.num_children *
|
||||
sizeof(rbd_child_info_t))
|
||||
with nogil:
|
||||
ret = rbd_list_children2(image.image, self.children, &self.num_children)
|
||||
if ret >= 0:
|
||||
self.num_children = ret
|
||||
break
|
||||
elif ret != -errno.ERANGE:
|
||||
raise make_ex(ret, 'error listing children.')
|
||||
|
||||
def __iter__(self):
|
||||
for i in range(self.num_children):
|
||||
yield {
|
||||
'pool' : decode_cstr(self.children[i].pool_name),
|
||||
'image' : decode_cstr(self.children[i].image_name),
|
||||
'id' : decode_cstr(self.children[i].image_id),
|
||||
'trash' : self.children[i].trash
|
||||
}
|
||||
|
||||
def __dealloc__(self):
|
||||
if self.children:
|
||||
rbd_list_children_cleanup(self.children, self.num_children)
|
||||
free(self.children)
|
||||
|
@ -144,7 +144,7 @@ Skip test on FreeBSD as it generates different output there.
|
||||
--io-type arg IO type (read , write, or readwrite(rw))
|
||||
|
||||
rbd help children
|
||||
usage: rbd children [--pool <pool>] [--image <image>] [--snap <snap>]
|
||||
usage: rbd children [--pool <pool>] [--image <image>] [--snap <snap>] [--all]
|
||||
[--format <format>] [--pretty-format]
|
||||
<snap-spec>
|
||||
|
||||
@ -158,6 +158,7 @@ Skip test on FreeBSD as it generates different output there.
|
||||
-p [ --pool ] arg pool name
|
||||
--image arg image name
|
||||
--snap arg snapshot name
|
||||
-a [ --all ] list all children of snapshot (include trash)
|
||||
--format arg output format (plain, json, or xml) [default: plain]
|
||||
--pretty-format pretty formatting (json and xml)
|
||||
|
||||
|
@ -3097,10 +3097,59 @@ static void test_list_children(rbd_image_t image, ssize_t num_expected, ...)
|
||||
free(children);
|
||||
}
|
||||
|
||||
static void test_list_children2(rbd_image_t image, int num_expected, ...)
|
||||
{
|
||||
int num_children, i, j, max_size = 10;
|
||||
va_list ap;
|
||||
rbd_child_info_t children[max_size];
|
||||
num_children = rbd_list_children2(image, children, &max_size);
|
||||
printf("num children is: %d\nexpected: %d\n", num_children, num_expected);
|
||||
|
||||
for (i = 0; i < num_children; i++) {
|
||||
printf("child: %s\n", children[i].image_name);
|
||||
}
|
||||
|
||||
va_start(ap, num_expected);
|
||||
for (i = num_expected; i > 0; i--) {
|
||||
char *expected_id = va_arg(ap, char *);
|
||||
char *expected_pool = va_arg(ap, char *);
|
||||
char *expected_image = va_arg(ap, char *);
|
||||
bool expected_trash = va_arg(ap, int);
|
||||
bool found = false;
|
||||
for (j = 0; j < num_children; j++) {
|
||||
if (children[j].pool_name == NULL ||
|
||||
children[j].image_name == NULL ||
|
||||
children[j].image_id == NULL)
|
||||
continue;
|
||||
if (strcmp(children[j].image_id, expected_id) == 0 &&
|
||||
strcmp(children[j].pool_name, expected_pool) == 0 &&
|
||||
strcmp(children[j].image_name, expected_image) == 0 &&
|
||||
children[j].trash == expected_trash) {
|
||||
printf("found child %s/%s/%s\n\n", children[j].pool_name, children[j].image_name, children[j].image_id);
|
||||
rbd_list_child_cleanup(&children[j]);
|
||||
children[j].pool_name = NULL;
|
||||
children[j].image_name = NULL;
|
||||
children[j].image_id = NULL;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(found);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
for (i = 0; i < num_children; i++) {
|
||||
EXPECT_EQ((const char *)0, children[i].pool_name);
|
||||
EXPECT_EQ((const char *)0, children[i].image_name);
|
||||
EXPECT_EQ((const char *)0, children[i].image_id);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestLibRBD, ListChildren)
|
||||
{
|
||||
REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
|
||||
|
||||
librbd::RBD rbd;
|
||||
rados_ioctx_t ioctx1, ioctx2;
|
||||
string pool_name1 = create_pool(true);
|
||||
string pool_name2 = create_pool(true);
|
||||
@ -3109,6 +3158,11 @@ TEST_F(TestLibRBD, ListChildren)
|
||||
rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
|
||||
rados_ioctx_create(_cluster, pool_name2.c_str(), &ioctx2);
|
||||
|
||||
rbd_image_t image1;
|
||||
rbd_image_t image2;
|
||||
rbd_image_t image3;
|
||||
rbd_image_t image4;
|
||||
|
||||
bool old_format;
|
||||
uint64_t features;
|
||||
rbd_image_t parent;
|
||||
@ -3123,6 +3177,11 @@ TEST_F(TestLibRBD, ListChildren)
|
||||
std::string child_name3 = get_temp_image_name();
|
||||
std::string child_name4 = get_temp_image_name();
|
||||
|
||||
char child_id1[4096];
|
||||
char child_id2[4096];
|
||||
char child_id3[4096];
|
||||
char child_id4[4096];
|
||||
|
||||
// make a parent to clone from
|
||||
ASSERT_EQ(0, create_image_full(ioctx1, parent_name.c_str(), 4<<20, &order,
|
||||
false, features));
|
||||
@ -3137,43 +3196,100 @@ TEST_F(TestLibRBD, ListChildren)
|
||||
|
||||
ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
|
||||
ioctx2, child_name1.c_str(), features, &order));
|
||||
ASSERT_EQ(0, rbd_open(ioctx2, child_name1.c_str(), &image1, NULL));
|
||||
ASSERT_EQ(0, rbd_get_id(image1, child_id1, sizeof(child_id1)));
|
||||
test_list_children(parent, 1, pool_name2.c_str(), child_name1.c_str());
|
||||
test_list_children2(parent, 1,
|
||||
child_id1, pool_name2.c_str(), child_name1.c_str(), false);
|
||||
|
||||
ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
|
||||
ioctx1, child_name2.c_str(), features, &order));
|
||||
ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &image2, NULL));
|
||||
ASSERT_EQ(0, rbd_get_id(image2, child_id2, sizeof(child_id2)));
|
||||
test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
|
||||
pool_name1.c_str(), child_name2.c_str());
|
||||
test_list_children2(parent, 2,
|
||||
child_id1, pool_name2.c_str(), child_name1.c_str(), false,
|
||||
child_id2, pool_name1.c_str(), child_name2.c_str(), false);
|
||||
|
||||
ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
|
||||
ioctx2, child_name3.c_str(), features, &order));
|
||||
ASSERT_EQ(0, rbd_open(ioctx2, child_name3.c_str(), &image3, NULL));
|
||||
ASSERT_EQ(0, rbd_get_id(image3, child_id3, sizeof(child_id3)));
|
||||
test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
|
||||
pool_name1.c_str(), child_name2.c_str(),
|
||||
pool_name2.c_str(), child_name3.c_str());
|
||||
test_list_children2(parent, 3,
|
||||
child_id1, pool_name2.c_str(), child_name1.c_str(), false,
|
||||
child_id2, pool_name1.c_str(), child_name2.c_str(), false,
|
||||
child_id3, pool_name2.c_str(), child_name3.c_str(), false);
|
||||
|
||||
librados::IoCtx ioctx3;
|
||||
ASSERT_EQ(0, _rados.ioctx_create(pool_name2.c_str(), ioctx3));
|
||||
ASSERT_EQ(0, rbd.trash_move(ioctx3, child_name3.c_str(), 0));
|
||||
test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
|
||||
pool_name1.c_str(), child_name2.c_str());
|
||||
test_list_children2(parent, 3,
|
||||
child_id1, pool_name2.c_str(), child_name1.c_str(), false,
|
||||
child_id2, pool_name1.c_str(), child_name2.c_str(), false,
|
||||
child_id3, pool_name2.c_str(), child_name3.c_str(), true);
|
||||
|
||||
ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
|
||||
ioctx2, child_name4.c_str(), features, &order));
|
||||
ASSERT_EQ(0, rbd_open(ioctx2, child_name4.c_str(), &image4, NULL));
|
||||
ASSERT_EQ(0, rbd_get_id(image4, child_id4, sizeof(child_id4)));
|
||||
test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
|
||||
pool_name1.c_str(), child_name2.c_str(),
|
||||
pool_name2.c_str(), child_name4.c_str());
|
||||
test_list_children2(parent, 4,
|
||||
child_id1, pool_name2.c_str(), child_name1.c_str(), false,
|
||||
child_id2, pool_name1.c_str(), child_name2.c_str(), false,
|
||||
child_id3, pool_name2.c_str(), child_name3.c_str(), true,
|
||||
child_id4, pool_name2.c_str(), child_name4.c_str(), false);
|
||||
|
||||
ASSERT_EQ(0, rbd.trash_restore(ioctx3, child_id3, ""));
|
||||
test_list_children(parent, 4, pool_name2.c_str(), child_name1.c_str(),
|
||||
pool_name1.c_str(), child_name2.c_str(),
|
||||
pool_name2.c_str(), child_name3.c_str(),
|
||||
pool_name2.c_str(), child_name4.c_str());
|
||||
test_list_children2(parent, 4,
|
||||
child_id1, pool_name2.c_str(), child_name1.c_str(), false,
|
||||
child_id2, pool_name1.c_str(), child_name2.c_str(), false,
|
||||
child_id3, pool_name2.c_str(), child_name3.c_str(), false,
|
||||
child_id4, pool_name2.c_str(), child_name4.c_str(), false);
|
||||
|
||||
ASSERT_EQ(0, rbd_close(image1));
|
||||
ASSERT_EQ(0, rbd_remove(ioctx2, child_name1.c_str()));
|
||||
test_list_children(parent, 3,
|
||||
pool_name1.c_str(), child_name2.c_str(),
|
||||
pool_name2.c_str(), child_name3.c_str(),
|
||||
pool_name2.c_str(), child_name4.c_str());
|
||||
test_list_children2(parent, 3,
|
||||
child_id2, pool_name1.c_str(), child_name2.c_str(), false,
|
||||
child_id3, pool_name2.c_str(), child_name3.c_str(), false,
|
||||
child_id4, pool_name2.c_str(), child_name4.c_str(), false);
|
||||
|
||||
ASSERT_EQ(0, rbd_close(image3));
|
||||
ASSERT_EQ(0, rbd_remove(ioctx2, child_name3.c_str()));
|
||||
test_list_children(parent, 2,
|
||||
pool_name1.c_str(), child_name2.c_str(),
|
||||
pool_name2.c_str(), child_name4.c_str());
|
||||
test_list_children2(parent, 2,
|
||||
child_id2, pool_name1.c_str(), child_name2.c_str(), false,
|
||||
child_id4, pool_name2.c_str(), child_name4.c_str(), false);
|
||||
|
||||
ASSERT_EQ(0, rbd_close(image4));
|
||||
ASSERT_EQ(0, rbd_remove(ioctx2, child_name4.c_str()));
|
||||
test_list_children(parent, 1,
|
||||
pool_name1.c_str(), child_name2.c_str());
|
||||
test_list_children2(parent, 1,
|
||||
child_id2, pool_name1.c_str(), child_name2.c_str(), false);
|
||||
|
||||
|
||||
ASSERT_EQ(0, rbd_close(image2));
|
||||
ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
|
||||
test_list_children(parent, 0);
|
||||
test_list_children2(parent, 0);
|
||||
|
||||
ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
|
||||
ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
|
||||
@ -3187,6 +3303,7 @@ TEST_F(TestLibRBD, ListChildrenTiered)
|
||||
{
|
||||
REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
|
||||
|
||||
librbd::RBD rbd;
|
||||
string pool_name1 = m_pool_name;
|
||||
string pool_name2 = create_pool(true);
|
||||
string pool_name3 = create_pool(true);
|
||||
@ -3217,6 +3334,16 @@ TEST_F(TestLibRBD, ListChildrenTiered)
|
||||
string child_name3 = get_temp_image_name();
|
||||
string child_name4 = get_temp_image_name();
|
||||
|
||||
char child_id1[4096];
|
||||
char child_id2[4096];
|
||||
char child_id3[4096];
|
||||
char child_id4[4096];
|
||||
|
||||
rbd_image_t image1;
|
||||
rbd_image_t image2;
|
||||
rbd_image_t image3;
|
||||
rbd_image_t image4;
|
||||
|
||||
rados_ioctx_t ioctx1, ioctx2;
|
||||
rados_ioctx_create(_cluster, pool_name1.c_str(), &ioctx1);
|
||||
rados_ioctx_create(_cluster, pool_name2.c_str(), &ioctx2);
|
||||
@ -3243,12 +3370,21 @@ TEST_F(TestLibRBD, ListChildrenTiered)
|
||||
|
||||
ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
|
||||
ioctx2, child_name1.c_str(), features, &order));
|
||||
ASSERT_EQ(0, rbd_open(ioctx2, child_name1.c_str(), &image1, NULL));
|
||||
ASSERT_EQ(0, rbd_get_id(image1, child_id1, sizeof(child_id1)));
|
||||
test_list_children(parent, 1, pool_name2.c_str(), child_name1.c_str());
|
||||
test_list_children2(parent, 1,
|
||||
child_id1, pool_name2.c_str(), child_name1.c_str(), false);
|
||||
|
||||
ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
|
||||
ioctx1, child_name2.c_str(), features, &order));
|
||||
ASSERT_EQ(0, rbd_open(ioctx1, child_name2.c_str(), &image2, NULL));
|
||||
ASSERT_EQ(0, rbd_get_id(image2, child_id2, sizeof(child_id2)));
|
||||
test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
|
||||
pool_name1.c_str(), child_name2.c_str());
|
||||
test_list_children2(parent, 2,
|
||||
child_id1, pool_name2.c_str(), child_name1.c_str(), false,
|
||||
child_id2, pool_name1.c_str(), child_name2.c_str(), false);
|
||||
|
||||
// read from the cache to populate it
|
||||
rbd_image_t tier_image;
|
||||
@ -3262,34 +3398,81 @@ TEST_F(TestLibRBD, ListChildrenTiered)
|
||||
|
||||
ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
|
||||
ioctx2, child_name3.c_str(), features, &order));
|
||||
ASSERT_EQ(0, rbd_open(ioctx2, child_name3.c_str(), &image3, NULL));
|
||||
ASSERT_EQ(0, rbd_get_id(image3, child_id3, sizeof(child_id3)));
|
||||
test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
|
||||
pool_name1.c_str(), child_name2.c_str(),
|
||||
pool_name2.c_str(), child_name3.c_str());
|
||||
test_list_children2(parent, 3,
|
||||
child_id1, pool_name2.c_str(), child_name1.c_str(), false,
|
||||
child_id2, pool_name1.c_str(), child_name2.c_str(), false,
|
||||
child_id3, pool_name2.c_str(), child_name3.c_str(), false);
|
||||
|
||||
librados::IoCtx ioctx3;
|
||||
ASSERT_EQ(0, _rados.ioctx_create(pool_name2.c_str(), ioctx3));
|
||||
ASSERT_EQ(0, rbd.trash_move(ioctx3, child_name3.c_str(), 0));
|
||||
test_list_children(parent, 2, pool_name2.c_str(), child_name1.c_str(),
|
||||
pool_name1.c_str(), child_name2.c_str());
|
||||
test_list_children2(parent, 3,
|
||||
child_id1, pool_name2.c_str(), child_name1.c_str(), false,
|
||||
child_id2, pool_name1.c_str(), child_name2.c_str(), false,
|
||||
child_id3, pool_name2.c_str(), child_name3.c_str(), true);
|
||||
|
||||
ASSERT_EQ(0, clone_image(ioctx1, parent, parent_name.c_str(), "parent_snap",
|
||||
ioctx2, child_name4.c_str(), features, &order));
|
||||
ASSERT_EQ(0, rbd_open(ioctx2, child_name4.c_str(), &image4, NULL));
|
||||
ASSERT_EQ(0, rbd_get_id(image4, child_id4, sizeof(child_id4)));
|
||||
test_list_children(parent, 3, pool_name2.c_str(), child_name1.c_str(),
|
||||
pool_name1.c_str(), child_name2.c_str(),
|
||||
pool_name2.c_str(), child_name4.c_str());
|
||||
test_list_children2(parent, 4,
|
||||
child_id1, pool_name2.c_str(), child_name1.c_str(), false,
|
||||
child_id2, pool_name1.c_str(), child_name2.c_str(), false,
|
||||
child_id3, pool_name2.c_str(), child_name3.c_str(), true,
|
||||
child_id4, pool_name2.c_str(), child_name4.c_str(), false);
|
||||
|
||||
ASSERT_EQ(0, rbd.trash_restore(ioctx3, child_id3, ""));
|
||||
test_list_children(parent, 4, pool_name2.c_str(), child_name1.c_str(),
|
||||
pool_name1.c_str(), child_name2.c_str(),
|
||||
pool_name2.c_str(), child_name3.c_str(),
|
||||
pool_name2.c_str(), child_name4.c_str());
|
||||
test_list_children2(parent, 4,
|
||||
child_id1, pool_name2.c_str(), child_name1.c_str(), false,
|
||||
child_id2, pool_name1.c_str(), child_name2.c_str(), false,
|
||||
child_id3, pool_name2.c_str(), child_name3.c_str(), false,
|
||||
child_id4, pool_name2.c_str(), child_name4.c_str(), false);
|
||||
|
||||
ASSERT_EQ(0, rbd_close(image1));
|
||||
ASSERT_EQ(0, rbd_remove(ioctx2, child_name1.c_str()));
|
||||
test_list_children(parent, 3,
|
||||
pool_name1.c_str(), child_name2.c_str(),
|
||||
pool_name2.c_str(), child_name3.c_str(),
|
||||
pool_name2.c_str(), child_name4.c_str());
|
||||
test_list_children2(parent, 3,
|
||||
child_id2, pool_name1.c_str(), child_name2.c_str(), false,
|
||||
child_id3, pool_name2.c_str(), child_name3.c_str(), false,
|
||||
child_id4, pool_name2.c_str(), child_name4.c_str(), false);
|
||||
|
||||
ASSERT_EQ(0, rbd_close(image3));
|
||||
ASSERT_EQ(0, rbd_remove(ioctx2, child_name3.c_str()));
|
||||
test_list_children(parent, 2,
|
||||
pool_name1.c_str(), child_name2.c_str(),
|
||||
pool_name2.c_str(), child_name4.c_str());
|
||||
test_list_children2(parent, 2,
|
||||
child_id2, pool_name1.c_str(), child_name2.c_str(), false,
|
||||
child_id4, pool_name2.c_str(), child_name4.c_str(), false);
|
||||
|
||||
ASSERT_EQ(0, rbd_close(image4));
|
||||
ASSERT_EQ(0, rbd_remove(ioctx2, child_name4.c_str()));
|
||||
test_list_children(parent, 1,
|
||||
pool_name1.c_str(), child_name2.c_str());
|
||||
test_list_children2(parent, 1,
|
||||
child_id2, pool_name1.c_str(), child_name2.c_str(), false);
|
||||
|
||||
ASSERT_EQ(0, rbd_close(image2));
|
||||
ASSERT_EQ(0, rbd_remove(ioctx1, child_name2.c_str()));
|
||||
test_list_children(parent, 0);
|
||||
test_list_children2(parent, 0);
|
||||
|
||||
ASSERT_EQ(0, rbd_snap_unprotect(parent, "parent_snap"));
|
||||
ASSERT_EQ(0, rbd_snap_remove(parent, "parent_snap"));
|
||||
|
@ -1043,32 +1043,74 @@ class TestClone(object):
|
||||
deduped = set([(pool_name, image[1]) for image in actual])
|
||||
eq(deduped, set(expected))
|
||||
|
||||
def check_children2(self, expected):
|
||||
actual = list(self.image.list_children2())
|
||||
eq(actual, expected)
|
||||
|
||||
def get_image_id(self, ioctx, name):
|
||||
with Image(ioctx, name) as image:
|
||||
return image.id()
|
||||
|
||||
def test_list_children(self):
|
||||
global ioctx
|
||||
global features
|
||||
self.image.set_snap('snap1')
|
||||
self.check_children([(pool_name, self.clone_name)])
|
||||
self.check_children2(
|
||||
[{'pool': pool_name, 'image': self.clone_name, 'trash': False,
|
||||
'id': self.get_image_id(ioctx, self.clone_name)}])
|
||||
self.clone.close()
|
||||
self.rbd.remove(ioctx, self.clone_name)
|
||||
eq(self.image.list_children(), [])
|
||||
eq(list(self.image.list_children2()), [])
|
||||
|
||||
clone_name = get_temp_image_name() + '_'
|
||||
expected_children = []
|
||||
expected_children2 = []
|
||||
for i in range(10):
|
||||
self.rbd.clone(ioctx, image_name, 'snap1', ioctx,
|
||||
clone_name + str(i), features)
|
||||
expected_children.append((pool_name, clone_name + str(i)))
|
||||
expected_children2.append(
|
||||
{'pool': pool_name, 'image': clone_name + str(i), 'trash': False,
|
||||
'id': self.get_image_id(ioctx, clone_name + str(i))})
|
||||
self.check_children(expected_children)
|
||||
self.check_children2(expected_children2)
|
||||
|
||||
image6_id = self.get_image_id(ioctx, clone_name + str(5))
|
||||
RBD().trash_move(ioctx, clone_name + str(5), 0)
|
||||
expected_children.remove((pool_name, clone_name + str(5)))
|
||||
for item in expected_children2:
|
||||
for k, v in item.items():
|
||||
if v == image6_id:
|
||||
item["trash"] = True
|
||||
self.check_children(expected_children)
|
||||
self.check_children2(expected_children2)
|
||||
|
||||
RBD().trash_restore(ioctx, image6_id, clone_name + str(5))
|
||||
expected_children.append((pool_name, clone_name + str(5)))
|
||||
for item in expected_children2:
|
||||
for k, v in item.items():
|
||||
if v == image6_id:
|
||||
item["trash"] = False
|
||||
self.check_children(expected_children)
|
||||
self.check_children2(expected_children2)
|
||||
|
||||
for i in range(10):
|
||||
self.rbd.remove(ioctx, clone_name + str(i))
|
||||
expected_children.pop(0)
|
||||
expected_children.remove((pool_name, clone_name + str(i)))
|
||||
expected_children2.pop(0)
|
||||
self.check_children(expected_children)
|
||||
self.check_children2(expected_children2)
|
||||
|
||||
eq(self.image.list_children(), [])
|
||||
eq(list(self.image.list_children2()), [])
|
||||
self.rbd.clone(ioctx, image_name, 'snap1', ioctx, self.clone_name,
|
||||
features)
|
||||
self.check_children([(pool_name, self.clone_name)])
|
||||
self.check_children2(
|
||||
[{'pool': pool_name, 'image': self.clone_name, 'trash': False,
|
||||
'id': self.get_image_id(ioctx, self.clone_name)}])
|
||||
self.clone = Image(ioctx, self.clone_name)
|
||||
|
||||
def test_flatten_errors(self):
|
||||
|
@ -16,26 +16,44 @@ namespace children {
|
||||
namespace at = argument_types;
|
||||
namespace po = boost::program_options;
|
||||
|
||||
int do_list_children(librbd::Image &image, Formatter *f)
|
||||
int do_list_children(librados::IoCtx &io_ctx, librbd::Image &image,
|
||||
bool all_flag, Formatter *f)
|
||||
{
|
||||
std::set<std::pair<std::string, std::string> > children;
|
||||
int r;
|
||||
|
||||
r = image.list_children(&children);
|
||||
std::vector<librbd::child_info_t> children;
|
||||
librbd::RBD rbd;
|
||||
int r = image.list_children2(&children);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (f)
|
||||
f->open_array_section("children");
|
||||
|
||||
for (auto &child_it : children) {
|
||||
for (std::vector<librbd::child_info_t>::iterator it = children.begin();
|
||||
it != children.end(); ++it) {
|
||||
bool trash = it->trash;
|
||||
if (f) {
|
||||
f->open_object_section("child");
|
||||
f->dump_string("pool", child_it.first);
|
||||
f->dump_string("image", child_it.second);
|
||||
f->close_section();
|
||||
if (all_flag) {
|
||||
f->open_object_section("child");
|
||||
f->dump_string("pool", it->pool_name);
|
||||
f->dump_string("image", it->image_name);
|
||||
f->dump_string("id", it->image_id);
|
||||
f->dump_bool("trash", it->trash);
|
||||
f->close_section();
|
||||
} else if (!trash) {
|
||||
f->open_object_section("child");
|
||||
f->dump_string("pool", it->pool_name);
|
||||
f->dump_string("image", it->image_name);
|
||||
f->close_section();
|
||||
}
|
||||
} else {
|
||||
std::cout << child_it.first << "/" << child_it.second << std::endl;
|
||||
if (all_flag) {
|
||||
std::cout << it->pool_name << "/" << it->image_name;
|
||||
if (trash)
|
||||
std::cout << " (trash " << it->image_id << ")";
|
||||
std::cout << std::endl;
|
||||
} else if (!trash) {
|
||||
std::cout << it->pool_name << "/" << it->image_name << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,6 +68,8 @@ int do_list_children(librbd::Image &image, Formatter *f)
|
||||
void get_arguments(po::options_description *positional,
|
||||
po::options_description *options) {
|
||||
at::add_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
|
||||
options->add_options()
|
||||
("all,a", po::bool_switch(), "list all children of snapshot (include trash)");
|
||||
at::add_format_options(options);
|
||||
}
|
||||
|
||||
@ -80,7 +100,7 @@ int execute(const po::variables_map &vm) {
|
||||
return r;
|
||||
}
|
||||
|
||||
r = do_list_children(image, formatter.get());
|
||||
r = do_list_children(io_ctx, image, vm["all"].as<bool>(), formatter.get());
|
||||
if (r < 0) {
|
||||
std::cerr << "rbd: listing children failed: " << cpp_strerror(r)
|
||||
<< std::endl;
|
||||
|
Loading…
Reference in New Issue
Block a user