]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd/action/Snap.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / tools / rbd / action / Snap.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
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"
12#include <iostream>
13#include <boost/program_options.hpp>
f67539c2 14#include <boost/bind/bind.hpp>
7c673cae
FG
15
16namespace rbd {
17namespace action {
18namespace snap {
19
f67539c2
TL
20using namespace boost::placeholders;
21
11fdf7f2
TL
22static const std::string ALL_NAME("all");
23
7c673cae
FG
24namespace at = argument_types;
25namespace po = boost::program_options;
26
11fdf7f2 27int do_list_snaps(librbd::Image& image, Formatter *f, bool all_snaps, librados::Rados& rados)
7c673cae
FG
28{
29 std::vector<librbd::snap_info_t> snaps;
30 TextTable t;
31 int r;
32
33 r = image.snap_list(snaps);
11fdf7f2
TL
34 if (r < 0) {
35 std::cerr << "rbd: unable to list snapshots" << std::endl;
7c673cae 36 return r;
11fdf7f2
TL
37 }
38
9f95a23c 39 librbd::image_info_t info;
11fdf7f2
TL
40 if (!all_snaps) {
41 snaps.erase(remove_if(snaps.begin(),
42 snaps.end(),
43 boost::bind(utils::is_not_user_snap_namespace, &image, _1)),
44 snaps.end());
9f95a23c
TL
45 } else if (!f) {
46 r = image.stat(info, sizeof(info));
47 if (r < 0) {
48 std::cerr << "rbd: unable to get image info" << std::endl;
49 return r;
50 }
11fdf7f2 51 }
7c673cae
FG
52
53 if (f) {
54 f->open_array_section("snapshots");
55 } else {
11fdf7f2 56 t.define_column("SNAPID", TextTable::LEFT, TextTable::RIGHT);
7c673cae 57 t.define_column("NAME", TextTable::LEFT, TextTable::LEFT);
11fdf7f2
TL
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);
61 if (all_snaps) {
62 t.define_column("NAMESPACE", TextTable::LEFT, TextTable::LEFT);
63 }
7c673cae
FG
64 }
65
11fdf7f2
TL
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());
69
7c673cae
FG
70 for (std::vector<librbd::snap_info_t>::iterator s = snaps.begin();
71 s != snaps.end(); ++s) {
72 struct timespec timestamp;
11fdf7f2 73 bool snap_protected = false;
7c673cae
FG
74 image.snap_get_timestamp(s->id, &timestamp);
75 string tt_str = "";
76 if(timestamp.tv_sec != 0) {
77 time_t tt = timestamp.tv_sec;
78 tt_str = ctime(&tt);
11fdf7f2
TL
79 tt_str = tt_str.substr(0, tt_str.length() - 1);
80 }
81
82 librbd::snap_namespace_type_t snap_namespace;
83 r = image.snap_get_namespace_type(s->id, &snap_namespace);
84 if (r < 0) {
85 std::cerr << "rbd: unable to retrieve snap namespace" << std::endl;
86 return r;
87 }
88
89 std::string snap_namespace_name = "Unknown";
90 switch (snap_namespace) {
91 case RBD_SNAP_NAMESPACE_TYPE_USER:
92 snap_namespace_name = "user";
93 break;
94 case RBD_SNAP_NAMESPACE_TYPE_GROUP:
95 snap_namespace_name = "group";
96 break;
97 case RBD_SNAP_NAMESPACE_TYPE_TRASH:
98 snap_namespace_name = "trash";
99 break;
9f95a23c
TL
100 case RBD_SNAP_NAMESPACE_TYPE_MIRROR:
101 snap_namespace_name = "mirror";
102 break;
11fdf7f2
TL
103 }
104
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;
9f95a23c
TL
109 int get_mirror_res = -ENOENT;
110 librbd::snap_mirror_namespace_t mirror_snap;
111 std::string mirror_snap_state = "unknown";
11fdf7f2
TL
112 if (snap_namespace == RBD_SNAP_NAMESPACE_TYPE_GROUP) {
113 get_group_res = image.snap_get_group_namespace(s->id, &group_snap,
114 sizeof(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);
9f95a23c
TL
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));
121
122 switch (mirror_snap.state) {
123 case RBD_SNAP_MIRROR_STATE_PRIMARY:
124 mirror_snap_state = "primary";
125 break;
126 case RBD_SNAP_MIRROR_STATE_NON_PRIMARY:
127 mirror_snap_state = "non-primary";
128 break;
129 case RBD_SNAP_MIRROR_STATE_PRIMARY_DEMOTED:
130 case RBD_SNAP_MIRROR_STATE_NON_PRIMARY_DEMOTED:
131 mirror_snap_state = "demoted";
132 break;
133 }
11fdf7f2
TL
134 }
135
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);
139 if (r < 0) {
140 std::cerr << "rbd: unable to retrieve snap protection" << std::endl;
141 return r;
142 }
7c673cae
FG
143 }
144
145 if (f) {
11fdf7f2 146 protected_str = snap_protected ? "true" : "false";
7c673cae
FG
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);
11fdf7f2 151 f->dump_string("protected", protected_str);
7c673cae 152 f->dump_string("timestamp", tt_str);
11fdf7f2 153 if (all_snaps) {
9f95a23c 154 f->open_object_section("namespace");
11fdf7f2 155 f->dump_string("type", snap_namespace_name);
9f95a23c
TL
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) {
11fdf7f2 162 f->dump_string("original_name", trash_original_name);
9f95a23c
TL
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);
168 }
169 f->close_section();
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);
179 }
11fdf7f2 180 }
9f95a23c 181 f->close_section();
11fdf7f2 182 }
7c673cae
FG
183 f->close_section();
184 } else {
11fdf7f2
TL
185 protected_str = snap_protected ? "yes" : "";
186 t << s->id << s->name << stringify(byte_u_t(s->size)) << protected_str << tt_str;
187
188 if (all_snaps) {
9f95a23c 189 ostringstream oss;
11fdf7f2
TL
190 oss << snap_namespace_name;
191
192 if (get_group_res == 0) {
9f95a23c
TL
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 << ")";
11fdf7f2
TL
197 } else if (get_trash_res == 0) {
198 oss << " (" << trash_original_name << ")";
9f95a23c
TL
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) {
1911f103
TL
204 oss << " " << mirror_snap.primary_mirror_uuid << ":"
205 << mirror_snap.primary_snap_id << " ";
9f95a23c
TL
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 /
210 info.num_objs);
211 oss << progress << "% ";
212 } else {
213 oss << "not ";
214 }
215 }
216 oss << "copied";
217 }
218 oss << ")";
11fdf7f2
TL
219 }
220
9f95a23c 221 t << oss.str();
11fdf7f2
TL
222 }
223 t << TextTable::endrow;
7c673cae
FG
224 }
225 }
226
227 if (f) {
228 f->close_section();
229 f->flush(std::cout);
230 } else if (snaps.size()) {
231 std::cout << t;
232 }
233
234 return 0;
235}
236
f67539c2
TL
237int do_add_snap(librbd::Image& image, const char *snapname,
238 uint32_t flags, bool no_progress)
7c673cae 239{
f67539c2
TL
240 utils::ProgressContext pc("Creating snap", no_progress);
241
242 int r = image.snap_create2(snapname, flags, pc);
243 if (r < 0) {
244 pc.fail();
7c673cae 245 return r;
f67539c2 246 }
7c673cae 247
f67539c2 248 pc.finish();
7c673cae
FG
249 return 0;
250}
251
252int do_remove_snap(librbd::Image& image, const char *snapname, bool force,
253 bool no_progress)
254{
255 uint32_t flags = force? RBD_SNAP_REMOVE_FORCE : 0;
256 int r = 0;
257 utils::ProgressContext pc("Removing snap", no_progress);
11fdf7f2 258
7c673cae
FG
259 r = image.snap_remove2(snapname, flags, pc);
260 if (r < 0) {
261 pc.fail();
262 return r;
263 }
264
265 pc.finish();
266 return 0;
267}
268
269int do_rollback_snap(librbd::Image& image, const char *snapname,
270 bool no_progress)
271{
272 utils::ProgressContext pc("Rolling back to snapshot", no_progress);
273 int r = image.snap_rollback_with_progress(snapname, pc);
274 if (r < 0) {
275 pc.fail();
276 return r;
277 }
278 pc.finish();
279 return 0;
280}
281
282int do_purge_snaps(librbd::Image& image, bool no_progress)
283{
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);
288 if (r < 0) {
289 pc.fail();
290 return r;
291 } else if (0 == snaps.size()) {
292 return 0;
293 } else {
11fdf7f2
TL
294 list<std::string> protect;
295 snaps.erase(remove_if(snaps.begin(),
296 snaps.end(),
297 boost::bind(utils::is_not_user_snap_namespace, &image, _1)),
298 snaps.end());
299 for (auto it = snaps.begin(); it != snaps.end();) {
300 r = image.snap_is_protected(it->name.c_str(), &is_protected);
7c673cae
FG
301 if (r < 0) {
302 pc.fail();
303 return r;
304 } else if (is_protected == true) {
11fdf7f2
TL
305 protect.push_back(it->name.c_str());
306 snaps.erase(it);
307 } else {
308 ++it;
7c673cae
FG
309 }
310 }
11fdf7f2
TL
311
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`."
317 << std::endl;
318 }
7c673cae
FG
319 for (size_t i = 0; i < snaps.size(); ++i) {
320 r = image.snap_remove(snaps[i].name.c_str());
321 if (r < 0) {
322 pc.fail();
323 return r;
324 }
11fdf7f2
TL
325 pc.update_progress(i + 1, snaps.size() + protect.size());
326 }
327
328 if (!protect.empty()) {
329 pc.fail();
330 } else if (snaps.size() > 0) {
331 pc.finish();
7c673cae
FG
332 }
333
7c673cae
FG
334 return 0;
335 }
336}
337
338int do_protect_snap(librbd::Image& image, const char *snapname)
339{
340 int r = image.snap_protect(snapname);
341 if (r < 0)
342 return r;
343
344 return 0;
345}
346
347int do_unprotect_snap(librbd::Image& image, const char *snapname)
348{
349 int r = image.snap_unprotect(snapname);
350 if (r < 0)
351 return r;
352
353 return 0;
354}
355
356int do_set_limit(librbd::Image& image, uint64_t limit)
357{
358 return image.snap_set_limit(limit);
359}
360
7c673cae
FG
361void 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);
11fdf7f2
TL
366
367 std::string name = ALL_NAME + ",a";
368
369 options->add_options()
370 (name.c_str(), po::bool_switch(), "list snapshots from all namespaces");
7c673cae
FG
371}
372
11fdf7f2
TL
373int execute_list(const po::variables_map &vm,
374 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
375 size_t arg_index = 0;
376 std::string pool_name;
11fdf7f2 377 std::string namespace_name;
7c673cae
FG
378 std::string image_name;
379 std::string snap_name;
380 std::string image_id;
381
382 if (vm.count(at::IMAGE_ID)) {
383 image_id = vm[at::IMAGE_ID].as<std::string>();
384 }
385
11fdf7f2
TL
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);
390 if (r < 0) {
391 return r;
392 }
7c673cae 393
11fdf7f2 394 if (!image_id.empty() && !image_name.empty()) {
7c673cae
FG
395 std::cerr << "rbd: trying to access image using both name and id. "
396 << std::endl;
397 return -EINVAL;
398 }
399
7c673cae
FG
400 at::Format::Formatter formatter;
401 r = utils::get_formatter(vm, &formatter);
402 if (r < 0) {
403 return r;
404 }
405
406 librados::Rados rados;
407 librados::IoCtx io_ctx;
408 librbd::Image image;
11fdf7f2
TL
409 r = utils::init_and_open_image(pool_name, namespace_name, image_name,
410 image_id, "", true, &rados, &io_ctx, &image);
7c673cae
FG
411 if (r < 0) {
412 return r;
413 }
414
11fdf7f2
TL
415 bool all_snaps = vm[ALL_NAME].as<bool>();
416 r = do_list_snaps(image, formatter.get(), all_snaps, rados);
7c673cae
FG
417 if (r < 0) {
418 cerr << "rbd: failed to list snapshots: " << cpp_strerror(r)
419 << std::endl;
420 return r;
421 }
422 return 0;
423}
424
425void get_create_arguments(po::options_description *positional,
426 po::options_description *options) {
427 at::add_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
f67539c2
TL
428 at::add_snap_create_options(options);
429 at::add_no_progress_option(options);
7c673cae
FG
430}
431
11fdf7f2
TL
432int execute_create(const po::variables_map &vm,
433 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
434 size_t arg_index = 0;
435 std::string pool_name;
11fdf7f2 436 std::string namespace_name;
7c673cae
FG
437 std::string image_name;
438 std::string snap_name;
439 int r = utils::get_pool_image_snapshot_names(
11fdf7f2
TL
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);
7c673cae
FG
443 if (r < 0) {
444 return r;
445 }
446
f67539c2
TL
447 uint32_t flags;
448 r = utils::get_snap_create_flags(vm, &flags);
449 if (r < 0) {
450 return r;
451 }
452
7c673cae
FG
453 librados::Rados rados;
454 librados::IoCtx io_ctx;
455 librbd::Image image;
11fdf7f2
TL
456 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
457 false, &rados, &io_ctx, &image);
7c673cae
FG
458 if (r < 0) {
459 return r;
460 }
461
f67539c2
TL
462 r = do_add_snap(image, snap_name.c_str(), flags,
463 vm[at::NO_PROGRESS].as<bool>());
7c673cae
FG
464 if (r < 0) {
465 cerr << "rbd: failed to create snapshot: " << cpp_strerror(r)
466 << std::endl;
467 return r;
468 }
469 return 0;
470}
471
472void get_remove_arguments(po::options_description *positional,
473 po::options_description *options) {
474 at::add_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
7c673cae 475 at::add_image_id_option(options);
11fdf7f2
TL
476 at::add_snap_id_option(options);
477 at::add_no_progress_option(options);
7c673cae
FG
478
479 options->add_options()
480 ("force", po::bool_switch(), "flatten children and unprotect snapshot if needed.");
481}
482
11fdf7f2
TL
483int execute_remove(const po::variables_map &vm,
484 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
485 size_t arg_index = 0;
486 std::string pool_name;
11fdf7f2 487 std::string namespace_name;
7c673cae
FG
488 std::string image_name;
489 std::string snap_name;
490 std::string image_id;
11fdf7f2 491 uint64_t snap_id = CEPH_NOSNAP;
7c673cae 492 bool force = vm["force"].as<bool>();
11fdf7f2 493 bool no_progress = vm[at::NO_PROGRESS].as<bool>();
7c673cae
FG
494
495 if (vm.count(at::IMAGE_ID)) {
496 image_id = vm[at::IMAGE_ID].as<std::string>();
497 }
11fdf7f2
TL
498 if (vm.count(at::SNAPSHOT_ID)) {
499 snap_id = vm[at::SNAPSHOT_ID].as<uint64_t>();
7c673cae
FG
500 }
501
11fdf7f2
TL
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);
7c673cae
FG
508 if (r < 0) {
509 return r;
510 }
511
11fdf7f2
TL
512 if (!image_id.empty() && !image_name.empty()) {
513 std::cerr << "rbd: trying to access image using both name and id."
514 << std::endl;
515 return -EINVAL;
516 } else if (!snap_name.empty() && snap_id != CEPH_NOSNAP) {
517 std::cerr << "rbd: trying to access snapshot using both name and id."
518 << std::endl;
519 return -EINVAL;
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;
523 return -EINVAL;
524 }
525
7c673cae
FG
526 librados::Rados rados;
527 librados::IoCtx io_ctx;
528 librbd::Image image;
11fdf7f2 529 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
7c673cae
FG
530 if (r < 0) {
531 return r;
532 }
533
9f95a23c 534 io_ctx.set_pool_full_try();
7c673cae
FG
535 if (image_id.empty()) {
536 r = utils::open_image(io_ctx, image_name, false, &image);
537 } else {
538 r = utils::open_image_by_id(io_ctx, image_id, false, &image);
539 }
540 if (r < 0) {
541 return r;
542 }
543
11fdf7f2
TL
544 if (!snap_name.empty()) {
545 r = do_remove_snap(image, snap_name.c_str(), force, no_progress);
546 } else {
547 r = image.snap_remove_by_id(snap_id);
548 }
549
7c673cae
FG
550 if (r < 0) {
551 if (r == -EBUSY) {
11fdf7f2
TL
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;
7c673cae
FG
556 } else {
557 std::cerr << "rbd: failed to remove snapshot: " << cpp_strerror(r)
558 << std::endl;
559 }
560 return r;
561 }
562 return 0;
563}
564
565void 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);
570}
571
11fdf7f2
TL
572int execute_purge(const po::variables_map &vm,
573 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
574 size_t arg_index = 0;
575 std::string pool_name;
11fdf7f2 576 std::string namespace_name;
7c673cae
FG
577 std::string image_name;
578 std::string snap_name;
579 std::string image_id;
580
581 if (vm.count(at::IMAGE_ID)) {
582 image_id = vm[at::IMAGE_ID].as<std::string>();
583 }
584
11fdf7f2
TL
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);
589 if (r < 0) {
590 return r;
591 }
7c673cae 592
11fdf7f2 593 if (!image_id.empty() && !image_name.empty()) {
7c673cae
FG
594 std::cerr << "rbd: trying to access image using both name and id. "
595 << std::endl;
596 return -EINVAL;
597 }
598
7c673cae
FG
599 librados::Rados rados;
600 librados::IoCtx io_ctx;
601 librbd::Image image;
11fdf7f2 602 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
7c673cae
FG
603 if (r < 0) {
604 return r;
605 }
606
9f95a23c 607 io_ctx.set_pool_full_try();
7c673cae
FG
608 if (image_id.empty()) {
609 r = utils::open_image(io_ctx, image_name, false, &image);
610 } else {
611 r = utils::open_image_by_id(io_ctx, image_id, false, &image);
612 }
613 if (r < 0) {
614 return r;
615 }
616
617 r = do_purge_snaps(image, vm[at::NO_PROGRESS].as<bool>());
618 if (r < 0) {
619 if (r != -EBUSY) {
620 std::cerr << "rbd: removing snaps failed: " << cpp_strerror(r)
621 << std::endl;
622 }
623 return r;
624 }
625 return 0;
626}
627
628void 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);
632}
633
11fdf7f2
TL
634int execute_rollback(const po::variables_map &vm,
635 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
636 size_t arg_index = 0;
637 std::string pool_name;
11fdf7f2 638 std::string namespace_name;
7c673cae
FG
639 std::string image_name;
640 std::string snap_name;
641 int r = utils::get_pool_image_snapshot_names(
11fdf7f2
TL
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);
7c673cae
FG
645 if (r < 0) {
646 return r;
647 }
648
649 librados::Rados rados;
650 librados::IoCtx io_ctx;
651 librbd::Image image;
11fdf7f2
TL
652 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
653 false, &rados, &io_ctx, &image);
7c673cae
FG
654 if (r < 0) {
655 return r;
656 }
657
658 r = do_rollback_snap(image, snap_name.c_str(),
659 vm[at::NO_PROGRESS].as<bool>());
660 if (r < 0) {
661 std::cerr << "rbd: rollback failed: " << cpp_strerror(r) << std::endl;
662 return r;
663 }
664 return 0;
665}
666
667void get_protect_arguments(po::options_description *positional,
668 po::options_description *options) {
669 at::add_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
670}
671
11fdf7f2
TL
672int execute_protect(const po::variables_map &vm,
673 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
674 size_t arg_index = 0;
675 std::string pool_name;
11fdf7f2 676 std::string namespace_name;
7c673cae
FG
677 std::string image_name;
678 std::string snap_name;
679 int r = utils::get_pool_image_snapshot_names(
11fdf7f2
TL
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);
7c673cae
FG
683 if (r < 0) {
684 return r;
685 }
686
687 librados::Rados rados;
688 librados::IoCtx io_ctx;
689 librbd::Image image;
11fdf7f2
TL
690 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
691 false, &rados, &io_ctx, &image);
7c673cae
FG
692 if (r < 0) {
693 return r;
694 }
695
696 bool is_protected = false;
697 r = image.snap_is_protected(snap_name.c_str(), &is_protected);
698 if (r < 0) {
699 std::cerr << "rbd: protecting snap failed: " << cpp_strerror(r)
700 << std::endl;
701 return r;
702 } else if (is_protected) {
703 std::cerr << "rbd: snap is already protected" << std::endl;
704 return -EBUSY;
705 }
706
707 r = do_protect_snap(image, snap_name.c_str());
708 if (r < 0) {
709 std::cerr << "rbd: protecting snap failed: " << cpp_strerror(r)
710 << std::endl;
711 return r;
712 }
713 return 0;
714}
715
716void 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);
720}
721
11fdf7f2
TL
722int execute_unprotect(const po::variables_map &vm,
723 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
724 size_t arg_index = 0;
725 std::string pool_name;
11fdf7f2 726 std::string namespace_name;
7c673cae
FG
727 std::string image_name;
728 std::string snap_name;
729 std::string image_id;
730
731 if (vm.count(at::IMAGE_ID)) {
732 image_id = vm[at::IMAGE_ID].as<std::string>();
733 }
734
11fdf7f2
TL
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);
739 if (r < 0) {
740 return r;
741 }
7c673cae 742
11fdf7f2 743 if (!image_id.empty() && !image_name.empty()) {
7c673cae
FG
744 std::cerr << "rbd: trying to access image using both name and id. "
745 << std::endl;
746 return -EINVAL;
747 }
748
7c673cae
FG
749 librados::Rados rados;
750 librados::IoCtx io_ctx;
751 librbd::Image image;
11fdf7f2 752 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
7c673cae
FG
753 if (r < 0) {
754 return r;
755 }
756
9f95a23c 757 io_ctx.set_pool_full_try();
7c673cae
FG
758 if (image_id.empty()) {
759 r = utils::open_image(io_ctx, image_name, false, &image);
760 } else {
761 r = utils::open_image_by_id(io_ctx, image_id, false, &image);
762 }
763 if (r < 0) {
764 return r;
765 }
766
767 bool is_protected = false;
768 r = image.snap_is_protected(snap_name.c_str(), &is_protected);
769 if (r < 0) {
770 std::cerr << "rbd: unprotecting snap failed: " << cpp_strerror(r)
771 << std::endl;
772 return r;
773 } else if (!is_protected) {
774 std::cerr << "rbd: snap is already unprotected" << std::endl;
775 return -EINVAL;
776 }
777
778 r = do_unprotect_snap(image, snap_name.c_str());
779 if (r < 0) {
780 std::cerr << "rbd: unprotecting snap failed: " << cpp_strerror(r)
781 << std::endl;
782 return r;
783 }
784 return 0;
785}
786
787void 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);
791}
792
11fdf7f2
TL
793int execute_set_limit(const po::variables_map &vm,
794 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
795 size_t arg_index = 0;
796 std::string pool_name;
11fdf7f2 797 std::string namespace_name;
7c673cae
FG
798 std::string image_name;
799 std::string snap_name;
800 uint64_t limit;
801
802 int r = utils::get_pool_image_snapshot_names(
11fdf7f2
TL
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);
7c673cae
FG
806 if (r < 0) {
807 return r;
808 }
809
810 if (vm.count(at::LIMIT)) {
811 limit = vm[at::LIMIT].as<uint64_t>();
812 } else {
813 std::cerr << "rbd: must specify --limit <num>" << std::endl;
814 return -ERANGE;
815 }
816
817 librados::Rados rados;
818 librados::IoCtx io_ctx;
819 librbd::Image image;
11fdf7f2
TL
820 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
821 false, &rados, &io_ctx, &image);
7c673cae
FG
822 if (r < 0) {
823 return r;
824 }
825
826 r = do_set_limit(image, limit);
827 if (r < 0) {
828 std::cerr << "rbd: setting snapshot limit failed: " << cpp_strerror(r)
829 << std::endl;
830 return r;
831 }
832 return 0;
833}
834
835void 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);
838}
839
11fdf7f2
TL
840int execute_clear_limit(const po::variables_map &vm,
841 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
842 size_t arg_index = 0;
843 std::string pool_name;
11fdf7f2 844 std::string namespace_name;
7c673cae
FG
845 std::string image_name;
846 std::string snap_name;
847
848 int r = utils::get_pool_image_snapshot_names(
11fdf7f2
TL
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);
7c673cae
FG
852 if (r < 0) {
853 return r;
854 }
855
856 librados::Rados rados;
857 librados::IoCtx io_ctx;
858 librbd::Image image;
11fdf7f2
TL
859 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
860 false, &rados, &io_ctx, &image);
7c673cae
FG
861 if (r < 0) {
862 return r;
863 }
864
11fdf7f2 865 r = do_set_limit(image, UINT64_MAX);
7c673cae
FG
866 if (r < 0) {
867 std::cerr << "rbd: clearing snapshot limit failed: " << cpp_strerror(r)
868 << std::endl;
869 return r;
870 }
871 return 0;
872}
873
874void 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);
878}
879
11fdf7f2
TL
880int execute_rename(const po::variables_map &vm,
881 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
882 size_t arg_index = 0;
883 std::string pool_name;
11fdf7f2 884 std::string namespace_name;
7c673cae
FG
885 std::string image_name;
886 std::string src_snap_name;
887 int r = utils::get_pool_image_snapshot_names(
11fdf7f2
TL
888 vm, at::ARGUMENT_MODIFIER_SOURCE, &arg_index, &pool_name, &namespace_name,
889 &image_name, &src_snap_name, true, utils::SNAPSHOT_PRESENCE_REQUIRED,
7c673cae
FG
890 utils::SPEC_VALIDATION_NONE);
891 if (r < 0) {
892 return -r;
893 }
894
895 std::string dest_pool_name(pool_name);
11fdf7f2 896 std::string dest_namespace_name(namespace_name);
7c673cae
FG
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,
11fdf7f2
TL
901 &dest_namespace_name, &dest_image_name, &dest_snap_name, true,
902 utils::SNAPSHOT_PRESENCE_REQUIRED, utils::SPEC_VALIDATION_SNAP);
7c673cae
FG
903 if (r < 0) {
904 return -r;
905 }
906
907 if (pool_name != dest_pool_name) {
908 std::cerr << "rbd: source and destination pool must be the same"
909 << std::endl;
910 return -EINVAL;
11fdf7f2
TL
911 } else if (namespace_name != dest_namespace_name) {
912 std::cerr << "rbd: source and destination namespace must be the same"
913 << std::endl;
914 return -EINVAL;
7c673cae
FG
915 } else if (image_name != dest_image_name) {
916 std::cerr << "rbd: source and destination image name must be the same"
917 << std::endl;
918 return -EINVAL;
919 }
11fdf7f2 920
7c673cae
FG
921 librados::Rados rados;
922 librados::IoCtx io_ctx;
923 librbd::Image image;
11fdf7f2
TL
924 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
925 false, &rados, &io_ctx, &image);
7c673cae
FG
926 if (r < 0) {
927 return r;
928 }
929
930 r = image.snap_rename(src_snap_name.c_str(), dest_snap_name.c_str());
931 if (r < 0) {
932 std::cerr << "rbd: renaming snap failed: " << cpp_strerror(r)
933 << std::endl;
934 return r;
935 }
936 return 0;
937}
938
939Shell::Action action_list(
940 {"snap", "list"}, {"snap", "ls"}, "Dump list of image snapshots.", "",
941 &get_list_arguments, &execute_list);
942Shell::Action action_create(
943 {"snap", "create"}, {"snap", "add"}, "Create a snapshot.", "",
944 &get_create_arguments, &execute_create);
945Shell::Action action_remove(
c07f9fc5 946 {"snap", "remove"}, {"snap", "rm"}, "Delete a snapshot.", "",
7c673cae
FG
947 &get_remove_arguments, &execute_remove);
948Shell::Action action_purge(
11fdf7f2 949 {"snap", "purge"}, {}, "Delete all unprotected snapshots.", "",
7c673cae
FG
950 &get_purge_arguments, &execute_purge);
951Shell::Action action_rollback(
952 {"snap", "rollback"}, {"snap", "revert"}, "Rollback image to snapshot.", "",
953 &get_rollback_arguments, &execute_rollback);
954Shell::Action action_protect(
955 {"snap", "protect"}, {}, "Prevent a snapshot from being deleted.", "",
956 &get_protect_arguments, &execute_protect);
957Shell::Action action_unprotect(
958 {"snap", "unprotect"}, {}, "Allow a snapshot to be deleted.", "",
959 &get_unprotect_arguments, &execute_unprotect);
960Shell::Action action_set_limit(
961 {"snap", "limit", "set"}, {}, "Limit the number of snapshots.", "",
962 &get_set_limit_arguments, &execute_set_limit);
963Shell::Action action_clear_limit(
964 {"snap", "limit", "clear"}, {}, "Remove snapshot limit.", "",
965 &get_clear_limit_arguments, &execute_clear_limit);
966Shell::Action action_rename(
967 {"snap", "rename"}, {}, "Rename a snapshot.", "",
968 &get_rename_arguments, &execute_rename);
969
970} // namespace snap
971} // namespace action
972} // namespace rbd