]>
Commit | Line | Data |
---|---|---|
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/stringify.h" | |
8 | #include "common/SubProcess.h" | |
9 | #include <iostream> | |
11fdf7f2 | 10 | #include <boost/algorithm/string.hpp> |
7c673cae | 11 | #include <boost/algorithm/string/predicate.hpp> |
7c673cae FG |
12 | #include <boost/program_options.hpp> |
13 | ||
14 | namespace rbd { | |
15 | namespace action { | |
16 | namespace nbd { | |
17 | ||
18 | namespace at = argument_types; | |
19 | namespace po = boost::program_options; | |
20 | ||
21 | static int call_nbd_cmd(const po::variables_map &vm, | |
11fdf7f2 TL |
22 | const std::vector<std::string> &args, |
23 | const std::vector<std::string> &ceph_global_init_args) { | |
f67539c2 TL |
24 | #ifdef _WIN32 |
25 | std::cerr << "rbd: nbd device is not supported" << std::endl; | |
26 | return -EOPNOTSUPP; | |
27 | #else | |
7c673cae FG |
28 | char exe_path[PATH_MAX]; |
29 | ssize_t exe_path_bytes = readlink("/proc/self/exe", exe_path, | |
30 | sizeof(exe_path) - 1); | |
31 | if (exe_path_bytes < 0) { | |
32 | strcpy(exe_path, "rbd-nbd"); | |
33 | } else { | |
34 | if (snprintf(exe_path + exe_path_bytes, | |
35 | sizeof(exe_path) - exe_path_bytes, | |
36 | "-nbd") < 0) { | |
37 | return -EOVERFLOW; | |
38 | } | |
39 | } | |
40 | ||
41 | SubProcess process(exe_path, SubProcess::KEEP, SubProcess::KEEP, SubProcess::KEEP); | |
42 | ||
11fdf7f2 TL |
43 | for (auto &arg : ceph_global_init_args) { |
44 | process.add_cmd_arg(arg.c_str()); | |
7c673cae FG |
45 | } |
46 | ||
11fdf7f2 TL |
47 | for (auto &arg : args) { |
48 | process.add_cmd_arg(arg.c_str()); | |
49 | } | |
7c673cae FG |
50 | |
51 | if (process.spawn()) { | |
52 | std::cerr << "rbd: failed to run rbd-nbd: " << process.err() << std::endl; | |
53 | return -EINVAL; | |
54 | } else if (process.join()) { | |
55 | std::cerr << "rbd: rbd-nbd failed with error: " << process.err() << std::endl; | |
56 | return -EINVAL; | |
57 | } | |
58 | ||
59 | return 0; | |
f67539c2 | 60 | #endif |
7c673cae FG |
61 | } |
62 | ||
11fdf7f2 | 63 | int get_image_or_snap_spec(const po::variables_map &vm, std::string *spec) { |
7c673cae FG |
64 | size_t arg_index = 0; |
65 | std::string pool_name; | |
11fdf7f2 | 66 | std::string nspace_name; |
7c673cae FG |
67 | std::string image_name; |
68 | std::string snap_name; | |
69 | int r = utils::get_pool_image_snapshot_names( | |
11fdf7f2 TL |
70 | vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &nspace_name, |
71 | &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_PERMITTED, | |
7c673cae FG |
72 | utils::SPEC_VALIDATION_NONE); |
73 | if (r < 0) { | |
74 | return r; | |
75 | } | |
76 | ||
522d829b TL |
77 | if (pool_name.empty()) { |
78 | // connect to the cluster to get the default pool | |
79 | librados::Rados rados; | |
80 | r = utils::init_rados(&rados); | |
81 | if (r < 0) { | |
82 | return r; | |
83 | } | |
84 | ||
85 | utils::normalize_pool_name(&pool_name); | |
86 | } | |
87 | ||
11fdf7f2 TL |
88 | spec->append(pool_name); |
89 | spec->append("/"); | |
90 | if (!nspace_name.empty()) { | |
91 | spec->append(nspace_name); | |
92 | spec->append("/"); | |
93 | } | |
94 | spec->append(image_name); | |
95 | if (!snap_name.empty()) { | |
96 | spec->append("@"); | |
97 | spec->append(snap_name); | |
98 | } | |
99 | ||
100 | return 0; | |
101 | } | |
102 | ||
103 | int parse_options(const std::vector<std::string> &options, | |
104 | std::vector<std::string> *args) { | |
105 | for (auto &opts : options) { | |
106 | std::vector<std::string> args_; | |
107 | boost::split(args_, opts, boost::is_any_of(",")); | |
108 | for (auto &o : args_) { | |
109 | args->push_back("--" + o); | |
110 | } | |
111 | } | |
112 | ||
113 | return 0; | |
114 | } | |
115 | ||
116 | int execute_list(const po::variables_map &vm, | |
117 | const std::vector<std::string> &ceph_global_init_args) { | |
f67539c2 | 118 | #if defined(__FreeBSD__) || defined(_WIN32) |
11fdf7f2 TL |
119 | std::cerr << "rbd: nbd device is not supported" << std::endl; |
120 | return -EOPNOTSUPP; | |
121 | #endif | |
122 | std::vector<std::string> args; | |
123 | ||
124 | args.push_back("list-mapped"); | |
125 | ||
126 | if (vm.count("format")) { | |
127 | args.push_back("--format"); | |
128 | args.push_back(vm["format"].as<at::Format>().value); | |
129 | } | |
130 | if (vm["pretty-format"].as<bool>()) { | |
131 | args.push_back("--pretty-format"); | |
132 | } | |
133 | ||
134 | return call_nbd_cmd(vm, args, ceph_global_init_args); | |
135 | } | |
136 | ||
137 | int execute_map(const po::variables_map &vm, | |
138 | const std::vector<std::string> &ceph_global_init_args) { | |
f67539c2 | 139 | #if defined(__FreeBSD__) || defined(_WIN32) |
11fdf7f2 TL |
140 | std::cerr << "rbd: nbd device is not supported" << std::endl; |
141 | return -EOPNOTSUPP; | |
142 | #endif | |
143 | std::vector<std::string> args; | |
7c673cae FG |
144 | |
145 | args.push_back("map"); | |
146 | std::string img; | |
11fdf7f2 TL |
147 | int r = get_image_or_snap_spec(vm, &img); |
148 | if (r < 0) { | |
149 | return r; | |
7c673cae | 150 | } |
11fdf7f2 | 151 | args.push_back(img); |
7c673cae | 152 | |
f67539c2 TL |
153 | if (vm["quiesce"].as<bool>()) { |
154 | args.push_back("--quiesce"); | |
155 | } | |
156 | ||
11fdf7f2 | 157 | if (vm["read-only"].as<bool>()) { |
7c673cae | 158 | args.push_back("--read-only"); |
11fdf7f2 | 159 | } |
7c673cae | 160 | |
11fdf7f2 | 161 | if (vm["exclusive"].as<bool>()) { |
7c673cae | 162 | args.push_back("--exclusive"); |
7c673cae FG |
163 | } |
164 | ||
f67539c2 TL |
165 | if (vm.count("quiesce-hook")) { |
166 | args.push_back("--quiesce-hook"); | |
167 | args.push_back(vm["quiesce-hook"].as<std::string>()); | |
168 | } | |
169 | ||
11fdf7f2 TL |
170 | if (vm.count("options")) { |
171 | r = parse_options(vm["options"].as<std::vector<std::string>>(), &args); | |
172 | if (r < 0) { | |
173 | return r; | |
174 | } | |
175 | } | |
7c673cae | 176 | |
11fdf7f2 | 177 | return call_nbd_cmd(vm, args, ceph_global_init_args); |
7c673cae FG |
178 | } |
179 | ||
11fdf7f2 TL |
180 | int execute_unmap(const po::variables_map &vm, |
181 | const std::vector<std::string> &ceph_global_init_args) { | |
f67539c2 | 182 | #if defined(__FreeBSD__) || defined(_WIN32) |
11fdf7f2 TL |
183 | std::cerr << "rbd: nbd device is not supported" << std::endl; |
184 | return -EOPNOTSUPP; | |
185 | #endif | |
7c673cae FG |
186 | std::string device_name = utils::get_positional_argument(vm, 0); |
187 | if (!boost::starts_with(device_name, "/dev/")) { | |
188 | device_name.clear(); | |
189 | } | |
190 | ||
11fdf7f2 | 191 | std::string image_name; |
7c673cae | 192 | if (device_name.empty()) { |
11fdf7f2 TL |
193 | int r = get_image_or_snap_spec(vm, &image_name); |
194 | if (r < 0) { | |
195 | return r; | |
196 | } | |
197 | } | |
198 | ||
199 | if (device_name.empty() && image_name.empty()) { | |
200 | std::cerr << "rbd: unmap requires either image name or device path" | |
201 | << std::endl; | |
7c673cae FG |
202 | return -EINVAL; |
203 | } | |
204 | ||
11fdf7f2 | 205 | std::vector<std::string> args; |
7c673cae FG |
206 | |
207 | args.push_back("unmap"); | |
11fdf7f2 TL |
208 | args.push_back(device_name.empty() ? image_name : device_name); |
209 | ||
210 | if (vm.count("options")) { | |
211 | int r = parse_options(vm["options"].as<std::vector<std::string>>(), &args); | |
212 | if (r < 0) { | |
213 | return r; | |
214 | } | |
215 | } | |
216 | ||
217 | return call_nbd_cmd(vm, args, ceph_global_init_args); | |
218 | } | |
219 | ||
220 | void get_list_arguments_deprecated(po::options_description *positional, | |
221 | po::options_description *options) { | |
222 | at::add_format_options(options); | |
223 | } | |
224 | ||
225 | int execute_list_deprecated(const po::variables_map &vm, | |
226 | const std::vector<std::string> &ceph_global_args) { | |
227 | std::cerr << "rbd: 'nbd list' command is deprecated, " | |
228 | << "use 'device list -t nbd' instead" << std::endl; | |
229 | return execute_list(vm, ceph_global_args); | |
230 | } | |
231 | ||
232 | void get_map_arguments_deprecated(po::options_description *positional, | |
233 | po::options_description *options) { | |
234 | at::add_image_or_snap_spec_options(positional, options, | |
235 | at::ARGUMENT_MODIFIER_NONE); | |
236 | options->add_options() | |
237 | ("read-only", po::bool_switch(), "map read-only") | |
238 | ("exclusive", po::bool_switch(), "forbid writes by other clients") | |
239 | ("device", po::value<std::string>(), "specify nbd device") | |
240 | ("nbds_max", po::value<std::string>(), "override module param nbds_max") | |
241 | ("max_part", po::value<std::string>(), "override module param max_part") | |
242 | ("timeout", po::value<std::string>(), "set nbd request timeout (seconds)"); | |
243 | } | |
244 | ||
245 | int execute_map_deprecated(const po::variables_map &vm_deprecated, | |
246 | const std::vector<std::string> &ceph_global_args) { | |
247 | std::cerr << "rbd: 'nbd map' command is deprecated, " | |
248 | << "use 'device map -t nbd' instead" << std::endl; | |
249 | ||
250 | po::options_description options; | |
251 | options.add_options() | |
252 | ("options,o", po::value<std::vector<std::string>>() | |
253 | ->default_value(std::vector<std::string>(), ""), ""); | |
254 | ||
255 | po::variables_map vm = vm_deprecated; | |
256 | po::store(po::command_line_parser({}).options(options).run(), vm); | |
257 | ||
258 | std::vector<std::string> opts; | |
259 | if (vm_deprecated.count("device")) { | |
260 | opts.push_back("device=" + vm_deprecated["device"].as<std::string>()); | |
261 | } | |
262 | if (vm_deprecated.count("nbds_max")) { | |
263 | opts.push_back("nbds_max=" + vm_deprecated["nbds_max"].as<std::string>()); | |
264 | } | |
265 | if (vm_deprecated.count("max_part")) { | |
266 | opts.push_back("max_part=" + vm_deprecated["max_part"].as<std::string>()); | |
267 | } | |
268 | if (vm_deprecated.count("timeout")) { | |
269 | opts.push_back("timeout=" + vm_deprecated["timeout"].as<std::string>()); | |
270 | } | |
271 | ||
272 | vm.at("options").value() = boost::any(opts); | |
273 | ||
274 | return execute_map(vm, ceph_global_args); | |
275 | } | |
276 | ||
277 | void get_unmap_arguments_deprecated(po::options_description *positional, | |
278 | po::options_description *options) { | |
279 | positional->add_options() | |
280 | ("image-or-snap-or-device-spec", | |
281 | "image, snapshot, or device specification\n" | |
f67539c2 | 282 | "[<pool-name>/]<image-name>[@<snap-name>] or <device-path>"); |
11fdf7f2 TL |
283 | at::add_pool_option(options, at::ARGUMENT_MODIFIER_NONE); |
284 | at::add_image_option(options, at::ARGUMENT_MODIFIER_NONE); | |
285 | at::add_snap_option(options, at::ARGUMENT_MODIFIER_NONE); | |
286 | } | |
7c673cae | 287 | |
11fdf7f2 TL |
288 | int execute_unmap_deprecated(const po::variables_map &vm, |
289 | const std::vector<std::string> &ceph_global_args) { | |
290 | std::cerr << "rbd: 'nbd unmap' command is deprecated, " | |
291 | << "use 'device unmap -t nbd' instead" << std::endl; | |
292 | return execute_unmap(vm, ceph_global_args); | |
7c673cae FG |
293 | } |
294 | ||
11fdf7f2 | 295 | Shell::SwitchArguments switched_arguments({"read-only", "exclusive"}); |
7c673cae | 296 | |
11fdf7f2 | 297 | Shell::Action action_show_deprecated( |
7c673cae | 298 | {"nbd", "list"}, {"nbd", "ls"}, "List the nbd devices already used.", "", |
11fdf7f2 | 299 | &get_list_arguments_deprecated, &execute_list_deprecated, false); |
7c673cae | 300 | |
11fdf7f2 | 301 | Shell::Action action_map_deprecated( |
7c673cae | 302 | {"nbd", "map"}, {}, "Map image to a nbd device.", "", |
11fdf7f2 | 303 | &get_map_arguments_deprecated, &execute_map_deprecated, false); |
7c673cae | 304 | |
11fdf7f2 | 305 | Shell::Action action_unmap_deprecated( |
7c673cae | 306 | {"nbd", "unmap"}, {}, "Unmap a nbd device.", "", |
11fdf7f2 | 307 | &get_unmap_arguments_deprecated, &execute_unmap_deprecated, false); |
7c673cae FG |
308 | |
309 | } // namespace nbd | |
310 | } // namespace action | |
311 | } // namespace rbd |