]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd/action/Group.cc
bump version to 18.2.2-pve1
[ceph.git] / ceph / src / tools / rbd / action / Group.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 <iostream>
5
6 #include "tools/rbd/ArgumentTypes.h"
7 #include "tools/rbd/Shell.h"
8 #include "tools/rbd/Utils.h"
9 #include "include/rbd_types.h"
10 #include "cls/rbd/cls_rbd_types.h"
11 #include "common/errno.h"
12 #include "common/Formatter.h"
13 #include "common/TextTable.h"
14
15 namespace rbd {
16 namespace action {
17 namespace group {
18
19 namespace at = argument_types;
20 namespace po = boost::program_options;
21
22 static const std::string GROUP_SPEC("group-spec");
23 static const std::string GROUP_SNAP_SPEC("group-snap-spec");
24
25 static const std::string GROUP_NAME("group");
26 static const std::string DEST_GROUP_NAME("dest-group");
27
28 static const std::string GROUP_POOL_NAME("group-" + at::POOL_NAME);
29 static const std::string IMAGE_POOL_NAME("image-" + at::POOL_NAME);
30
31 void add_group_option(po::options_description *opt,
32 at::ArgumentModifier modifier) {
33 std::string name = GROUP_NAME;
34 std::string description = at::get_description_prefix(modifier) + "group name";
35 switch (modifier) {
36 case at::ARGUMENT_MODIFIER_NONE:
37 case at::ARGUMENT_MODIFIER_SOURCE:
38 break;
39 case at::ARGUMENT_MODIFIER_DEST:
40 name = DEST_GROUP_NAME;
41 break;
42 }
43
44 // TODO add validator
45 opt->add_options()
46 (name.c_str(), po::value<std::string>(), description.c_str());
47 }
48
49 void add_prefixed_pool_option(po::options_description *opt,
50 const std::string &prefix) {
51 std::string name = prefix + "-" + at::POOL_NAME;
52 std::string description = prefix + " pool name";
53
54 opt->add_options()
55 (name.c_str(), po::value<std::string>(), description.c_str());
56 }
57
58 void add_prefixed_namespace_option(po::options_description *opt,
59 const std::string &prefix) {
60 std::string name = prefix + "-" + at::NAMESPACE_NAME;
61 std::string description = prefix + " namespace name";
62
63 opt->add_options()
64 (name.c_str(), po::value<std::string>(), description.c_str());
65 }
66
67 void add_group_spec_options(po::options_description *pos,
68 po::options_description *opt,
69 at::ArgumentModifier modifier,
70 bool snap) {
71 at::add_pool_option(opt, modifier);
72 at::add_namespace_option(opt, modifier);
73 add_group_option(opt, modifier);
74 if (!snap) {
75 pos->add_options()
76 ((get_name_prefix(modifier) + GROUP_SPEC).c_str(),
77 (get_description_prefix(modifier) + "group specification\n" +
78 "(example: [<pool-name>/[<namespace>/]]<group-name>)").c_str());
79 } else {
80 add_snap_option(opt, modifier);
81 pos->add_options()
82 ((get_name_prefix(modifier) + GROUP_SNAP_SPEC).c_str(),
83 (get_description_prefix(modifier) + "group specification\n" +
84 "(example: [<pool-name>/[<namespace>/]]<group-name>@<snap-name>)").c_str());
85 }
86 }
87
88 int execute_create(const po::variables_map &vm,
89 const std::vector<std::string> &ceph_global_init_args) {
90 size_t arg_index = 0;
91
92 std::string pool_name;
93 std::string namespace_name;
94 std::string group_name;
95
96 int r = utils::get_pool_generic_snapshot_names(
97 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, at::POOL_NAME, &pool_name,
98 &namespace_name, GROUP_NAME, "group", &group_name, nullptr, true,
99 utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_FULL);
100 if (r < 0) {
101 return r;
102 }
103
104 librados::Rados rados;
105 librados::IoCtx io_ctx;
106
107 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
108 if (r < 0) {
109 return r;
110 }
111 librbd::RBD rbd;
112 r = rbd.group_create(io_ctx, group_name.c_str());
113 if (r < 0) {
114 std::cerr << "rbd: create error: " << cpp_strerror(r) << std::endl;
115 return r;
116 }
117
118 return 0;
119 }
120
121 int execute_list(const po::variables_map &vm,
122 const std::vector<std::string> &ceph_global_init_args) {
123 std::string pool_name;
124 std::string namespace_name;
125 size_t arg_index = 0;
126 int r = utils::get_pool_and_namespace_names(vm, false, &pool_name,
127 &namespace_name, &arg_index);
128 if (r < 0) {
129 return r;
130 }
131
132 at::Format::Formatter formatter;
133 r = utils::get_formatter(vm, &formatter);
134 if (r < 0) {
135 return r;
136 }
137 Formatter *f = formatter.get();
138
139 librados::Rados rados;
140 librados::IoCtx io_ctx;
141 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
142 if (r < 0) {
143 return r;
144 }
145
146 librbd::RBD rbd;
147 std::vector<std::string> names;
148 r = rbd.group_list(io_ctx, &names);
149 if (r < 0)
150 return r;
151
152 if (f)
153 f->open_array_section("groups");
154 for (auto i : names) {
155 if (f)
156 f->dump_string("name", i);
157 else
158 std::cout << i << std::endl;
159 }
160 if (f) {
161 f->close_section();
162 f->flush(std::cout);
163 }
164
165 return 0;
166 }
167
168 int execute_remove(const po::variables_map &vm,
169 const std::vector<std::string> &ceph_global_init_args) {
170 size_t arg_index = 0;
171
172 std::string pool_name;
173 std::string namespace_name;
174 std::string group_name;
175
176 int r = utils::get_pool_generic_snapshot_names(
177 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, at::POOL_NAME, &pool_name,
178 &namespace_name, GROUP_NAME, "group", &group_name, nullptr, true,
179 utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_FULL);
180 if (r < 0) {
181 return r;
182 }
183
184 librados::Rados rados;
185 librados::IoCtx io_ctx;
186
187 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
188 if (r < 0) {
189 return r;
190 }
191 librbd::RBD rbd;
192
193 r = rbd.group_remove(io_ctx, group_name.c_str());
194 if (r < 0) {
195 std::cerr << "rbd: remove error: " << cpp_strerror(r) << std::endl;
196 return r;
197 }
198
199 return 0;
200 }
201
202 int execute_rename(const po::variables_map &vm,
203 const std::vector<std::string> &ceph_global_init_args) {
204 size_t arg_index = 0;
205
206 std::string pool_name;
207 std::string namespace_name;
208 std::string group_name;
209
210 int r = utils::get_pool_generic_snapshot_names(
211 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, at::POOL_NAME, &pool_name,
212 &namespace_name, GROUP_NAME, "group", &group_name, nullptr, true,
213 utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_FULL);
214 if (r < 0) {
215 return r;
216 }
217
218 std::string dest_pool_name;
219 std::string dest_namespace_name;
220 std::string dest_group_name;
221
222 r = utils::get_pool_generic_snapshot_names(
223 vm, at::ARGUMENT_MODIFIER_DEST, &arg_index, at::DEST_POOL_NAME,
224 &dest_pool_name, &dest_namespace_name, DEST_GROUP_NAME, "group",
225 &dest_group_name, nullptr, true, utils::SNAPSHOT_PRESENCE_NONE,
226 utils::SPEC_VALIDATION_FULL);
227 if (r < 0) {
228 return r;
229 }
230
231 if (pool_name != dest_pool_name) {
232 std::cerr << "rbd: group rename across pools not supported" << std::endl
233 << "source pool: " << pool_name << ", dest pool: "
234 << dest_pool_name << std::endl;
235 return -EINVAL;
236 } else if (namespace_name != dest_namespace_name) {
237 std::cerr << "rbd: group rename across namespaces not supported"
238 << std::endl
239 << "source namespace: " << namespace_name << ", dest namespace: "
240 << dest_namespace_name << std::endl;
241 return -EINVAL;
242 }
243
244 librados::Rados rados;
245 librados::IoCtx io_ctx;
246 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
247 if (r < 0) {
248 return r;
249 }
250
251 librbd::RBD rbd;
252 r = rbd.group_rename(io_ctx, group_name.c_str(),
253 dest_group_name.c_str());
254
255 if (r < 0) {
256 std::cerr << "rbd: failed to rename group: "
257 << cpp_strerror(r) << std::endl;
258 return r;
259 }
260
261 return 0;
262 }
263
264 int execute_add(const po::variables_map &vm,
265 const std::vector<std::string> &ceph_global_init_args) {
266 size_t arg_index = 0;
267 // Parse group data.
268 std::string group_pool_name;
269 std::string group_namespace_name;
270 std::string group_name;
271
272 int r = utils::get_pool_generic_snapshot_names(
273 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, GROUP_POOL_NAME,
274 &group_pool_name, &group_namespace_name, GROUP_NAME, "group", &group_name,
275 nullptr, true, utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_FULL);
276 if (r < 0) {
277 return r;
278 }
279
280 std::string image_pool_name;
281 std::string image_namespace_name;
282 std::string image_name;
283
284 r = utils::get_pool_generic_snapshot_names(
285 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, IMAGE_POOL_NAME,
286 &image_pool_name, &image_namespace_name, at::IMAGE_NAME, "image",
287 &image_name, nullptr, true, utils::SNAPSHOT_PRESENCE_NONE,
288 utils::SPEC_VALIDATION_FULL);
289 if (r < 0) {
290 return r;
291 }
292
293 if (group_namespace_name != image_namespace_name) {
294 std::cerr << "rbd: group and image namespace must match." << std::endl;
295 return -EINVAL;
296 }
297
298 librados::Rados rados;
299 librados::IoCtx cg_io_ctx;
300 r = utils::init(group_pool_name, group_namespace_name, &rados, &cg_io_ctx);
301 if (r < 0) {
302 return r;
303 }
304
305 librados::IoCtx image_io_ctx;
306 r = utils::init(image_pool_name, group_namespace_name, &rados, &image_io_ctx);
307 if (r < 0) {
308 return r;
309 }
310
311 librbd::RBD rbd;
312 r = rbd.group_image_add(cg_io_ctx, group_name.c_str(),
313 image_io_ctx, image_name.c_str());
314 if (r < 0) {
315 std::cerr << "rbd: add image error: " << cpp_strerror(r) << std::endl;
316 return r;
317 }
318
319 return 0;
320 }
321
322 int execute_remove_image(const po::variables_map &vm,
323 const std::vector<std::string> &ceph_global_init_args) {
324 size_t arg_index = 0;
325
326 std::string group_pool_name;
327 std::string group_namespace_name;
328 std::string group_name;
329
330 int r = utils::get_pool_generic_snapshot_names(
331 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, GROUP_POOL_NAME,
332 &group_pool_name, &group_namespace_name, GROUP_NAME, "group", &group_name,
333 nullptr, true, utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_FULL);
334 if (r < 0) {
335 return r;
336 }
337
338 std::string image_pool_name;
339 std::string image_namespace_name;
340 std::string image_name;
341 std::string image_id;
342
343 if (vm.count(at::IMAGE_ID)) {
344 image_id = vm[at::IMAGE_ID].as<std::string>();
345 }
346
347 r = utils::get_pool_generic_snapshot_names(
348 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, IMAGE_POOL_NAME,
349 &image_pool_name, &image_namespace_name, at::IMAGE_NAME, "image",
350 &image_name, nullptr, image_id.empty(), utils::SNAPSHOT_PRESENCE_NONE,
351 utils::SPEC_VALIDATION_FULL);
352 if (r < 0) {
353 return r;
354 }
355
356 if (group_namespace_name != image_namespace_name) {
357 std::cerr << "rbd: group and image namespace must match." << std::endl;
358 return -EINVAL;
359 } else if (!image_id.empty() && !image_name.empty()) {
360 std::cerr << "rbd: trying to access image using both name and id. "
361 << std::endl;
362 return -EINVAL;
363 }
364
365 librados::Rados rados;
366 librados::IoCtx cg_io_ctx;
367 r = utils::init(group_pool_name, group_namespace_name, &rados, &cg_io_ctx);
368 if (r < 0) {
369 return r;
370 }
371
372 librados::IoCtx image_io_ctx;
373 r = utils::init(image_pool_name, group_namespace_name, &rados, &image_io_ctx);
374 if (r < 0) {
375 return r;
376 }
377
378 librbd::RBD rbd;
379 if (image_id.empty()) {
380 r = rbd.group_image_remove(cg_io_ctx, group_name.c_str(),
381 image_io_ctx, image_name.c_str());
382 } else {
383 r = rbd.group_image_remove_by_id(cg_io_ctx, group_name.c_str(),
384 image_io_ctx, image_id.c_str());
385 }
386 if (r < 0) {
387 std::cerr << "rbd: remove image error: " << cpp_strerror(r) << std::endl;
388 return r;
389 }
390
391 return 0;
392 }
393
394 int execute_list_images(const po::variables_map &vm,
395 const std::vector<std::string> &ceph_global_init_args) {
396 size_t arg_index = 0;
397 std::string pool_name;
398 std::string namespace_name;
399 std::string group_name;
400
401 int r = utils::get_pool_generic_snapshot_names(
402 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, at::POOL_NAME, &pool_name,
403 &namespace_name, GROUP_NAME, "group", &group_name, nullptr, true,
404 utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_FULL);
405 if (r < 0) {
406 return r;
407 }
408
409 at::Format::Formatter formatter;
410 r = utils::get_formatter(vm, &formatter);
411 if (r < 0) {
412 return r;
413 }
414 Formatter *f = formatter.get();
415
416 librados::Rados rados;
417 librados::IoCtx io_ctx;
418 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
419 if (r < 0) {
420 return r;
421 }
422
423 librbd::RBD rbd;
424 std::vector<librbd::group_image_info_t> images;
425
426 r = rbd.group_image_list(io_ctx, group_name.c_str(), &images,
427 sizeof(librbd::group_image_info_t));
428
429 if (r == -ENOENT)
430 r = 0;
431
432 if (r < 0)
433 return r;
434
435 std::sort(images.begin(), images.end(),
436 [](const librbd::group_image_info_t &lhs,
437 const librbd::group_image_info_t &rhs) {
438 if (lhs.pool != rhs.pool) {
439 return lhs.pool < rhs.pool;
440 }
441 return lhs.name < rhs.name;
442 }
443 );
444
445 if (f)
446 f->open_array_section("images");
447
448 for (auto image : images) {
449 std::string image_name = image.name;
450 int state = image.state;
451 std::string state_string;
452 if (RBD_GROUP_IMAGE_STATE_INCOMPLETE == state) {
453 state_string = "incomplete";
454 }
455
456 std::string pool_name = "";
457
458 librados::Rados rados(io_ctx);
459 librados::IoCtx pool_io_ctx;
460 r = rados.ioctx_create2(image.pool, pool_io_ctx);
461 if (r < 0) {
462 pool_name = "<missing image pool " + stringify(image.pool) + ">";
463 } else {
464 pool_name = pool_io_ctx.get_pool_name();
465 }
466
467 if (f) {
468 f->open_object_section("image");
469 f->dump_string("image", image_name);
470 f->dump_string("pool", pool_name);
471 f->dump_string("namespace", io_ctx.get_namespace());
472 f->dump_int("state", state);
473 f->close_section();
474 } else {
475 std::cout << pool_name << "/";
476 if (!io_ctx.get_namespace().empty()) {
477 std::cout << io_ctx.get_namespace() << "/";
478 }
479 std::cout << image_name << " " << state_string << std::endl;
480 }
481 }
482
483 if (f) {
484 f->close_section();
485 f->flush(std::cout);
486 }
487
488 return 0;
489 }
490
491 int execute_group_snap_create(const po::variables_map &vm,
492 const std::vector<std::string> &global_args) {
493 size_t arg_index = 0;
494
495 std::string pool_name;
496 std::string namespace_name;
497 std::string group_name;
498 std::string snap_name;
499
500 int r = utils::get_pool_generic_snapshot_names(
501 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, at::POOL_NAME, &pool_name,
502 &namespace_name, GROUP_NAME, "group", &group_name, &snap_name, true,
503 utils::SNAPSHOT_PRESENCE_REQUIRED, utils::SPEC_VALIDATION_FULL);
504 if (r < 0) {
505 return r;
506 }
507
508 uint32_t flags;
509 r = utils::get_snap_create_flags(vm, &flags);
510 if (r < 0) {
511 return r;
512 }
513
514 librados::IoCtx io_ctx;
515 librados::Rados rados;
516
517 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
518 if (r < 0) {
519 return r;
520 }
521
522 librbd::RBD rbd;
523 r = rbd.group_snap_create2(io_ctx, group_name.c_str(), snap_name.c_str(),
524 flags);
525 if (r < 0) {
526 return r;
527 }
528
529 return 0;
530 }
531
532 int execute_group_snap_remove(const po::variables_map &vm,
533 const std::vector<std::string> &global_args) {
534 size_t arg_index = 0;
535
536 std::string pool_name;
537 std::string namespace_name;
538 std::string group_name;
539 std::string snap_name;
540
541 int r = utils::get_pool_generic_snapshot_names(
542 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, at::POOL_NAME, &pool_name,
543 &namespace_name, GROUP_NAME, "group", &group_name, &snap_name, true,
544 utils::SNAPSHOT_PRESENCE_REQUIRED, utils::SPEC_VALIDATION_FULL);
545 if (r < 0) {
546 return r;
547 }
548
549 librados::IoCtx io_ctx;
550 librados::Rados rados;
551
552 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
553 if (r < 0) {
554 return r;
555 }
556
557 librbd::RBD rbd;
558 r = rbd.group_snap_remove(io_ctx, group_name.c_str(), snap_name.c_str());
559 if (r < 0) {
560 std::cerr << "rbd: failed to remove group snapshot: "
561 << cpp_strerror(r) << std::endl;
562 return r;
563 }
564
565 return 0;
566 }
567
568 int execute_group_snap_rename(const po::variables_map &vm,
569 const std::vector<std::string> &global_args) {
570 size_t arg_index = 0;
571
572 std::string pool_name;
573 std::string namespace_name;
574 std::string group_name;
575 std::string source_snap_name;
576
577 int r = utils::get_pool_generic_snapshot_names(
578 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, at::POOL_NAME, &pool_name,
579 &namespace_name, GROUP_NAME, "group", &group_name, &source_snap_name, true,
580 utils::SNAPSHOT_PRESENCE_REQUIRED, utils::SPEC_VALIDATION_FULL);
581 if (r < 0) {
582 return r;
583 }
584
585 std::string dest_snap_name;
586 if (vm.count(at::DEST_SNAPSHOT_NAME)) {
587 dest_snap_name = vm[at::DEST_SNAPSHOT_NAME].as<std::string>();
588 }
589
590 if (dest_snap_name.empty()) {
591 dest_snap_name = utils::get_positional_argument(vm, arg_index++);
592 }
593
594 if (dest_snap_name.empty()) {
595 std::cerr << "rbd: destination snapshot name was not specified"
596 << std::endl;
597 return -EINVAL;
598 }
599
600 r = utils::validate_snapshot_name(at::ARGUMENT_MODIFIER_DEST, dest_snap_name,
601 utils::SNAPSHOT_PRESENCE_REQUIRED,
602 utils::SPEC_VALIDATION_SNAP);
603 if (r < 0) {
604 return r;
605 }
606 librados::Rados rados;
607 librados::IoCtx io_ctx;
608 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
609 if (r < 0) {
610 return r;
611 }
612
613 librbd::RBD rbd;
614 r = rbd.group_snap_rename(io_ctx, group_name.c_str(),
615 source_snap_name.c_str(), dest_snap_name.c_str());
616
617 if (r < 0) {
618 std::cerr << "rbd: failed to rename group snapshot: "
619 << cpp_strerror(r) << std::endl;
620 return r;
621 }
622
623 return 0;
624 }
625
626 int execute_group_snap_list(const po::variables_map &vm,
627 const std::vector<std::string> &ceph_global_args) {
628 size_t arg_index = 0;
629 std::string pool_name;
630 std::string namespace_name;
631 std::string group_name;
632
633 int r = utils::get_pool_generic_snapshot_names(
634 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, at::POOL_NAME, &pool_name,
635 &namespace_name, GROUP_NAME, "group", &group_name, nullptr, true,
636 utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_FULL);
637 if (r < 0) {
638 return r;
639 }
640
641 at::Format::Formatter formatter;
642 r = utils::get_formatter(vm, &formatter);
643 if (r < 0) {
644 return r;
645 }
646 Formatter *f = formatter.get();
647
648 librados::Rados rados;
649 librados::IoCtx io_ctx;
650 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
651 if (r < 0) {
652 return r;
653 }
654
655 librbd::RBD rbd;
656 std::vector<librbd::group_snap_info_t> snaps;
657
658 r = rbd.group_snap_list(io_ctx, group_name.c_str(), &snaps,
659 sizeof(librbd::group_snap_info_t));
660
661 if (r == -ENOENT) {
662 r = 0;
663 }
664 if (r < 0) {
665 return r;
666 }
667
668 TextTable t;
669 if (f) {
670 f->open_array_section("group_snaps");
671 } else {
672 t.define_column("NAME", TextTable::LEFT, TextTable::LEFT);
673 t.define_column("STATUS", TextTable::LEFT, TextTable::RIGHT);
674 }
675
676 for (auto i : snaps) {
677 std::string snap_name = i.name;
678 int state = i.state;
679 std::string state_string;
680 if (RBD_GROUP_SNAP_STATE_INCOMPLETE == state) {
681 state_string = "incomplete";
682 } else {
683 state_string = "ok";
684 }
685 if (r < 0) {
686 return r;
687 }
688 if (f) {
689 f->open_object_section("group_snap");
690 f->dump_string("snapshot", snap_name);
691 f->dump_string("state", state_string);
692 f->close_section();
693 } else {
694 t << snap_name << state_string << TextTable::endrow;
695 }
696 }
697
698 if (f) {
699 f->close_section();
700 f->flush(std::cout);
701 } else if (snaps.size()) {
702 std::cout << t;
703 }
704 return 0;
705 }
706
707 int execute_group_snap_rollback(const po::variables_map &vm,
708 const std::vector<std::string> &global_args) {
709 size_t arg_index = 0;
710
711 std::string group_name;
712 std::string namespace_name;
713 std::string pool_name;
714 std::string snap_name;
715
716 int r = utils::get_pool_generic_snapshot_names(
717 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, at::POOL_NAME, &pool_name,
718 &namespace_name, GROUP_NAME, "group", &group_name, &snap_name, true,
719 utils::SNAPSHOT_PRESENCE_REQUIRED, utils::SPEC_VALIDATION_FULL);
720 if (r < 0) {
721 return r;
722 }
723
724 librados::IoCtx io_ctx;
725 librados::Rados rados;
726
727 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
728 if (r < 0) {
729 return r;
730 }
731
732 librbd::RBD rbd;
733 utils::ProgressContext pc("Rolling back to group snapshot",
734 vm[at::NO_PROGRESS].as<bool>());
735 r = rbd.group_snap_rollback_with_progress(io_ctx, group_name.c_str(),
736 snap_name.c_str(), pc);
737 if (r < 0) {
738 pc.fail();
739 std::cerr << "rbd: rollback group to snapshot failed: "
740 << cpp_strerror(r) << std::endl;
741 return r;
742 }
743
744 pc.finish();
745 return 0;
746 }
747
748 void get_create_arguments(po::options_description *positional,
749 po::options_description *options) {
750 add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE,
751 false);
752 }
753
754 void get_remove_arguments(po::options_description *positional,
755 po::options_description *options) {
756 add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE,
757 false);
758 }
759
760 void get_list_arguments(po::options_description *positional,
761 po::options_description *options) {
762 at::add_pool_options(positional, options, true);
763 at::add_format_options(options);
764 }
765
766 void get_rename_arguments(po::options_description *positional,
767 po::options_description *options) {
768 add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_SOURCE,
769 false);
770 add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_DEST,
771 false);
772 }
773
774 void get_add_arguments(po::options_description *positional,
775 po::options_description *options) {
776 positional->add_options()
777 (GROUP_SPEC.c_str(),
778 "group specification\n"
779 "(example: [<pool-name>/[<namespace>/]]<group-name>)");
780
781 add_prefixed_pool_option(options, "group");
782 add_prefixed_namespace_option(options, "group");
783 add_group_option(options, at::ARGUMENT_MODIFIER_NONE);
784
785 positional->add_options()
786 (at::IMAGE_SPEC.c_str(),
787 "image specification\n"
788 "(example: [<pool-name>/[<namespace>/]]<image-name>)");
789
790 add_prefixed_pool_option(options, "image");
791 add_prefixed_namespace_option(options, "image");
792 at::add_image_option(options, at::ARGUMENT_MODIFIER_NONE);
793
794 at::add_pool_option(options, at::ARGUMENT_MODIFIER_NONE,
795 " unless overridden");
796 }
797
798 void get_remove_image_arguments(po::options_description *positional,
799 po::options_description *options) {
800 positional->add_options()
801 (GROUP_SPEC.c_str(),
802 "group specification\n"
803 "(example: [<pool-name>/[<namespace>/]]<group-name>)");
804
805 add_prefixed_pool_option(options, "group");
806 add_prefixed_namespace_option(options, "group");
807 add_group_option(options, at::ARGUMENT_MODIFIER_NONE);
808
809 positional->add_options()
810 (at::IMAGE_SPEC.c_str(),
811 "image specification\n"
812 "(example: [<pool-name>/[<namespace>/]]<image-name>)");
813
814 add_prefixed_pool_option(options, "image");
815 add_prefixed_namespace_option(options, "image");
816 at::add_image_option(options, at::ARGUMENT_MODIFIER_NONE);
817
818 at::add_pool_option(options, at::ARGUMENT_MODIFIER_NONE,
819 " unless overridden");
820 at::add_image_id_option(options);
821 }
822
823 void get_list_images_arguments(po::options_description *positional,
824 po::options_description *options) {
825 at::add_format_options(options);
826 add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE,
827 false);
828 }
829
830 void get_group_snap_create_arguments(po::options_description *positional,
831 po::options_description *options) {
832 add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE,
833 true);
834 at::add_snap_create_options(options);
835 }
836
837 void get_group_snap_remove_arguments(po::options_description *positional,
838 po::options_description *options) {
839 add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE,
840 true);
841 }
842
843 void get_group_snap_rename_arguments(po::options_description *positional,
844 po::options_description *options) {
845 add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE,
846 true);
847
848 positional->add_options()
849 (at::DEST_SNAPSHOT_NAME.c_str(),
850 "destination snapshot name\n(example: <snap-name>)");
851 at::add_snap_option(options, at::ARGUMENT_MODIFIER_DEST);
852 }
853
854 void get_group_snap_list_arguments(po::options_description *positional,
855 po::options_description *options) {
856 at::add_format_options(options);
857 add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE,
858 false);
859 }
860
861 void get_group_snap_rollback_arguments(po::options_description *positional,
862 po::options_description *options) {
863 at::add_no_progress_option(options);
864 add_group_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE,
865 true);
866 }
867
868 Shell::Action action_create(
869 {"group", "create"}, {}, "Create a group.",
870 "", &get_create_arguments, &execute_create);
871 Shell::Action action_remove(
872 {"group", "remove"}, {"group", "rm"}, "Delete a group.",
873 "", &get_remove_arguments, &execute_remove);
874 Shell::Action action_list(
875 {"group", "list"}, {"group", "ls"}, "List rbd groups.",
876 "", &get_list_arguments, &execute_list);
877 Shell::Action action_rename(
878 {"group", "rename"}, {}, "Rename a group within pool.",
879 "", &get_rename_arguments, &execute_rename);
880 Shell::Action action_add(
881 {"group", "image", "add"}, {}, "Add an image to a group.",
882 "", &get_add_arguments, &execute_add);
883 Shell::Action action_remove_image(
884 {"group", "image", "remove"}, {"group", "image", "rm"},
885 "Remove an image from a group.", "",
886 &get_remove_image_arguments, &execute_remove_image);
887 Shell::Action action_list_images(
888 {"group", "image", "list"}, {"group", "image", "ls"},
889 "List images in a group.", "",
890 &get_list_images_arguments, &execute_list_images);
891 Shell::Action action_group_snap_create(
892 {"group", "snap", "create"}, {}, "Make a snapshot of a group.",
893 "", &get_group_snap_create_arguments, &execute_group_snap_create);
894 Shell::Action action_group_snap_remove(
895 {"group", "snap", "remove"}, {"group", "snap", "rm"},
896 "Remove a snapshot from a group.",
897 "", &get_group_snap_remove_arguments, &execute_group_snap_remove);
898 Shell::Action action_group_snap_rename(
899 {"group", "snap", "rename"}, {}, "Rename group's snapshot.",
900 "", &get_group_snap_rename_arguments, &execute_group_snap_rename);
901 Shell::Action action_group_snap_list(
902 {"group", "snap", "list"}, {"group", "snap", "ls"},
903 "List snapshots of a group.",
904 "", &get_group_snap_list_arguments, &execute_group_snap_list);
905 Shell::Action action_group_snap_rollback(
906 {"group", "snap", "rollback"}, {},
907 "Rollback group to snapshot.",
908 "", &get_group_snap_rollback_arguments, &execute_group_snap_rollback);
909
910 } // namespace group
911 } // namespace action
912 } // namespace rbd