]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd/action/Remove.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / tools / rbd / action / Remove.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 "common/errno.h"
8 #include "include/stringify.h"
9 #include <iostream>
10 #include <boost/program_options.hpp>
11
12 namespace rbd {
13 namespace action {
14 namespace remove {
15
16 namespace {
17
18 bool is_auto_delete_snapshot(librbd::Image* image,
19 const librbd::snap_info_t &snap_info) {
20 librbd::snap_namespace_type_t namespace_type;
21 int r = image->snap_get_namespace_type(snap_info.id, &namespace_type);
22 if (r < 0) {
23 return false;
24 }
25
26 switch (namespace_type) {
27 case RBD_SNAP_NAMESPACE_TYPE_TRASH:
28 return true;
29 default:
30 return false;
31 }
32 }
33
34 } // anonymous namespace
35
36 namespace at = argument_types;
37 namespace po = boost::program_options;
38
39 static int do_delete(librbd::RBD &rbd, librados::IoCtx& io_ctx,
40 const char *imgname, bool no_progress)
41 {
42 utils::ProgressContext pc("Removing image", no_progress);
43 int r = rbd.remove_with_progress(io_ctx, imgname, pc);
44 if (r < 0) {
45 pc.fail();
46 return r;
47 }
48 pc.finish();
49 return 0;
50 }
51
52 void get_arguments(po::options_description *positional,
53 po::options_description *options) {
54 at::add_image_spec_options(positional, options, at::ARGUMENT_MODIFIER_NONE);
55 at::add_no_progress_option(options);
56 }
57
58 int execute(const po::variables_map &vm,
59 const std::vector<std::string> &ceph_global_init_args) {
60 size_t arg_index = 0;
61 std::string pool_name;
62 std::string namespace_name;
63 std::string image_name;
64 std::string snap_name;
65 int r = utils::get_pool_image_snapshot_names(
66 vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name,
67 &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_NONE,
68 utils::SPEC_VALIDATION_NONE);
69 if (r < 0) {
70 return r;
71 }
72
73 librados::Rados rados;
74 librados::IoCtx io_ctx;
75 r = utils::init(pool_name, namespace_name, &rados, &io_ctx);
76 if (r < 0) {
77 return r;
78 }
79
80 io_ctx.set_osdmap_full_try();
81
82 librbd::RBD rbd;
83 r = do_delete(rbd, io_ctx, image_name.c_str(),
84 vm[at::NO_PROGRESS].as<bool>());
85 if (r < 0) {
86 if (r == -ENOTEMPTY) {
87 librbd::Image image;
88 std::vector<librbd::snap_info_t> snaps;
89 int image_r = utils::open_image(io_ctx, image_name, true, &image);
90 if (image_r >= 0) {
91 image_r = image.snap_list(snaps);
92 }
93 if (image_r >= 0) {
94 snaps.erase(std::remove_if(snaps.begin(), snaps.end(),
95 [&image](const librbd::snap_info_t& snap) {
96 return is_auto_delete_snapshot(&image,
97 snap);
98 }),
99 snaps.end());
100 }
101
102 if (!snaps.empty()) {
103 std::cerr << "rbd: image has snapshots - these must be deleted"
104 << " with 'rbd snap purge' before the image can be removed."
105 << std::endl;
106 } else {
107 std::cerr << "rbd: image has snapshots with linked clones - these must "
108 << "be deleted or flattened before the image can be removed."
109 << std::endl;
110 }
111 } else if (r == -EBUSY) {
112 std::cerr << "rbd: error: image still has watchers"
113 << std::endl
114 << "This means the image is still open or the client using "
115 << "it crashed. Try again after closing/unmapping it or "
116 << "waiting 30s for the crashed client to timeout."
117 << std::endl;
118 } else if (r == -EMLINK) {
119 librbd::Image image;
120 int image_r = utils::open_image(io_ctx, image_name, true, &image);
121 librbd::group_info_t group_info;
122 if (image_r == 0) {
123 image_r = image.get_group(&group_info, sizeof(group_info));
124 }
125 if (image_r == 0) {
126 std::string pool_name = "";
127 librados::Rados rados(io_ctx);
128 librados::IoCtx pool_io_ctx;
129 image_r = rados.ioctx_create2(group_info.pool, pool_io_ctx);
130 if (image_r < 0) {
131 pool_name = "<missing group pool " + stringify(group_info.pool) + ">";
132 } else {
133 pool_name = pool_io_ctx.get_pool_name();
134 }
135 std::cerr << "rbd: error: image belongs to a group "
136 << pool_name << "/";
137 if (!io_ctx.get_namespace().empty()) {
138 std::cerr << io_ctx.get_namespace() << "/";
139 }
140 std::cerr << group_info.name;
141 } else
142 std::cerr << "rbd: error: image belongs to a group";
143
144 std::cerr << std::endl
145 << "Remove the image from the group and try again."
146 << std::endl;
147 image.close();
148 } else {
149 std::cerr << "rbd: delete error: " << cpp_strerror(r) << std::endl;
150 }
151 return r;
152 }
153 return 0;
154 }
155
156 Shell::Action action(
157 {"remove"}, {"rm"}, "Delete an image.", "", &get_arguments, &execute);
158
159 } // namespace remove
160 } // namespace action
161 } // namespace rbd