]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/cls_rbd/test_cls_rbd.cc
5b33597455643ab0c9ddacc39c4a8f6d05f2e5a6
[ceph.git] / ceph / src / test / cls_rbd / test_cls_rbd.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "include/compat.h"
5 #include "common/ceph_context.h"
6 #include "common/config.h"
7 #include "common/snap_types.h"
8 #include "common/Clock.h"
9 #include "common/bit_vector.hpp"
10 #include "include/encoding.h"
11 #include "include/types.h"
12 #include "include/rados/librados.h"
13 #include "include/rbd/object_map_types.h"
14 #include "include/rbd_types.h"
15 #include "include/stringify.h"
16 #include "cls/rbd/cls_rbd.h"
17 #include "cls/rbd/cls_rbd_client.h"
18 #include "cls/rbd/cls_rbd_types.h"
19 #include "librbd/Types.h"
20
21 #include "gtest/gtest.h"
22 #include "test/librados/test_cxx.h"
23
24 #include <errno.h>
25 #include <string>
26 #include <vector>
27
28 using namespace std;
29 using namespace librbd::cls_client;
30 using cls::rbd::MIRROR_PEER_DIRECTION_RX;
31 using cls::rbd::MIRROR_PEER_DIRECTION_TX;
32 using cls::rbd::MIRROR_PEER_DIRECTION_RX_TX;
33 using ::librbd::ParentImageInfo;
34 using ceph::encode;
35 using ceph::decode;
36
37 static int snapshot_add(librados::IoCtx *ioctx, const std::string &oid,
38 uint64_t snap_id, const std::string &snap_name) {
39 librados::ObjectWriteOperation op;
40 ::librbd::cls_client::snapshot_add(&op, snap_id, snap_name, cls::rbd::UserSnapshotNamespace());
41 return ioctx->operate(oid, &op);
42 }
43
44 static int snapshot_remove(librados::IoCtx *ioctx, const std::string &oid,
45 uint64_t snap_id) {
46 librados::ObjectWriteOperation op;
47 ::librbd::cls_client::snapshot_remove(&op, snap_id);
48 return ioctx->operate(oid, &op);
49 }
50
51 static int snapshot_rename(librados::IoCtx *ioctx, const std::string &oid,
52 uint64_t snap_id, const std::string &snap_name) {
53 librados::ObjectWriteOperation op;
54 ::librbd::cls_client::snapshot_rename(&op, snap_id, snap_name);
55 return ioctx->operate(oid, &op);
56 }
57
58 static int old_snapshot_add(librados::IoCtx *ioctx, const std::string &oid,
59 uint64_t snap_id, const std::string &snap_name) {
60 librados::ObjectWriteOperation op;
61 ::librbd::cls_client::old_snapshot_add(&op, snap_id, snap_name);
62 return ioctx->operate(oid, &op);
63 }
64
65 static char *random_buf(size_t len)
66 {
67 char *b = new char[len];
68 for (size_t i = 0; i < len; i++)
69 b[i] = (rand() % (128 - 32)) + 32;
70 return b;
71 }
72
73 static bool is_sparse_read_supported(librados::IoCtx &ioctx,
74 const std::string &oid) {
75 EXPECT_EQ(0, ioctx.create(oid, true));
76 bufferlist inbl;
77 inbl.append(std::string(1, 'X'));
78 EXPECT_EQ(0, ioctx.write(oid, inbl, inbl.length(), 1));
79 EXPECT_EQ(0, ioctx.write(oid, inbl, inbl.length(), 3));
80
81 std::map<uint64_t, uint64_t> m;
82 bufferlist outbl;
83 int r = ioctx.sparse_read(oid, m, outbl, 4, 0);
84 ioctx.remove(oid);
85
86 int expected_r = 2;
87 std::map<uint64_t, uint64_t> expected_m = {{1, 1}, {3, 1}};
88 bufferlist expected_outbl;
89 expected_outbl.append(std::string(2, 'X'));
90
91 return (r == expected_r && m == expected_m &&
92 outbl.contents_equal(expected_outbl));
93 }
94
95 class TestClsRbd : public ::testing::Test {
96 public:
97
98 static void SetUpTestCase() {
99 _pool_name = get_temp_pool_name();
100 ASSERT_EQ("", create_one_pool_pp(_pool_name, _rados));
101 }
102
103 static void TearDownTestCase() {
104 ASSERT_EQ(0, destroy_one_pool_pp(_pool_name, _rados));
105 }
106
107 std::string get_temp_image_name() {
108 ++_image_number;
109 return "image" + stringify(_image_number);
110 }
111
112 static std::string _pool_name;
113 static librados::Rados _rados;
114 static uint64_t _image_number;
115
116 };
117
118 std::string TestClsRbd::_pool_name;
119 librados::Rados TestClsRbd::_rados;
120 uint64_t TestClsRbd::_image_number = 0;
121
122 TEST_F(TestClsRbd, get_all_features)
123 {
124 librados::IoCtx ioctx;
125 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
126
127 string oid = get_temp_image_name();
128 ASSERT_EQ(0, ioctx.create(oid, false));
129
130 uint64_t all_features = 0;
131 ASSERT_EQ(0, get_all_features(&ioctx, oid, &all_features));
132 ASSERT_EQ(static_cast<uint64_t>(RBD_FEATURES_ALL),
133 static_cast<uint64_t>(all_features & RBD_FEATURES_ALL));
134
135 ioctx.close();
136 }
137
138 TEST_F(TestClsRbd, copyup)
139 {
140 librados::IoCtx ioctx;
141 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
142
143 string oid = get_temp_image_name();
144 bufferlist inbl, outbl;
145
146 // copyup of 0-len nonexistent object should create new 0-len object
147 ioctx.remove(oid);
148 ASSERT_EQ(0, copyup(&ioctx, oid, inbl));
149 uint64_t size;
150 ASSERT_EQ(0, ioctx.stat(oid, &size, NULL));
151 ASSERT_EQ(0U, size);
152
153 // create some random data to write
154 size_t l = 4 << 20;
155 char *b = random_buf(l);
156 inbl.append(b, l);
157 delete [] b;
158 ASSERT_EQ(l, inbl.length());
159
160 // copyup to nonexistent object should create new object
161 ioctx.remove(oid);
162 ASSERT_EQ(-ENOENT, ioctx.remove(oid));
163 ASSERT_EQ(0, copyup(&ioctx, oid, inbl));
164 // and its contents should match
165 ASSERT_EQ(l, (size_t)ioctx.read(oid, outbl, l, 0));
166 ASSERT_TRUE(outbl.contents_equal(inbl));
167
168 // now send different data, but with a preexisting object
169 bufferlist inbl2;
170 b = random_buf(l);
171 inbl2.append(b, l);
172 delete [] b;
173 ASSERT_EQ(l, inbl2.length());
174
175 // should still succeed
176 ASSERT_EQ(0, copyup(&ioctx, oid, inbl));
177 ASSERT_EQ(l, (size_t)ioctx.read(oid, outbl, l, 0));
178 // but contents should not have changed
179 ASSERT_FALSE(outbl.contents_equal(inbl2));
180 ASSERT_TRUE(outbl.contents_equal(inbl));
181
182 ASSERT_EQ(0, ioctx.remove(oid));
183 ioctx.close();
184 }
185
186 TEST_F(TestClsRbd, sparse_copyup)
187 {
188 librados::IoCtx ioctx;
189 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
190
191 string oid = get_temp_image_name();
192 ioctx.remove(oid);
193
194 bool sparse_read_supported = is_sparse_read_supported(ioctx, oid);
195
196 // copyup of 0-len nonexistent object should create new 0-len object
197 uint64_t size;
198 ASSERT_EQ(-ENOENT, ioctx.stat(oid, &size, nullptr));
199 std::map<uint64_t, uint64_t> m;
200 bufferlist inbl;
201 ASSERT_EQ(0, sparse_copyup(&ioctx, oid, m, inbl));
202 ASSERT_EQ(0, ioctx.stat(oid, &size, nullptr));
203 ASSERT_EQ(0U, size);
204
205 // create some data to write
206 inbl.append(std::string(4096, '1'));
207 inbl.append(std::string(4096, '2'));
208 m = {{1024, 4096}, {8192, 4096}};
209
210 // copyup to nonexistent object should create new object
211 ioctx.remove(oid);
212 ASSERT_EQ(-ENOENT, ioctx.remove(oid));
213 ASSERT_EQ(0, sparse_copyup(&ioctx, oid, m, inbl));
214 // and its contents should match
215 bufferlist outbl;
216 bufferlist expected_outbl;
217 expected_outbl.append(std::string(1024, '\0'));
218 expected_outbl.append(std::string(4096, '1'));
219 expected_outbl.append(std::string(8192 - 4096 - 1024, '\0'));
220 expected_outbl.append(std::string(4096, '2'));
221 ASSERT_EQ((int)expected_outbl.length(),
222 ioctx.read(oid, outbl, expected_outbl.length() + 1, 0));
223 ASSERT_TRUE(outbl.contents_equal(expected_outbl));
224 std::map<uint64_t, uint64_t> expected_m;
225 if (sparse_read_supported) {
226 expected_m = m;
227 expected_outbl = inbl;
228 } else {
229 expected_m = {{0, expected_outbl.length()}};
230 }
231 m.clear();
232 outbl.clear();
233 ASSERT_EQ((int)expected_m.size(), ioctx.sparse_read(oid, m, outbl, 65536, 0));
234 ASSERT_EQ(m, expected_m);
235 ASSERT_TRUE(outbl.contents_equal(expected_outbl));
236
237 // now send different data, but with a preexisting object
238 bufferlist inbl2;
239 inbl2.append(std::string(1024, 'X'));
240
241 // should still succeed
242 ASSERT_EQ(0, sparse_copyup(&ioctx, oid, {{0, 1024}}, inbl2));
243 // but contents should not have changed
244 m.clear();
245 outbl.clear();
246 ASSERT_EQ((int)expected_m.size(), ioctx.sparse_read(oid, m, outbl, 65536, 0));
247 ASSERT_EQ(m, expected_m);
248 ASSERT_TRUE(outbl.contents_equal(expected_outbl));
249
250 ASSERT_EQ(0, ioctx.remove(oid));
251 ioctx.close();
252 }
253
254 TEST_F(TestClsRbd, get_and_set_id)
255 {
256 librados::IoCtx ioctx;
257 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
258
259 string oid = get_temp_image_name();
260 string id;
261 string valid_id = "0123abcxyzZYXCBA";
262 string invalid_id = ".abc";
263 string empty_id;
264
265 ASSERT_EQ(-ENOENT, get_id(&ioctx, oid, &id));
266 ASSERT_EQ(-ENOENT, set_id(&ioctx, oid, valid_id));
267
268 ASSERT_EQ(0, ioctx.create(oid, true));
269 ASSERT_EQ(-EINVAL, set_id(&ioctx, oid, invalid_id));
270 ASSERT_EQ(-EINVAL, set_id(&ioctx, oid, empty_id));
271 ASSERT_EQ(-ENOENT, get_id(&ioctx, oid, &id));
272
273 ASSERT_EQ(0, set_id(&ioctx, oid, valid_id));
274 ASSERT_EQ(-EEXIST, set_id(&ioctx, oid, valid_id));
275 ASSERT_EQ(-EEXIST, set_id(&ioctx, oid, valid_id + valid_id));
276 ASSERT_EQ(0, get_id(&ioctx, oid, &id));
277 ASSERT_EQ(id, valid_id);
278
279 ioctx.close();
280 }
281
282 TEST_F(TestClsRbd, add_remove_child)
283 {
284 librados::IoCtx ioctx;
285 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
286
287 string oid = get_temp_image_name();
288 ASSERT_EQ(0, ioctx.create(oid, true));
289
290 string snapname = "parent_snap";
291 snapid_t snapid(10);
292 string parent_image = "parent_id";
293 set<string>children;
294 cls::rbd::ParentImageSpec pspec(ioctx.get_id(), "", parent_image, snapid);
295
296 // nonexistent children cannot be listed or removed
297 ASSERT_EQ(-ENOENT, get_children(&ioctx, oid, pspec, children));
298 ASSERT_EQ(-ENOENT, remove_child(&ioctx, oid, pspec, "child1"));
299
300 // create the parent and snapshot
301 ASSERT_EQ(0, create_image(&ioctx, parent_image, 2<<20, 0,
302 RBD_FEATURE_LAYERING, parent_image, -1));
303 ASSERT_EQ(0, snapshot_add(&ioctx, parent_image, snapid, snapname));
304
305 // add child to it, verify it showed up
306 ASSERT_EQ(0, add_child(&ioctx, oid, pspec, "child1"));
307 ASSERT_EQ(0, get_children(&ioctx, oid, pspec, children));
308 ASSERT_TRUE(children.find("child1") != children.end());
309 // add another child to it, verify it showed up
310 ASSERT_EQ(0, add_child(&ioctx, oid, pspec, "child2"));
311 ASSERT_EQ(0, get_children(&ioctx, oid, pspec, children));
312 ASSERT_TRUE(children.find("child2") != children.end());
313 // add child2 again, expect -EEXIST
314 ASSERT_EQ(-EEXIST, add_child(&ioctx, oid, pspec, "child2"));
315 // remove first, verify it's gone
316 ASSERT_EQ(0, remove_child(&ioctx, oid, pspec, "child1"));
317 ASSERT_EQ(0, get_children(&ioctx, oid, pspec, children));
318 ASSERT_FALSE(children.find("child1") != children.end());
319 // remove second, verify list empty
320 ASSERT_EQ(0, remove_child(&ioctx, oid, pspec, "child2"));
321 ASSERT_EQ(-ENOENT, get_children(&ioctx, oid, pspec, children));
322 // try to remove again, validate -ENOENT to that as well
323 ASSERT_EQ(-ENOENT, remove_child(&ioctx, oid, pspec, "child2"));
324
325 ioctx.close();
326 }
327
328 TEST_F(TestClsRbd, directory_methods)
329 {
330 librados::IoCtx ioctx;
331 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
332
333 string oid = get_temp_image_name();
334 string id, name;
335 string imgname = get_temp_image_name();
336 string imgname2 = get_temp_image_name();
337 string imgname3 = get_temp_image_name();
338 string valid_id = "0123abcxyzZYXCBA";
339 string valid_id2 = "5";
340 string invalid_id = ".abc";
341 string empty;
342
343 ASSERT_EQ(-ENOENT, dir_state_assert(&ioctx, oid,
344 cls::rbd::DIRECTORY_STATE_READY));
345 ASSERT_EQ(-ENOENT, dir_state_set(&ioctx, oid,
346 cls::rbd::DIRECTORY_STATE_ADD_DISABLED));
347
348 ASSERT_EQ(-ENOENT, dir_get_id(&ioctx, oid, imgname, &id));
349 ASSERT_EQ(-ENOENT, dir_get_name(&ioctx, oid, valid_id, &name));
350 ASSERT_EQ(-ENOENT, dir_remove_image(&ioctx, oid, imgname, valid_id));
351
352 ASSERT_EQ(-EINVAL, dir_add_image(&ioctx, oid, imgname, invalid_id));
353 ASSERT_EQ(-EINVAL, dir_add_image(&ioctx, oid, imgname, empty));
354 ASSERT_EQ(-EINVAL, dir_add_image(&ioctx, oid, empty, valid_id));
355
356 map<string, string> images;
357 ASSERT_EQ(-ENOENT, dir_list(&ioctx, oid, "", 30, &images));
358
359 ASSERT_EQ(0, ioctx.create(oid, true));
360 ASSERT_EQ(0, dir_list(&ioctx, oid, "", 30, &images));
361 ASSERT_EQ(0u, images.size());
362 ASSERT_EQ(0, ioctx.remove(oid));
363
364 ASSERT_EQ(0, dir_state_set(&ioctx, oid, cls::rbd::DIRECTORY_STATE_READY));
365 ASSERT_EQ(0, dir_state_assert(&ioctx, oid, cls::rbd::DIRECTORY_STATE_READY));
366
367 ASSERT_EQ(0, dir_add_image(&ioctx, oid, imgname, valid_id));
368 ASSERT_EQ(-EBUSY, dir_state_set(&ioctx, oid,
369 cls::rbd::DIRECTORY_STATE_ADD_DISABLED));
370
371 ASSERT_EQ(-EEXIST, dir_add_image(&ioctx, oid, imgname, valid_id2));
372 ASSERT_EQ(-EBADF, dir_add_image(&ioctx, oid, imgname2, valid_id));
373 ASSERT_EQ(0, dir_list(&ioctx, oid, "", 30, &images));
374 ASSERT_EQ(1u, images.size());
375 ASSERT_EQ(valid_id, images[imgname]);
376 ASSERT_EQ(0, dir_list(&ioctx, oid, "", 0, &images));
377 ASSERT_EQ(0u, images.size());
378 ASSERT_EQ(0, dir_get_name(&ioctx, oid, valid_id, &name));
379 ASSERT_EQ(imgname, name);
380 ASSERT_EQ(0, dir_get_id(&ioctx, oid, imgname, &id));
381 ASSERT_EQ(valid_id, id);
382
383 ASSERT_EQ(0, dir_add_image(&ioctx, oid, imgname2, valid_id2));
384 ASSERT_EQ(0, dir_list(&ioctx, oid, "", 30, &images));
385 ASSERT_EQ(2u, images.size());
386 ASSERT_EQ(valid_id, images[imgname]);
387 ASSERT_EQ(valid_id2, images[imgname2]);
388 ASSERT_EQ(0, dir_list(&ioctx, oid, imgname, 0, &images));
389 ASSERT_EQ(0u, images.size());
390 ASSERT_EQ(0, dir_list(&ioctx, oid, imgname, 2, &images));
391 ASSERT_EQ(1u, images.size());
392 ASSERT_EQ(valid_id2, images[imgname2]);
393 ASSERT_EQ(0, dir_get_name(&ioctx, oid, valid_id2, &name));
394 ASSERT_EQ(imgname2, name);
395 ASSERT_EQ(0, dir_get_id(&ioctx, oid, imgname2, &id));
396 ASSERT_EQ(valid_id2, id);
397
398 librados::ObjectWriteOperation op1;
399 dir_rename_image(&op1, imgname, imgname2, valid_id2);
400 ASSERT_EQ(-ESTALE, ioctx.operate(oid, &op1));
401 ASSERT_EQ(-ESTALE, dir_remove_image(&ioctx, oid, imgname, valid_id2));
402 librados::ObjectWriteOperation op2;
403 dir_rename_image(&op2, imgname, imgname2, valid_id);
404 ASSERT_EQ(-EEXIST, ioctx.operate(oid, &op2));
405 ASSERT_EQ(0, dir_get_id(&ioctx, oid, imgname, &id));
406 ASSERT_EQ(valid_id, id);
407 ASSERT_EQ(0, dir_get_name(&ioctx, oid, valid_id2, &name));
408 ASSERT_EQ(imgname2, name);
409
410 librados::ObjectWriteOperation op3;
411 dir_rename_image(&op3, imgname, imgname3, valid_id);
412 ASSERT_EQ(0, ioctx.operate(oid, &op3));
413 ASSERT_EQ(0, dir_get_id(&ioctx, oid, imgname3, &id));
414 ASSERT_EQ(valid_id, id);
415 ASSERT_EQ(0, dir_get_name(&ioctx, oid, valid_id, &name));
416 ASSERT_EQ(imgname3, name);
417 librados::ObjectWriteOperation op4;
418 dir_rename_image(&op4, imgname3, imgname, valid_id);
419 ASSERT_EQ(0, ioctx.operate(oid, &op4));
420
421 ASSERT_EQ(0, dir_remove_image(&ioctx, oid, imgname, valid_id));
422 ASSERT_EQ(0, dir_list(&ioctx, oid, "", 30, &images));
423 ASSERT_EQ(1u, images.size());
424 ASSERT_EQ(valid_id2, images[imgname2]);
425 ASSERT_EQ(0, dir_list(&ioctx, oid, imgname2, 30, &images));
426 ASSERT_EQ(0u, images.size());
427 ASSERT_EQ(0, dir_get_name(&ioctx, oid, valid_id2, &name));
428 ASSERT_EQ(imgname2, name);
429 ASSERT_EQ(0, dir_get_id(&ioctx, oid, imgname2, &id));
430 ASSERT_EQ(valid_id2, id);
431 ASSERT_EQ(-ENOENT, dir_get_name(&ioctx, oid, valid_id, &name));
432 ASSERT_EQ(-ENOENT, dir_get_id(&ioctx, oid, imgname, &id));
433
434 ASSERT_EQ(0, dir_add_image(&ioctx, oid, imgname, valid_id));
435 ASSERT_EQ(0, dir_list(&ioctx, oid, "", 30, &images));
436 ASSERT_EQ(2u, images.size());
437 ASSERT_EQ(valid_id, images[imgname]);
438 ASSERT_EQ(valid_id2, images[imgname2]);
439 ASSERT_EQ(0, dir_remove_image(&ioctx, oid, imgname, valid_id));
440 ASSERT_EQ(-ENOENT, dir_remove_image(&ioctx, oid, imgname, valid_id));
441 ASSERT_EQ(0, dir_remove_image(&ioctx, oid, imgname2, valid_id2));
442 ASSERT_EQ(0, dir_list(&ioctx, oid, "", 30, &images));
443 ASSERT_EQ(0u, images.size());
444
445 ioctx.close();
446 }
447
448 TEST_F(TestClsRbd, create)
449 {
450 librados::IoCtx ioctx;
451 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
452
453 string oid = get_temp_image_name();
454 uint64_t size = 20ULL << 30;
455 uint64_t features = 0;
456 uint8_t order = 22;
457 string object_prefix = oid;
458
459 ASSERT_EQ(0, create_image(&ioctx, oid, size, order,
460 features, object_prefix, -1));
461 ASSERT_EQ(-EEXIST, create_image(&ioctx, oid, size, order,
462 features, object_prefix, -1));
463 ASSERT_EQ(0, ioctx.remove(oid));
464
465 ASSERT_EQ(-EINVAL, create_image(&ioctx, oid, size, order,
466 features, "", -1));
467 ASSERT_EQ(-ENOENT, ioctx.remove(oid));
468
469 ASSERT_EQ(0, create_image(&ioctx, oid, 0, order,
470 features, object_prefix, -1));
471 ASSERT_EQ(0, ioctx.remove(oid));
472
473 ASSERT_EQ(-ENOSYS, create_image(&ioctx, oid, size, order,
474 -1, object_prefix, -1));
475 ASSERT_EQ(-ENOENT, ioctx.remove(oid));
476
477 ASSERT_EQ(0, create_image(&ioctx, oid, size, order, RBD_FEATURE_DATA_POOL,
478 object_prefix, 123));
479 ASSERT_EQ(0, ioctx.remove(oid));
480 ASSERT_EQ(-EINVAL, create_image(&ioctx, oid, size, order,
481 RBD_FEATURE_OPERATIONS, object_prefix, -1));
482 ASSERT_EQ(-EINVAL, create_image(&ioctx, oid, size, order,
483 RBD_FEATURE_DATA_POOL, object_prefix, -1));
484 ASSERT_EQ(-EINVAL, create_image(&ioctx, oid, size, order, 0, object_prefix,
485 123));
486
487 bufferlist inbl, outbl;
488 ASSERT_EQ(-EINVAL, ioctx.exec(oid, "rbd", "create", inbl, outbl));
489
490 ioctx.close();
491 }
492
493 TEST_F(TestClsRbd, get_features)
494 {
495 librados::IoCtx ioctx;
496 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
497
498 string oid = get_temp_image_name();
499
500 uint64_t features;
501 uint64_t incompatible_features;
502 ASSERT_EQ(-ENOENT, get_features(&ioctx, oid, false, &features,
503 &incompatible_features));
504
505 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, 0, oid, -1));
506 ASSERT_EQ(0, get_features(&ioctx, oid, false, &features,
507 &incompatible_features));
508 ASSERT_EQ(0u, features);
509 ioctx.close();
510 }
511
512 TEST_F(TestClsRbd, get_object_prefix)
513 {
514 librados::IoCtx ioctx;
515 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
516
517 string oid = get_temp_image_name();
518
519 string object_prefix;
520 ASSERT_EQ(-ENOENT, get_object_prefix(&ioctx, oid, &object_prefix));
521
522 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, 0, oid, -1));
523 ASSERT_EQ(0, get_object_prefix(&ioctx, oid, &object_prefix));
524 ASSERT_EQ(oid, object_prefix);
525
526 ioctx.close();
527 }
528
529 TEST_F(TestClsRbd, get_create_timestamp)
530 {
531 librados::IoCtx ioctx;
532 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
533
534 string oid = get_temp_image_name();
535 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, 0, oid, -1));
536
537 utime_t timestamp;
538 ASSERT_EQ(0, get_create_timestamp(&ioctx, oid, &timestamp));
539 ASSERT_LT(0U, timestamp.tv.tv_sec);
540
541 ioctx.close();
542 }
543
544 TEST_F(TestClsRbd, get_access_timestamp)
545 {
546 librados::IoCtx ioctx;
547 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
548
549 string oid = get_temp_image_name();
550 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, 0, oid, -1));
551
552 utime_t timestamp;
553 ASSERT_EQ(0, get_access_timestamp(&ioctx, oid, &timestamp));
554 ASSERT_LT(0U, timestamp.tv.tv_sec);
555
556 ioctx.close();
557 }
558 TEST_F(TestClsRbd, get_modify_timestamp)
559 {
560 librados::IoCtx ioctx;
561 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
562
563 string oid = get_temp_image_name();
564 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, 0, oid, -1));
565
566 utime_t timestamp;
567 ASSERT_EQ(0, get_modify_timestamp(&ioctx, oid, &timestamp));
568 ASSERT_LT(0U, timestamp.tv.tv_sec);
569
570 ioctx.close();
571 }
572 TEST_F(TestClsRbd, get_data_pool)
573 {
574 librados::IoCtx ioctx;
575 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
576
577 string oid = get_temp_image_name();
578
579 int64_t data_pool_id;
580 ASSERT_EQ(0, ioctx.create(oid, true));
581 ASSERT_EQ(0, get_data_pool(&ioctx, oid, &data_pool_id));
582 ASSERT_EQ(-1, data_pool_id);
583 ASSERT_EQ(0, ioctx.remove(oid));
584
585 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, RBD_FEATURE_DATA_POOL, oid,
586 12));
587 ASSERT_EQ(0, get_data_pool(&ioctx, oid, &data_pool_id));
588 ASSERT_EQ(12, data_pool_id);
589 }
590
591 TEST_F(TestClsRbd, get_size)
592 {
593 librados::IoCtx ioctx;
594 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
595
596 string oid = get_temp_image_name();
597 uint64_t size;
598 uint8_t order;
599 ASSERT_EQ(-ENOENT, get_size(&ioctx, oid, CEPH_NOSNAP, &size, &order));
600
601 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, 0, oid, -1));
602 ASSERT_EQ(0, get_size(&ioctx, oid, CEPH_NOSNAP, &size, &order));
603 ASSERT_EQ(0u, size);
604 ASSERT_EQ(22, order);
605 ASSERT_EQ(0, ioctx.remove(oid));
606
607 ASSERT_EQ(0, create_image(&ioctx, oid, 2 << 22, 0, 0, oid, -1));
608 ASSERT_EQ(0, get_size(&ioctx, oid, CEPH_NOSNAP, &size, &order));
609 ASSERT_EQ(2u << 22, size);
610 ASSERT_EQ(0, order);
611
612 ASSERT_EQ(-ENOENT, get_size(&ioctx, oid, 1, &size, &order));
613
614 ioctx.close();
615 }
616
617 TEST_F(TestClsRbd, set_size)
618 {
619 librados::IoCtx ioctx;
620 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
621
622 string oid = get_temp_image_name();
623 ASSERT_EQ(-ENOENT, set_size(&ioctx, oid, 5));
624
625 uint64_t size;
626 uint8_t order;
627 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, 0, oid, -1));
628 ASSERT_EQ(0, get_size(&ioctx, oid, CEPH_NOSNAP, &size, &order));
629 ASSERT_EQ(0u, size);
630 ASSERT_EQ(22, order);
631
632 ASSERT_EQ(0, set_size(&ioctx, oid, 0));
633 ASSERT_EQ(0, get_size(&ioctx, oid, CEPH_NOSNAP, &size, &order));
634 ASSERT_EQ(0u, size);
635 ASSERT_EQ(22, order);
636
637 ASSERT_EQ(0, set_size(&ioctx, oid, 3 << 22));
638 ASSERT_EQ(0, get_size(&ioctx, oid, CEPH_NOSNAP, &size, &order));
639 ASSERT_EQ(3u << 22, size);
640 ASSERT_EQ(22, order);
641
642 ioctx.close();
643 }
644
645 TEST_F(TestClsRbd, protection_status)
646 {
647 librados::IoCtx ioctx;
648 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
649
650 string oid = get_temp_image_name();
651 string oid2 = get_temp_image_name();
652 uint8_t status = RBD_PROTECTION_STATUS_UNPROTECTED;
653 ASSERT_EQ(-ENOENT, get_protection_status(&ioctx, oid,
654 CEPH_NOSNAP, &status));
655 ASSERT_EQ(-ENOENT, set_protection_status(&ioctx, oid,
656 CEPH_NOSNAP, status));
657
658 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, RBD_FEATURE_LAYERING, oid, -1));
659 ASSERT_EQ(0, create_image(&ioctx, oid2, 0, 22, 0, oid, -1));
660 ASSERT_EQ(-EINVAL, get_protection_status(&ioctx, oid2,
661 CEPH_NOSNAP, &status));
662 ASSERT_EQ(-ENOEXEC, set_protection_status(&ioctx, oid2,
663 CEPH_NOSNAP, status));
664 ASSERT_EQ(-EINVAL, get_protection_status(&ioctx, oid,
665 CEPH_NOSNAP, &status));
666 ASSERT_EQ(-EINVAL, set_protection_status(&ioctx, oid,
667 CEPH_NOSNAP, status));
668 ASSERT_EQ(-ENOENT, get_protection_status(&ioctx, oid,
669 2, &status));
670 ASSERT_EQ(-ENOENT, set_protection_status(&ioctx, oid,
671 2, status));
672
673 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 10, "snap1"));
674 ASSERT_EQ(0, get_protection_status(&ioctx, oid,
675 10, &status));
676 ASSERT_EQ(+RBD_PROTECTION_STATUS_UNPROTECTED, status);
677
678 ASSERT_EQ(0, set_protection_status(&ioctx, oid,
679 10, RBD_PROTECTION_STATUS_PROTECTED));
680 ASSERT_EQ(0, get_protection_status(&ioctx, oid,
681 10, &status));
682 ASSERT_EQ(+RBD_PROTECTION_STATUS_PROTECTED, status);
683 ASSERT_EQ(-EBUSY, snapshot_remove(&ioctx, oid, 10));
684
685 ASSERT_EQ(0, set_protection_status(&ioctx, oid,
686 10, RBD_PROTECTION_STATUS_UNPROTECTING));
687 ASSERT_EQ(0, get_protection_status(&ioctx, oid,
688 10, &status));
689 ASSERT_EQ(+RBD_PROTECTION_STATUS_UNPROTECTING, status);
690 ASSERT_EQ(-EBUSY, snapshot_remove(&ioctx, oid, 10));
691
692 ASSERT_EQ(-EINVAL, set_protection_status(&ioctx, oid,
693 10, RBD_PROTECTION_STATUS_LAST));
694 ASSERT_EQ(0, get_protection_status(&ioctx, oid,
695 10, &status));
696 ASSERT_EQ(+RBD_PROTECTION_STATUS_UNPROTECTING, status);
697
698 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 20, "snap2"));
699 ASSERT_EQ(0, get_protection_status(&ioctx, oid,
700 20, &status));
701 ASSERT_EQ(+RBD_PROTECTION_STATUS_UNPROTECTED, status);
702 ASSERT_EQ(0, set_protection_status(&ioctx, oid,
703 10, RBD_PROTECTION_STATUS_UNPROTECTED));
704 ASSERT_EQ(0, get_protection_status(&ioctx, oid,
705 10, &status));
706 ASSERT_EQ(+RBD_PROTECTION_STATUS_UNPROTECTED, status);
707
708 ASSERT_EQ(0, snapshot_remove(&ioctx, oid, 10));
709 ASSERT_EQ(0, snapshot_remove(&ioctx, oid, 20));
710
711 ioctx.close();
712 }
713
714 TEST_F(TestClsRbd, snapshot_limits)
715 {
716 librados::IoCtx ioctx;
717 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
718
719 librados::ObjectWriteOperation op;
720 string oid = get_temp_image_name();
721 uint64_t limit;
722
723 ASSERT_EQ(-ENOENT, snapshot_get_limit(&ioctx, oid, &limit));
724
725 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, RBD_FEATURE_LAYERING, oid, -1));
726
727 // if snapshot doesn't set limit, the limit is UINT64_MAX
728 ASSERT_EQ(0, snapshot_get_limit(&ioctx, oid, &limit));
729 ASSERT_EQ(UINT64_MAX, limit);
730
731 snapshot_set_limit(&op, 2);
732
733 ASSERT_EQ(0, ioctx.operate(oid, &op));
734
735 ASSERT_EQ(0, snapshot_get_limit(&ioctx, oid, &limit));
736 ASSERT_EQ(2U, limit);
737
738 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 10, "snap1"));
739 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 20, "snap2"));
740 ASSERT_EQ(-EDQUOT, snapshot_add(&ioctx, oid, 30, "snap3"));
741
742 ASSERT_EQ(0, snapshot_remove(&ioctx, oid, 10));
743 ASSERT_EQ(0, snapshot_remove(&ioctx, oid, 20));
744
745 ioctx.close();
746 }
747
748 TEST_F(TestClsRbd, parents_v1)
749 {
750 librados::IoCtx ioctx;
751 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
752
753 cls::rbd::ParentImageSpec pspec;
754 uint64_t size;
755
756 ASSERT_EQ(-ENOENT, get_parent(&ioctx, "doesnotexist", CEPH_NOSNAP, &pspec, &size));
757
758 // old image should fail
759 std::string oid = get_temp_image_name();
760 ASSERT_EQ(0, create_image(&ioctx, oid, 33<<20, 22, 0, "old_blk.", -1));
761 // get nonexistent parent: succeed, return (-1, "", CEPH_NOSNAP), overlap 0
762 ASSERT_EQ(0, get_parent(&ioctx, oid, CEPH_NOSNAP, &pspec, &size));
763 ASSERT_EQ(pspec.pool_id, -1);
764 ASSERT_STREQ("", pspec.image_id.c_str());
765 ASSERT_EQ(pspec.snap_id, CEPH_NOSNAP);
766 ASSERT_EQ(size, 0ULL);
767 pspec = {-1, "", "parent", 3};
768 ASSERT_EQ(-ENOEXEC, set_parent(&ioctx, oid, {-1, "", "parent", 3}, 10<<20));
769 ASSERT_EQ(-ENOEXEC, remove_parent(&ioctx, oid));
770
771 // new image will work
772 oid = get_temp_image_name();
773 ASSERT_EQ(0, create_image(&ioctx, oid, 33<<20, 22, RBD_FEATURE_LAYERING,
774 "foo.", -1));
775
776 ASSERT_EQ(0, get_parent(&ioctx, oid, CEPH_NOSNAP, &pspec, &size));
777 ASSERT_EQ(-1, pspec.pool_id);
778 ASSERT_EQ(0, get_parent(&ioctx, oid, 123, &pspec, &size));
779 ASSERT_EQ(-1, pspec.pool_id);
780
781 ASSERT_EQ(-EINVAL, set_parent(&ioctx, oid, {-1, "", "parent", 3}, 10<<20));
782 ASSERT_EQ(-EINVAL, set_parent(&ioctx, oid, {1, "", "", 3}, 10<<20));
783 ASSERT_EQ(-EINVAL, set_parent(&ioctx, oid, {1, "", "parent", CEPH_NOSNAP}, 10<<20));
784 ASSERT_EQ(-EINVAL, set_parent(&ioctx, oid, {1, "", "parent", 3}, 0));
785
786 pspec = {1, "", "parent", 3};
787 ASSERT_EQ(0, set_parent(&ioctx, oid, pspec, 10<<20));
788 ASSERT_EQ(-EEXIST, set_parent(&ioctx, oid, pspec, 10<<20));
789 ASSERT_EQ(-EEXIST, set_parent(&ioctx, oid, {2, "", "parent", 34}, 10<<20));
790
791 ASSERT_EQ(0, get_parent(&ioctx, oid, CEPH_NOSNAP, &pspec, &size));
792 ASSERT_EQ(pspec.pool_id, 1);
793 ASSERT_EQ(pspec.image_id, "parent");
794 ASSERT_EQ(pspec.snap_id, snapid_t(3));
795
796 ASSERT_EQ(0, remove_parent(&ioctx, oid));
797 ASSERT_EQ(-ENOENT, remove_parent(&ioctx, oid));
798 ASSERT_EQ(0, get_parent(&ioctx, oid, CEPH_NOSNAP, &pspec, &size));
799 ASSERT_EQ(-1, pspec.pool_id);
800
801 // snapshots
802 ASSERT_EQ(0, set_parent(&ioctx, oid, {1, "", "parent", 3}, 10<<20));
803 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 10, "snap1"));
804 ASSERT_EQ(0, get_parent(&ioctx, oid, 10, &pspec, &size));
805 ASSERT_EQ(pspec.pool_id, 1);
806 ASSERT_EQ(pspec.image_id, "parent");
807 ASSERT_EQ(pspec.snap_id, snapid_t(3));
808 ASSERT_EQ(size, 10ull<<20);
809
810 ASSERT_EQ(0, remove_parent(&ioctx, oid));
811 ASSERT_EQ(0, set_parent(&ioctx, oid, {1, "", "parent", 3}, 5<<20));
812 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 11, "snap2"));
813 ASSERT_EQ(0, get_parent(&ioctx, oid, 10, &pspec, &size));
814 ASSERT_EQ(pspec.pool_id, 1);
815 ASSERT_EQ(pspec.image_id, "parent");
816 ASSERT_EQ(pspec.snap_id, snapid_t(3));
817 ASSERT_EQ(size, 10ull<<20);
818 ASSERT_EQ(0, get_parent(&ioctx, oid, 11, &pspec, &size));
819 ASSERT_EQ(pspec.pool_id, 1);
820 ASSERT_EQ(pspec.image_id, "parent");
821 ASSERT_EQ(pspec.snap_id, snapid_t(3));
822 ASSERT_EQ(size, 5ull<<20);
823
824 ASSERT_EQ(0, remove_parent(&ioctx, oid));
825 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 12, "snap3"));
826 ASSERT_EQ(0, get_parent(&ioctx, oid, 10, &pspec, &size));
827 ASSERT_EQ(pspec.pool_id, 1);
828 ASSERT_EQ(pspec.image_id, "parent");
829 ASSERT_EQ(pspec.snap_id, snapid_t(3));
830 ASSERT_EQ(size, 10ull<<20);
831 ASSERT_EQ(0, get_parent(&ioctx, oid, 11, &pspec, &size));
832 ASSERT_EQ(pspec.pool_id, 1);
833 ASSERT_EQ(pspec.image_id, "parent");
834 ASSERT_EQ(pspec.snap_id, snapid_t(3));
835 ASSERT_EQ(size, 5ull<<20);
836 ASSERT_EQ(0, get_parent(&ioctx, oid, 12, &pspec, &size));
837 ASSERT_EQ(-1, pspec.pool_id);
838
839 // make sure set_parent takes min of our size and parent's size
840 ASSERT_EQ(0, set_parent(&ioctx, oid, {1, "", "parent", 3}, 1<<20));
841 ASSERT_EQ(0, get_parent(&ioctx, oid, CEPH_NOSNAP, &pspec, &size));
842 ASSERT_EQ(pspec.pool_id, 1);
843 ASSERT_EQ(pspec.image_id, "parent");
844 ASSERT_EQ(pspec.snap_id, snapid_t(3));
845 ASSERT_EQ(size, 1ull<<20);
846 ASSERT_EQ(0, remove_parent(&ioctx, oid));
847
848 ASSERT_EQ(0, set_parent(&ioctx, oid, {1, "", "parent", 3}, 100<<20));
849 ASSERT_EQ(0, get_parent(&ioctx, oid, CEPH_NOSNAP, &pspec, &size));
850 ASSERT_EQ(pspec.pool_id, 1);
851 ASSERT_EQ(pspec.image_id, "parent");
852 ASSERT_EQ(pspec.snap_id, snapid_t(3));
853 ASSERT_EQ(size, 33ull<<20);
854 ASSERT_EQ(0, remove_parent(&ioctx, oid));
855
856 // make sure resize adjust parent overlap
857 ASSERT_EQ(0, set_parent(&ioctx, oid, {1, "", "parent", 3}, 10<<20));
858
859 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 14, "snap4"));
860 ASSERT_EQ(0, set_size(&ioctx, oid, 3 << 20));
861 ASSERT_EQ(0, get_parent(&ioctx, oid, CEPH_NOSNAP, &pspec, &size));
862 ASSERT_EQ(pspec.pool_id, 1);
863 ASSERT_EQ(pspec.image_id, "parent");
864 ASSERT_EQ(pspec.snap_id, snapid_t(3));
865 ASSERT_EQ(size, 3ull<<20);
866 ASSERT_EQ(0, get_parent(&ioctx, oid, 14, &pspec, &size));
867 ASSERT_EQ(pspec.pool_id, 1);
868 ASSERT_EQ(pspec.image_id, "parent");
869 ASSERT_EQ(pspec.snap_id, snapid_t(3));
870 ASSERT_EQ(size, 10ull<<20);
871
872 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 15, "snap5"));
873 ASSERT_EQ(0, set_size(&ioctx, oid, 30 << 20));
874 ASSERT_EQ(0, get_parent(&ioctx, oid, CEPH_NOSNAP, &pspec, &size));
875 ASSERT_EQ(pspec.pool_id, 1);
876 ASSERT_EQ(pspec.image_id, "parent");
877 ASSERT_EQ(pspec.snap_id, snapid_t(3));
878 ASSERT_EQ(size, 3ull<<20);
879 ASSERT_EQ(0, get_parent(&ioctx, oid, 14, &pspec, &size));
880 ASSERT_EQ(pspec.pool_id, 1);
881 ASSERT_EQ(pspec.image_id, "parent");
882 ASSERT_EQ(pspec.snap_id, snapid_t(3));
883 ASSERT_EQ(size, 10ull<<20);
884 ASSERT_EQ(0, get_parent(&ioctx, oid, 15, &pspec, &size));
885 ASSERT_EQ(pspec.pool_id, 1);
886 ASSERT_EQ(pspec.image_id, "parent");
887 ASSERT_EQ(pspec.snap_id, snapid_t(3));
888 ASSERT_EQ(size, 3ull<<20);
889
890 ASSERT_EQ(0, set_size(&ioctx, oid, 2 << 20));
891 ASSERT_EQ(0, get_parent(&ioctx, oid, CEPH_NOSNAP, &pspec, &size));
892 ASSERT_EQ(pspec.pool_id, 1);
893 ASSERT_EQ(pspec.image_id, "parent");
894 ASSERT_EQ(pspec.snap_id, snapid_t(3));
895 ASSERT_EQ(size, 2ull<<20);
896
897 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 16, "snap6"));
898 ASSERT_EQ(0, get_parent(&ioctx, oid, 16, &pspec, &size));
899 ASSERT_EQ(pspec.pool_id, 1);
900 ASSERT_EQ(pspec.image_id, "parent");
901 ASSERT_EQ(pspec.snap_id, snapid_t(3));
902 ASSERT_EQ(size, 2ull<<20);
903
904 ASSERT_EQ(0, ioctx.remove(oid));
905 ASSERT_EQ(0, create_image(&ioctx, oid, 33<<20, 22,
906 RBD_FEATURE_LAYERING | RBD_FEATURE_DEEP_FLATTEN,
907 "foo.", -1));
908 ASSERT_EQ(0, set_parent(&ioctx, oid, {1, "", "parent", 3}, 100<<20));
909 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 1, "snap1"));
910 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 2, "snap2"));
911 ASSERT_EQ(0, remove_parent(&ioctx, oid));
912
913 ASSERT_EQ(0, get_parent(&ioctx, oid, 1, &pspec, &size));
914 ASSERT_EQ(-1, pspec.pool_id);
915 ASSERT_EQ(0, get_parent(&ioctx, oid, 2, &pspec, &size));
916 ASSERT_EQ(-1, pspec.pool_id);
917 ASSERT_EQ(0, get_parent(&ioctx, oid, CEPH_NOSNAP, &pspec, &size));
918 ASSERT_EQ(-1, pspec.pool_id);
919
920 ioctx.close();
921 }
922
923 TEST_F(TestClsRbd, parents_v2)
924 {
925 librados::IoCtx ioctx;
926 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
927
928 std::string oid = get_temp_image_name();
929 cls::rbd::ParentImageSpec parent_image_spec;
930 std::optional<uint64_t> parent_overlap;
931
932 ASSERT_EQ(-ENOENT, parent_get(&ioctx, oid, &parent_image_spec));
933 ASSERT_EQ(-ENOENT, parent_overlap_get(&ioctx, oid, CEPH_NOSNAP,
934 &parent_overlap));
935 ASSERT_EQ(-ENOENT, parent_attach(&ioctx, oid, parent_image_spec, 0ULL,
936 false));
937 ASSERT_EQ(-ENOENT, parent_detach(&ioctx, oid));
938
939 // no layering support should fail
940 oid = get_temp_image_name();
941 ASSERT_EQ(0, create_image(&ioctx, oid, 33<<20, 22, 0, "old_blk.", -1));
942 ASSERT_EQ(0, parent_get(&ioctx, oid, &parent_image_spec));
943 ASSERT_FALSE(parent_image_spec.exists());
944 ASSERT_EQ(0, parent_overlap_get(&ioctx, oid, CEPH_NOSNAP, &parent_overlap));
945 ASSERT_EQ(std::nullopt, parent_overlap);
946 ASSERT_EQ(-ENOEXEC, parent_attach(&ioctx, oid, parent_image_spec, 0ULL, false));
947 ASSERT_EQ(-ENOEXEC, parent_detach(&ioctx, oid));
948
949 // layering support available -- no pool namespaces
950 oid = get_temp_image_name();
951 ASSERT_EQ(0, create_image(&ioctx, oid, 33<<20, 22, RBD_FEATURE_LAYERING,
952 "foo.", -1));
953
954 ASSERT_EQ(0, parent_get(&ioctx, oid, &parent_image_spec));
955 ASSERT_FALSE(parent_image_spec.exists());
956 ASSERT_EQ(0, parent_overlap_get(&ioctx, oid, CEPH_NOSNAP, &parent_overlap));
957 ASSERT_EQ(std::nullopt, parent_overlap);
958 ASSERT_EQ(-EINVAL, parent_attach(&ioctx, oid, parent_image_spec, 0ULL, false));
959 ASSERT_EQ(-ENOENT, parent_detach(&ioctx, oid));
960
961 parent_image_spec = {1, "", "parent", 2};
962 parent_overlap = (33 << 20) + 1;
963 ASSERT_EQ(0, parent_attach(&ioctx, oid, parent_image_spec, *parent_overlap,
964 false));
965 ASSERT_EQ(-EEXIST, parent_attach(&ioctx, oid, parent_image_spec,
966 *parent_overlap, false));
967 ASSERT_EQ(0, parent_attach(&ioctx, oid, parent_image_spec, *parent_overlap,
968 true));
969 --(*parent_overlap);
970
971 cls::rbd::ParentImageSpec on_disk_parent_image_spec;
972 std::optional<uint64_t> on_disk_parent_overlap;
973 ASSERT_EQ(0, parent_get(&ioctx, oid, &on_disk_parent_image_spec));
974 ASSERT_EQ(parent_image_spec, on_disk_parent_image_spec);
975 ASSERT_EQ(0, parent_overlap_get(&ioctx, oid, CEPH_NOSNAP,
976 &on_disk_parent_overlap));
977 ASSERT_EQ(parent_overlap, on_disk_parent_overlap);
978
979 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 10, "snap1"));
980 ASSERT_EQ(0, parent_overlap_get(&ioctx, oid, 10, &on_disk_parent_overlap));
981 std::optional<uint64_t> snap_1_parent_overlap = parent_overlap;
982 ASSERT_EQ(snap_1_parent_overlap, on_disk_parent_overlap);
983
984 parent_overlap = (32 << 20);
985 ASSERT_EQ(0, set_size(&ioctx, oid, *parent_overlap));
986 ASSERT_EQ(0, parent_overlap_get(&ioctx, oid, CEPH_NOSNAP,
987 &on_disk_parent_overlap));
988 ASSERT_EQ(parent_overlap, on_disk_parent_overlap);
989
990 ASSERT_EQ(0, parent_overlap_get(&ioctx, oid, 10, &on_disk_parent_overlap));
991 ASSERT_EQ(snap_1_parent_overlap, on_disk_parent_overlap);
992
993 ASSERT_EQ(0, parent_detach(&ioctx, oid));
994 ASSERT_EQ(-ENOENT, parent_detach(&ioctx, oid));
995
996 ASSERT_EQ(0, parent_get(&ioctx, oid, &on_disk_parent_image_spec));
997 ASSERT_EQ(parent_image_spec, on_disk_parent_image_spec);
998 ASSERT_EQ(0, parent_overlap_get(&ioctx, oid, CEPH_NOSNAP,
999 &on_disk_parent_overlap));
1000 ASSERT_EQ(std::nullopt, on_disk_parent_overlap);
1001
1002 ASSERT_EQ(0, snapshot_remove(&ioctx, oid, 10));
1003 ASSERT_EQ(0, parent_get(&ioctx, oid, &on_disk_parent_image_spec));
1004 ASSERT_FALSE(on_disk_parent_image_spec.exists());
1005
1006 // clone across pool namespaces
1007 parent_image_spec.pool_namespace = "ns";
1008 parent_overlap = 31 << 20;
1009 ASSERT_EQ(0, parent_attach(&ioctx, oid, parent_image_spec, *parent_overlap,
1010 false));
1011 ASSERT_EQ(-EEXIST, parent_attach(&ioctx, oid, parent_image_spec,
1012 *parent_overlap, false));
1013 ASSERT_EQ(0, parent_attach(&ioctx, oid, parent_image_spec, *parent_overlap,
1014 true));
1015
1016 ASSERT_EQ(0, parent_get(&ioctx, oid, &on_disk_parent_image_spec));
1017 ASSERT_EQ(parent_image_spec, on_disk_parent_image_spec);
1018 ASSERT_EQ(0, parent_overlap_get(&ioctx, oid, CEPH_NOSNAP,
1019 &on_disk_parent_overlap));
1020 ASSERT_EQ(parent_overlap, on_disk_parent_overlap);
1021
1022 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 10, "snap1"));
1023 ASSERT_EQ(0, parent_overlap_get(&ioctx, oid, 10, &on_disk_parent_overlap));
1024 snap_1_parent_overlap = parent_overlap;
1025 ASSERT_EQ(snap_1_parent_overlap, on_disk_parent_overlap);
1026
1027 parent_overlap = (30 << 20);
1028 ASSERT_EQ(0, set_size(&ioctx, oid, *parent_overlap));
1029 ASSERT_EQ(0, parent_overlap_get(&ioctx, oid, CEPH_NOSNAP,
1030 &on_disk_parent_overlap));
1031 ASSERT_EQ(parent_overlap, on_disk_parent_overlap);
1032
1033 ASSERT_EQ(0, parent_overlap_get(&ioctx, oid, 10, &on_disk_parent_overlap));
1034 ASSERT_EQ(snap_1_parent_overlap, on_disk_parent_overlap);
1035
1036 ASSERT_EQ(-EXDEV, remove_parent(&ioctx, oid));
1037 ASSERT_EQ(0, parent_detach(&ioctx, oid));
1038 ASSERT_EQ(-ENOENT, parent_detach(&ioctx, oid));
1039
1040 cls::rbd::ParentImageSpec on_disk_parent_spec;
1041 uint64_t legacy_parent_overlap;
1042 ASSERT_EQ(-EXDEV, get_parent(&ioctx, oid, CEPH_NOSNAP, &on_disk_parent_spec,
1043 &legacy_parent_overlap));
1044 ASSERT_EQ(-EXDEV, get_parent(&ioctx, oid, 10, &on_disk_parent_spec,
1045 &legacy_parent_overlap));
1046
1047 ASSERT_EQ(0, parent_get(&ioctx, oid, &on_disk_parent_image_spec));
1048 ASSERT_EQ(parent_image_spec, on_disk_parent_image_spec);
1049 ASSERT_EQ(0, parent_overlap_get(&ioctx, oid, CEPH_NOSNAP,
1050 &on_disk_parent_overlap));
1051 ASSERT_EQ(std::nullopt, on_disk_parent_overlap);
1052
1053 ASSERT_EQ(0, snapshot_remove(&ioctx, oid, 10));
1054 ASSERT_EQ(0, parent_get(&ioctx, oid, &on_disk_parent_image_spec));
1055 ASSERT_FALSE(on_disk_parent_image_spec.exists());
1056 }
1057
1058 TEST_F(TestClsRbd, snapshots)
1059 {
1060 cls::rbd::SnapshotNamespace userSnapNamespace = cls::rbd::UserSnapshotNamespace();
1061 librados::IoCtx ioctx;
1062 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
1063
1064 string oid = get_temp_image_name();
1065 ASSERT_EQ(-ENOENT, snapshot_add(&ioctx, oid, 0, "snap1"));
1066
1067 ASSERT_EQ(0, create_image(&ioctx, oid, 10, 22, 0, oid, -1));
1068
1069 SnapContext snapc;
1070 cls::rbd::SnapshotInfo snap;
1071 std::string snap_name;
1072 uint64_t snap_size;
1073 uint8_t snap_order;
1074 ParentImageInfo parent;
1075 uint8_t protection_status;
1076 utime_t snap_timestamp;
1077
1078 ASSERT_EQ(0, get_snapcontext(&ioctx, oid, &snapc));
1079 ASSERT_EQ(0u, snapc.snaps.size());
1080 ASSERT_EQ(0u, snapc.seq);
1081
1082 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 0, "snap1"));
1083 ASSERT_EQ(0, get_snapcontext(&ioctx, oid, &snapc));
1084 ASSERT_EQ(1u, snapc.snaps.size());
1085 ASSERT_EQ(0u, snapc.snaps[0]);
1086 ASSERT_EQ(0u, snapc.seq);
1087
1088 ASSERT_EQ(0, snapshot_get(&ioctx, oid, 0, &snap));
1089 ASSERT_EQ("snap1", snap.name);
1090 ASSERT_EQ(userSnapNamespace, snap.snapshot_namespace);
1091 ASSERT_EQ(0, get_snapshot_name(&ioctx, oid, 0, &snap_name));
1092 ASSERT_EQ("snap1", snap_name);
1093 ASSERT_EQ(0, get_size(&ioctx, oid, 0, &snap_size, &snap_order));
1094 ASSERT_EQ(10U, snap_size);
1095 ASSERT_EQ(0, get_parent(&ioctx, oid, 0, &parent.spec, &parent.overlap));
1096 ASSERT_EQ(0, get_protection_status(&ioctx, oid, 0, &protection_status));
1097 ASSERT_EQ(0, get_snapshot_timestamp(&ioctx, oid, 0, &snap_timestamp));
1098
1099 // snap with same id and name
1100 ASSERT_EQ(-EEXIST, snapshot_add(&ioctx, oid, 0, "snap1"));
1101 ASSERT_EQ(0, get_snapcontext(&ioctx, oid, &snapc));
1102 ASSERT_EQ(1u, snapc.snaps.size());
1103 ASSERT_EQ(0u, snapc.snaps[0]);
1104 ASSERT_EQ(0u, snapc.seq);
1105
1106 // snap with same id, different name
1107 ASSERT_EQ(-EEXIST, snapshot_add(&ioctx, oid, 0, "snap2"));
1108 ASSERT_EQ(0, get_snapcontext(&ioctx, oid, &snapc));
1109 ASSERT_EQ(1u, snapc.snaps.size());
1110 ASSERT_EQ(0u, snapc.snaps[0]);
1111 ASSERT_EQ(0u, snapc.seq);
1112
1113 // snap with different id, same name
1114 ASSERT_EQ(-EEXIST, snapshot_add(&ioctx, oid, 1, "snap1"));
1115 ASSERT_EQ(0, get_snapcontext(&ioctx, oid, &snapc));
1116 ASSERT_EQ(1u, snapc.snaps.size());
1117 ASSERT_EQ(0u, snapc.snaps[0]);
1118 ASSERT_EQ(0u, snapc.seq);
1119
1120 // snap with different id, different name
1121 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 1, "snap2"));
1122 ASSERT_EQ(0, get_snapcontext(&ioctx, oid, &snapc));
1123 ASSERT_EQ(2u, snapc.snaps.size());
1124 ASSERT_EQ(1u, snapc.snaps[0]);
1125 ASSERT_EQ(0u, snapc.snaps[1]);
1126 ASSERT_EQ(1u, snapc.seq);
1127
1128 // snap id less than current snap seq
1129 ASSERT_EQ(-ESTALE, snapshot_add(&ioctx, oid, 0, "snap3"));
1130
1131 ASSERT_EQ(0, snapshot_get(&ioctx, oid, 1, &snap));
1132 ASSERT_EQ("snap2", snap.name);
1133 ASSERT_EQ(userSnapNamespace, snap.snapshot_namespace);
1134 ASSERT_EQ(0, get_snapshot_name(&ioctx, oid, 1, &snap_name));
1135 ASSERT_EQ("snap2", snap_name);
1136 ASSERT_EQ(0, get_size(&ioctx, oid, 1, &snap_size, &snap_order));
1137 ASSERT_EQ(10U, snap_size);
1138 ASSERT_EQ(0, get_parent(&ioctx, oid, 1, &parent.spec, &parent.overlap));
1139 ASSERT_EQ(0, get_protection_status(&ioctx, oid, 1, &protection_status));
1140 ASSERT_EQ(0, get_snapshot_timestamp(&ioctx, oid, 1, &snap_timestamp));
1141
1142 ASSERT_EQ(0, snapshot_rename(&ioctx, oid, 0, "snap1-rename"));
1143 ASSERT_EQ(0, snapshot_get(&ioctx, oid, 0, &snap));
1144 ASSERT_EQ("snap1-rename", snap.name);
1145 ASSERT_EQ(0, get_snapshot_name(&ioctx, oid, 0, &snap_name));
1146 ASSERT_EQ("snap1-rename", snap_name);
1147
1148 ASSERT_EQ(0, snapshot_remove(&ioctx, oid, 0));
1149 ASSERT_EQ(0, get_snapcontext(&ioctx, oid, &snapc));
1150 ASSERT_EQ(1u, snapc.snaps.size());
1151 ASSERT_EQ(1u, snapc.snaps[0]);
1152 ASSERT_EQ(1u, snapc.seq);
1153
1154 uint64_t size;
1155 uint8_t order;
1156 ASSERT_EQ(0, set_size(&ioctx, oid, 0));
1157 ASSERT_EQ(0, get_size(&ioctx, oid, CEPH_NOSNAP, &size, &order));
1158 ASSERT_EQ(0u, size);
1159 ASSERT_EQ(22u, order);
1160
1161 uint64_t large_snap_id = 1ull << 63;
1162 ASSERT_EQ(0, snapshot_add(&ioctx, oid, large_snap_id, "snap3"));
1163 ASSERT_EQ(0, get_snapcontext(&ioctx, oid, &snapc));
1164 ASSERT_EQ(2u, snapc.snaps.size());
1165 ASSERT_EQ(large_snap_id, snapc.snaps[0]);
1166 ASSERT_EQ(1u, snapc.snaps[1]);
1167 ASSERT_EQ(large_snap_id, snapc.seq);
1168
1169 ASSERT_EQ(0, snapshot_get(&ioctx, oid, large_snap_id, &snap));
1170 ASSERT_EQ("snap3", snap.name);
1171 ASSERT_EQ(0, get_snapshot_name(&ioctx, oid, large_snap_id, &snap_name));
1172 ASSERT_EQ("snap3", snap_name);
1173 ASSERT_EQ(0, get_size(&ioctx, oid, large_snap_id, &snap_size, &snap_order));
1174 ASSERT_EQ(0U, snap_size);
1175 ASSERT_EQ(22u, snap_order);
1176
1177 ASSERT_EQ(0, get_size(&ioctx, oid, 1, &snap_size, &snap_order));
1178 ASSERT_EQ(10u, snap_size);
1179 ASSERT_EQ(22u, snap_order);
1180
1181 ASSERT_EQ(0, snapshot_remove(&ioctx, oid, large_snap_id));
1182 ASSERT_EQ(0, get_snapcontext(&ioctx, oid, &snapc));
1183 ASSERT_EQ(1u, snapc.snaps.size());
1184 ASSERT_EQ(1u, snapc.snaps[0]);
1185 ASSERT_EQ(large_snap_id, snapc.seq);
1186
1187 ASSERT_EQ(-ENOENT, snapshot_remove(&ioctx, oid, large_snap_id));
1188 ASSERT_EQ(0, snapshot_remove(&ioctx, oid, 1));
1189 ASSERT_EQ(0, get_snapcontext(&ioctx, oid, &snapc));
1190 ASSERT_EQ(0u, snapc.snaps.size());
1191 ASSERT_EQ(large_snap_id, snapc.seq);
1192 ioctx.close();
1193 }
1194
1195 TEST_F(TestClsRbd, snapid_race)
1196 {
1197 librados::IoCtx ioctx;
1198 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
1199
1200 buffer::list bl;
1201 buffer::ptr bp(4096);
1202 bp.zero();
1203 bl.append(bp);
1204
1205 string oid = get_temp_image_name();
1206 ASSERT_EQ(0, ioctx.write(oid, bl, 4096, 0));
1207 ASSERT_EQ(0, old_snapshot_add(&ioctx, oid, 1, "test1"));
1208 ASSERT_EQ(0, old_snapshot_add(&ioctx, oid, 3, "test3"));
1209 ASSERT_EQ(-ESTALE, old_snapshot_add(&ioctx, oid, 2, "test2"));
1210
1211 ioctx.close();
1212 }
1213
1214 TEST_F(TestClsRbd, stripingv2)
1215 {
1216 librados::IoCtx ioctx;
1217 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
1218
1219 string oid = get_temp_image_name();
1220 string oid2 = get_temp_image_name();
1221 ASSERT_EQ(0, create_image(&ioctx, oid, 10, 22, 0, oid, -1));
1222
1223 uint64_t su = 65536, sc = 12;
1224 ASSERT_EQ(-ENOEXEC, get_stripe_unit_count(&ioctx, oid, &su, &sc));
1225 ASSERT_EQ(-ENOEXEC, set_stripe_unit_count(&ioctx, oid, su, sc));
1226
1227 ASSERT_EQ(0, create_image(&ioctx, oid2, 10, 22, RBD_FEATURE_STRIPINGV2,
1228 oid2, -1));
1229 ASSERT_EQ(0, get_stripe_unit_count(&ioctx, oid2, &su, &sc));
1230 ASSERT_EQ(1ull << 22, su);
1231 ASSERT_EQ(1ull, sc);
1232 su = 8192;
1233 sc = 456;
1234 ASSERT_EQ(0, set_stripe_unit_count(&ioctx, oid2, su, sc));
1235 su = sc = 0;
1236 ASSERT_EQ(0, get_stripe_unit_count(&ioctx, oid2, &su, &sc));
1237 ASSERT_EQ(8192ull, su);
1238 ASSERT_EQ(456ull, sc);
1239
1240 // su must not be larger than an object
1241 ASSERT_EQ(-EINVAL, set_stripe_unit_count(&ioctx, oid2, 1 << 23, 1));
1242 // su must be a factor of object size
1243 ASSERT_EQ(-EINVAL, set_stripe_unit_count(&ioctx, oid2, 511, 1));
1244 // su and sc must be non-zero
1245 ASSERT_EQ(-EINVAL, set_stripe_unit_count(&ioctx, oid2, 0, 1));
1246 ASSERT_EQ(-EINVAL, set_stripe_unit_count(&ioctx, oid2, 1, 0));
1247 ASSERT_EQ(-EINVAL, set_stripe_unit_count(&ioctx, oid2, 0, 0));
1248
1249 ioctx.close();
1250 }
1251
1252 TEST_F(TestClsRbd, object_map_save)
1253 {
1254 librados::IoCtx ioctx;
1255 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
1256
1257 string oid = get_temp_image_name();
1258 BitVector<2> ref_bit_vector;
1259 ref_bit_vector.resize(32);
1260 for (uint64_t i = 0; i < ref_bit_vector.size(); ++i) {
1261 ref_bit_vector[i] = 1;
1262 }
1263
1264 librados::ObjectWriteOperation op;
1265 object_map_save(&op, ref_bit_vector);
1266 ASSERT_EQ(0, ioctx.operate(oid, &op));
1267
1268 BitVector<2> osd_bit_vector;
1269 ASSERT_EQ(0, object_map_load(&ioctx, oid, &osd_bit_vector));
1270 ASSERT_EQ(ref_bit_vector, osd_bit_vector);
1271 }
1272
1273 TEST_F(TestClsRbd, object_map_resize)
1274 {
1275 librados::IoCtx ioctx;
1276 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
1277
1278 string oid = get_temp_image_name();
1279 BitVector<2> ref_bit_vector;
1280 ref_bit_vector.resize(32);
1281 for (uint64_t i = 0; i < ref_bit_vector.size(); ++i) {
1282 ref_bit_vector[i] = 1;
1283 }
1284
1285 librados::ObjectWriteOperation op1;
1286 object_map_resize(&op1, ref_bit_vector.size(), 1);
1287 ASSERT_EQ(0, ioctx.operate(oid, &op1));
1288
1289 BitVector<2> osd_bit_vector;
1290 ASSERT_EQ(0, object_map_load(&ioctx, oid, &osd_bit_vector));
1291 ASSERT_EQ(ref_bit_vector, osd_bit_vector);
1292
1293 ref_bit_vector.resize(64);
1294 for (uint64_t i = 32; i < ref_bit_vector.size(); ++i) {
1295 ref_bit_vector[i] = 2;
1296 }
1297
1298 librados::ObjectWriteOperation op2;
1299 object_map_resize(&op2, ref_bit_vector.size(), 2);
1300 ASSERT_EQ(0, ioctx.operate(oid, &op2));
1301 ASSERT_EQ(0, object_map_load(&ioctx, oid, &osd_bit_vector));
1302 ASSERT_EQ(ref_bit_vector, osd_bit_vector);
1303
1304 ref_bit_vector.resize(32);
1305
1306 librados::ObjectWriteOperation op3;
1307 object_map_resize(&op3, ref_bit_vector.size(), 1);
1308 ASSERT_EQ(-ESTALE, ioctx.operate(oid, &op3));
1309
1310 librados::ObjectWriteOperation op4;
1311 object_map_resize(&op4, ref_bit_vector.size(), 2);
1312 ASSERT_EQ(0, ioctx.operate(oid, &op4));
1313
1314 ASSERT_EQ(0, object_map_load(&ioctx, oid, &osd_bit_vector));
1315 ASSERT_EQ(ref_bit_vector, osd_bit_vector);
1316
1317 ioctx.close();
1318 }
1319
1320 TEST_F(TestClsRbd, object_map_update)
1321 {
1322 librados::IoCtx ioctx;
1323 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
1324
1325 string oid = get_temp_image_name();
1326 BitVector<2> ref_bit_vector;
1327 ref_bit_vector.resize(16);
1328 for (uint64_t i = 0; i < ref_bit_vector.size(); ++i) {
1329 ref_bit_vector[i] = 2;
1330 }
1331
1332 BitVector<2> osd_bit_vector;
1333
1334 librados::ObjectWriteOperation op1;
1335 object_map_resize(&op1, ref_bit_vector.size(), 2);
1336 ASSERT_EQ(0, ioctx.operate(oid, &op1));
1337 ASSERT_EQ(0, object_map_load(&ioctx, oid, &osd_bit_vector));
1338 ASSERT_EQ(ref_bit_vector, osd_bit_vector);
1339
1340 ref_bit_vector[7] = 1;
1341 ref_bit_vector[8] = 1;
1342
1343 librados::ObjectWriteOperation op2;
1344 object_map_update(&op2, 7, 9, 1, boost::optional<uint8_t>());
1345 ASSERT_EQ(0, ioctx.operate(oid, &op2));
1346 ASSERT_EQ(0, object_map_load(&ioctx, oid, &osd_bit_vector));
1347 ASSERT_EQ(ref_bit_vector, osd_bit_vector);
1348
1349 ref_bit_vector[7] = 3;
1350 ref_bit_vector[8] = 3;
1351
1352 librados::ObjectWriteOperation op3;
1353 object_map_update(&op3, 6, 10, 3, 1);
1354 ASSERT_EQ(0, ioctx.operate(oid, &op3));
1355 ASSERT_EQ(0, object_map_load(&ioctx, oid, &osd_bit_vector));
1356 ASSERT_EQ(ref_bit_vector, osd_bit_vector);
1357
1358 ioctx.close();
1359 }
1360
1361 TEST_F(TestClsRbd, object_map_load_enoent)
1362 {
1363 librados::IoCtx ioctx;
1364 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
1365
1366 string oid = get_temp_image_name();
1367 BitVector<2> osd_bit_vector;
1368 ASSERT_EQ(-ENOENT, object_map_load(&ioctx, oid, &osd_bit_vector));
1369
1370 ioctx.close();
1371 }
1372
1373 TEST_F(TestClsRbd, object_map_snap_add)
1374 {
1375 librados::IoCtx ioctx;
1376 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
1377
1378 string oid = get_temp_image_name();
1379 BitVector<2> ref_bit_vector;
1380 ref_bit_vector.resize(16);
1381 for (uint64_t i = 0; i < ref_bit_vector.size(); ++i) {
1382 if (i < 4) {
1383 ref_bit_vector[i] = OBJECT_NONEXISTENT;
1384 } else {
1385 ref_bit_vector[i] = OBJECT_EXISTS;
1386 }
1387 }
1388
1389 BitVector<2> osd_bit_vector;
1390
1391 librados::ObjectWriteOperation op1;
1392 object_map_resize(&op1, ref_bit_vector.size(), OBJECT_EXISTS);
1393 ASSERT_EQ(0, ioctx.operate(oid, &op1));
1394
1395 librados::ObjectWriteOperation op2;
1396 object_map_update(&op2, 0, 4, OBJECT_NONEXISTENT, boost::optional<uint8_t>());
1397 ASSERT_EQ(0, ioctx.operate(oid, &op2));
1398
1399 ASSERT_EQ(0, object_map_load(&ioctx, oid, &osd_bit_vector));
1400 ASSERT_EQ(ref_bit_vector, osd_bit_vector);
1401
1402 librados::ObjectWriteOperation op3;
1403 object_map_snap_add(&op3);
1404 ASSERT_EQ(0, ioctx.operate(oid, &op3));
1405
1406 for (uint64_t i = 0; i < ref_bit_vector.size(); ++i) {
1407 if (ref_bit_vector[i] == OBJECT_EXISTS) {
1408 ref_bit_vector[i] = OBJECT_EXISTS_CLEAN;
1409 }
1410 }
1411
1412 ASSERT_EQ(0, object_map_load(&ioctx, oid, &osd_bit_vector));
1413 ASSERT_EQ(ref_bit_vector, osd_bit_vector);
1414 }
1415
1416 TEST_F(TestClsRbd, object_map_snap_remove)
1417 {
1418 librados::IoCtx ioctx;
1419 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
1420
1421 string oid = get_temp_image_name();
1422 BitVector<2> ref_bit_vector;
1423 ref_bit_vector.resize(16);
1424 for (uint64_t i = 0; i < ref_bit_vector.size(); ++i) {
1425 if (i < 4) {
1426 ref_bit_vector[i] = OBJECT_EXISTS_CLEAN;
1427 } else {
1428 ref_bit_vector[i] = OBJECT_EXISTS;
1429 }
1430 }
1431
1432 BitVector<2> osd_bit_vector;
1433
1434 librados::ObjectWriteOperation op1;
1435 object_map_resize(&op1, ref_bit_vector.size(), OBJECT_EXISTS);
1436 ASSERT_EQ(0, ioctx.operate(oid, &op1));
1437
1438 librados::ObjectWriteOperation op2;
1439 object_map_update(&op2, 0, 4, OBJECT_EXISTS_CLEAN, boost::optional<uint8_t>());
1440 ASSERT_EQ(0, ioctx.operate(oid, &op2));
1441
1442 ASSERT_EQ(0, object_map_load(&ioctx, oid, &osd_bit_vector));
1443 ASSERT_EQ(ref_bit_vector, osd_bit_vector);
1444
1445 BitVector<2> snap_bit_vector;
1446 snap_bit_vector.resize(4);
1447 for (uint64_t i = 0; i < snap_bit_vector.size(); ++i) {
1448 if (i == 1 || i == 2) {
1449 snap_bit_vector[i] = OBJECT_EXISTS;
1450 } else {
1451 snap_bit_vector[i] = OBJECT_NONEXISTENT;
1452 }
1453 }
1454
1455 librados::ObjectWriteOperation op3;
1456 object_map_snap_remove(&op3, snap_bit_vector);
1457 ASSERT_EQ(0, ioctx.operate(oid, &op3));
1458
1459 ref_bit_vector[1] = OBJECT_EXISTS;
1460 ref_bit_vector[2] = OBJECT_EXISTS;
1461 ASSERT_EQ(0, object_map_load(&ioctx, oid, &osd_bit_vector));
1462 ASSERT_EQ(ref_bit_vector, osd_bit_vector);
1463 }
1464
1465 TEST_F(TestClsRbd, flags)
1466 {
1467 librados::IoCtx ioctx;
1468 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
1469
1470 string oid = get_temp_image_name();
1471 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, 0, oid, -1));
1472
1473 uint64_t flags;
1474 ASSERT_EQ(0, get_flags(&ioctx, oid, CEPH_NOSNAP, &flags));
1475 ASSERT_EQ(0U, flags);
1476
1477 librados::ObjectWriteOperation op1;
1478 set_flags(&op1, CEPH_NOSNAP, 3, 2);
1479 ASSERT_EQ(0, ioctx.operate(oid, &op1));
1480 ASSERT_EQ(0, get_flags(&ioctx, oid, CEPH_NOSNAP, &flags));
1481 ASSERT_EQ(2U, flags);
1482
1483 uint64_t snap_id = 10;
1484 ASSERT_EQ(-ENOENT, get_flags(&ioctx, oid, snap_id, &flags));
1485 ASSERT_EQ(0, snapshot_add(&ioctx, oid, snap_id, "snap"));
1486
1487 librados::ObjectWriteOperation op2;
1488 set_flags(&op2, snap_id, 31, 4);
1489 ASSERT_EQ(0, ioctx.operate(oid, &op2));
1490 ASSERT_EQ(0, get_flags(&ioctx, oid, snap_id, &flags));
1491 ASSERT_EQ(6U, flags);
1492
1493 ioctx.close();
1494 }
1495
1496 TEST_F(TestClsRbd, metadata)
1497 {
1498 librados::IoCtx ioctx;
1499 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
1500
1501 string oid = get_temp_image_name();
1502 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, 0, oid, -1));
1503
1504 map<string, bufferlist> pairs;
1505 string value;
1506 ASSERT_EQ(0, metadata_list(&ioctx, oid, "", 0, &pairs));
1507 ASSERT_TRUE(pairs.empty());
1508
1509 pairs["key1"].append("value1");
1510 pairs["key2"].append("value2");
1511 ASSERT_EQ(0, metadata_set(&ioctx, oid, pairs));
1512 ASSERT_EQ(0, metadata_get(&ioctx, oid, "key1", &value));
1513 ASSERT_EQ(0, strcmp("value1", value.c_str()));
1514 pairs.clear();
1515 ASSERT_EQ(0, metadata_list(&ioctx, oid, "", 0, &pairs));
1516 ASSERT_EQ(2U, pairs.size());
1517 ASSERT_EQ(0, strncmp("value1", pairs["key1"].c_str(), 6));
1518 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
1519
1520 pairs.clear();
1521 ASSERT_EQ(0, metadata_remove(&ioctx, oid, "key1"));
1522 ASSERT_EQ(0, metadata_remove(&ioctx, oid, "key3"));
1523 ASSERT_TRUE(metadata_get(&ioctx, oid, "key1", &value) < 0);
1524 ASSERT_EQ(0, metadata_list(&ioctx, oid, "", 0, &pairs));
1525 ASSERT_EQ(1U, pairs.size());
1526 ASSERT_EQ(0, strncmp("value2", pairs["key2"].c_str(), 6));
1527
1528 pairs.clear();
1529 char key[10], val[20];
1530 for (int i = 0; i < 1024; i++) {
1531 sprintf(key, "key%d", i);
1532 sprintf(val, "value%d", i);
1533 pairs[key].append(val, strlen(val));
1534 }
1535 ASSERT_EQ(0, metadata_set(&ioctx, oid, pairs));
1536
1537 string last_read = "";
1538 uint64_t max_read = 48, r;
1539 uint64_t size = 0;
1540 map<string, bufferlist> data;
1541 do {
1542 map<string, bufferlist> cur;
1543 metadata_list(&ioctx, oid, last_read, max_read, &cur);
1544 size += cur.size();
1545 for (map<string, bufferlist>::iterator it = cur.begin();
1546 it != cur.end(); ++it)
1547 data[it->first] = it->second;
1548 last_read = cur.rbegin()->first;
1549 r = cur.size();
1550 } while (r == max_read);
1551 ASSERT_EQ(size, 1024U);
1552 for (map<string, bufferlist>::iterator it = data.begin();
1553 it != data.end(); ++it) {
1554 ASSERT_TRUE(it->second.contents_equal(pairs[it->first]));
1555 }
1556
1557 ioctx.close();
1558 }
1559
1560 TEST_F(TestClsRbd, set_features)
1561 {
1562 librados::IoCtx ioctx;
1563 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
1564
1565 string oid = get_temp_image_name();
1566 uint64_t base_features = RBD_FEATURE_LAYERING | RBD_FEATURE_DEEP_FLATTEN;
1567 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, base_features, oid, -1));
1568
1569 uint64_t features = RBD_FEATURES_MUTABLE;
1570 uint64_t mask = RBD_FEATURES_MUTABLE;
1571 ASSERT_EQ(0, set_features(&ioctx, oid, features, mask));
1572
1573 uint64_t actual_features;
1574 uint64_t incompatible_features;
1575 ASSERT_EQ(0, get_features(&ioctx, oid, true, &actual_features,
1576 &incompatible_features));
1577
1578 uint64_t expected_features = RBD_FEATURES_MUTABLE | base_features;
1579 ASSERT_EQ(expected_features, actual_features);
1580
1581 features = 0;
1582 mask = RBD_FEATURE_OBJECT_MAP;
1583 ASSERT_EQ(0, set_features(&ioctx, oid, features, mask));
1584
1585 ASSERT_EQ(0, get_features(&ioctx, oid, true, &actual_features,
1586 &incompatible_features));
1587
1588 expected_features = (RBD_FEATURES_MUTABLE | base_features) &
1589 ~RBD_FEATURE_OBJECT_MAP;
1590 ASSERT_EQ(expected_features, actual_features);
1591
1592 ASSERT_EQ(0, set_features(&ioctx, oid, 0, RBD_FEATURE_DEEP_FLATTEN));
1593 ASSERT_EQ(-EINVAL, set_features(&ioctx, oid, RBD_FEATURE_DEEP_FLATTEN,
1594 RBD_FEATURE_DEEP_FLATTEN));
1595
1596 ASSERT_EQ(-EINVAL, set_features(&ioctx, oid, 0, RBD_FEATURE_LAYERING));
1597 ASSERT_EQ(-EINVAL, set_features(&ioctx, oid, 0, RBD_FEATURE_OPERATIONS));
1598 }
1599
1600 TEST_F(TestClsRbd, mirror) {
1601 librados::IoCtx ioctx;
1602 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
1603 ioctx.remove(RBD_MIRRORING);
1604
1605 std::vector<cls::rbd::MirrorPeer> peers;
1606 ASSERT_EQ(-ENOENT, mirror_peer_list(&ioctx, &peers));
1607
1608 std::string uuid;
1609 ASSERT_EQ(-ENOENT, mirror_uuid_get(&ioctx, &uuid));
1610 ASSERT_EQ(-EINVAL, mirror_peer_add(&ioctx, {"uuid1", MIRROR_PEER_DIRECTION_RX,
1611 "siteA", "client",
1612 "mirror uuid"}));
1613 ASSERT_EQ(-EINVAL, mirror_peer_ping(&ioctx, "siteA", "mirror uuid"));
1614
1615 cls::rbd::MirrorMode mirror_mode;
1616 ASSERT_EQ(0, mirror_mode_get(&ioctx, &mirror_mode));
1617 ASSERT_EQ(cls::rbd::MIRROR_MODE_DISABLED, mirror_mode);
1618
1619 ASSERT_EQ(-EINVAL, mirror_mode_set(&ioctx, cls::rbd::MIRROR_MODE_IMAGE));
1620 ASSERT_EQ(-EINVAL, mirror_uuid_set(&ioctx, ""));
1621 ASSERT_EQ(0, mirror_uuid_set(&ioctx, "mirror-uuid"));
1622 ASSERT_EQ(0, mirror_uuid_get(&ioctx, &uuid));
1623 ASSERT_EQ("mirror-uuid", uuid);
1624
1625 ASSERT_EQ(0, mirror_mode_set(&ioctx, cls::rbd::MIRROR_MODE_IMAGE));
1626 ASSERT_EQ(0, mirror_mode_get(&ioctx, &mirror_mode));
1627 ASSERT_EQ(cls::rbd::MIRROR_MODE_IMAGE, mirror_mode);
1628
1629 ASSERT_EQ(-EINVAL, mirror_uuid_set(&ioctx, "new-mirror-uuid"));
1630
1631 ASSERT_EQ(0, mirror_mode_set(&ioctx, cls::rbd::MIRROR_MODE_POOL));
1632 ASSERT_EQ(0, mirror_mode_get(&ioctx, &mirror_mode));
1633 ASSERT_EQ(cls::rbd::MIRROR_MODE_POOL, mirror_mode);
1634
1635 ASSERT_EQ(-EINVAL, mirror_peer_add(&ioctx, {"mirror-uuid",
1636 MIRROR_PEER_DIRECTION_RX, "siteA",
1637 "client", ""}));
1638 ASSERT_EQ(-EINVAL, mirror_peer_add(&ioctx, {"uuid1", MIRROR_PEER_DIRECTION_TX,
1639 "siteA", "client",
1640 "mirror uuid"}));
1641 ASSERT_EQ(0, mirror_peer_add(&ioctx, {"uuid1", MIRROR_PEER_DIRECTION_RX,
1642 "siteA", "client", "fsidA"}));
1643 ASSERT_EQ(0, mirror_peer_add(&ioctx, {"uuid2", MIRROR_PEER_DIRECTION_RX,
1644 "siteB", "admin", ""}));
1645 ASSERT_EQ(-ESTALE, mirror_peer_add(&ioctx, {"uuid2", MIRROR_PEER_DIRECTION_RX,
1646 "siteC", "foo", ""}));
1647 ASSERT_EQ(-EEXIST, mirror_peer_add(&ioctx, {"uuid3", MIRROR_PEER_DIRECTION_RX,
1648 "siteA", "foo", ""}));
1649 ASSERT_EQ(-EEXIST, mirror_peer_add(&ioctx, {"uuid3", MIRROR_PEER_DIRECTION_RX,
1650 "siteC", "client", "fsidA"}));
1651 ASSERT_EQ(0, mirror_peer_add(&ioctx, {"uuid3", MIRROR_PEER_DIRECTION_RX,
1652 "siteC", "admin", ""}));
1653 ASSERT_EQ(0, mirror_peer_add(&ioctx, {"uuid4", MIRROR_PEER_DIRECTION_RX,
1654 "siteD", "admin", ""}));
1655
1656 ASSERT_EQ(0, mirror_peer_list(&ioctx, &peers));
1657 std::vector<cls::rbd::MirrorPeer> expected_peers = {
1658 {"uuid1", MIRROR_PEER_DIRECTION_RX, "siteA", "client", "fsidA"},
1659 {"uuid2", MIRROR_PEER_DIRECTION_RX, "siteB", "admin", ""},
1660 {"uuid3", MIRROR_PEER_DIRECTION_RX, "siteC", "admin", ""},
1661 {"uuid4", MIRROR_PEER_DIRECTION_RX, "siteD", "admin", ""}};
1662 ASSERT_EQ(expected_peers, peers);
1663
1664 ASSERT_EQ(0, mirror_peer_remove(&ioctx, "uuid5"));
1665 ASSERT_EQ(0, mirror_peer_remove(&ioctx, "uuid4"));
1666 ASSERT_EQ(0, mirror_peer_remove(&ioctx, "uuid2"));
1667
1668 ASSERT_EQ(0, mirror_peer_list(&ioctx, &peers));
1669 expected_peers = {
1670 {"uuid1", MIRROR_PEER_DIRECTION_RX, "siteA", "client", "fsidA"},
1671 {"uuid3", MIRROR_PEER_DIRECTION_RX, "siteC", "admin", ""}};
1672 ASSERT_EQ(expected_peers, peers);
1673
1674 ASSERT_EQ(-ENOENT, mirror_peer_set_client(&ioctx, "uuid4", "new client"));
1675 ASSERT_EQ(0, mirror_peer_set_client(&ioctx, "uuid1", "new client"));
1676
1677 ASSERT_EQ(-ENOENT, mirror_peer_set_cluster(&ioctx, "uuid4", "new site"));
1678 ASSERT_EQ(0, mirror_peer_set_cluster(&ioctx, "uuid3", "new site"));
1679
1680 ASSERT_EQ(0, mirror_peer_list(&ioctx, &peers));
1681 expected_peers = {
1682 {"uuid1", MIRROR_PEER_DIRECTION_RX, "siteA", "new client", "fsidA"},
1683 {"uuid3", MIRROR_PEER_DIRECTION_RX, "new site", "admin", ""}};
1684 ASSERT_EQ(expected_peers, peers);
1685
1686 ASSERT_EQ(0, mirror_peer_remove(&ioctx, "uuid1"));
1687
1688 ASSERT_EQ(0, mirror_peer_list(&ioctx, &peers));
1689 expected_peers = {
1690 {"uuid3", MIRROR_PEER_DIRECTION_RX, "new site", "admin", ""}};
1691 ASSERT_EQ(expected_peers, peers);
1692
1693 ASSERT_EQ(-EINVAL, mirror_peer_ping(&ioctx, "", "mirror uuid"));
1694 ASSERT_EQ(-EINVAL, mirror_peer_ping(&ioctx, "new site", ""));
1695 ASSERT_EQ(0, mirror_peer_ping(&ioctx, "new site", "mirror uuid"));
1696
1697 ASSERT_EQ(0, mirror_peer_list(&ioctx, &peers));
1698 ASSERT_EQ(1U, peers.size());
1699 ASSERT_LT(utime_t{}, peers[0].last_seen);
1700 expected_peers = {
1701 {"uuid3", MIRROR_PEER_DIRECTION_RX_TX, "new site", "admin", "mirror uuid"}};
1702 expected_peers[0].last_seen = peers[0].last_seen;
1703 ASSERT_EQ(expected_peers, peers);
1704 ASSERT_EQ(0, mirror_peer_remove(&ioctx, "uuid3"));
1705
1706 ASSERT_EQ(0, mirror_peer_ping(&ioctx, "siteA", "mirror uuid"));
1707
1708 ASSERT_EQ(0, mirror_peer_list(&ioctx, &peers));
1709 ASSERT_EQ(1U, peers.size());
1710 ASSERT_FALSE(peers[0].uuid.empty());
1711 ASSERT_LT(utime_t{}, peers[0].last_seen);
1712 expected_peers = {
1713 {peers[0].uuid, MIRROR_PEER_DIRECTION_TX, "siteA", "", "mirror uuid"}};
1714 expected_peers[0].last_seen = peers[0].last_seen;
1715 ASSERT_EQ(expected_peers, peers);
1716
1717 ASSERT_EQ(-EBUSY, mirror_mode_set(&ioctx, cls::rbd::MIRROR_MODE_DISABLED));
1718 ASSERT_EQ(0, mirror_peer_remove(&ioctx, peers[0].uuid));
1719
1720 ASSERT_EQ(0, mirror_peer_remove(&ioctx, "DNE"));
1721 ASSERT_EQ(0, mirror_peer_list(&ioctx, &peers));
1722 expected_peers = {};
1723 ASSERT_EQ(expected_peers, peers);
1724
1725 ASSERT_EQ(0, mirror_mode_set(&ioctx, cls::rbd::MIRROR_MODE_DISABLED));
1726 ASSERT_EQ(0, mirror_mode_get(&ioctx, &mirror_mode));
1727 ASSERT_EQ(cls::rbd::MIRROR_MODE_DISABLED, mirror_mode);
1728 ASSERT_EQ(-ENOENT, mirror_uuid_get(&ioctx, &uuid));
1729 }
1730
1731 TEST_F(TestClsRbd, mirror_image) {
1732 librados::IoCtx ioctx;
1733 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
1734 ioctx.remove(RBD_MIRRORING);
1735
1736 std::map<std::string, std::string> mirror_image_ids;
1737 ASSERT_EQ(-ENOENT, mirror_image_list(&ioctx, "", 0, &mirror_image_ids));
1738
1739 cls::rbd::MirrorImage image1(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid1",
1740 cls::rbd::MIRROR_IMAGE_STATE_ENABLED);
1741 cls::rbd::MirrorImage image2(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid2",
1742 cls::rbd::MIRROR_IMAGE_STATE_DISABLING);
1743 cls::rbd::MirrorImage image3(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid3",
1744 cls::rbd::MIRROR_IMAGE_STATE_ENABLED);
1745
1746 ASSERT_EQ(0, mirror_image_set(&ioctx, "image_id1", image1));
1747 ASSERT_EQ(-ENOENT, mirror_image_set(&ioctx, "image_id2", image2));
1748 image2.state = cls::rbd::MIRROR_IMAGE_STATE_ENABLED;
1749 ASSERT_EQ(0, mirror_image_set(&ioctx, "image_id2", image2));
1750 image2.state = cls::rbd::MIRROR_IMAGE_STATE_DISABLING;
1751 ASSERT_EQ(0, mirror_image_set(&ioctx, "image_id2", image2));
1752 ASSERT_EQ(-EINVAL, mirror_image_set(&ioctx, "image_id1", image2));
1753 ASSERT_EQ(-EEXIST, mirror_image_set(&ioctx, "image_id3", image2));
1754 ASSERT_EQ(0, mirror_image_set(&ioctx, "image_id3", image3));
1755
1756 std::string image_id;
1757 ASSERT_EQ(0, mirror_image_get_image_id(&ioctx, "uuid2", &image_id));
1758 ASSERT_EQ("image_id2", image_id);
1759
1760 cls::rbd::MirrorImage read_image;
1761 ASSERT_EQ(0, mirror_image_get(&ioctx, "image_id1", &read_image));
1762 ASSERT_EQ(read_image, image1);
1763 ASSERT_EQ(0, mirror_image_get(&ioctx, "image_id2", &read_image));
1764 ASSERT_EQ(read_image, image2);
1765 ASSERT_EQ(0, mirror_image_get(&ioctx, "image_id3", &read_image));
1766 ASSERT_EQ(read_image, image3);
1767
1768 ASSERT_EQ(0, mirror_image_list(&ioctx, "", 1, &mirror_image_ids));
1769 std::map<std::string, std::string> expected_mirror_image_ids = {
1770 {"image_id1", "uuid1"}};
1771 ASSERT_EQ(expected_mirror_image_ids, mirror_image_ids);
1772
1773 ASSERT_EQ(0, mirror_image_list(&ioctx, "image_id1", 2, &mirror_image_ids));
1774 expected_mirror_image_ids = {{"image_id2", "uuid2"}, {"image_id3", "uuid3"}};
1775 ASSERT_EQ(expected_mirror_image_ids, mirror_image_ids);
1776
1777 ASSERT_EQ(0, mirror_image_remove(&ioctx, "image_id2"));
1778 ASSERT_EQ(-ENOENT, mirror_image_get_image_id(&ioctx, "uuid2", &image_id));
1779 ASSERT_EQ(-EBUSY, mirror_image_remove(&ioctx, "image_id1"));
1780
1781 ASSERT_EQ(0, mirror_image_list(&ioctx, "", 3, &mirror_image_ids));
1782 expected_mirror_image_ids = {{"image_id1", "uuid1"}, {"image_id3", "uuid3"}};
1783 ASSERT_EQ(expected_mirror_image_ids, mirror_image_ids);
1784
1785 image1.state = cls::rbd::MIRROR_IMAGE_STATE_DISABLING;
1786 image3.state = cls::rbd::MIRROR_IMAGE_STATE_DISABLING;
1787 ASSERT_EQ(0, mirror_image_set(&ioctx, "image_id1", image1));
1788 ASSERT_EQ(0, mirror_image_get(&ioctx, "image_id1", &read_image));
1789 ASSERT_EQ(read_image, image1);
1790 ASSERT_EQ(0, mirror_image_set(&ioctx, "image_id3", image3));
1791 ASSERT_EQ(0, mirror_image_remove(&ioctx, "image_id1"));
1792 ASSERT_EQ(0, mirror_image_remove(&ioctx, "image_id3"));
1793
1794 ASSERT_EQ(0, mirror_image_list(&ioctx, "", 3, &mirror_image_ids));
1795 expected_mirror_image_ids = {};
1796 ASSERT_EQ(expected_mirror_image_ids, mirror_image_ids);
1797 }
1798
1799 TEST_F(TestClsRbd, mirror_image_status) {
1800 struct WatchCtx : public librados::WatchCtx2 {
1801 librados::IoCtx *m_ioctx;
1802
1803 explicit WatchCtx(librados::IoCtx *ioctx) : m_ioctx(ioctx) {}
1804 void handle_notify(uint64_t notify_id, uint64_t cookie,
1805 uint64_t notifier_id, bufferlist& bl_) override {
1806 bufferlist bl;
1807 m_ioctx->notify_ack(RBD_MIRRORING, notify_id, cookie, bl);
1808 }
1809 void handle_error(uint64_t cookie, int err) override {}
1810 };
1811
1812 map<std::string, cls::rbd::MirrorImage> images;
1813 map<std::string, cls::rbd::MirrorImageStatus> statuses;
1814 std::map<cls::rbd::MirrorImageStatusState, int32_t> states;
1815 std::map<std::string, entity_inst_t> instances;
1816 cls::rbd::MirrorImageStatus read_status;
1817 entity_inst_t read_instance;
1818 uint64_t watch_handle;
1819 librados::IoCtx ioctx;
1820
1821 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
1822 ioctx.remove(RBD_MIRRORING);
1823
1824 int64_t instance_id = librados::Rados(ioctx).get_instance_id();
1825
1826 // Test list fails on nonexistent RBD_MIRRORING object
1827
1828 ASSERT_EQ(-ENOENT, mirror_image_status_list(&ioctx, "", 1024, &images,
1829 &statuses));
1830
1831 // Test status set
1832
1833 cls::rbd::MirrorImage image1(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid1",
1834 cls::rbd::MIRROR_IMAGE_STATE_ENABLED);
1835 cls::rbd::MirrorImage image2(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid2",
1836 cls::rbd::MIRROR_IMAGE_STATE_ENABLED);
1837 cls::rbd::MirrorImage image3(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "uuid3",
1838 cls::rbd::MIRROR_IMAGE_STATE_ENABLED);
1839
1840 ASSERT_EQ(0, mirror_image_set(&ioctx, "image_id1", image1));
1841 ASSERT_EQ(0, mirror_image_set(&ioctx, "image_id2", image2));
1842 ASSERT_EQ(0, mirror_image_set(&ioctx, "image_id3", image3));
1843
1844 cls::rbd::MirrorImageSiteStatus status1(
1845 "", cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN, "");
1846 cls::rbd::MirrorImageSiteStatus status2(
1847 "", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING, "");
1848 cls::rbd::MirrorImageSiteStatus status3(
1849 "", cls::rbd::MIRROR_IMAGE_STATUS_STATE_ERROR, "");
1850
1851 ASSERT_EQ(0, mirror_image_status_set(&ioctx, "uuid1", status1));
1852 images.clear();
1853 statuses.clear();
1854 ASSERT_EQ(0, mirror_image_status_list(&ioctx, "", 1024, &images, &statuses));
1855 ASSERT_EQ(3U, images.size());
1856 ASSERT_EQ(1U, statuses.size());
1857
1858 // Test status is down due to RBD_MIRRORING is not watched
1859
1860 status1.up = false;
1861 ASSERT_EQ(statuses["image_id1"], cls::rbd::MirrorImageStatus{{status1}});
1862 ASSERT_EQ(0, mirror_image_status_get(&ioctx, "uuid1", &read_status));
1863 ASSERT_EQ(read_status, cls::rbd::MirrorImageStatus{{status1}});
1864
1865 // Test status summary. All statuses are unknown due to down.
1866 states.clear();
1867 cls::rbd::MirrorPeer mirror_peer{
1868 "uuid", cls::rbd::MIRROR_PEER_DIRECTION_RX, "siteA", "client", "fsidA"};
1869 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx, {mirror_peer}, &states));
1870 ASSERT_EQ(1U, states.size());
1871 ASSERT_EQ(3, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN]);
1872
1873 // Test get instance return -ESTALE due to down.
1874
1875 ASSERT_EQ(-ESTALE, mirror_image_instance_get(&ioctx, "uuid1", &read_instance));
1876 instances.clear();
1877 ASSERT_EQ(0, mirror_image_instance_list(&ioctx, "", 1024, &instances));
1878 ASSERT_TRUE(instances.empty());
1879
1880 // Test remove_down removes stale statuses
1881
1882 ASSERT_EQ(0, mirror_image_status_remove_down(&ioctx));
1883 ASSERT_EQ(-ENOENT, mirror_image_status_get(&ioctx, "uuid1", &read_status));
1884 ASSERT_EQ(-ENOENT, mirror_image_instance_get(&ioctx, "uuid1", &read_instance));
1885 ASSERT_EQ(0, mirror_image_status_list(&ioctx, "", 1024, &images, &statuses));
1886 ASSERT_EQ(3U, images.size());
1887 ASSERT_TRUE(statuses.empty());
1888 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx, {mirror_peer}, &states));
1889 ASSERT_EQ(1U, states.size());
1890 ASSERT_EQ(3, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN]);
1891
1892 // Test remove of status
1893 ASSERT_EQ(0, mirror_image_status_set(&ioctx, "uuid1", status1));
1894 ASSERT_EQ(0, mirror_image_status_remove(&ioctx, "uuid1"));
1895 ASSERT_EQ(-ENOENT, mirror_image_instance_get(&ioctx, "uuid1", &read_instance));
1896
1897 // Test statuses are not down after watcher is started
1898
1899 ASSERT_EQ(0, mirror_image_status_set(&ioctx, "uuid1", status1));
1900
1901 WatchCtx watch_ctx(&ioctx);
1902 ASSERT_EQ(0, ioctx.watch2(RBD_MIRRORING, &watch_handle, &watch_ctx));
1903
1904 ASSERT_EQ(0, mirror_image_status_set(&ioctx, "uuid2", status2));
1905 ASSERT_EQ(0, mirror_image_status_set(&ioctx, "uuid3", status3));
1906
1907 ASSERT_EQ(0, mirror_image_status_get(&ioctx, "uuid1", &read_status));
1908 status1.up = true;
1909 ASSERT_EQ(read_status, cls::rbd::MirrorImageStatus{{status1}});
1910 ASSERT_EQ(0, mirror_image_status_get(&ioctx, "uuid2", &read_status));
1911 status2.up = true;
1912 ASSERT_EQ(read_status, cls::rbd::MirrorImageStatus{{status2}});
1913 ASSERT_EQ(0, mirror_image_status_get(&ioctx, "uuid3", &read_status));
1914 status3.up = true;
1915 ASSERT_EQ(read_status, cls::rbd::MirrorImageStatus{{status3}});
1916
1917 images.clear();
1918 statuses.clear();
1919 ASSERT_EQ(0, mirror_image_status_list(&ioctx, "", 1024, &images, &statuses));
1920 ASSERT_EQ(3U, images.size());
1921 ASSERT_EQ(3U, statuses.size());
1922 ASSERT_EQ(statuses["image_id1"], cls::rbd::MirrorImageStatus{{status1}});
1923 ASSERT_EQ(statuses["image_id2"], cls::rbd::MirrorImageStatus{{status2}});
1924 ASSERT_EQ(statuses["image_id3"], cls::rbd::MirrorImageStatus{{status3}});
1925
1926 read_instance = {};
1927 ASSERT_EQ(0, mirror_image_instance_get(&ioctx, "uuid1", &read_instance));
1928 ASSERT_EQ(read_instance.name.num(), instance_id);
1929 instances.clear();
1930 ASSERT_EQ(0, mirror_image_instance_list(&ioctx, "", 1024, &instances));
1931 ASSERT_EQ(3U, instances.size());
1932 ASSERT_EQ(instances["image_id1"].name.num(), instance_id);
1933 ASSERT_EQ(instances["image_id2"].name.num(), instance_id);
1934 ASSERT_EQ(instances["image_id3"].name.num(), instance_id);
1935
1936 ASSERT_EQ(0, mirror_image_status_remove_down(&ioctx));
1937 ASSERT_EQ(0, mirror_image_status_get(&ioctx, "uuid1", &read_status));
1938 ASSERT_EQ(read_status, cls::rbd::MirrorImageStatus{{status1}});
1939 images.clear();
1940 statuses.clear();
1941 ASSERT_EQ(0, mirror_image_status_list(&ioctx, "", 1024, &images, &statuses));
1942 ASSERT_EQ(3U, images.size());
1943 ASSERT_EQ(3U, statuses.size());
1944 ASSERT_EQ(statuses["image_id1"], cls::rbd::MirrorImageStatus{{status1}});
1945 ASSERT_EQ(statuses["image_id2"], cls::rbd::MirrorImageStatus{{status2}});
1946 ASSERT_EQ(statuses["image_id3"], cls::rbd::MirrorImageStatus{{status3}});
1947
1948 states.clear();
1949 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx, {mirror_peer}, &states));
1950 ASSERT_EQ(3U, states.size());
1951 ASSERT_EQ(1, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN]);
1952 ASSERT_EQ(1, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING]);
1953 ASSERT_EQ(1, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_ERROR]);
1954
1955 // Test update
1956
1957 status1.state = status3.state = cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING;
1958 ASSERT_EQ(0, mirror_image_status_set(&ioctx, "uuid1", status1));
1959 ASSERT_EQ(0, mirror_image_status_set(&ioctx, "uuid3", status3));
1960 ASSERT_EQ(0, mirror_image_status_get(&ioctx, "uuid3", &read_status));
1961 ASSERT_EQ(read_status, cls::rbd::MirrorImageStatus{{status3}});
1962
1963 states.clear();
1964 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx, {mirror_peer}, &states));
1965 ASSERT_EQ(1U, states.size());
1966 ASSERT_EQ(3, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING]);
1967
1968 // Remote status
1969
1970 ASSERT_EQ(0, mirror_uuid_set(&ioctx, "mirror-uuid"));
1971 ASSERT_EQ(0, mirror_mode_set(&ioctx, cls::rbd::MIRROR_MODE_POOL));
1972
1973 ASSERT_EQ(0, mirror_image_status_get(&ioctx, "uuid1", &read_status));
1974 cls::rbd::MirrorImageStatus expected_status1({status1});
1975 ASSERT_EQ(expected_status1, read_status);
1976
1977 cls::rbd::MirrorImageSiteStatus remote_status1(
1978 "fsidA", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING, "");
1979 ASSERT_EQ(0, mirror_image_status_set(&ioctx, "uuid1", remote_status1));
1980 ASSERT_EQ(0, mirror_image_status_get(&ioctx, "uuid1", &read_status));
1981 remote_status1.up = true;
1982 expected_status1 = {{status1, remote_status1}};
1983 ASSERT_EQ(expected_status1, read_status);
1984
1985 // summary under different modes
1986 cls::rbd::MirrorImageSiteStatus remote_status2(
1987 "fsidA", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING, "");
1988 remote_status2.up = true;
1989 cls::rbd::MirrorImageSiteStatus remote_status3(
1990 "fsidA", cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN, "");
1991 remote_status3.up = true;
1992
1993 status1.state = cls::rbd::MIRROR_IMAGE_STATUS_STATE_ERROR;
1994 ASSERT_EQ(0, mirror_image_status_set(&ioctx, "uuid1", status1));
1995 ASSERT_EQ(0, mirror_image_status_set(&ioctx, "uuid2", status2));
1996 ASSERT_EQ(0, mirror_image_status_set(&ioctx, "uuid3", status3));
1997 ASSERT_EQ(0, mirror_image_status_set(&ioctx, "uuid2", remote_status2));
1998 ASSERT_EQ(0, mirror_image_status_set(&ioctx, "uuid3", remote_status3));
1999
2000 expected_status1 = {{status1, remote_status1}};
2001 cls::rbd::MirrorImageStatus expected_status2({status2, remote_status2});
2002 cls::rbd::MirrorImageStatus expected_status3({status3, remote_status3});
2003
2004 images.clear();
2005 statuses.clear();
2006 ASSERT_EQ(0, mirror_image_status_list(&ioctx, "", 1024, &images, &statuses));
2007 ASSERT_EQ(3U, images.size());
2008 ASSERT_EQ(3U, statuses.size());
2009 ASSERT_EQ(statuses["image_id1"], expected_status1);
2010 ASSERT_EQ(statuses["image_id2"], expected_status2);
2011 ASSERT_EQ(statuses["image_id3"], expected_status3);
2012
2013 states.clear();
2014 mirror_peer.mirror_peer_direction = cls::rbd::MIRROR_PEER_DIRECTION_RX;
2015 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx, {mirror_peer}, &states));
2016 ASSERT_EQ(2U, states.size());
2017 ASSERT_EQ(2, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING]);
2018 ASSERT_EQ(1, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_ERROR]);
2019
2020 states.clear();
2021 mirror_peer.mirror_peer_direction = cls::rbd::MIRROR_PEER_DIRECTION_TX;
2022 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx, {mirror_peer}, &states));
2023 ASSERT_EQ(2U, states.size());
2024 ASSERT_EQ(2, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING]);
2025 ASSERT_EQ(1, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN]);
2026
2027 states.clear();
2028 mirror_peer.mirror_peer_direction = cls::rbd::MIRROR_PEER_DIRECTION_RX_TX;
2029 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx, {mirror_peer}, &states));
2030 ASSERT_EQ(3U, states.size());
2031 ASSERT_EQ(1, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING]);
2032 ASSERT_EQ(1, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN]);
2033 ASSERT_EQ(1, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_ERROR]);
2034
2035 // Test statuses are down after removing watcher
2036 ioctx.unwatch2(watch_handle);
2037
2038 ASSERT_EQ(0, mirror_image_status_list(&ioctx, "", 1024, &images, &statuses));
2039 ASSERT_EQ(3U, images.size());
2040 ASSERT_EQ(3U, statuses.size());
2041 status1.up = false;
2042 remote_status1.up = false;
2043 expected_status1 = {{status1, remote_status1}};
2044 ASSERT_EQ(statuses["image_id1"], expected_status1);
2045 status2.up = false;
2046 remote_status2.up = false;
2047 expected_status2 = {{status2, remote_status2}};
2048 ASSERT_EQ(statuses["image_id2"], expected_status2);
2049 status3.up = false;
2050 remote_status3.up = false;
2051 expected_status3 = {{status3, remote_status3}};
2052 ASSERT_EQ(statuses["image_id3"], expected_status3);
2053
2054 ASSERT_EQ(0, mirror_image_status_get(&ioctx, "uuid1", &read_status));
2055 ASSERT_EQ(read_status, expected_status1);
2056
2057 states.clear();
2058 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx, {mirror_peer}, &states));
2059 ASSERT_EQ(1U, states.size());
2060 ASSERT_EQ(3, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN]);
2061
2062 ASSERT_EQ(-ESTALE, mirror_image_instance_get(&ioctx, "uuid1", &read_instance));
2063 instances.clear();
2064 ASSERT_EQ(0, mirror_image_instance_list(&ioctx, "", 1024, &instances));
2065 ASSERT_TRUE(instances.empty());
2066
2067 ASSERT_EQ(0, mirror_image_status_remove_down(&ioctx));
2068 ASSERT_EQ(-ENOENT, mirror_image_status_get(&ioctx, "uuid1", &read_status));
2069
2070 images.clear();
2071 statuses.clear();
2072 ASSERT_EQ(0, mirror_image_status_list(&ioctx, "", 1024, &images, &statuses));
2073 ASSERT_EQ(3U, images.size());
2074 ASSERT_TRUE(statuses.empty());
2075
2076 states.clear();
2077 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx, {mirror_peer}, &states));
2078 ASSERT_EQ(1U, states.size());
2079 ASSERT_EQ(3, states[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN]);
2080
2081 // Remove images
2082
2083 image1.state = cls::rbd::MIRROR_IMAGE_STATE_DISABLING;
2084 image2.state = cls::rbd::MIRROR_IMAGE_STATE_DISABLING;
2085 image3.state = cls::rbd::MIRROR_IMAGE_STATE_DISABLING;
2086
2087 ASSERT_EQ(0, mirror_image_set(&ioctx, "image_id1", image1));
2088 ASSERT_EQ(0, mirror_image_set(&ioctx, "image_id2", image2));
2089 ASSERT_EQ(0, mirror_image_set(&ioctx, "image_id3", image3));
2090
2091 ASSERT_EQ(0, mirror_image_remove(&ioctx, "image_id1"));
2092 ASSERT_EQ(0, mirror_image_remove(&ioctx, "image_id2"));
2093 ASSERT_EQ(0, mirror_image_remove(&ioctx, "image_id3"));
2094
2095 states.clear();
2096 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx, {}, &states));
2097 ASSERT_EQ(0U, states.size());
2098
2099 // Test status list with large number of images
2100
2101 size_t N = 1024;
2102 ASSERT_EQ(0U, N % 2);
2103
2104 for (size_t i = 0; i < N; i++) {
2105 std::string id = "id" + stringify(i);
2106 std::string uuid = "uuid" + stringify(i);
2107 cls::rbd::MirrorImage image(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, uuid,
2108 cls::rbd::MIRROR_IMAGE_STATE_ENABLED);
2109 cls::rbd::MirrorImageSiteStatus status(
2110 "", cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN, "");
2111 ASSERT_EQ(0, mirror_image_set(&ioctx, id, image));
2112 ASSERT_EQ(0, mirror_image_status_set(&ioctx, uuid, status));
2113 }
2114
2115 std::string last_read = "";
2116 images.clear();
2117 statuses.clear();
2118 ASSERT_EQ(0, mirror_image_status_list(&ioctx, last_read, N * 2, &images,
2119 &statuses));
2120 ASSERT_EQ(N, images.size());
2121 ASSERT_EQ(N, statuses.size());
2122
2123 images.clear();
2124 statuses.clear();
2125 ASSERT_EQ(0, mirror_image_status_list(&ioctx, last_read, N / 2, &images,
2126 &statuses));
2127 ASSERT_EQ(N / 2, images.size());
2128 ASSERT_EQ(N / 2, statuses.size());
2129
2130 last_read = images.rbegin()->first;
2131 images.clear();
2132 statuses.clear();
2133 ASSERT_EQ(0, mirror_image_status_list(&ioctx, last_read, N / 2, &images,
2134 &statuses));
2135 ASSERT_EQ(N / 2, images.size());
2136 ASSERT_EQ(N / 2, statuses.size());
2137
2138 last_read = images.rbegin()->first;
2139 images.clear();
2140 statuses.clear();
2141 ASSERT_EQ(0, mirror_image_status_list(&ioctx, last_read, N / 2, &images,
2142 &statuses));
2143 ASSERT_EQ(0U, images.size());
2144 ASSERT_EQ(0U, statuses.size());
2145 }
2146
2147 TEST_F(TestClsRbd, mirror_image_map)
2148 {
2149 librados::IoCtx ioctx;
2150 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2151 ioctx.remove(RBD_MIRRORING);
2152
2153 std::map<std::string, cls::rbd::MirrorImageMap> image_mapping;
2154 ASSERT_EQ(-ENOENT, mirror_image_map_list(&ioctx, "", 0, &image_mapping));
2155
2156 utime_t expected_time = ceph_clock_now();
2157
2158 bufferlist expected_data;
2159 expected_data.append("test");
2160
2161 std::map<std::string, cls::rbd::MirrorImageMap> expected_image_mapping;
2162 while (expected_image_mapping.size() < 1024) {
2163 librados::ObjectWriteOperation op;
2164 for (uint32_t i = 0; i < 32; ++i) {
2165 std::string global_image_id{stringify(expected_image_mapping.size())};
2166 cls::rbd::MirrorImageMap mirror_image_map{
2167 stringify(i), expected_time, expected_data};
2168 expected_image_mapping.emplace(global_image_id, mirror_image_map);
2169
2170 mirror_image_map_update(&op, global_image_id, mirror_image_map);
2171 }
2172 ASSERT_EQ(0, ioctx.operate(RBD_MIRRORING, &op));
2173 }
2174
2175 ASSERT_EQ(0, mirror_image_map_list(&ioctx, "", 1000, &image_mapping));
2176 ASSERT_EQ(1000U, image_mapping.size());
2177
2178 ASSERT_EQ(0, mirror_image_map_list(&ioctx, image_mapping.rbegin()->first,
2179 1000, &image_mapping));
2180 ASSERT_EQ(24U, image_mapping.size());
2181
2182 const auto& image_map = *image_mapping.begin();
2183 ASSERT_EQ("978", image_map.first);
2184
2185 cls::rbd::MirrorImageMap expected_mirror_image_map{
2186 stringify(18), expected_time, expected_data};
2187 ASSERT_EQ(expected_mirror_image_map, image_map.second);
2188
2189 expected_time = ceph_clock_now();
2190 expected_mirror_image_map.mapped_time = expected_time;
2191
2192 expected_data.append("update");
2193 expected_mirror_image_map.data = expected_data;
2194
2195 librados::ObjectWriteOperation op;
2196 mirror_image_map_remove(&op, "1");
2197 mirror_image_map_update(&op, "10", expected_mirror_image_map);
2198 ASSERT_EQ(0, ioctx.operate(RBD_MIRRORING, &op));
2199
2200 ASSERT_EQ(0, mirror_image_map_list(&ioctx, "0", 1, &image_mapping));
2201 ASSERT_EQ(1U, image_mapping.size());
2202
2203 const auto& updated_image_map = *image_mapping.begin();
2204 ASSERT_EQ("10", updated_image_map.first);
2205 ASSERT_EQ(expected_mirror_image_map, updated_image_map.second);
2206 }
2207
2208 TEST_F(TestClsRbd, mirror_instances) {
2209 librados::IoCtx ioctx;
2210 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2211 ioctx.remove(RBD_MIRROR_LEADER);
2212
2213 std::vector<std::string> instance_ids;
2214 ASSERT_EQ(-ENOENT, mirror_instances_list(&ioctx, &instance_ids));
2215
2216 ASSERT_EQ(0, ioctx.create(RBD_MIRROR_LEADER, true));
2217 ASSERT_EQ(0, mirror_instances_list(&ioctx, &instance_ids));
2218 ASSERT_EQ(0U, instance_ids.size());
2219
2220 ASSERT_EQ(0, mirror_instances_add(&ioctx, "instance_id1"));
2221 ASSERT_EQ(0, mirror_instances_list(&ioctx, &instance_ids));
2222 ASSERT_EQ(1U, instance_ids.size());
2223 ASSERT_EQ(instance_ids[0], "instance_id1");
2224
2225 ASSERT_EQ(0, mirror_instances_add(&ioctx, "instance_id1"));
2226 ASSERT_EQ(0, mirror_instances_add(&ioctx, "instance_id2"));
2227 ASSERT_EQ(0, mirror_instances_list(&ioctx, &instance_ids));
2228 ASSERT_EQ(2U, instance_ids.size());
2229
2230 ASSERT_EQ(0, mirror_instances_remove(&ioctx, "instance_id1"));
2231 ASSERT_EQ(0, mirror_instances_list(&ioctx, &instance_ids));
2232 ASSERT_EQ(1U, instance_ids.size());
2233 ASSERT_EQ(instance_ids[0], "instance_id2");
2234
2235 ASSERT_EQ(0, mirror_instances_remove(&ioctx, "instance_id2"));
2236 ASSERT_EQ(0, mirror_instances_list(&ioctx, &instance_ids));
2237 ASSERT_EQ(0U, instance_ids.size());
2238 }
2239
2240 TEST_F(TestClsRbd, mirror_snapshot) {
2241 librados::IoCtx ioctx;
2242 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2243
2244 string oid = get_temp_image_name();
2245 ASSERT_EQ(0, create_image(&ioctx, oid, 10, 22, 0, oid, -1));
2246
2247 cls::rbd::MirrorSnapshotNamespace primary = {
2248 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"peer1", "peer2"}, "",
2249 CEPH_NOSNAP};
2250 cls::rbd::MirrorSnapshotNamespace non_primary = {
2251 cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {"peer1"}, "uuid", 123};
2252 librados::ObjectWriteOperation op;
2253 ::librbd::cls_client::snapshot_add(&op, 1, "primary", primary);
2254 ::librbd::cls_client::snapshot_add(&op, 2, "non_primary", non_primary);
2255 ASSERT_EQ(0, ioctx.operate(oid, &op));
2256
2257 cls::rbd::SnapshotInfo snap;
2258 ASSERT_EQ(0, snapshot_get(&ioctx, oid, 1, &snap));
2259 auto sn = boost::get<cls::rbd::MirrorSnapshotNamespace>(
2260 &snap.snapshot_namespace);
2261 ASSERT_NE(nullptr, sn);
2262 ASSERT_EQ(primary, *sn);
2263 ASSERT_EQ(2U, sn->mirror_peer_uuids.size());
2264 ASSERT_EQ(1U, sn->mirror_peer_uuids.count("peer1"));
2265 ASSERT_EQ(1U, sn->mirror_peer_uuids.count("peer2"));
2266
2267 ASSERT_EQ(-ENOENT, mirror_image_snapshot_unlink_peer(&ioctx, oid, 1, "peer"));
2268 ASSERT_EQ(0, mirror_image_snapshot_unlink_peer(&ioctx, oid, 1, "peer1"));
2269 ASSERT_EQ(-ENOENT, mirror_image_snapshot_unlink_peer(&ioctx, oid, 1,
2270 "peer1"));
2271 ASSERT_EQ(0, snapshot_get(&ioctx, oid, 1, &snap));
2272 sn = boost::get<cls::rbd::MirrorSnapshotNamespace>(
2273 &snap.snapshot_namespace);
2274 ASSERT_NE(nullptr, sn);
2275 ASSERT_EQ(1U, sn->mirror_peer_uuids.size());
2276 ASSERT_EQ(1U, sn->mirror_peer_uuids.count("peer2"));
2277
2278 ASSERT_EQ(-ERESTART,
2279 mirror_image_snapshot_unlink_peer(&ioctx, oid, 1, "peer2"));
2280 ASSERT_EQ(0, snapshot_get(&ioctx, oid, 1, &snap));
2281 sn = boost::get<cls::rbd::MirrorSnapshotNamespace>(
2282 &snap.snapshot_namespace);
2283 ASSERT_NE(nullptr, sn);
2284 ASSERT_EQ(1U, sn->mirror_peer_uuids.size());
2285 ASSERT_EQ(1U, sn->mirror_peer_uuids.count("peer2"));
2286
2287 ASSERT_EQ(0, snapshot_get(&ioctx, oid, 2, &snap));
2288 auto nsn = boost::get<cls::rbd::MirrorSnapshotNamespace>(
2289 &snap.snapshot_namespace);
2290 ASSERT_NE(nullptr, nsn);
2291 ASSERT_EQ(non_primary, *nsn);
2292 ASSERT_EQ(1U, nsn->mirror_peer_uuids.size());
2293 ASSERT_EQ(1U, nsn->mirror_peer_uuids.count("peer1"));
2294 ASSERT_FALSE(nsn->complete);
2295 ASSERT_EQ(nsn->last_copied_object_number, 0);
2296
2297 ASSERT_EQ(0, mirror_image_snapshot_set_copy_progress(&ioctx, oid, 2, true,
2298 10));
2299 ASSERT_EQ(0, snapshot_get(&ioctx, oid, 2, &snap));
2300 nsn = boost::get<cls::rbd::MirrorSnapshotNamespace>(
2301 &snap.snapshot_namespace);
2302 ASSERT_NE(nullptr, nsn);
2303 ASSERT_TRUE(nsn->complete);
2304 ASSERT_EQ(nsn->last_copied_object_number, 10);
2305
2306 ASSERT_EQ(0, mirror_image_snapshot_unlink_peer(&ioctx, oid, 2, "peer1"));
2307
2308 ASSERT_EQ(0, snapshot_remove(&ioctx, oid, 1));
2309 ASSERT_EQ(0, snapshot_remove(&ioctx, oid, 2));
2310 }
2311
2312 TEST_F(TestClsRbd, group_dir_list) {
2313 librados::IoCtx ioctx;
2314 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2315
2316 string group_id1 = "cgid1";
2317 string group_name1 = "cgname1";
2318 string group_id2 = "cgid2";
2319 string group_name2 = "cgname2";
2320 ASSERT_EQ(0, group_dir_add(&ioctx, RBD_GROUP_DIRECTORY, group_name1, group_id1));
2321 ASSERT_EQ(0, group_dir_add(&ioctx, RBD_GROUP_DIRECTORY, group_name2, group_id2));
2322
2323 map<string, string> cgs;
2324 ASSERT_EQ(0, group_dir_list(&ioctx, RBD_GROUP_DIRECTORY, "", 10, &cgs));
2325
2326 ASSERT_EQ(2U, cgs.size());
2327
2328 auto it = cgs.begin();
2329 ASSERT_EQ(group_id1, it->second);
2330 ASSERT_EQ(group_name1, it->first);
2331
2332 ++it;
2333 ASSERT_EQ(group_id2, it->second);
2334 ASSERT_EQ(group_name2, it->first);
2335 }
2336
2337 void add_group_to_dir(librados::IoCtx ioctx, string group_id, string group_name) {
2338 ASSERT_EQ(0, group_dir_add(&ioctx, RBD_GROUP_DIRECTORY, group_name, group_id));
2339
2340 set<string> keys;
2341 ASSERT_EQ(0, ioctx.omap_get_keys(RBD_GROUP_DIRECTORY, "", 10, &keys));
2342 ASSERT_EQ(2U, keys.size());
2343 ASSERT_EQ("id_" + group_id, *keys.begin());
2344 ASSERT_EQ("name_" + group_name, *keys.rbegin());
2345 }
2346
2347 TEST_F(TestClsRbd, group_dir_add) {
2348 librados::IoCtx ioctx;
2349 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2350 ioctx.remove(RBD_GROUP_DIRECTORY);
2351
2352 string group_id = "cgid";
2353 string group_name = "cgname";
2354 add_group_to_dir(ioctx, group_id, group_name);
2355 }
2356
2357 TEST_F(TestClsRbd, dir_add_already_existing) {
2358 librados::IoCtx ioctx;
2359 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2360 ioctx.remove(RBD_GROUP_DIRECTORY);
2361
2362 string group_id = "cgidexisting";
2363 string group_name = "cgnameexisting";
2364 add_group_to_dir(ioctx, group_id, group_name);
2365
2366 ASSERT_EQ(-EEXIST, group_dir_add(&ioctx, RBD_GROUP_DIRECTORY, group_name, group_id));
2367 }
2368
2369 TEST_F(TestClsRbd, group_dir_rename) {
2370 librados::IoCtx ioctx;
2371 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2372 ioctx.remove(RBD_GROUP_DIRECTORY);
2373
2374 string group_id = "cgid";
2375 string src_name = "cgnamesrc";
2376 string dest_name = "cgnamedest";
2377 add_group_to_dir(ioctx, group_id, src_name);
2378
2379 ASSERT_EQ(0, group_dir_rename(&ioctx, RBD_GROUP_DIRECTORY,
2380 src_name, dest_name, group_id));
2381 map<string, string> cgs;
2382 ASSERT_EQ(0, group_dir_list(&ioctx, RBD_GROUP_DIRECTORY, "", 10, &cgs));
2383 ASSERT_EQ(1U, cgs.size());
2384 auto it = cgs.begin();
2385 ASSERT_EQ(group_id, it->second);
2386 ASSERT_EQ(dest_name, it->first);
2387
2388 // destination group name existing
2389 ASSERT_EQ(-EEXIST, group_dir_rename(&ioctx, RBD_GROUP_DIRECTORY,
2390 dest_name, dest_name, group_id));
2391 ASSERT_EQ(0, group_dir_remove(&ioctx, RBD_GROUP_DIRECTORY, dest_name, group_id));
2392 // source group name missing
2393 ASSERT_EQ(-ENOENT, group_dir_rename(&ioctx, RBD_GROUP_DIRECTORY,
2394 dest_name, src_name, group_id));
2395 }
2396
2397 TEST_F(TestClsRbd, group_dir_remove) {
2398 librados::IoCtx ioctx;
2399 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2400 ioctx.remove(RBD_GROUP_DIRECTORY);
2401
2402 string group_id = "cgidtodel";
2403 string group_name = "cgnametodel";
2404 add_group_to_dir(ioctx, group_id, group_name);
2405
2406 ASSERT_EQ(0, group_dir_remove(&ioctx, RBD_GROUP_DIRECTORY, group_name, group_id));
2407
2408 set<string> keys;
2409 ASSERT_EQ(0, ioctx.omap_get_keys(RBD_GROUP_DIRECTORY, "", 10, &keys));
2410 ASSERT_EQ(0U, keys.size());
2411 }
2412
2413 TEST_F(TestClsRbd, group_dir_remove_missing) {
2414 librados::IoCtx ioctx;
2415 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2416 ioctx.remove(RBD_GROUP_DIRECTORY);
2417
2418 string group_id = "cgidtodelmissing";
2419 string group_name = "cgnametodelmissing";
2420 // These two lines ensure that RBD_GROUP_DIRECTORY exists. It's important for the
2421 // last two lines.
2422 add_group_to_dir(ioctx, group_id, group_name);
2423
2424 ASSERT_EQ(0, group_dir_remove(&ioctx, RBD_GROUP_DIRECTORY, group_name, group_id));
2425
2426 // Removing missing
2427 ASSERT_EQ(-ENOENT, group_dir_remove(&ioctx, RBD_GROUP_DIRECTORY, group_name, group_id));
2428
2429 set<string> keys;
2430 ASSERT_EQ(0, ioctx.omap_get_keys(RBD_GROUP_DIRECTORY, "", 10, &keys));
2431 ASSERT_EQ(0U, keys.size());
2432 }
2433
2434 void test_image_add(librados::IoCtx &ioctx, const string& group_id,
2435 const string& image_id, int64_t pool_id) {
2436
2437 cls::rbd::GroupImageStatus st(image_id, pool_id,
2438 cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE);
2439 ASSERT_EQ(0, group_image_set(&ioctx, group_id, st));
2440
2441 set<string> keys;
2442 ASSERT_EQ(0, ioctx.omap_get_keys(group_id, "", 10, &keys));
2443
2444 auto it = keys.begin();
2445 ASSERT_EQ(1U, keys.size());
2446
2447 string image_key = cls::rbd::GroupImageSpec(image_id, pool_id).image_key();
2448 ASSERT_EQ(image_key, *it);
2449 }
2450
2451 TEST_F(TestClsRbd, group_image_add) {
2452 librados::IoCtx ioctx;
2453 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2454
2455 string group_id = "group_id";
2456 ASSERT_EQ(0, ioctx.create(group_id, true));
2457
2458 int64_t pool_id = ioctx.get_id();
2459 string image_id = "image_id";
2460 test_image_add(ioctx, group_id, image_id, pool_id);
2461 }
2462
2463 TEST_F(TestClsRbd, group_image_remove) {
2464 librados::IoCtx ioctx;
2465 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2466
2467 string group_id = "group_id1";
2468 ASSERT_EQ(0, ioctx.create(group_id, true));
2469
2470 int64_t pool_id = ioctx.get_id();
2471 string image_id = "image_id";
2472 test_image_add(ioctx, group_id, image_id, pool_id);
2473
2474 cls::rbd::GroupImageSpec spec(image_id, pool_id);
2475 ASSERT_EQ(0, group_image_remove(&ioctx, group_id, spec));
2476 set<string> keys;
2477 ASSERT_EQ(0, ioctx.omap_get_keys(group_id, "", 10, &keys));
2478 ASSERT_EQ(0U, keys.size());
2479 }
2480
2481 TEST_F(TestClsRbd, group_image_list) {
2482 librados::IoCtx ioctx;
2483 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2484
2485 string group_id = "group_id2";
2486 ASSERT_EQ(0, ioctx.create(group_id, true));
2487
2488 int64_t pool_id = ioctx.get_id();
2489 string image_id = "imageid"; // Image id shouldn't contain underscores
2490 test_image_add(ioctx, group_id, image_id, pool_id);
2491
2492 vector<cls::rbd::GroupImageStatus> images;
2493 cls::rbd::GroupImageSpec empty_image_spec = cls::rbd::GroupImageSpec();
2494 ASSERT_EQ(0, group_image_list(&ioctx, group_id, empty_image_spec, 1024,
2495 &images));
2496 ASSERT_EQ(1U, images.size());
2497 ASSERT_EQ(image_id, images[0].spec.image_id);
2498 ASSERT_EQ(pool_id, images[0].spec.pool_id);
2499 ASSERT_EQ(cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE, images[0].state);
2500
2501 cls::rbd::GroupImageStatus last_image = *images.rbegin();
2502 ASSERT_EQ(0, group_image_list(&ioctx, group_id, last_image.spec, 1024,
2503 &images));
2504 ASSERT_EQ(0U, images.size());
2505 }
2506
2507 TEST_F(TestClsRbd, group_image_clean) {
2508 librados::IoCtx ioctx;
2509 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2510
2511 string group_id = "group_id3";
2512 ASSERT_EQ(0, ioctx.create(group_id, true));
2513
2514 int64_t pool_id = ioctx.get_id();
2515 string image_id = "image_id";
2516 test_image_add(ioctx, group_id, image_id, pool_id);
2517
2518 cls::rbd::GroupImageStatus incomplete_st(image_id, pool_id,
2519 cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE);
2520
2521 ASSERT_EQ(0, group_image_set(&ioctx, group_id, incomplete_st));
2522 // Set to dirty first in order to make sure that group_image_clean
2523 // actually does something.
2524 cls::rbd::GroupImageStatus attached_st(image_id, pool_id,
2525 cls::rbd::GROUP_IMAGE_LINK_STATE_ATTACHED);
2526 ASSERT_EQ(0, group_image_set(&ioctx, group_id, attached_st));
2527
2528 string image_key = cls::rbd::GroupImageSpec(image_id, pool_id).image_key();
2529
2530 map<string, bufferlist> vals;
2531 ASSERT_EQ(0, ioctx.omap_get_vals(group_id, "", 10, &vals));
2532
2533 cls::rbd::GroupImageLinkState ref_state;
2534 auto it = vals[image_key].cbegin();
2535 decode(ref_state, it);
2536 ASSERT_EQ(cls::rbd::GROUP_IMAGE_LINK_STATE_ATTACHED, ref_state);
2537 }
2538
2539 TEST_F(TestClsRbd, image_group_add) {
2540 librados::IoCtx ioctx;
2541 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2542
2543 int64_t pool_id = ioctx.get_id();
2544 string image_id = "imageid";
2545
2546 ASSERT_EQ(0, create_image(&ioctx, image_id, 2<<20, 0,
2547 RBD_FEATURE_LAYERING, image_id, -1));
2548
2549 string group_id = "group_id";
2550
2551 cls::rbd::GroupSpec spec(group_id, pool_id);
2552 ASSERT_EQ(0, image_group_add(&ioctx, image_id, spec));
2553
2554 map<string, bufferlist> vals;
2555 ASSERT_EQ(0, ioctx.omap_get_vals(image_id, "", RBD_GROUP_REF, 10, &vals));
2556
2557 cls::rbd::GroupSpec val_spec;
2558 auto it = vals[RBD_GROUP_REF].cbegin();
2559 decode(val_spec, it);
2560
2561 ASSERT_EQ(group_id, val_spec.group_id);
2562 ASSERT_EQ(pool_id, val_spec.pool_id);
2563 }
2564
2565 TEST_F(TestClsRbd, image_group_remove) {
2566 librados::IoCtx ioctx;
2567 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2568
2569 int64_t pool_id = ioctx.get_id();
2570 string image_id = "image_id";
2571
2572 ASSERT_EQ(0, create_image(&ioctx, image_id, 2<<20, 0,
2573 RBD_FEATURE_LAYERING, image_id, -1));
2574
2575 string group_id = "group_id";
2576
2577 cls::rbd::GroupSpec spec(group_id, pool_id);
2578 ASSERT_EQ(0, image_group_add(&ioctx, image_id, spec));
2579 // Add reference in order to make sure that image_group_remove actually
2580 // does something.
2581 ASSERT_EQ(0, image_group_remove(&ioctx, image_id, spec));
2582
2583 map<string, bufferlist> vals;
2584 ASSERT_EQ(0, ioctx.omap_get_vals(image_id, "", RBD_GROUP_REF, 10, &vals));
2585
2586 ASSERT_EQ(0U, vals.size());
2587 }
2588
2589 TEST_F(TestClsRbd, image_group_get) {
2590 librados::IoCtx ioctx;
2591 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2592
2593 int64_t pool_id = ioctx.get_id();
2594 string image_id = "imageidgroupspec";
2595
2596 ASSERT_EQ(0, create_image(&ioctx, image_id, 2<<20, 0,
2597 RBD_FEATURE_LAYERING, image_id, -1));
2598
2599 string group_id = "group_id_get_group_spec";
2600
2601 cls::rbd::GroupSpec spec_add(group_id, pool_id);
2602 ASSERT_EQ(0, image_group_add(&ioctx, image_id, spec_add));
2603
2604 cls::rbd::GroupSpec spec;
2605 ASSERT_EQ(0, image_group_get(&ioctx, image_id, &spec));
2606
2607 ASSERT_EQ(group_id, spec.group_id);
2608 ASSERT_EQ(pool_id, spec.pool_id);
2609 }
2610
2611 TEST_F(TestClsRbd, group_snap_set_empty_name) {
2612 librados::IoCtx ioctx;
2613 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2614
2615 string image_id = "image_id_snap_add_emtpy_name";
2616
2617 string group_id = "group_id_snap_add_empty_name";
2618 ASSERT_EQ(0, ioctx.create(group_id, true));
2619
2620 string snap_id = "snap_id";
2621 cls::rbd::GroupSnapshot snap = {snap_id, "", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
2622 ASSERT_EQ(-EINVAL, group_snap_set(&ioctx, group_id, snap));
2623 }
2624
2625 TEST_F(TestClsRbd, group_snap_set_empty_id) {
2626 librados::IoCtx ioctx;
2627 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2628
2629 string image_id = "image_id_snap_add_empty_id";
2630
2631 string group_id = "group_id_snap_add_empty_id";
2632 ASSERT_EQ(0, ioctx.create(group_id, true));
2633
2634 string snap_id = "snap_id";
2635 cls::rbd::GroupSnapshot snap = {"", "snap_name", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
2636 ASSERT_EQ(-EINVAL, group_snap_set(&ioctx, group_id, snap));
2637 }
2638
2639 TEST_F(TestClsRbd, group_snap_set_duplicate_id) {
2640 librados::IoCtx ioctx;
2641 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2642
2643 string image_id = "image_id_snap_add_duplicate_id";
2644
2645 string group_id = "group_id_snap_add_duplicate_id";
2646 ASSERT_EQ(0, ioctx.create(group_id, true));
2647
2648 string snap_id = "snap_id";
2649 cls::rbd::GroupSnapshot snap = {snap_id, "snap_name", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
2650 ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
2651
2652 cls::rbd::GroupSnapshot snap1 = {snap_id, "snap_name1", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
2653 ASSERT_EQ(-EEXIST, group_snap_set(&ioctx, group_id, snap1));
2654 }
2655
2656 TEST_F(TestClsRbd, group_snap_set_duplicate_name) {
2657 librados::IoCtx ioctx;
2658 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2659
2660 string image_id = "image_id_snap_add_duplicate_name";
2661
2662 string group_id = "group_id_snap_add_duplicate_name";
2663 ASSERT_EQ(0, ioctx.create(group_id, true));
2664
2665 string snap_id1 = "snap_id1";
2666 cls::rbd::GroupSnapshot snap = {snap_id1, "snap_name", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
2667 ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
2668
2669 string snap_id2 = "snap_id2";
2670 cls::rbd::GroupSnapshot snap1 = {snap_id2, "snap_name", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
2671 ASSERT_EQ(-EEXIST, group_snap_set(&ioctx, group_id, snap1));
2672 }
2673
2674 TEST_F(TestClsRbd, group_snap_set) {
2675 librados::IoCtx ioctx;
2676 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2677
2678 string image_id = "image_id_snap_add";
2679
2680 string group_id = "group_id_snap_add";
2681 ASSERT_EQ(0, ioctx.create(group_id, true));
2682
2683 string snap_id = "snap_id";
2684 cls::rbd::GroupSnapshot snap = {snap_id, "test_snapshot", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
2685 ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
2686
2687 set<string> keys;
2688 ASSERT_EQ(0, ioctx.omap_get_keys(group_id, "", 10, &keys));
2689
2690 auto it = keys.begin();
2691 ASSERT_EQ(1U, keys.size());
2692
2693 string snap_key = "snapshot_" + stringify(snap.id);
2694 ASSERT_EQ(snap_key, *it);
2695 }
2696
2697 TEST_F(TestClsRbd, group_snap_list) {
2698 librados::IoCtx ioctx;
2699 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2700
2701 string image_id = "image_id_snap_list";
2702
2703 string group_id = "group_id_snap_list";
2704 ASSERT_EQ(0, ioctx.create(group_id, true));
2705
2706 string snap_id1 = "snap_id1";
2707 cls::rbd::GroupSnapshot snap1 = {snap_id1, "test_snapshot1", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
2708 ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap1));
2709
2710 string snap_id2 = "snap_id2";
2711 cls::rbd::GroupSnapshot snap2 = {snap_id2, "test_snapshot2", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
2712 ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap2));
2713
2714 std::vector<cls::rbd::GroupSnapshot> snapshots;
2715 ASSERT_EQ(0, group_snap_list(&ioctx, group_id, cls::rbd::GroupSnapshot(), 10, &snapshots));
2716 ASSERT_EQ(2U, snapshots.size());
2717 ASSERT_EQ(snap_id1, snapshots[0].id);
2718 ASSERT_EQ(snap_id2, snapshots[1].id);
2719 }
2720
2721 static std::string hexify(int v) {
2722 ostringstream oss;
2723 oss << std::setw(8) << std::setfill('0') << std::hex << v;
2724 //oss << v;
2725 return oss.str();
2726 }
2727
2728 TEST_F(TestClsRbd, group_snap_list_max_return) {
2729 librados::IoCtx ioctx;
2730 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2731
2732 string image_id = "image_id_snap_list_max_return";
2733
2734 string group_id = "group_id_snap_list_max_return";
2735 ASSERT_EQ(0, ioctx.create(group_id, true));
2736
2737 for (int i = 0; i < 15; ++i) {
2738 string snap_id = "snap_id" + hexify(i);
2739 cls::rbd::GroupSnapshot snap = {snap_id,
2740 "test_snapshot" + hexify(i),
2741 cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
2742 ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
2743 }
2744
2745 std::vector<cls::rbd::GroupSnapshot> snapshots;
2746 ASSERT_EQ(0, group_snap_list(&ioctx, group_id, cls::rbd::GroupSnapshot(), 10, &snapshots));
2747 ASSERT_EQ(10U, snapshots.size());
2748
2749 for (int i = 0; i < 10; ++i) {
2750 string snap_id = "snap_id" + hexify(i);
2751 ASSERT_EQ(snap_id, snapshots[i].id);
2752 }
2753
2754 cls::rbd::GroupSnapshot last_snap = *snapshots.rbegin();
2755
2756 ASSERT_EQ(0, group_snap_list(&ioctx, group_id, last_snap, 10, &snapshots));
2757 ASSERT_EQ(5U, snapshots.size());
2758 for (int i = 10; i < 15; ++i) {
2759 string snap_id = "snap_id" + hexify(i);
2760 ASSERT_EQ(snap_id, snapshots[i - 10].id);
2761 }
2762 }
2763
2764 TEST_F(TestClsRbd, group_snap_remove) {
2765 librados::IoCtx ioctx;
2766
2767 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2768
2769 string image_id = "image_id_snap_remove";
2770
2771 string group_id = "group_id_snap_remove";
2772 ASSERT_EQ(0, ioctx.create(group_id, true));
2773
2774 string snap_id = "snap_id";
2775 cls::rbd::GroupSnapshot snap = {snap_id, "test_snapshot", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
2776 ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
2777
2778 set<string> keys;
2779 ASSERT_EQ(0, ioctx.omap_get_keys(group_id, "", 10, &keys));
2780
2781 auto it = keys.begin();
2782 ASSERT_EQ(1U, keys.size());
2783
2784 string snap_key = "snapshot_" + stringify(snap.id);
2785 ASSERT_EQ(snap_key, *it);
2786
2787 // Remove the snapshot
2788
2789 ASSERT_EQ(0, group_snap_remove(&ioctx, group_id, snap_id));
2790
2791 ASSERT_EQ(0, ioctx.omap_get_keys(group_id, "", 10, &keys));
2792
2793 ASSERT_EQ(0U, keys.size());
2794 }
2795
2796 TEST_F(TestClsRbd, group_snap_get_by_id) {
2797 librados::IoCtx ioctx;
2798
2799 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2800
2801 string image_id = "image_id_snap_get_by_id";
2802
2803 string group_id = "group_id_snap_get_by_id";
2804 ASSERT_EQ(0, ioctx.create(group_id, true));
2805
2806 string snap_id = "snap_id";
2807 cls::rbd::GroupSnapshot snap = {snap_id,
2808 "test_snapshot",
2809 cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE};
2810 ASSERT_EQ(0, group_snap_set(&ioctx, group_id, snap));
2811
2812 cls::rbd::GroupSnapshot received_snap;
2813 ASSERT_EQ(0, group_snap_get_by_id(&ioctx, group_id, snap_id, &received_snap));
2814
2815 ASSERT_EQ(snap.id, received_snap.id);
2816 ASSERT_EQ(snap.name, received_snap.name);
2817 ASSERT_EQ(snap.state, received_snap.state);
2818 }
2819
2820 TEST_F(TestClsRbd, trash_methods)
2821 {
2822 librados::IoCtx ioctx;
2823 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2824
2825 string id = "123456789";
2826 string id2 = "123456780";
2827
2828 std::map<string, cls::rbd::TrashImageSpec> entries;
2829 ASSERT_EQ(-ENOENT, trash_list(&ioctx, "", 1024, &entries));
2830
2831 utime_t now1 = ceph_clock_now();
2832 utime_t now1_delay = now1;
2833 now1_delay += 380;
2834 cls::rbd::TrashImageSpec trash_spec(cls::rbd::TRASH_IMAGE_SOURCE_USER, "name",
2835 now1, now1_delay);
2836 ASSERT_EQ(0, trash_add(&ioctx, id, trash_spec));
2837
2838 utime_t now2 = ceph_clock_now();
2839 utime_t now2_delay = now2;
2840 now2_delay += 480;
2841 cls::rbd::TrashImageSpec trash_spec2(cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING,
2842 "name2", now2, now2_delay);
2843 ASSERT_EQ(-EEXIST, trash_add(&ioctx, id, trash_spec2));
2844
2845 ASSERT_EQ(0, trash_remove(&ioctx, id));
2846 ASSERT_EQ(-ENOENT, trash_remove(&ioctx, id));
2847
2848 ASSERT_EQ(0, trash_list(&ioctx, "", 1024, &entries));
2849 ASSERT_TRUE(entries.empty());
2850
2851 ASSERT_EQ(0, trash_add(&ioctx, id, trash_spec2));
2852 ASSERT_EQ(0, trash_add(&ioctx, id2, trash_spec));
2853
2854 ASSERT_EQ(0, trash_list(&ioctx, "", 1, &entries));
2855 ASSERT_TRUE(entries.find(id2) != entries.end());
2856 ASSERT_EQ(cls::rbd::TRASH_IMAGE_SOURCE_USER, entries[id2].source);
2857 ASSERT_EQ(std::string("name"), entries[id2].name);
2858 ASSERT_EQ(now1, entries[id2].deletion_time);
2859 ASSERT_EQ(now1_delay, entries[id2].deferment_end_time);
2860
2861 ASSERT_EQ(0, trash_list(&ioctx, id2, 1, &entries));
2862 ASSERT_TRUE(entries.find(id) != entries.end());
2863 ASSERT_EQ(cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING, entries[id].source);
2864 ASSERT_EQ(std::string("name2"), entries[id].name);
2865 ASSERT_EQ(now2, entries[id].deletion_time);
2866 ASSERT_EQ(now2_delay, entries[id].deferment_end_time);
2867
2868 ASSERT_EQ(0, trash_list(&ioctx, id, 1, &entries));
2869 ASSERT_TRUE(entries.empty());
2870
2871 cls::rbd::TrashImageSpec spec_res1;
2872 ASSERT_EQ(0, trash_get(&ioctx, id, &spec_res1));
2873 cls::rbd::TrashImageSpec spec_res2;
2874 ASSERT_EQ(0, trash_get(&ioctx, id2, &spec_res2));
2875
2876 ASSERT_EQ(spec_res1.name, "name2");
2877 ASSERT_EQ(spec_res1.deletion_time, now2);
2878 ASSERT_EQ(spec_res1.deferment_end_time, now2_delay);
2879
2880 ASSERT_EQ(spec_res2.name, "name");
2881 ASSERT_EQ(spec_res2.deletion_time, now1);
2882 ASSERT_EQ(spec_res2.deferment_end_time, now1_delay);
2883
2884 ioctx.close();
2885 }
2886
2887 TEST_F(TestClsRbd, op_features)
2888 {
2889 librados::IoCtx ioctx;
2890 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2891
2892 string oid = get_temp_image_name();
2893 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, 0, oid, -1));
2894
2895 uint64_t op_features = RBD_OPERATION_FEATURE_CLONE_PARENT;
2896 uint64_t mask = ~RBD_OPERATION_FEATURES_ALL;
2897 ASSERT_EQ(-EINVAL, op_features_set(&ioctx, oid, op_features, mask));
2898
2899 mask = 0;
2900 ASSERT_EQ(0, op_features_set(&ioctx, oid, op_features, mask));
2901
2902 uint64_t actual_op_features;
2903 ASSERT_EQ(0, op_features_get(&ioctx, oid, &actual_op_features));
2904 ASSERT_EQ(0u, actual_op_features);
2905
2906 uint64_t features;
2907 uint64_t incompatible_features;
2908 ASSERT_EQ(0, get_features(&ioctx, oid, true, &features,
2909 &incompatible_features));
2910 ASSERT_EQ(0u, features);
2911
2912 op_features = RBD_OPERATION_FEATURES_ALL;
2913 mask = RBD_OPERATION_FEATURES_ALL;
2914 ASSERT_EQ(0, op_features_set(&ioctx, oid, op_features, mask));
2915 ASSERT_EQ(0, op_features_get(&ioctx, oid, &actual_op_features));
2916 ASSERT_EQ(mask, actual_op_features);
2917
2918 ASSERT_EQ(0, get_features(&ioctx, oid, true, &features,
2919 &incompatible_features));
2920 ASSERT_EQ(RBD_FEATURE_OPERATIONS, features);
2921
2922 op_features = 0;
2923 mask = RBD_OPERATION_FEATURE_CLONE_PARENT;
2924 ASSERT_EQ(0, op_features_set(&ioctx, oid, op_features, mask));
2925 ASSERT_EQ(0, op_features_get(&ioctx, oid, &actual_op_features));
2926
2927 uint64_t expected_op_features = RBD_OPERATION_FEATURES_ALL &
2928 ~RBD_OPERATION_FEATURE_CLONE_PARENT;
2929 ASSERT_EQ(expected_op_features, actual_op_features);
2930
2931 mask = RBD_OPERATION_FEATURES_ALL;
2932 ASSERT_EQ(0, op_features_set(&ioctx, oid, op_features, mask));
2933 ASSERT_EQ(0, get_features(&ioctx, oid, true, &features,
2934 &incompatible_features));
2935 ASSERT_EQ(0u, features);
2936 }
2937
2938 TEST_F(TestClsRbd, clone_parent)
2939 {
2940 librados::IoCtx ioctx;
2941 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
2942
2943 string oid = get_temp_image_name();
2944 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, 0, oid, -1));
2945 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 123, "user_snap"));
2946
2947 ASSERT_EQ(-ENOENT, child_attach(&ioctx, oid, 345, {}));
2948 ASSERT_EQ(-ENOENT, child_detach(&ioctx, oid, 123, {}));
2949 ASSERT_EQ(-ENOENT, child_detach(&ioctx, oid, 345, {}));
2950
2951 ASSERT_EQ(0, child_attach(&ioctx, oid, 123, {1, "", "image1"}));
2952 ASSERT_EQ(-EEXIST, child_attach(&ioctx, oid, 123, {1, "", "image1"}));
2953 ASSERT_EQ(0, child_attach(&ioctx, oid, 123, {1, "", "image2"}));
2954 ASSERT_EQ(0, child_attach(&ioctx, oid, 123, {2, "", "image2"}));
2955
2956 cls::rbd::SnapshotInfo snap;
2957 ASSERT_EQ(0, snapshot_get(&ioctx, oid, 123, &snap));
2958 ASSERT_EQ(3U, snap.child_count);
2959
2960 // op feature should have been enabled
2961 uint64_t op_features;
2962 uint64_t expected_op_features = RBD_OPERATION_FEATURE_CLONE_PARENT;
2963 ASSERT_EQ(0, op_features_get(&ioctx, oid, &op_features));
2964 ASSERT_TRUE((op_features & expected_op_features) == expected_op_features);
2965
2966 // cannot attach to trashed snapshot
2967 librados::ObjectWriteOperation op1;
2968 ::librbd::cls_client::snapshot_add(&op1, 234, "trash_snap",
2969 cls::rbd::UserSnapshotNamespace());
2970 ASSERT_EQ(0, ioctx.operate(oid, &op1));
2971 librados::ObjectWriteOperation op2;
2972 ::librbd::cls_client::snapshot_trash_add(&op2, 234);
2973 ASSERT_EQ(0, ioctx.operate(oid, &op2));
2974 ASSERT_EQ(-ENOENT, child_attach(&ioctx, oid, 234, {}));
2975
2976 cls::rbd::ChildImageSpecs child_images;
2977 ASSERT_EQ(0, children_list(&ioctx, oid, 123, &child_images));
2978
2979 cls::rbd::ChildImageSpecs expected_child_images = {
2980 {1, "", "image1"}, {1, "", "image2"}, {2, "", "image2"}};
2981 ASSERT_EQ(expected_child_images, child_images);
2982
2983 // move snapshot to the trash
2984 ASSERT_EQ(-EBUSY, snapshot_remove(&ioctx, oid, 123));
2985 librados::ObjectWriteOperation op3;
2986 ::librbd::cls_client::snapshot_trash_add(&op3, 123);
2987 ASSERT_EQ(0, ioctx.operate(oid, &op3));
2988 ASSERT_EQ(0, snapshot_get(&ioctx, oid, 123, &snap));
2989 ASSERT_EQ(cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH,
2990 cls::rbd::get_snap_namespace_type(snap.snapshot_namespace));
2991
2992 expected_op_features |= RBD_OPERATION_FEATURE_SNAP_TRASH;
2993 ASSERT_EQ(0, op_features_get(&ioctx, oid, &op_features));
2994 ASSERT_TRUE((op_features & expected_op_features) == expected_op_features);
2995
2996 expected_child_images = {{1, "", "image1"}, {2, "", "image2"}};
2997 ASSERT_EQ(0, child_detach(&ioctx, oid, 123, {1, "", "image2"}));
2998 ASSERT_EQ(0, children_list(&ioctx, oid, 123, &child_images));
2999 ASSERT_EQ(expected_child_images, child_images);
3000
3001 ASSERT_EQ(0, child_detach(&ioctx, oid, 123, {2, "", "image2"}));
3002
3003 ASSERT_EQ(0, op_features_get(&ioctx, oid, &op_features));
3004 ASSERT_TRUE((op_features & expected_op_features) == expected_op_features);
3005
3006 ASSERT_EQ(0, child_detach(&ioctx, oid, 123, {1, "", "image1"}));
3007 ASSERT_EQ(-ENOENT, children_list(&ioctx, oid, 123, &child_images));
3008
3009 ASSERT_EQ(0, snapshot_remove(&ioctx, oid, 234));
3010 ASSERT_EQ(0, op_features_get(&ioctx, oid, &op_features));
3011 ASSERT_TRUE((op_features & expected_op_features) ==
3012 RBD_OPERATION_FEATURE_SNAP_TRASH);
3013
3014 ASSERT_EQ(0, snapshot_remove(&ioctx, oid, 123));
3015 ASSERT_EQ(0, op_features_get(&ioctx, oid, &op_features));
3016 ASSERT_TRUE((op_features & expected_op_features) == 0);
3017 }
3018
3019 TEST_F(TestClsRbd, clone_parent_ns)
3020 {
3021 librados::IoCtx ioctx;
3022 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
3023
3024 string oid = get_temp_image_name();
3025 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, 0, oid, -1));
3026 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 123, "user_snap"));
3027
3028 ASSERT_EQ(0, child_attach(&ioctx, oid, 123, {1, "ns1", "image1"}));
3029 ASSERT_EQ(-EEXIST, child_attach(&ioctx, oid, 123, {1, "ns1", "image1"}));
3030 ASSERT_EQ(0, child_attach(&ioctx, oid, 123, {1, "ns2", "image1"}));
3031
3032 cls::rbd::ChildImageSpecs child_images;
3033 ASSERT_EQ(0, children_list(&ioctx, oid, 123, &child_images));
3034
3035 cls::rbd::ChildImageSpecs expected_child_images = {
3036 {1, "ns1", "image1"}, {1, "ns2", "image1"}};
3037 ASSERT_EQ(expected_child_images, child_images);
3038
3039 expected_child_images = {{1, "ns1", "image1"}};
3040 ASSERT_EQ(0, child_detach(&ioctx, oid, 123, {1, "ns2", "image1"}));
3041 ASSERT_EQ(0, children_list(&ioctx, oid, 123, &child_images));
3042 ASSERT_EQ(expected_child_images, child_images);
3043
3044 ASSERT_EQ(0, child_detach(&ioctx, oid, 123, {1, "ns1", "image1"}));
3045 ASSERT_EQ(-ENOENT, children_list(&ioctx, oid, 123, &child_images));
3046
3047 ASSERT_EQ(0, snapshot_remove(&ioctx, oid, 123));
3048 }
3049
3050 TEST_F(TestClsRbd, clone_child)
3051 {
3052 librados::IoCtx ioctx;
3053 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
3054
3055 string oid = get_temp_image_name();
3056 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22,
3057 RBD_FEATURE_LAYERING | RBD_FEATURE_DEEP_FLATTEN,
3058 oid, -1));
3059 ASSERT_EQ(0, set_parent(&ioctx, oid, {1, "", "parent", 2}, 1));
3060 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 123, "user_snap1"));
3061 ASSERT_EQ(0, op_features_set(&ioctx, oid, RBD_OPERATION_FEATURE_CLONE_CHILD,
3062 RBD_OPERATION_FEATURE_CLONE_CHILD));
3063
3064 // clone child should be disabled due to deep flatten
3065 ASSERT_EQ(0, remove_parent(&ioctx, oid));
3066 uint64_t op_features;
3067 ASSERT_EQ(0, op_features_get(&ioctx, oid, &op_features));
3068 ASSERT_TRUE((op_features & RBD_OPERATION_FEATURE_CLONE_CHILD) == 0ULL);
3069
3070 ASSERT_EQ(0, set_features(&ioctx, oid, 0, RBD_FEATURE_DEEP_FLATTEN));
3071 ASSERT_EQ(0, set_parent(&ioctx, oid, {1, "", "parent", 2}, 1));
3072 ASSERT_EQ(0, snapshot_add(&ioctx, oid, 124, "user_snap2"));
3073 ASSERT_EQ(0, op_features_set(&ioctx, oid, RBD_OPERATION_FEATURE_CLONE_CHILD,
3074 RBD_OPERATION_FEATURE_CLONE_CHILD));
3075
3076 // clone child should remain enabled w/o deep flatten
3077 ASSERT_EQ(0, remove_parent(&ioctx, oid));
3078 ASSERT_EQ(0, op_features_get(&ioctx, oid, &op_features));
3079 ASSERT_TRUE((op_features & RBD_OPERATION_FEATURE_CLONE_CHILD) ==
3080 RBD_OPERATION_FEATURE_CLONE_CHILD);
3081
3082 // ... but removing the last linked snapshot should disable it
3083 ASSERT_EQ(0, snapshot_remove(&ioctx, oid, 124));
3084 ASSERT_EQ(0, op_features_get(&ioctx, oid, &op_features));
3085 ASSERT_TRUE((op_features & RBD_OPERATION_FEATURE_CLONE_CHILD) == 0ULL);
3086 }
3087
3088 TEST_F(TestClsRbd, namespace_methods)
3089 {
3090 librados::IoCtx ioctx;
3091 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
3092
3093 string name1 = "123456789";
3094 string name2 = "123456780";
3095
3096 std::list<std::string> entries;
3097 ASSERT_EQ(-ENOENT, namespace_list(&ioctx, "", 1024, &entries));
3098
3099 ASSERT_EQ(0, namespace_add(&ioctx, name1));
3100 ASSERT_EQ(-EEXIST, namespace_add(&ioctx, name1));
3101
3102 ASSERT_EQ(0, namespace_remove(&ioctx, name1));
3103 ASSERT_EQ(-ENOENT, namespace_remove(&ioctx, name1));
3104
3105 ASSERT_EQ(0, namespace_list(&ioctx, "", 1024, &entries));
3106 ASSERT_TRUE(entries.empty());
3107
3108 ASSERT_EQ(0, namespace_add(&ioctx, name1));
3109 ASSERT_EQ(0, namespace_add(&ioctx, name2));
3110
3111 ASSERT_EQ(0, namespace_list(&ioctx, "", 1, &entries));
3112 ASSERT_EQ(1U, entries.size());
3113 ASSERT_EQ(name2, entries.front());
3114
3115 ASSERT_EQ(0, namespace_list(&ioctx, name2, 1, &entries));
3116 ASSERT_EQ(1U, entries.size());
3117 ASSERT_EQ(name1, entries.front());
3118
3119 ASSERT_EQ(0, namespace_list(&ioctx, name1, 1, &entries));
3120 ASSERT_TRUE(entries.empty());
3121 }
3122
3123 TEST_F(TestClsRbd, migration)
3124 {
3125 librados::IoCtx ioctx;
3126 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
3127
3128 string oid = get_temp_image_name();
3129 ASSERT_EQ(0, create_image(&ioctx, oid, 0, 22, 0, oid, -1));
3130
3131 cls::rbd::MigrationSpec migration_spec(cls::rbd::MIGRATION_HEADER_TYPE_DST,
3132 -1, "", "", "",
3133 "{\"format\": \"raw\"}", {}, 0, false,
3134 cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
3135 false,
3136 cls::rbd::MIGRATION_STATE_PREPARING,
3137 "123");
3138 cls::rbd::MigrationSpec read_migration_spec;
3139
3140 ASSERT_EQ(-EINVAL, migration_get(&ioctx, oid, &read_migration_spec));
3141
3142 uint64_t features;
3143 uint64_t incompatible_features;
3144 ASSERT_EQ(0, get_features(&ioctx, oid, CEPH_NOSNAP, &features,
3145 &incompatible_features));
3146 ASSERT_EQ(0U, features);
3147
3148 ASSERT_EQ(0, migration_set(&ioctx, oid, migration_spec));
3149 ASSERT_EQ(0, migration_get(&ioctx, oid, &read_migration_spec));
3150 ASSERT_EQ(migration_spec, read_migration_spec);
3151
3152 ASSERT_EQ(0, get_features(&ioctx, oid, CEPH_NOSNAP, &features,
3153 &incompatible_features));
3154 ASSERT_EQ(RBD_FEATURE_MIGRATING, features);
3155
3156 ASSERT_EQ(-EEXIST, migration_set(&ioctx, oid, migration_spec));
3157
3158 migration_spec.state = cls::rbd::MIGRATION_STATE_PREPARED;
3159 migration_spec.state_description = "456";
3160 ASSERT_EQ(0, migration_set_state(&ioctx, oid, migration_spec.state,
3161 migration_spec.state_description));
3162 ASSERT_EQ(0, migration_get(&ioctx, oid, &read_migration_spec));
3163 ASSERT_EQ(migration_spec, read_migration_spec);
3164
3165 ASSERT_EQ(0, migration_remove(&ioctx, oid));
3166
3167 ASSERT_EQ(0, get_features(&ioctx, oid, CEPH_NOSNAP, &features,
3168 &incompatible_features));
3169 ASSERT_EQ(0U, features);
3170
3171 ASSERT_EQ(-EINVAL, migration_get(&ioctx, oid, &read_migration_spec));
3172 ASSERT_EQ(-EINVAL, migration_set_state(&ioctx, oid, migration_spec.state,
3173 migration_spec.state_description));
3174
3175 migration_spec.header_type = cls::rbd::MIGRATION_HEADER_TYPE_SRC;
3176
3177 ASSERT_EQ(0, migration_set(&ioctx, oid, migration_spec));
3178
3179 ASSERT_EQ(0, get_features(&ioctx, oid, CEPH_NOSNAP, &features,
3180 &incompatible_features));
3181 ASSERT_EQ(RBD_FEATURE_MIGRATING, features);
3182
3183 ASSERT_EQ(0, migration_remove(&ioctx, oid));
3184
3185 ASSERT_EQ(-EINVAL, migration_get(&ioctx, oid, &read_migration_spec));
3186 ASSERT_EQ(0, get_features(&ioctx, oid, CEPH_NOSNAP, &features,
3187 &incompatible_features));
3188 ASSERT_EQ(0U, features);
3189
3190 ioctx.close();
3191 }
3192
3193 TEST_F(TestClsRbd, migration_v1)
3194 {
3195 librados::IoCtx ioctx;
3196 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
3197
3198 bufferlist header;
3199 header.append(RBD_HEADER_TEXT, sizeof(RBD_HEADER_TEXT));
3200 string oid = get_temp_image_name();
3201 ASSERT_EQ(0, ioctx.write(oid, header, header.length(), 0));
3202
3203 cls::rbd::MigrationSpec migration_spec(cls::rbd::MIGRATION_HEADER_TYPE_DST, 1,
3204 "name", "ns", "id", "", {}, 0, false,
3205 cls::rbd::MIRROR_IMAGE_MODE_JOURNAL,
3206 false,
3207 cls::rbd::MIGRATION_STATE_PREPARING,
3208 "123");
3209 cls::rbd::MigrationSpec read_migration_spec;
3210
3211 ASSERT_EQ(-EINVAL, migration_get(&ioctx, oid, &read_migration_spec));
3212
3213 // v1 format image can only be migration source
3214 ASSERT_EQ(-EINVAL, migration_set(&ioctx, oid, migration_spec));
3215
3216 migration_spec.header_type = cls::rbd::MIGRATION_HEADER_TYPE_SRC;
3217 ASSERT_EQ(0, migration_set(&ioctx, oid, migration_spec));
3218
3219 ASSERT_EQ(0, migration_get(&ioctx, oid, &read_migration_spec));
3220 ASSERT_EQ(migration_spec, read_migration_spec);
3221
3222 header.clear();
3223 ASSERT_EQ(static_cast<int>(sizeof(RBD_MIGRATE_HEADER_TEXT)),
3224 ioctx.read(oid, header, sizeof(RBD_MIGRATE_HEADER_TEXT), 0));
3225 ASSERT_STREQ(RBD_MIGRATE_HEADER_TEXT, header.c_str());
3226
3227 ASSERT_EQ(-EEXIST, migration_set(&ioctx, oid, migration_spec));
3228
3229 migration_spec.state = cls::rbd::MIGRATION_STATE_PREPARED;
3230 migration_spec.state_description = "456";
3231 ASSERT_EQ(0, migration_set_state(&ioctx, oid, migration_spec.state,
3232 migration_spec.state_description));
3233 ASSERT_EQ(0, migration_get(&ioctx, oid, &read_migration_spec));
3234 ASSERT_EQ(migration_spec, read_migration_spec);
3235
3236 ASSERT_EQ(0, migration_remove(&ioctx, oid));
3237
3238 ASSERT_EQ(-EINVAL, migration_get(&ioctx, oid, &read_migration_spec));
3239 ASSERT_EQ(-EINVAL, migration_set_state(&ioctx, oid, migration_spec.state,
3240 migration_spec.state_description));
3241 header.clear();
3242 ASSERT_EQ(static_cast<int>(sizeof(RBD_HEADER_TEXT)),
3243 ioctx.read(oid, header, sizeof(RBD_HEADER_TEXT), 0));
3244 ASSERT_STREQ(RBD_HEADER_TEXT, header.c_str());
3245
3246 ioctx.close();
3247 }
3248
3249 TEST_F(TestClsRbd, assert_snapc_seq)
3250 {
3251 librados::IoCtx ioctx;
3252 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
3253
3254 string oid = get_temp_image_name();
3255
3256 ASSERT_EQ(0,
3257 assert_snapc_seq(&ioctx, oid, 0,
3258 cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ));
3259 ASSERT_EQ(-ERANGE,
3260 assert_snapc_seq(&ioctx, oid, 0,
3261 cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ));
3262
3263 ASSERT_EQ(0, ioctx.create(oid, true));
3264
3265 uint64_t snapc_seq = 0;
3266
3267 ASSERT_EQ(-ERANGE,
3268 assert_snapc_seq(&ioctx, oid, snapc_seq,
3269 cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ));
3270 ASSERT_EQ(0,
3271 assert_snapc_seq(&ioctx, oid, snapc_seq,
3272 cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ));
3273
3274 std::vector<uint64_t> snaps;
3275 snaps.push_back(CEPH_NOSNAP);
3276 ASSERT_EQ(0, ioctx.selfmanaged_snap_create(&snaps.back()));
3277 snapc_seq = snaps[0];
3278
3279 ASSERT_EQ(0,
3280 assert_snapc_seq(&ioctx, oid, snapc_seq,
3281 cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ));
3282 ASSERT_EQ(-ERANGE,
3283 assert_snapc_seq(&ioctx, oid, snapc_seq,
3284 cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ));
3285
3286 ASSERT_EQ(0, ioctx.selfmanaged_snap_set_write_ctx(snaps[0], snaps));
3287 bufferlist bl;
3288 bl.append("foo");
3289 ASSERT_EQ(0, ioctx.write(oid, bl, bl.length(), 0));
3290
3291 ASSERT_EQ(-ERANGE,
3292 assert_snapc_seq(&ioctx, oid, snapc_seq,
3293 cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ));
3294 ASSERT_EQ(0,
3295 assert_snapc_seq(&ioctx, oid, snapc_seq,
3296 cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ));
3297
3298 ASSERT_EQ(0,
3299 assert_snapc_seq(&ioctx, oid, snapc_seq + 1,
3300 cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ));
3301 ASSERT_EQ(-ERANGE,
3302 assert_snapc_seq(&ioctx, oid, snapc_seq + 1,
3303 cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ));
3304
3305 ASSERT_EQ(0, ioctx.selfmanaged_snap_remove(snapc_seq));
3306 }
3307
3308 TEST_F(TestClsRbd, sparsify)
3309 {
3310 librados::IoCtx ioctx;
3311 ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
3312
3313 string oid = get_temp_image_name();
3314 ioctx.remove(oid);
3315
3316 bool sparse_read_supported = is_sparse_read_supported(ioctx, oid);
3317
3318 // test sparsify on a non-existent object
3319
3320 ASSERT_EQ(-ENOENT, sparsify(&ioctx, oid, 16, false));
3321 uint64_t size;
3322 ASSERT_EQ(-ENOENT, ioctx.stat(oid, &size, NULL));
3323 ASSERT_EQ(-ENOENT, sparsify(&ioctx, oid, 16, true));
3324 ASSERT_EQ(-ENOENT, ioctx.stat(oid, &size, NULL));
3325
3326 // test sparsify on an empty object
3327
3328 ASSERT_EQ(0, ioctx.create(oid, true));
3329 ASSERT_EQ(0, sparsify(&ioctx, oid, 16, false));
3330 ASSERT_EQ(0, sparsify(&ioctx, oid, 16, true));
3331 ASSERT_EQ(-ENOENT, sparsify(&ioctx, oid, 16, false));
3332
3333 // test sparsify on a zeroed object
3334
3335 bufferlist inbl;
3336 inbl.append(std::string(4096, '\0'));
3337 ASSERT_EQ(0, ioctx.write(oid, inbl, inbl.length(), 0));
3338 ASSERT_EQ(0, sparsify(&ioctx, oid, 16, false));
3339 std::map<uint64_t, uint64_t> m;
3340 bufferlist outbl;
3341 std::map<uint64_t, uint64_t> expected_m;
3342 bufferlist expected_outbl;
3343 switch (int r = ioctx.sparse_read(oid, m, outbl, inbl.length(), 0); r) {
3344 case 0:
3345 expected_m = {};
3346 ASSERT_EQ(expected_m, m);
3347 break;
3348 case 1:
3349 expected_m = {{0, 0}};
3350 ASSERT_EQ(expected_m, m);
3351 break;
3352 default:
3353 FAIL() << r << " is odd";
3354 }
3355 ASSERT_EQ(m, expected_m);
3356 ASSERT_EQ(0, sparsify(&ioctx, oid, 16, true));
3357 ASSERT_EQ(-ENOENT, sparsify(&ioctx, oid, 16, true));
3358 ASSERT_EQ(0, ioctx.write(oid, inbl, inbl.length(), 0));
3359 ASSERT_EQ(0, sparsify(&ioctx, oid, 16, true));
3360 ASSERT_EQ(-ENOENT, sparsify(&ioctx, oid, 16, true));
3361
3362 // test sparsify on an object with zeroes
3363
3364 inbl.append(std::string(4096, '1'));
3365 inbl.append(std::string(4096, '\0'));
3366 inbl.append(std::string(4096, '2'));
3367 inbl.append(std::string(4096, '\0'));
3368 ASSERT_EQ(0, ioctx.write(oid, inbl, inbl.length(), 0));
3369
3370 // try to sparsify with sparse_size too large
3371
3372 ASSERT_EQ(0, sparsify(&ioctx, oid, inbl.length(), true));
3373 expected_m = {{0, inbl.length()}};
3374 expected_outbl = inbl;
3375 ASSERT_EQ((int)expected_m.size(),
3376 ioctx.sparse_read(oid, m, outbl, inbl.length(), 0));
3377 ASSERT_EQ(m, expected_m);
3378 ASSERT_TRUE(outbl.contents_equal(expected_outbl));
3379
3380 // sparsify with small sparse_size
3381
3382 ASSERT_EQ(0, sparsify(&ioctx, oid, 16, true));
3383 outbl.clear();
3384 ASSERT_EQ((int)(inbl.length() - 4096),
3385 ioctx.read(oid, outbl, inbl.length(), 0));
3386 outbl.append(std::string(4096, '\0'));
3387 ASSERT_TRUE(outbl.contents_equal(expected_outbl));
3388 if (sparse_read_supported) {
3389 expected_m = {{4096 * 1, 4096}, {4096 * 3, 4096}};
3390 expected_outbl.clear();
3391 expected_outbl.append(std::string(4096, '1'));
3392 expected_outbl.append(std::string(4096, '2'));
3393 } else {
3394 expected_m = {{0, 4 * 4096}};
3395 expected_outbl.clear();
3396 expected_outbl.append(std::string(4096, '\0'));
3397 expected_outbl.append(std::string(4096, '1'));
3398 expected_outbl.append(std::string(4096, '\0'));
3399 expected_outbl.append(std::string(4096, '2'));
3400 }
3401 m.clear();
3402 outbl.clear();
3403 ASSERT_EQ((int)expected_m.size(),
3404 ioctx.sparse_read(oid, m, outbl, inbl.length(), 0));
3405 ASSERT_EQ(m, expected_m);
3406 ASSERT_TRUE(outbl.contents_equal(expected_outbl));
3407
3408 // test it is the same after yet another sparsify
3409
3410 ASSERT_EQ(0, sparsify(&ioctx, oid, 16, true));
3411 m.clear();
3412 outbl.clear();
3413 ASSERT_EQ((int)expected_m.size(),
3414 ioctx.sparse_read(oid, m, outbl, inbl.length(), 0));
3415 ASSERT_EQ(m, expected_m);
3416 ASSERT_TRUE(outbl.contents_equal(expected_outbl));
3417
3418 ASSERT_EQ(0, ioctx.remove(oid));
3419 ioctx.close();
3420 }