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