1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "tools/rbd/ArgumentTypes.h"
5 #include "tools/rbd/Shell.h"
6 #include "tools/rbd/Utils.h"
7 #include "include/types.h"
8 #include "include/stringify.h"
9 #include "common/errno.h"
10 #include "common/Formatter.h"
11 #include "common/TextTable.h"
13 #include <boost/program_options.hpp>
14 #include <boost/bind/bind.hpp>
20 using namespace boost::placeholders
;
22 static const std::string
ALL_NAME("all");
24 namespace at
= argument_types
;
25 namespace po
= boost::program_options
;
27 int do_list_snaps(librbd::Image
& image
, Formatter
*f
, bool all_snaps
, librados::Rados
& rados
)
29 std::vector
<librbd::snap_info_t
> snaps
;
33 r
= image
.snap_list(snaps
);
35 std::cerr
<< "rbd: unable to list snapshots" << std::endl
;
39 librbd::image_info_t info
;
41 snaps
.erase(remove_if(snaps
.begin(),
43 boost::bind(utils::is_not_user_snap_namespace
, &image
, _1
)),
46 r
= image
.stat(info
, sizeof(info
));
48 std::cerr
<< "rbd: unable to get image info" << std::endl
;
54 f
->open_array_section("snapshots");
56 t
.define_column("SNAPID", TextTable::LEFT
, TextTable::RIGHT
);
57 t
.define_column("NAME", TextTable::LEFT
, TextTable::LEFT
);
58 t
.define_column("SIZE", TextTable::LEFT
, TextTable::RIGHT
);
59 t
.define_column("PROTECTED", TextTable::LEFT
, TextTable::LEFT
);
60 t
.define_column("TIMESTAMP", TextTable::LEFT
, TextTable::RIGHT
);
62 t
.define_column("NAMESPACE", TextTable::LEFT
, TextTable::LEFT
);
66 std::list
<std::pair
<int64_t, std::string
>> pool_list
;
67 rados
.pool_list2(pool_list
);
68 std::map
<int64_t, std::string
> pool_map(pool_list
.begin(), pool_list
.end());
70 for (std::vector
<librbd::snap_info_t
>::iterator s
= snaps
.begin();
71 s
!= snaps
.end(); ++s
) {
72 struct timespec timestamp
;
73 bool snap_protected
= false;
74 image
.snap_get_timestamp(s
->id
, ×tamp
);
75 std::string tt_str
= "";
76 if(timestamp
.tv_sec
!= 0) {
77 time_t tt
= timestamp
.tv_sec
;
79 tt_str
= tt_str
.substr(0, tt_str
.length() - 1);
82 librbd::snap_namespace_type_t snap_namespace
;
83 r
= image
.snap_get_namespace_type(s
->id
, &snap_namespace
);
85 std::cerr
<< "rbd: unable to retrieve snap namespace" << std::endl
;
89 std::string snap_namespace_name
= "Unknown";
90 switch (snap_namespace
) {
91 case RBD_SNAP_NAMESPACE_TYPE_USER
:
92 snap_namespace_name
= "user";
94 case RBD_SNAP_NAMESPACE_TYPE_GROUP
:
95 snap_namespace_name
= "group";
97 case RBD_SNAP_NAMESPACE_TYPE_TRASH
:
98 snap_namespace_name
= "trash";
100 case RBD_SNAP_NAMESPACE_TYPE_MIRROR
:
101 snap_namespace_name
= "mirror";
105 int get_trash_res
= -ENOENT
;
106 std::string trash_original_name
;
107 int get_group_res
= -ENOENT
;
108 librbd::snap_group_namespace_t group_snap
;
109 int get_mirror_res
= -ENOENT
;
110 librbd::snap_mirror_namespace_t mirror_snap
;
111 std::string mirror_snap_state
= "unknown";
112 if (snap_namespace
== RBD_SNAP_NAMESPACE_TYPE_GROUP
) {
113 get_group_res
= image
.snap_get_group_namespace(s
->id
, &group_snap
,
115 } else if (snap_namespace
== RBD_SNAP_NAMESPACE_TYPE_TRASH
) {
116 get_trash_res
= image
.snap_get_trash_namespace(
117 s
->id
, &trash_original_name
);
118 } else if (snap_namespace
== RBD_SNAP_NAMESPACE_TYPE_MIRROR
) {
119 get_mirror_res
= image
.snap_get_mirror_namespace(
120 s
->id
, &mirror_snap
, sizeof(mirror_snap
));
122 switch (mirror_snap
.state
) {
123 case RBD_SNAP_MIRROR_STATE_PRIMARY
:
124 mirror_snap_state
= "primary";
126 case RBD_SNAP_MIRROR_STATE_NON_PRIMARY
:
127 mirror_snap_state
= "non-primary";
129 case RBD_SNAP_MIRROR_STATE_PRIMARY_DEMOTED
:
130 case RBD_SNAP_MIRROR_STATE_NON_PRIMARY_DEMOTED
:
131 mirror_snap_state
= "demoted";
136 std::string protected_str
= "";
137 if (snap_namespace
== RBD_SNAP_NAMESPACE_TYPE_USER
) {
138 r
= image
.snap_is_protected(s
->name
.c_str(), &snap_protected
);
140 std::cerr
<< "rbd: unable to retrieve snap protection" << std::endl
;
146 protected_str
= snap_protected
? "true" : "false";
147 f
->open_object_section("snapshot");
148 f
->dump_unsigned("id", s
->id
);
149 f
->dump_string("name", s
->name
);
150 f
->dump_unsigned("size", s
->size
);
151 f
->dump_string("protected", protected_str
);
152 f
->dump_string("timestamp", tt_str
);
154 f
->open_object_section("namespace");
155 f
->dump_string("type", snap_namespace_name
);
156 if (get_group_res
== 0) {
157 std::string pool_name
= pool_map
[group_snap
.group_pool
];
158 f
->dump_string("pool", pool_name
);
159 f
->dump_string("group", group_snap
.group_name
);
160 f
->dump_string("group snap", group_snap
.group_snap_name
);
161 } else if (get_trash_res
== 0) {
162 f
->dump_string("original_name", trash_original_name
);
163 } else if (get_mirror_res
== 0) {
164 f
->dump_string("state", mirror_snap_state
);
165 f
->open_array_section("mirror_peer_uuids");
166 for (auto &uuid
: mirror_snap
.mirror_peer_uuids
) {
167 f
->dump_string("peer_uuid", uuid
);
170 f
->dump_bool("complete", mirror_snap
.complete
);
171 if (mirror_snap
.state
== RBD_SNAP_MIRROR_STATE_NON_PRIMARY
||
172 mirror_snap
.state
== RBD_SNAP_MIRROR_STATE_NON_PRIMARY_DEMOTED
) {
173 f
->dump_string("primary_mirror_uuid",
174 mirror_snap
.primary_mirror_uuid
);
175 f
->dump_unsigned("primary_snap_id",
176 mirror_snap
.primary_snap_id
);
177 f
->dump_unsigned("last_copied_object_number",
178 mirror_snap
.last_copied_object_number
);
185 protected_str
= snap_protected
? "yes" : "";
186 t
<< s
->id
<< s
->name
<< stringify(byte_u_t(s
->size
)) << protected_str
<< tt_str
;
189 std::ostringstream oss
;
190 oss
<< snap_namespace_name
;
192 if (get_group_res
== 0) {
193 std::string pool_name
= pool_map
[group_snap
.group_pool
];
194 oss
<< " (" << pool_name
<< "/"
195 << group_snap
.group_name
<< "@"
196 << group_snap
.group_snap_name
<< ")";
197 } else if (get_trash_res
== 0) {
198 oss
<< " (" << trash_original_name
<< ")";
199 } else if (get_mirror_res
== 0) {
200 oss
<< " (" << mirror_snap_state
<< " "
201 << "peer_uuids:[" << mirror_snap
.mirror_peer_uuids
<< "]";
202 if (mirror_snap
.state
== RBD_SNAP_MIRROR_STATE_NON_PRIMARY
||
203 mirror_snap
.state
== RBD_SNAP_MIRROR_STATE_NON_PRIMARY_DEMOTED
) {
204 oss
<< " " << mirror_snap
.primary_mirror_uuid
<< ":"
205 << mirror_snap
.primary_snap_id
<< " ";
206 if (!mirror_snap
.complete
) {
207 if (info
.num_objs
> 0) {
208 auto progress
= std::min
<uint64_t>(
209 100, 100 * mirror_snap
.last_copied_object_number
/
211 oss
<< progress
<< "% ";
223 t
<< TextTable::endrow
;
230 } else if (snaps
.size()) {
237 int do_add_snap(librbd::Image
& image
, const char *snapname
,
238 uint32_t flags
, bool no_progress
)
240 utils::ProgressContext
pc("Creating snap", no_progress
);
242 int r
= image
.snap_create2(snapname
, flags
, pc
);
252 int do_remove_snap(librbd::Image
& image
, const char *snapname
, bool force
,
255 uint32_t flags
= force
? RBD_SNAP_REMOVE_FORCE
: 0;
257 utils::ProgressContext
pc("Removing snap", no_progress
);
259 r
= image
.snap_remove2(snapname
, flags
, pc
);
269 int do_rollback_snap(librbd::Image
& image
, const char *snapname
,
272 utils::ProgressContext
pc("Rolling back to snapshot", no_progress
);
273 int r
= image
.snap_rollback_with_progress(snapname
, pc
);
282 int do_purge_snaps(librbd::Image
& image
, bool no_progress
)
284 utils::ProgressContext
pc("Removing all snapshots", no_progress
);
285 std::vector
<librbd::snap_info_t
> snaps
;
286 bool is_protected
= false;
287 int r
= image
.snap_list(snaps
);
291 } else if (0 == snaps
.size()) {
294 std::list
<std::string
> protect
;
295 snaps
.erase(remove_if(snaps
.begin(),
297 boost::bind(utils::is_not_user_snap_namespace
, &image
, _1
)),
299 for (auto it
= snaps
.begin(); it
!= snaps
.end();) {
300 r
= image
.snap_is_protected(it
->name
.c_str(), &is_protected
);
304 } else if (is_protected
== true) {
305 protect
.push_back(it
->name
.c_str());
312 if (!protect
.empty()) {
313 std::cout
<< "rbd: error removing snapshot(s) '" << protect
<< "', which "
314 << (1 == protect
.size() ? "is" : "are")
315 << " protected - these must be unprotected with "
316 << "`rbd snap unprotect`."
319 for (size_t i
= 0; i
< snaps
.size(); ++i
) {
320 r
= image
.snap_remove(snaps
[i
].name
.c_str());
325 pc
.update_progress(i
+ 1, snaps
.size() + protect
.size());
328 if (!protect
.empty()) {
330 } else if (snaps
.size() > 0) {
338 int do_protect_snap(librbd::Image
& image
, const char *snapname
)
340 int r
= image
.snap_protect(snapname
);
347 int do_unprotect_snap(librbd::Image
& image
, const char *snapname
)
349 int r
= image
.snap_unprotect(snapname
);
356 int do_set_limit(librbd::Image
& image
, uint64_t limit
)
358 return image
.snap_set_limit(limit
);
361 void get_list_arguments(po::options_description
*positional
,
362 po::options_description
*options
) {
363 at::add_image_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_NONE
);
364 at::add_image_id_option(options
);
365 at::add_format_options(options
);
367 std::string name
= ALL_NAME
+ ",a";
369 options
->add_options()
370 (name
.c_str(), po::bool_switch(), "list snapshots from all namespaces");
373 int execute_list(const po::variables_map
&vm
,
374 const std::vector
<std::string
> &ceph_global_init_args
) {
375 size_t arg_index
= 0;
376 std::string pool_name
;
377 std::string namespace_name
;
378 std::string image_name
;
379 std::string snap_name
;
380 std::string image_id
;
382 if (vm
.count(at::IMAGE_ID
)) {
383 image_id
= vm
[at::IMAGE_ID
].as
<std::string
>();
386 int r
= utils::get_pool_image_snapshot_names(
387 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
388 &image_name
, &snap_name
, image_id
.empty(),
389 utils::SNAPSHOT_PRESENCE_NONE
, utils::SPEC_VALIDATION_NONE
);
394 if (!image_id
.empty() && !image_name
.empty()) {
395 std::cerr
<< "rbd: trying to access image using both name and id. "
400 at::Format::Formatter formatter
;
401 r
= utils::get_formatter(vm
, &formatter
);
406 librados::Rados rados
;
407 librados::IoCtx io_ctx
;
409 r
= utils::init_and_open_image(pool_name
, namespace_name
, image_name
,
410 image_id
, "", true, &rados
, &io_ctx
, &image
);
415 bool all_snaps
= vm
[ALL_NAME
].as
<bool>();
416 r
= do_list_snaps(image
, formatter
.get(), all_snaps
, rados
);
418 std::cerr
<< "rbd: failed to list snapshots: " << cpp_strerror(r
)
425 void get_create_arguments(po::options_description
*positional
,
426 po::options_description
*options
) {
427 at::add_snap_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_NONE
);
428 at::add_snap_create_options(options
);
429 at::add_no_progress_option(options
);
432 int execute_create(const po::variables_map
&vm
,
433 const std::vector
<std::string
> &ceph_global_init_args
) {
434 size_t arg_index
= 0;
435 std::string pool_name
;
436 std::string namespace_name
;
437 std::string image_name
;
438 std::string snap_name
;
439 int r
= utils::get_pool_image_snapshot_names(
440 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
441 &image_name
, &snap_name
, true, utils::SNAPSHOT_PRESENCE_REQUIRED
,
442 utils::SPEC_VALIDATION_SNAP
);
448 r
= utils::get_snap_create_flags(vm
, &flags
);
453 librados::Rados rados
;
454 librados::IoCtx io_ctx
;
456 r
= utils::init_and_open_image(pool_name
, namespace_name
, image_name
, "", "",
457 false, &rados
, &io_ctx
, &image
);
462 r
= do_add_snap(image
, snap_name
.c_str(), flags
,
463 vm
[at::NO_PROGRESS
].as
<bool>());
465 std::cerr
<< "rbd: failed to create snapshot: " << cpp_strerror(r
)
472 void get_remove_arguments(po::options_description
*positional
,
473 po::options_description
*options
) {
474 at::add_snap_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_NONE
);
475 at::add_image_id_option(options
);
476 at::add_snap_id_option(options
);
477 at::add_no_progress_option(options
);
479 options
->add_options()
480 ("force", po::bool_switch(), "flatten children and unprotect snapshot if needed.");
483 int execute_remove(const po::variables_map
&vm
,
484 const std::vector
<std::string
> &ceph_global_init_args
) {
485 size_t arg_index
= 0;
486 std::string pool_name
;
487 std::string namespace_name
;
488 std::string image_name
;
489 std::string snap_name
;
490 std::string image_id
;
491 uint64_t snap_id
= CEPH_NOSNAP
;
492 bool force
= vm
["force"].as
<bool>();
493 bool no_progress
= vm
[at::NO_PROGRESS
].as
<bool>();
495 if (vm
.count(at::IMAGE_ID
)) {
496 image_id
= vm
[at::IMAGE_ID
].as
<std::string
>();
498 if (vm
.count(at::SNAPSHOT_ID
)) {
499 snap_id
= vm
[at::SNAPSHOT_ID
].as
<uint64_t>();
502 int r
= utils::get_pool_image_snapshot_names(
503 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
504 &image_name
, &snap_name
, image_id
.empty(),
505 (snap_id
== CEPH_NOSNAP
? utils::SNAPSHOT_PRESENCE_REQUIRED
:
506 utils::SNAPSHOT_PRESENCE_PERMITTED
),
507 utils::SPEC_VALIDATION_NONE
);
512 if (!image_id
.empty() && !image_name
.empty()) {
513 std::cerr
<< "rbd: trying to access image using both name and id."
516 } else if (!snap_name
.empty() && snap_id
!= CEPH_NOSNAP
) {
517 std::cerr
<< "rbd: trying to access snapshot using both name and id."
520 } else if ((force
|| no_progress
) && snap_id
!= CEPH_NOSNAP
) {
521 std::cerr
<< "rbd: force and no-progress options not permitted when "
522 << "removing by id." << std::endl
;
526 librados::Rados rados
;
527 librados::IoCtx io_ctx
;
529 r
= utils::init(pool_name
, namespace_name
, &rados
, &io_ctx
);
534 io_ctx
.set_pool_full_try();
535 if (image_id
.empty()) {
536 r
= utils::open_image(io_ctx
, image_name
, false, &image
);
538 r
= utils::open_image_by_id(io_ctx
, image_id
, false, &image
);
544 if (!snap_name
.empty()) {
545 r
= do_remove_snap(image
, snap_name
.c_str(), force
, no_progress
);
547 r
= image
.snap_remove_by_id(snap_id
);
552 std::cerr
<< "rbd: snapshot "
553 << (snap_name
.empty() ? std::string("id ") + stringify(snap_id
) :
554 std::string("'") + snap_name
+ "'")
555 << " is protected from removal." << std::endl
;
557 std::cerr
<< "rbd: failed to remove snapshot: " << cpp_strerror(r
)
565 void get_purge_arguments(po::options_description
*positional
,
566 po::options_description
*options
) {
567 at::add_image_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_NONE
);
568 at::add_image_id_option(options
);
569 at::add_no_progress_option(options
);
572 int execute_purge(const po::variables_map
&vm
,
573 const std::vector
<std::string
> &ceph_global_init_args
) {
574 size_t arg_index
= 0;
575 std::string pool_name
;
576 std::string namespace_name
;
577 std::string image_name
;
578 std::string snap_name
;
579 std::string image_id
;
581 if (vm
.count(at::IMAGE_ID
)) {
582 image_id
= vm
[at::IMAGE_ID
].as
<std::string
>();
585 int r
= utils::get_pool_image_snapshot_names(
586 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
587 &image_name
, &snap_name
, image_id
.empty(),
588 utils::SNAPSHOT_PRESENCE_NONE
, utils::SPEC_VALIDATION_NONE
);
593 if (!image_id
.empty() && !image_name
.empty()) {
594 std::cerr
<< "rbd: trying to access image using both name and id. "
599 librados::Rados rados
;
600 librados::IoCtx io_ctx
;
602 r
= utils::init(pool_name
, namespace_name
, &rados
, &io_ctx
);
607 io_ctx
.set_pool_full_try();
608 if (image_id
.empty()) {
609 r
= utils::open_image(io_ctx
, image_name
, false, &image
);
611 r
= utils::open_image_by_id(io_ctx
, image_id
, false, &image
);
617 r
= do_purge_snaps(image
, vm
[at::NO_PROGRESS
].as
<bool>());
620 std::cerr
<< "rbd: removing snaps failed: " << cpp_strerror(r
)
628 void get_rollback_arguments(po::options_description
*positional
,
629 po::options_description
*options
) {
630 at::add_snap_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_NONE
);
631 at::add_no_progress_option(options
);
634 int execute_rollback(const po::variables_map
&vm
,
635 const std::vector
<std::string
> &ceph_global_init_args
) {
636 size_t arg_index
= 0;
637 std::string pool_name
;
638 std::string namespace_name
;
639 std::string image_name
;
640 std::string snap_name
;
641 int r
= utils::get_pool_image_snapshot_names(
642 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
643 &image_name
, &snap_name
, true, utils::SNAPSHOT_PRESENCE_REQUIRED
,
644 utils::SPEC_VALIDATION_NONE
);
649 librados::Rados rados
;
650 librados::IoCtx io_ctx
;
652 r
= utils::init_and_open_image(pool_name
, namespace_name
, image_name
, "", "",
653 false, &rados
, &io_ctx
, &image
);
658 r
= do_rollback_snap(image
, snap_name
.c_str(),
659 vm
[at::NO_PROGRESS
].as
<bool>());
661 std::cerr
<< "rbd: rollback failed: " << cpp_strerror(r
) << std::endl
;
667 void get_protect_arguments(po::options_description
*positional
,
668 po::options_description
*options
) {
669 at::add_snap_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_NONE
);
672 int execute_protect(const po::variables_map
&vm
,
673 const std::vector
<std::string
> &ceph_global_init_args
) {
674 size_t arg_index
= 0;
675 std::string pool_name
;
676 std::string namespace_name
;
677 std::string image_name
;
678 std::string snap_name
;
679 int r
= utils::get_pool_image_snapshot_names(
680 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
681 &image_name
, &snap_name
, true, utils::SNAPSHOT_PRESENCE_REQUIRED
,
682 utils::SPEC_VALIDATION_NONE
);
687 librados::Rados rados
;
688 librados::IoCtx io_ctx
;
690 r
= utils::init_and_open_image(pool_name
, namespace_name
, image_name
, "", "",
691 false, &rados
, &io_ctx
, &image
);
696 bool is_protected
= false;
697 r
= image
.snap_is_protected(snap_name
.c_str(), &is_protected
);
699 std::cerr
<< "rbd: protecting snap failed: " << cpp_strerror(r
)
702 } else if (is_protected
) {
703 std::cerr
<< "rbd: snap is already protected" << std::endl
;
707 r
= do_protect_snap(image
, snap_name
.c_str());
709 std::cerr
<< "rbd: protecting snap failed: " << cpp_strerror(r
)
716 void get_unprotect_arguments(po::options_description
*positional
,
717 po::options_description
*options
) {
718 at::add_snap_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_NONE
);
719 at::add_image_id_option(options
);
722 int execute_unprotect(const po::variables_map
&vm
,
723 const std::vector
<std::string
> &ceph_global_init_args
) {
724 size_t arg_index
= 0;
725 std::string pool_name
;
726 std::string namespace_name
;
727 std::string image_name
;
728 std::string snap_name
;
729 std::string image_id
;
731 if (vm
.count(at::IMAGE_ID
)) {
732 image_id
= vm
[at::IMAGE_ID
].as
<std::string
>();
735 int r
= utils::get_pool_image_snapshot_names(
736 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
737 &image_name
, &snap_name
, image_id
.empty(),
738 utils::SNAPSHOT_PRESENCE_REQUIRED
, utils::SPEC_VALIDATION_NONE
);
743 if (!image_id
.empty() && !image_name
.empty()) {
744 std::cerr
<< "rbd: trying to access image using both name and id. "
749 librados::Rados rados
;
750 librados::IoCtx io_ctx
;
752 r
= utils::init(pool_name
, namespace_name
, &rados
, &io_ctx
);
757 io_ctx
.set_pool_full_try();
758 if (image_id
.empty()) {
759 r
= utils::open_image(io_ctx
, image_name
, false, &image
);
761 r
= utils::open_image_by_id(io_ctx
, image_id
, false, &image
);
767 bool is_protected
= false;
768 r
= image
.snap_is_protected(snap_name
.c_str(), &is_protected
);
770 std::cerr
<< "rbd: unprotecting snap failed: " << cpp_strerror(r
)
773 } else if (!is_protected
) {
774 std::cerr
<< "rbd: snap is already unprotected" << std::endl
;
778 r
= do_unprotect_snap(image
, snap_name
.c_str());
780 std::cerr
<< "rbd: unprotecting snap failed: " << cpp_strerror(r
)
787 void get_set_limit_arguments(po::options_description
*pos
,
788 po::options_description
*opt
) {
789 at::add_image_spec_options(pos
, opt
, at::ARGUMENT_MODIFIER_NONE
);
790 at::add_limit_option(opt
);
793 int execute_set_limit(const po::variables_map
&vm
,
794 const std::vector
<std::string
> &ceph_global_init_args
) {
795 size_t arg_index
= 0;
796 std::string pool_name
;
797 std::string namespace_name
;
798 std::string image_name
;
799 std::string snap_name
;
802 int r
= utils::get_pool_image_snapshot_names(
803 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
804 &image_name
, &snap_name
, true, utils::SNAPSHOT_PRESENCE_NONE
,
805 utils::SPEC_VALIDATION_NONE
);
810 if (vm
.count(at::LIMIT
)) {
811 limit
= vm
[at::LIMIT
].as
<uint64_t>();
813 std::cerr
<< "rbd: must specify --limit <num>" << std::endl
;
817 librados::Rados rados
;
818 librados::IoCtx io_ctx
;
820 r
= utils::init_and_open_image(pool_name
, namespace_name
, image_name
, "", "",
821 false, &rados
, &io_ctx
, &image
);
826 r
= do_set_limit(image
, limit
);
828 std::cerr
<< "rbd: setting snapshot limit failed: " << cpp_strerror(r
)
835 void get_clear_limit_arguments(po::options_description
*pos
,
836 po::options_description
*opt
) {
837 at::add_image_spec_options(pos
, opt
, at::ARGUMENT_MODIFIER_NONE
);
840 int execute_clear_limit(const po::variables_map
&vm
,
841 const std::vector
<std::string
> &ceph_global_init_args
) {
842 size_t arg_index
= 0;
843 std::string pool_name
;
844 std::string namespace_name
;
845 std::string image_name
;
846 std::string snap_name
;
848 int r
= utils::get_pool_image_snapshot_names(
849 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
850 &image_name
, &snap_name
, true, utils::SNAPSHOT_PRESENCE_NONE
,
851 utils::SPEC_VALIDATION_NONE
);
856 librados::Rados rados
;
857 librados::IoCtx io_ctx
;
859 r
= utils::init_and_open_image(pool_name
, namespace_name
, image_name
, "", "",
860 false, &rados
, &io_ctx
, &image
);
865 r
= do_set_limit(image
, UINT64_MAX
);
867 std::cerr
<< "rbd: clearing snapshot limit failed: " << cpp_strerror(r
)
874 void get_rename_arguments(po::options_description
*positional
,
875 po::options_description
*options
) {
876 at::add_snap_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_SOURCE
);
877 at::add_snap_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_DEST
);
880 int execute_rename(const po::variables_map
&vm
,
881 const std::vector
<std::string
> &ceph_global_init_args
) {
882 size_t arg_index
= 0;
883 std::string pool_name
;
884 std::string namespace_name
;
885 std::string image_name
;
886 std::string src_snap_name
;
887 int r
= utils::get_pool_image_snapshot_names(
888 vm
, at::ARGUMENT_MODIFIER_SOURCE
, &arg_index
, &pool_name
, &namespace_name
,
889 &image_name
, &src_snap_name
, true, utils::SNAPSHOT_PRESENCE_REQUIRED
,
890 utils::SPEC_VALIDATION_NONE
);
895 std::string
dest_pool_name(pool_name
);
896 std::string
dest_namespace_name(namespace_name
);
897 std::string dest_image_name
;
898 std::string dest_snap_name
;
899 r
= utils::get_pool_image_snapshot_names(
900 vm
, at::ARGUMENT_MODIFIER_DEST
, &arg_index
, &dest_pool_name
,
901 &dest_namespace_name
, &dest_image_name
, &dest_snap_name
, true,
902 utils::SNAPSHOT_PRESENCE_REQUIRED
, utils::SPEC_VALIDATION_SNAP
);
907 if (pool_name
!= dest_pool_name
) {
908 std::cerr
<< "rbd: source and destination pool must be the same"
911 } else if (namespace_name
!= dest_namespace_name
) {
912 std::cerr
<< "rbd: source and destination namespace must be the same"
915 } else if (image_name
!= dest_image_name
) {
916 std::cerr
<< "rbd: source and destination image name must be the same"
921 librados::Rados rados
;
922 librados::IoCtx io_ctx
;
924 r
= utils::init_and_open_image(pool_name
, namespace_name
, image_name
, "", "",
925 false, &rados
, &io_ctx
, &image
);
930 r
= image
.snap_rename(src_snap_name
.c_str(), dest_snap_name
.c_str());
932 std::cerr
<< "rbd: renaming snap failed: " << cpp_strerror(r
)
939 Shell::Action
action_list(
940 {"snap", "list"}, {"snap", "ls"}, "Dump list of image snapshots.", "",
941 &get_list_arguments
, &execute_list
);
942 Shell::Action
action_create(
943 {"snap", "create"}, {"snap", "add"}, "Create a snapshot.", "",
944 &get_create_arguments
, &execute_create
);
945 Shell::Action
action_remove(
946 {"snap", "remove"}, {"snap", "rm"}, "Delete a snapshot.", "",
947 &get_remove_arguments
, &execute_remove
);
948 Shell::Action
action_purge(
949 {"snap", "purge"}, {}, "Delete all unprotected snapshots.", "",
950 &get_purge_arguments
, &execute_purge
);
951 Shell::Action
action_rollback(
952 {"snap", "rollback"}, {"snap", "revert"}, "Rollback image to snapshot.", "",
953 &get_rollback_arguments
, &execute_rollback
);
954 Shell::Action
action_protect(
955 {"snap", "protect"}, {}, "Prevent a snapshot from being deleted.", "",
956 &get_protect_arguments
, &execute_protect
);
957 Shell::Action
action_unprotect(
958 {"snap", "unprotect"}, {}, "Allow a snapshot to be deleted.", "",
959 &get_unprotect_arguments
, &execute_unprotect
);
960 Shell::Action
action_set_limit(
961 {"snap", "limit", "set"}, {}, "Limit the number of snapshots.", "",
962 &get_set_limit_arguments
, &execute_set_limit
);
963 Shell::Action
action_clear_limit(
964 {"snap", "limit", "clear"}, {}, "Remove snapshot limit.", "",
965 &get_clear_limit_arguments
, &execute_clear_limit
);
966 Shell::Action
action_rename(
967 {"snap", "rename"}, {}, "Rename a snapshot.", "",
968 &get_rename_arguments
, &execute_rename
);
971 } // namespace action