]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd/action/Snap.cc
update sources to ceph Nautilus 14.2.1
[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>
11fdf7f2 14#include <boost/bind.hpp>
7c673cae
FG
15
16namespace rbd {
17namespace action {
18namespace snap {
19
11fdf7f2
TL
20static const std::string ALL_NAME("all");
21
7c673cae
FG
22namespace at = argument_types;
23namespace po = boost::program_options;
24
11fdf7f2 25int do_list_snaps(librbd::Image& image, Formatter *f, bool all_snaps, librados::Rados& rados)
7c673cae
FG
26{
27 std::vector<librbd::snap_info_t> snaps;
28 TextTable t;
29 int r;
30
31 r = image.snap_list(snaps);
11fdf7f2
TL
32 if (r < 0) {
33 std::cerr << "rbd: unable to list snapshots" << std::endl;
7c673cae 34 return r;
11fdf7f2
TL
35 }
36
37 if (!all_snaps) {
38 snaps.erase(remove_if(snaps.begin(),
39 snaps.end(),
40 boost::bind(utils::is_not_user_snap_namespace, &image, _1)),
41 snaps.end());
42 }
7c673cae
FG
43
44 if (f) {
45 f->open_array_section("snapshots");
46 } else {
11fdf7f2 47 t.define_column("SNAPID", TextTable::LEFT, TextTable::RIGHT);
7c673cae 48 t.define_column("NAME", TextTable::LEFT, TextTable::LEFT);
11fdf7f2
TL
49 t.define_column("SIZE", TextTable::LEFT, TextTable::RIGHT);
50 t.define_column("PROTECTED", TextTable::LEFT, TextTable::LEFT);
51 t.define_column("TIMESTAMP", TextTable::LEFT, TextTable::RIGHT);
52 if (all_snaps) {
53 t.define_column("NAMESPACE", TextTable::LEFT, TextTable::LEFT);
54 }
7c673cae
FG
55 }
56
11fdf7f2
TL
57 std::list<std::pair<int64_t, std::string>> pool_list;
58 rados.pool_list2(pool_list);
59 std::map<int64_t, std::string> pool_map(pool_list.begin(), pool_list.end());
60
7c673cae
FG
61 for (std::vector<librbd::snap_info_t>::iterator s = snaps.begin();
62 s != snaps.end(); ++s) {
63 struct timespec timestamp;
11fdf7f2 64 bool snap_protected = false;
7c673cae
FG
65 image.snap_get_timestamp(s->id, &timestamp);
66 string tt_str = "";
67 if(timestamp.tv_sec != 0) {
68 time_t tt = timestamp.tv_sec;
69 tt_str = ctime(&tt);
11fdf7f2
TL
70 tt_str = tt_str.substr(0, tt_str.length() - 1);
71 }
72
73 librbd::snap_namespace_type_t snap_namespace;
74 r = image.snap_get_namespace_type(s->id, &snap_namespace);
75 if (r < 0) {
76 std::cerr << "rbd: unable to retrieve snap namespace" << std::endl;
77 return r;
78 }
79
80 std::string snap_namespace_name = "Unknown";
81 switch (snap_namespace) {
82 case RBD_SNAP_NAMESPACE_TYPE_USER:
83 snap_namespace_name = "user";
84 break;
85 case RBD_SNAP_NAMESPACE_TYPE_GROUP:
86 snap_namespace_name = "group";
87 break;
88 case RBD_SNAP_NAMESPACE_TYPE_TRASH:
89 snap_namespace_name = "trash";
90 break;
91 }
92
93 int get_trash_res = -ENOENT;
94 std::string trash_original_name;
95 int get_group_res = -ENOENT;
96 librbd::snap_group_namespace_t group_snap;
97 if (snap_namespace == RBD_SNAP_NAMESPACE_TYPE_GROUP) {
98 get_group_res = image.snap_get_group_namespace(s->id, &group_snap,
99 sizeof(group_snap));
100 } else if (snap_namespace == RBD_SNAP_NAMESPACE_TYPE_TRASH) {
101 get_trash_res = image.snap_get_trash_namespace(
102 s->id, &trash_original_name);
103 }
104
105 std::string protected_str = "";
106 if (snap_namespace == RBD_SNAP_NAMESPACE_TYPE_USER) {
107 r = image.snap_is_protected(s->name.c_str(), &snap_protected);
108 if (r < 0) {
109 std::cerr << "rbd: unable to retrieve snap protection" << std::endl;
110 return r;
111 }
7c673cae
FG
112 }
113
114 if (f) {
11fdf7f2 115 protected_str = snap_protected ? "true" : "false";
7c673cae
FG
116 f->open_object_section("snapshot");
117 f->dump_unsigned("id", s->id);
118 f->dump_string("name", s->name);
119 f->dump_unsigned("size", s->size);
11fdf7f2 120 f->dump_string("protected", protected_str);
7c673cae 121 f->dump_string("timestamp", tt_str);
11fdf7f2
TL
122 if (all_snaps) {
123 f->open_object_section("namespace");
124 f->dump_string("type", snap_namespace_name);
125 if (get_group_res == 0) {
126 std::string pool_name = pool_map[group_snap.group_pool];
127 f->dump_string("pool", pool_name);
128 f->dump_string("group", group_snap.group_name);
129 f->dump_string("group snap", group_snap.group_snap_name);
130 } else if (get_trash_res == 0) {
131 f->dump_string("original_name", trash_original_name);
132 }
133 f->close_section();
134 }
7c673cae
FG
135 f->close_section();
136 } else {
11fdf7f2
TL
137 protected_str = snap_protected ? "yes" : "";
138 t << s->id << s->name << stringify(byte_u_t(s->size)) << protected_str << tt_str;
139
140 if (all_snaps) {
141 ostringstream oss;
142 oss << snap_namespace_name;
143
144 if (get_group_res == 0) {
145 std::string pool_name = pool_map[group_snap.group_pool];
146 oss << " (" << pool_name << "/"
147 << group_snap.group_name << "@"
148 << group_snap.group_snap_name << ")";
149 } else if (get_trash_res == 0) {
150 oss << " (" << trash_original_name << ")";
151 }
152
153 t << oss.str();
154 }
155 t << TextTable::endrow;
7c673cae
FG
156 }
157 }
158
159 if (f) {
160 f->close_section();
161 f->flush(std::cout);
162 } else if (snaps.size()) {
163 std::cout << t;
164 }
165
166 return 0;
167}
168
169int do_add_snap(librbd::Image& image, const char *snapname)
170{
171 int r = image.snap_create(snapname);
172 if (r < 0)
173 return r;
174
175 return 0;
176}
177
178int do_remove_snap(librbd::Image& image, const char *snapname, bool force,
179 bool no_progress)
180{
181 uint32_t flags = force? RBD_SNAP_REMOVE_FORCE : 0;
182 int r = 0;
183 utils::ProgressContext pc("Removing snap", no_progress);
11fdf7f2 184
7c673cae
FG
185 r = image.snap_remove2(snapname, flags, pc);
186 if (r < 0) {
187 pc.fail();
188 return r;
189 }
190
191 pc.finish();
192 return 0;
193}
194
195int do_rollback_snap(librbd::Image& image, const char *snapname,
196 bool no_progress)
197{
198 utils::ProgressContext pc("Rolling back to snapshot", no_progress);
199 int r = image.snap_rollback_with_progress(snapname, pc);
200 if (r < 0) {
201 pc.fail();
202 return r;
203 }
204 pc.finish();
205 return 0;
206}
207
208int do_purge_snaps(librbd::Image& image, bool no_progress)
209{
210 utils::ProgressContext pc("Removing all snapshots", no_progress);
211 std::vector<librbd::snap_info_t> snaps;
212 bool is_protected = false;
213 int r = image.snap_list(snaps);
214 if (r < 0) {
215 pc.fail();
216 return r;
217 } else if (0 == snaps.size()) {
218 return 0;
219 } else {
11fdf7f2
TL
220 list<std::string> protect;
221 snaps.erase(remove_if(snaps.begin(),
222 snaps.end(),
223 boost::bind(utils::is_not_user_snap_namespace, &image, _1)),
224 snaps.end());
225 for (auto it = snaps.begin(); it != snaps.end();) {
226 r = image.snap_is_protected(it->name.c_str(), &is_protected);
7c673cae
FG
227 if (r < 0) {
228 pc.fail();
229 return r;
230 } else if (is_protected == true) {
11fdf7f2
TL
231 protect.push_back(it->name.c_str());
232 snaps.erase(it);
233 } else {
234 ++it;
7c673cae
FG
235 }
236 }
11fdf7f2
TL
237
238 if (!protect.empty()) {
239 std::cout << "rbd: error removing snapshot(s) '" << protect << "', which "
240 << (1 == protect.size() ? "is" : "are")
241 << " protected - these must be unprotected with "
242 << "`rbd snap unprotect`."
243 << std::endl;
244 }
7c673cae
FG
245 for (size_t i = 0; i < snaps.size(); ++i) {
246 r = image.snap_remove(snaps[i].name.c_str());
247 if (r < 0) {
248 pc.fail();
249 return r;
250 }
11fdf7f2
TL
251 pc.update_progress(i + 1, snaps.size() + protect.size());
252 }
253
254 if (!protect.empty()) {
255 pc.fail();
256 } else if (snaps.size() > 0) {
257 pc.finish();
7c673cae
FG
258 }
259
7c673cae
FG
260 return 0;
261 }
262}
263
264int do_protect_snap(librbd::Image& image, const char *snapname)
265{
266 int r = image.snap_protect(snapname);
267 if (r < 0)
268 return r;
269
270 return 0;
271}
272
273int do_unprotect_snap(librbd::Image& image, const char *snapname)
274{
275 int r = image.snap_unprotect(snapname);
276 if (r < 0)
277 return r;
278
279 return 0;
280}
281
282int do_set_limit(librbd::Image& image, uint64_t limit)
283{
284 return image.snap_set_limit(limit);
285}
286
7c673cae
FG
287void get_list_arguments(po::options_description *positional,
288 po::options_description *options) {
289 at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
290 at::add_image_id_option(options);
291 at::add_format_options(options);
11fdf7f2
TL
292
293 std::string name = ALL_NAME + ",a";
294
295 options->add_options()
296 (name.c_str(), po::bool_switch(), "list snapshots from all namespaces");
7c673cae
FG
297}
298
11fdf7f2
TL
299int execute_list(const po::variables_map &vm,
300 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
301 size_t arg_index = 0;
302 std::string pool_name;
11fdf7f2 303 std::string namespace_name;
7c673cae
FG
304 std::string image_name;
305 std::string snap_name;
306 std::string image_id;
307
308 if (vm.count(at::IMAGE_ID)) {
309 image_id = vm[at::IMAGE_ID].as<std::string>();
310 }
311
11fdf7f2
TL
312 int r = utils::get_pool_image_snapshot_names(
313 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
314 &image_name, &snap_name, image_id.empty(),
315 utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_NONE);
316 if (r < 0) {
317 return r;
318 }
7c673cae 319
11fdf7f2 320 if (!image_id.empty() && !image_name.empty()) {
7c673cae
FG
321 std::cerr << "rbd: trying to access image using both name and id. "
322 << std::endl;
323 return -EINVAL;
324 }
325
7c673cae
FG
326 at::Format::Formatter formatter;
327 r = utils::get_formatter(vm, &formatter);
328 if (r < 0) {
329 return r;
330 }
331
332 librados::Rados rados;
333 librados::IoCtx io_ctx;
334 librbd::Image image;
11fdf7f2
TL
335 r = utils::init_and_open_image(pool_name, namespace_name, image_name,
336 image_id, "", true, &rados, &io_ctx, &image);
7c673cae
FG
337 if (r < 0) {
338 return r;
339 }
340
11fdf7f2
TL
341 bool all_snaps = vm[ALL_NAME].as<bool>();
342 r = do_list_snaps(image, formatter.get(), all_snaps, rados);
7c673cae
FG
343 if (r < 0) {
344 cerr << "rbd: failed to list snapshots: " << cpp_strerror(r)
345 << std::endl;
346 return r;
347 }
348 return 0;
349}
350
351void get_create_arguments(po::options_description *positional,
352 po::options_description *options) {
353 at::add_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
354}
355
11fdf7f2
TL
356int execute_create(const po::variables_map &vm,
357 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
358 size_t arg_index = 0;
359 std::string pool_name;
11fdf7f2 360 std::string namespace_name;
7c673cae
FG
361 std::string image_name;
362 std::string snap_name;
363 int r = utils::get_pool_image_snapshot_names(
11fdf7f2
TL
364 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
365 &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_REQUIRED,
366 utils::SPEC_VALIDATION_SNAP);
7c673cae
FG
367 if (r < 0) {
368 return r;
369 }
370
371 librados::Rados rados;
372 librados::IoCtx io_ctx;
373 librbd::Image image;
11fdf7f2
TL
374 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
375 false, &rados, &io_ctx, &image);
7c673cae
FG
376 if (r < 0) {
377 return r;
378 }
379
380 r = do_add_snap(image, snap_name.c_str());
381 if (r < 0) {
382 cerr << "rbd: failed to create snapshot: " << cpp_strerror(r)
383 << std::endl;
384 return r;
385 }
386 return 0;
387}
388
389void get_remove_arguments(po::options_description *positional,
390 po::options_description *options) {
391 at::add_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
7c673cae 392 at::add_image_id_option(options);
11fdf7f2
TL
393 at::add_snap_id_option(options);
394 at::add_no_progress_option(options);
7c673cae
FG
395
396 options->add_options()
397 ("force", po::bool_switch(), "flatten children and unprotect snapshot if needed.");
398}
399
11fdf7f2
TL
400int execute_remove(const po::variables_map &vm,
401 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
402 size_t arg_index = 0;
403 std::string pool_name;
11fdf7f2 404 std::string namespace_name;
7c673cae
FG
405 std::string image_name;
406 std::string snap_name;
407 std::string image_id;
11fdf7f2 408 uint64_t snap_id = CEPH_NOSNAP;
7c673cae 409 bool force = vm["force"].as<bool>();
11fdf7f2 410 bool no_progress = vm[at::NO_PROGRESS].as<bool>();
7c673cae
FG
411
412 if (vm.count(at::IMAGE_ID)) {
413 image_id = vm[at::IMAGE_ID].as<std::string>();
414 }
11fdf7f2
TL
415 if (vm.count(at::SNAPSHOT_ID)) {
416 snap_id = vm[at::SNAPSHOT_ID].as<uint64_t>();
7c673cae
FG
417 }
418
11fdf7f2
TL
419 int r = utils::get_pool_image_snapshot_names(
420 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
421 &image_name, &snap_name, image_id.empty(),
422 (snap_id == CEPH_NOSNAP ? utils::SNAPSHOT_PRESENCE_REQUIRED :
423 utils::SNAPSHOT_PRESENCE_PERMITTED),
424 utils::SPEC_VALIDATION_NONE);
7c673cae
FG
425 if (r < 0) {
426 return r;
427 }
428
11fdf7f2
TL
429 if (!image_id.empty() && !image_name.empty()) {
430 std::cerr << "rbd: trying to access image using both name and id."
431 << std::endl;
432 return -EINVAL;
433 } else if (!snap_name.empty() && snap_id != CEPH_NOSNAP) {
434 std::cerr << "rbd: trying to access snapshot using both name and id."
435 << std::endl;
436 return -EINVAL;
437 } else if ((force || no_progress) && snap_id != CEPH_NOSNAP) {
438 std::cerr << "rbd: force and no-progress options not permitted when "
439 << "removing by id." << std::endl;
440 return -EINVAL;
441 }
442
7c673cae
FG
443 librados::Rados rados;
444 librados::IoCtx io_ctx;
445 librbd::Image image;
11fdf7f2 446 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
7c673cae
FG
447 if (r < 0) {
448 return r;
449 }
450
451 io_ctx.set_osdmap_full_try();
452 if (image_id.empty()) {
453 r = utils::open_image(io_ctx, image_name, false, &image);
454 } else {
455 r = utils::open_image_by_id(io_ctx, image_id, false, &image);
456 }
457 if (r < 0) {
458 return r;
459 }
460
11fdf7f2
TL
461 if (!snap_name.empty()) {
462 r = do_remove_snap(image, snap_name.c_str(), force, no_progress);
463 } else {
464 r = image.snap_remove_by_id(snap_id);
465 }
466
7c673cae
FG
467 if (r < 0) {
468 if (r == -EBUSY) {
11fdf7f2
TL
469 std::cerr << "rbd: snapshot "
470 << (snap_name.empty() ? std::string("id ") + stringify(snap_id) :
471 std::string("'") + snap_name + "'")
472 << " is protected from removal." << std::endl;
7c673cae
FG
473 } else {
474 std::cerr << "rbd: failed to remove snapshot: " << cpp_strerror(r)
475 << std::endl;
476 }
477 return r;
478 }
479 return 0;
480}
481
482void get_purge_arguments(po::options_description *positional,
483 po::options_description *options) {
484 at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
485 at::add_image_id_option(options);
486 at::add_no_progress_option(options);
487}
488
11fdf7f2
TL
489int execute_purge(const po::variables_map &vm,
490 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
491 size_t arg_index = 0;
492 std::string pool_name;
11fdf7f2 493 std::string namespace_name;
7c673cae
FG
494 std::string image_name;
495 std::string snap_name;
496 std::string image_id;
497
498 if (vm.count(at::IMAGE_ID)) {
499 image_id = vm[at::IMAGE_ID].as<std::string>();
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 utils::SNAPSHOT_PRESENCE_NONE, utils::SPEC_VALIDATION_NONE);
506 if (r < 0) {
507 return r;
508 }
7c673cae 509
11fdf7f2 510 if (!image_id.empty() && !image_name.empty()) {
7c673cae
FG
511 std::cerr << "rbd: trying to access image using both name and id. "
512 << std::endl;
513 return -EINVAL;
514 }
515
7c673cae
FG
516 librados::Rados rados;
517 librados::IoCtx io_ctx;
518 librbd::Image image;
11fdf7f2 519 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
7c673cae
FG
520 if (r < 0) {
521 return r;
522 }
523
524 io_ctx.set_osdmap_full_try();
525 if (image_id.empty()) {
526 r = utils::open_image(io_ctx, image_name, false, &image);
527 } else {
528 r = utils::open_image_by_id(io_ctx, image_id, false, &image);
529 }
530 if (r < 0) {
531 return r;
532 }
533
534 r = do_purge_snaps(image, vm[at::NO_PROGRESS].as<bool>());
535 if (r < 0) {
536 if (r != -EBUSY) {
537 std::cerr << "rbd: removing snaps failed: " << cpp_strerror(r)
538 << std::endl;
539 }
540 return r;
541 }
542 return 0;
543}
544
545void get_rollback_arguments(po::options_description *positional,
546 po::options_description *options) {
547 at::add_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
548 at::add_no_progress_option(options);
549}
550
11fdf7f2
TL
551int execute_rollback(const po::variables_map &vm,
552 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
553 size_t arg_index = 0;
554 std::string pool_name;
11fdf7f2 555 std::string namespace_name;
7c673cae
FG
556 std::string image_name;
557 std::string snap_name;
558 int r = utils::get_pool_image_snapshot_names(
11fdf7f2
TL
559 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
560 &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_REQUIRED,
561 utils::SPEC_VALIDATION_NONE);
7c673cae
FG
562 if (r < 0) {
563 return r;
564 }
565
566 librados::Rados rados;
567 librados::IoCtx io_ctx;
568 librbd::Image image;
11fdf7f2
TL
569 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
570 false, &rados, &io_ctx, &image);
7c673cae
FG
571 if (r < 0) {
572 return r;
573 }
574
575 r = do_rollback_snap(image, snap_name.c_str(),
576 vm[at::NO_PROGRESS].as<bool>());
577 if (r < 0) {
578 std::cerr << "rbd: rollback failed: " << cpp_strerror(r) << std::endl;
579 return r;
580 }
581 return 0;
582}
583
584void get_protect_arguments(po::options_description *positional,
585 po::options_description *options) {
586 at::add_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
587}
588
11fdf7f2
TL
589int execute_protect(const po::variables_map &vm,
590 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
591 size_t arg_index = 0;
592 std::string pool_name;
11fdf7f2 593 std::string namespace_name;
7c673cae
FG
594 std::string image_name;
595 std::string snap_name;
596 int r = utils::get_pool_image_snapshot_names(
11fdf7f2
TL
597 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
598 &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_REQUIRED,
599 utils::SPEC_VALIDATION_NONE);
7c673cae
FG
600 if (r < 0) {
601 return r;
602 }
603
604 librados::Rados rados;
605 librados::IoCtx io_ctx;
606 librbd::Image image;
11fdf7f2
TL
607 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
608 false, &rados, &io_ctx, &image);
7c673cae
FG
609 if (r < 0) {
610 return r;
611 }
612
613 bool is_protected = false;
614 r = image.snap_is_protected(snap_name.c_str(), &is_protected);
615 if (r < 0) {
616 std::cerr << "rbd: protecting snap failed: " << cpp_strerror(r)
617 << std::endl;
618 return r;
619 } else if (is_protected) {
620 std::cerr << "rbd: snap is already protected" << std::endl;
621 return -EBUSY;
622 }
623
624 r = do_protect_snap(image, snap_name.c_str());
625 if (r < 0) {
626 std::cerr << "rbd: protecting snap failed: " << cpp_strerror(r)
627 << std::endl;
628 return r;
629 }
630 return 0;
631}
632
633void get_unprotect_arguments(po::options_description *positional,
634 po::options_description *options) {
635 at::add_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
636 at::add_image_id_option(options);
637}
638
11fdf7f2
TL
639int execute_unprotect(const po::variables_map &vm,
640 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
641 size_t arg_index = 0;
642 std::string pool_name;
11fdf7f2 643 std::string namespace_name;
7c673cae
FG
644 std::string image_name;
645 std::string snap_name;
646 std::string image_id;
647
648 if (vm.count(at::IMAGE_ID)) {
649 image_id = vm[at::IMAGE_ID].as<std::string>();
650 }
651
11fdf7f2
TL
652 int r = utils::get_pool_image_snapshot_names(
653 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
654 &image_name, &snap_name, image_id.empty(),
655 utils::SNAPSHOT_PRESENCE_REQUIRED, utils::SPEC_VALIDATION_NONE);
656 if (r < 0) {
657 return r;
658 }
7c673cae 659
11fdf7f2 660 if (!image_id.empty() && !image_name.empty()) {
7c673cae
FG
661 std::cerr << "rbd: trying to access image using both name and id. "
662 << std::endl;
663 return -EINVAL;
664 }
665
7c673cae
FG
666 librados::Rados rados;
667 librados::IoCtx io_ctx;
668 librbd::Image image;
11fdf7f2 669 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
7c673cae
FG
670 if (r < 0) {
671 return r;
672 }
673
674 io_ctx.set_osdmap_full_try();
675 if (image_id.empty()) {
676 r = utils::open_image(io_ctx, image_name, false, &image);
677 } else {
678 r = utils::open_image_by_id(io_ctx, image_id, false, &image);
679 }
680 if (r < 0) {
681 return r;
682 }
683
684 bool is_protected = false;
685 r = image.snap_is_protected(snap_name.c_str(), &is_protected);
686 if (r < 0) {
687 std::cerr << "rbd: unprotecting snap failed: " << cpp_strerror(r)
688 << std::endl;
689 return r;
690 } else if (!is_protected) {
691 std::cerr << "rbd: snap is already unprotected" << std::endl;
692 return -EINVAL;
693 }
694
695 r = do_unprotect_snap(image, snap_name.c_str());
696 if (r < 0) {
697 std::cerr << "rbd: unprotecting snap failed: " << cpp_strerror(r)
698 << std::endl;
699 return r;
700 }
701 return 0;
702}
703
704void get_set_limit_arguments(po::options_description *pos,
705 po::options_description *opt) {
706 at::add_image_spec_options(pos, opt, at::ARGUMENT_MODIFIER_NONE);
707 at::add_limit_option(opt);
708}
709
11fdf7f2
TL
710int execute_set_limit(const po::variables_map &vm,
711 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
712 size_t arg_index = 0;
713 std::string pool_name;
11fdf7f2 714 std::string namespace_name;
7c673cae
FG
715 std::string image_name;
716 std::string snap_name;
717 uint64_t limit;
718
719 int r = utils::get_pool_image_snapshot_names(
11fdf7f2
TL
720 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
721 &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_NONE,
722 utils::SPEC_VALIDATION_NONE);
7c673cae
FG
723 if (r < 0) {
724 return r;
725 }
726
727 if (vm.count(at::LIMIT)) {
728 limit = vm[at::LIMIT].as<uint64_t>();
729 } else {
730 std::cerr << "rbd: must specify --limit <num>" << std::endl;
731 return -ERANGE;
732 }
733
734 librados::Rados rados;
735 librados::IoCtx io_ctx;
736 librbd::Image image;
11fdf7f2
TL
737 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
738 false, &rados, &io_ctx, &image);
7c673cae
FG
739 if (r < 0) {
740 return r;
741 }
742
743 r = do_set_limit(image, limit);
744 if (r < 0) {
745 std::cerr << "rbd: setting snapshot limit failed: " << cpp_strerror(r)
746 << std::endl;
747 return r;
748 }
749 return 0;
750}
751
752void get_clear_limit_arguments(po::options_description *pos,
753 po::options_description *opt) {
754 at::add_image_spec_options(pos, opt, at::ARGUMENT_MODIFIER_NONE);
755}
756
11fdf7f2
TL
757int execute_clear_limit(const po::variables_map &vm,
758 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
759 size_t arg_index = 0;
760 std::string pool_name;
11fdf7f2 761 std::string namespace_name;
7c673cae
FG
762 std::string image_name;
763 std::string snap_name;
764
765 int r = utils::get_pool_image_snapshot_names(
11fdf7f2
TL
766 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
767 &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_NONE,
768 utils::SPEC_VALIDATION_NONE);
7c673cae
FG
769 if (r < 0) {
770 return r;
771 }
772
773 librados::Rados rados;
774 librados::IoCtx io_ctx;
775 librbd::Image image;
11fdf7f2
TL
776 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
777 false, &rados, &io_ctx, &image);
7c673cae
FG
778 if (r < 0) {
779 return r;
780 }
781
11fdf7f2 782 r = do_set_limit(image, UINT64_MAX);
7c673cae
FG
783 if (r < 0) {
784 std::cerr << "rbd: clearing snapshot limit failed: " << cpp_strerror(r)
785 << std::endl;
786 return r;
787 }
788 return 0;
789}
790
791void get_rename_arguments(po::options_description *positional,
792 po::options_description *options) {
793 at::add_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_SOURCE);
794 at::add_snap_spec_options(positional, options, at::ARGUMENT_MODIFIER_DEST);
795}
796
11fdf7f2
TL
797int execute_rename(const po::variables_map &vm,
798 const std::vector<std::string> &ceph_global_init_args) {
7c673cae
FG
799 size_t arg_index = 0;
800 std::string pool_name;
11fdf7f2 801 std::string namespace_name;
7c673cae
FG
802 std::string image_name;
803 std::string src_snap_name;
804 int r = utils::get_pool_image_snapshot_names(
11fdf7f2
TL
805 vm, at::ARGUMENT_MODIFIER_SOURCE, &arg_index, &pool_name, &namespace_name,
806 &image_name, &src_snap_name, true, utils::SNAPSHOT_PRESENCE_REQUIRED,
7c673cae
FG
807 utils::SPEC_VALIDATION_NONE);
808 if (r < 0) {
809 return -r;
810 }
811
812 std::string dest_pool_name(pool_name);
11fdf7f2 813 std::string dest_namespace_name(namespace_name);
7c673cae
FG
814 std::string dest_image_name;
815 std::string dest_snap_name;
816 r = utils::get_pool_image_snapshot_names(
817 vm, at::ARGUMENT_MODIFIER_DEST, &arg_index, &dest_pool_name,
11fdf7f2
TL
818 &dest_namespace_name, &dest_image_name, &dest_snap_name, true,
819 utils::SNAPSHOT_PRESENCE_REQUIRED, utils::SPEC_VALIDATION_SNAP);
7c673cae
FG
820 if (r < 0) {
821 return -r;
822 }
823
824 if (pool_name != dest_pool_name) {
825 std::cerr << "rbd: source and destination pool must be the same"
826 << std::endl;
827 return -EINVAL;
11fdf7f2
TL
828 } else if (namespace_name != dest_namespace_name) {
829 std::cerr << "rbd: source and destination namespace must be the same"
830 << std::endl;
831 return -EINVAL;
7c673cae
FG
832 } else if (image_name != dest_image_name) {
833 std::cerr << "rbd: source and destination image name must be the same"
834 << std::endl;
835 return -EINVAL;
836 }
11fdf7f2 837
7c673cae
FG
838 librados::Rados rados;
839 librados::IoCtx io_ctx;
840 librbd::Image image;
11fdf7f2
TL
841 r = utils::init_and_open_image(pool_name, namespace_name, image_name, "", "",
842 false, &rados, &io_ctx, &image);
7c673cae
FG
843 if (r < 0) {
844 return r;
845 }
846
847 r = image.snap_rename(src_snap_name.c_str(), dest_snap_name.c_str());
848 if (r < 0) {
849 std::cerr << "rbd: renaming snap failed: " << cpp_strerror(r)
850 << std::endl;
851 return r;
852 }
853 return 0;
854}
855
856Shell::Action action_list(
857 {"snap", "list"}, {"snap", "ls"}, "Dump list of image snapshots.", "",
858 &get_list_arguments, &execute_list);
859Shell::Action action_create(
860 {"snap", "create"}, {"snap", "add"}, "Create a snapshot.", "",
861 &get_create_arguments, &execute_create);
862Shell::Action action_remove(
c07f9fc5 863 {"snap", "remove"}, {"snap", "rm"}, "Delete a snapshot.", "",
7c673cae
FG
864 &get_remove_arguments, &execute_remove);
865Shell::Action action_purge(
11fdf7f2 866 {"snap", "purge"}, {}, "Delete all unprotected snapshots.", "",
7c673cae
FG
867 &get_purge_arguments, &execute_purge);
868Shell::Action action_rollback(
869 {"snap", "rollback"}, {"snap", "revert"}, "Rollback image to snapshot.", "",
870 &get_rollback_arguments, &execute_rollback);
871Shell::Action action_protect(
872 {"snap", "protect"}, {}, "Prevent a snapshot from being deleted.", "",
873 &get_protect_arguments, &execute_protect);
874Shell::Action action_unprotect(
875 {"snap", "unprotect"}, {}, "Allow a snapshot to be deleted.", "",
876 &get_unprotect_arguments, &execute_unprotect);
877Shell::Action action_set_limit(
878 {"snap", "limit", "set"}, {}, "Limit the number of snapshots.", "",
879 &get_set_limit_arguments, &execute_set_limit);
880Shell::Action action_clear_limit(
881 {"snap", "limit", "clear"}, {}, "Remove snapshot limit.", "",
882 &get_clear_limit_arguments, &execute_clear_limit);
883Shell::Action action_rename(
884 {"snap", "rename"}, {}, "Rename a snapshot.", "",
885 &get_rename_arguments, &execute_rename);
886
887} // namespace snap
888} // namespace action
889} // namespace rbd