]>
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/types.h" | |
8 | #include "include/stringify.h" | |
9 | #include "common/errno.h" | |
10 | #include "common/Formatter.h" | |
11 | #include <iostream> | |
12 | #include <boost/program_options.hpp> | |
13 | ||
11fdf7f2 TL |
14 | #include "common/Clock.h" |
15 | ||
7c673cae FG |
16 | namespace rbd { |
17 | namespace action { | |
18 | namespace info { | |
19 | ||
20 | namespace at = argument_types; | |
21 | namespace po = boost::program_options; | |
22 | ||
23 | static void format_bitmask(Formatter *f, const std::string &name, | |
24 | const std::map<uint64_t, std::string>& mapping, | |
25 | uint64_t bitmask) | |
26 | { | |
27 | int count = 0; | |
28 | std::string group_name(name + "s"); | |
29 | if (f == NULL) { | |
30 | std::cout << "\t" << group_name << ": "; | |
31 | } else { | |
32 | f->open_array_section(group_name.c_str()); | |
33 | } | |
34 | for (std::map<uint64_t, std::string>::const_iterator it = mapping.begin(); | |
35 | it != mapping.end(); ++it) { | |
36 | if ((it->first & bitmask) == 0) { | |
37 | continue; | |
38 | } | |
39 | ||
40 | if (f == NULL) { | |
41 | if (count++ > 0) { | |
42 | std::cout << ", "; | |
43 | } | |
44 | std::cout << it->second; | |
45 | } else { | |
46 | f->dump_string(name.c_str(), it->second); | |
47 | } | |
48 | } | |
49 | if (f == NULL) { | |
50 | std::cout << std::endl; | |
51 | } else { | |
52 | f->close_section(); | |
53 | } | |
54 | } | |
55 | ||
56 | static void format_features(Formatter *f, uint64_t features) | |
57 | { | |
58 | format_bitmask(f, "feature", at::ImageFeatures::FEATURE_MAPPING, features); | |
59 | } | |
60 | ||
11fdf7f2 TL |
61 | static void format_op_features(Formatter *f, uint64_t op_features) |
62 | { | |
63 | static std::map<uint64_t, std::string> mapping = { | |
64 | {RBD_OPERATION_FEATURE_CLONE_PARENT, RBD_OPERATION_FEATURE_NAME_CLONE_PARENT}, | |
65 | {RBD_OPERATION_FEATURE_CLONE_CHILD, RBD_OPERATION_FEATURE_NAME_CLONE_CHILD}, | |
66 | {RBD_OPERATION_FEATURE_GROUP, RBD_OPERATION_FEATURE_NAME_GROUP}, | |
67 | {RBD_OPERATION_FEATURE_SNAP_TRASH, RBD_OPERATION_FEATURE_NAME_SNAP_TRASH}}; | |
68 | format_bitmask(f, "op_feature", mapping, op_features); | |
69 | } | |
70 | ||
7c673cae FG |
71 | static void format_flags(Formatter *f, uint64_t flags) |
72 | { | |
73 | std::map<uint64_t, std::string> mapping = { | |
74 | {RBD_FLAG_OBJECT_MAP_INVALID, "object map invalid"}, | |
75 | {RBD_FLAG_FAST_DIFF_INVALID, "fast diff invalid"}}; | |
76 | format_bitmask(f, "flag", mapping, flags); | |
77 | } | |
78 | ||
11fdf7f2 TL |
79 | void format_timestamp(struct timespec timestamp, std::string ×tamp_str) { |
80 | if(timestamp.tv_sec != 0) { | |
81 | time_t ts = timestamp.tv_sec; | |
82 | timestamp_str = ctime(&ts); | |
83 | timestamp_str = timestamp_str.substr(0, timestamp_str.length() - 1); | |
84 | } | |
85 | } | |
86 | ||
7c673cae | 87 | static int do_show_info(librados::IoCtx &io_ctx, librbd::Image& image, |
7c673cae FG |
88 | const std::string &snapname, Formatter *f) |
89 | { | |
90 | librbd::image_info_t info; | |
91 | uint8_t old_format; | |
92 | uint64_t overlap, features, flags, snap_limit; | |
93 | bool snap_protected = false; | |
94 | librbd::mirror_image_info_t mirror_image; | |
9f95a23c | 95 | librbd::mirror_image_mode_t mirror_mode = RBD_MIRROR_IMAGE_MODE_JOURNAL; |
11fdf7f2 | 96 | std::vector<librbd::snap_info_t> snaps; |
7c673cae FG |
97 | int r; |
98 | ||
11fdf7f2 TL |
99 | std::string imgname; |
100 | r = image.get_name(&imgname); | |
101 | if (r < 0) | |
102 | return r; | |
103 | ||
104 | r = image.snap_list(snaps); | |
105 | if (r < 0) | |
106 | return r; | |
107 | ||
7c673cae FG |
108 | r = image.stat(info, sizeof(info)); |
109 | if (r < 0) | |
110 | return r; | |
111 | ||
112 | r = image.old_format(&old_format); | |
113 | if (r < 0) | |
114 | return r; | |
115 | ||
11fdf7f2 TL |
116 | std::string imgid; |
117 | if (!old_format) { | |
118 | r = image.get_id(&imgid); | |
119 | if (r < 0) | |
120 | return r; | |
121 | } | |
122 | ||
7c673cae FG |
123 | std::string data_pool; |
124 | if (!old_format) { | |
125 | int64_t data_pool_id = image.get_data_pool_id(); | |
126 | if (data_pool_id != io_ctx.get_id()) { | |
127 | librados::Rados rados(io_ctx); | |
128 | librados::IoCtx data_io_ctx; | |
129 | r = rados.ioctx_create2(data_pool_id, data_io_ctx); | |
130 | if (r < 0) { | |
131 | data_pool = "<missing data pool " + stringify(data_pool_id) + ">"; | |
132 | } else { | |
133 | data_pool = data_io_ctx.get_pool_name(); | |
134 | } | |
135 | } | |
136 | } | |
137 | ||
138 | r = image.overlap(&overlap); | |
139 | if (r < 0) | |
140 | return r; | |
141 | ||
142 | r = image.features(&features); | |
143 | if (r < 0) | |
144 | return r; | |
145 | ||
11fdf7f2 TL |
146 | uint64_t op_features; |
147 | r = image.get_op_features(&op_features); | |
148 | if (r < 0) { | |
149 | return r; | |
150 | } | |
151 | ||
7c673cae FG |
152 | r = image.get_flags(&flags); |
153 | if (r < 0) { | |
154 | return r; | |
155 | } | |
156 | ||
157 | if (!snapname.empty()) { | |
158 | r = image.snap_is_protected(snapname.c_str(), &snap_protected); | |
159 | if (r < 0) | |
160 | return r; | |
161 | } | |
162 | ||
9f95a23c TL |
163 | mirror_image.state = RBD_MIRROR_IMAGE_DISABLED; |
164 | r = image.mirror_image_get_info(&mirror_image, sizeof(mirror_image)); | |
165 | if (r < 0) { | |
166 | return r; | |
167 | } | |
168 | ||
169 | if (mirror_image.state != RBD_MIRROR_IMAGE_DISABLED) { | |
170 | r = image.mirror_image_get_mode(&mirror_mode); | |
7c673cae FG |
171 | if (r < 0) { |
172 | return r; | |
173 | } | |
174 | } | |
175 | ||
176 | r = image.snap_get_limit(&snap_limit); | |
177 | if (r < 0) | |
178 | return r; | |
179 | ||
180 | std::string prefix = image.get_block_name_prefix(); | |
181 | ||
11fdf7f2 TL |
182 | librbd::group_info_t group_info; |
183 | r = image.get_group(&group_info, sizeof(group_info)); | |
184 | if (r < 0) { | |
185 | return r; | |
186 | } | |
187 | ||
188 | std::string group_string = ""; | |
189 | if (RBD_GROUP_INVALID_POOL != group_info.pool) { | |
190 | std::string group_pool; | |
191 | librados::Rados rados(io_ctx); | |
192 | librados::IoCtx group_io_ctx; | |
193 | r = rados.ioctx_create2(group_info.pool, group_io_ctx); | |
194 | if (r < 0) { | |
195 | group_pool = "<missing group pool " + stringify(group_info.pool) + ">"; | |
196 | } else { | |
197 | group_pool = group_io_ctx.get_pool_name(); | |
198 | } | |
199 | ||
200 | group_string = group_pool + "/"; | |
201 | if (!io_ctx.get_namespace().empty()) { | |
202 | group_string += io_ctx.get_namespace() + "/"; | |
203 | } | |
204 | group_string += group_info.name; | |
205 | } | |
206 | ||
31f18b77 FG |
207 | struct timespec create_timestamp; |
208 | image.get_create_timestamp(&create_timestamp); | |
209 | ||
11fdf7f2 TL |
210 | std::string create_timestamp_str = ""; |
211 | format_timestamp(create_timestamp, create_timestamp_str); | |
212 | ||
213 | struct timespec access_timestamp; | |
214 | image.get_access_timestamp(&access_timestamp); | |
215 | ||
216 | std::string access_timestamp_str = ""; | |
217 | format_timestamp(access_timestamp, access_timestamp_str); | |
218 | ||
219 | struct timespec modify_timestamp; | |
220 | image.get_modify_timestamp(&modify_timestamp); | |
221 | ||
222 | std::string modify_timestamp_str = ""; | |
223 | format_timestamp(modify_timestamp, modify_timestamp_str); | |
31f18b77 | 224 | |
7c673cae FG |
225 | if (f) { |
226 | f->open_object_section("image"); | |
11fdf7f2 TL |
227 | f->dump_string("name", imgname); |
228 | f->dump_string("id", imgid); | |
7c673cae FG |
229 | f->dump_unsigned("size", info.size); |
230 | f->dump_unsigned("objects", info.num_objs); | |
231 | f->dump_int("order", info.order); | |
232 | f->dump_unsigned("object_size", info.obj_size); | |
11fdf7f2 | 233 | f->dump_int("snapshot_count", snaps.size()); |
7c673cae FG |
234 | if (!data_pool.empty()) { |
235 | f->dump_string("data_pool", data_pool); | |
236 | } | |
237 | f->dump_string("block_name_prefix", prefix); | |
238 | f->dump_int("format", (old_format ? 1 : 2)); | |
239 | } else { | |
11fdf7f2 | 240 | std::cout << "rbd image '" << imgname << "':\n" |
1adf2230 | 241 | << "\tsize " << byte_u_t(info.size) << " in " |
7c673cae FG |
242 | << info.num_objs << " objects" |
243 | << std::endl | |
244 | << "\torder " << info.order | |
1adf2230 | 245 | << " (" << byte_u_t(info.obj_size) << " objects)" |
11fdf7f2 TL |
246 | << std::endl |
247 | << "\tsnapshot_count: " << snaps.size() | |
7c673cae | 248 | << std::endl; |
11fdf7f2 TL |
249 | if (!imgid.empty()) { |
250 | std::cout << "\tid: " << imgid << std::endl; | |
251 | } | |
7c673cae FG |
252 | if (!data_pool.empty()) { |
253 | std::cout << "\tdata_pool: " << data_pool << std::endl; | |
254 | } | |
255 | std::cout << "\tblock_name_prefix: " << prefix | |
256 | << std::endl | |
257 | << "\tformat: " << (old_format ? "1" : "2") | |
258 | << std::endl; | |
259 | } | |
260 | ||
261 | if (!old_format) { | |
262 | format_features(f, features); | |
11fdf7f2 | 263 | format_op_features(f, op_features); |
7c673cae FG |
264 | format_flags(f, flags); |
265 | } | |
266 | ||
11fdf7f2 TL |
267 | if (!group_string.empty()) { |
268 | if (f) { | |
269 | f->dump_string("group", group_string); | |
270 | } else { | |
271 | std::cout << "\tgroup: " << group_string | |
272 | << std::endl; | |
273 | } | |
274 | } | |
275 | ||
31f18b77 FG |
276 | if (!create_timestamp_str.empty()) { |
277 | if (f) { | |
278 | f->dump_string("create_timestamp", create_timestamp_str); | |
279 | } else { | |
280 | std::cout << "\tcreate_timestamp: " << create_timestamp_str | |
281 | << std::endl; | |
282 | } | |
283 | } | |
284 | ||
11fdf7f2 TL |
285 | if (!access_timestamp_str.empty()) { |
286 | if (f) { | |
287 | f->dump_string("access_timestamp", access_timestamp_str); | |
288 | } else { | |
289 | std::cout << "\taccess_timestamp: " << access_timestamp_str | |
290 | << std::endl; | |
291 | } | |
292 | } | |
293 | ||
294 | if (!modify_timestamp_str.empty()) { | |
295 | if (f) { | |
296 | f->dump_string("modify_timestamp", modify_timestamp_str); | |
297 | } else { | |
298 | std::cout << "\tmodify_timestamp: " << modify_timestamp_str | |
299 | << std::endl; | |
300 | } | |
301 | } | |
302 | ||
7c673cae FG |
303 | // snapshot info, if present |
304 | if (!snapname.empty()) { | |
305 | if (f) { | |
306 | f->dump_string("protected", snap_protected ? "true" : "false"); | |
307 | } else { | |
308 | std::cout << "\tprotected: " << (snap_protected ? "True" : "False") | |
309 | << std::endl; | |
310 | } | |
311 | } | |
312 | ||
313 | if (snap_limit < UINT64_MAX) { | |
314 | if (f) { | |
315 | f->dump_unsigned("snapshot_limit", snap_limit); | |
316 | } else { | |
317 | std::cout << "\tsnapshot_limit: " << snap_limit << std::endl; | |
318 | } | |
319 | } | |
320 | ||
321 | // parent info, if present | |
11fdf7f2 TL |
322 | librbd::linked_image_spec_t parent_image_spec; |
323 | librbd::snap_spec_t parent_snap_spec; | |
324 | if ((image.get_parent(&parent_image_spec, &parent_snap_spec) == 0) && | |
325 | (parent_image_spec.image_name.length() > 0)) { | |
7c673cae FG |
326 | if (f) { |
327 | f->open_object_section("parent"); | |
11fdf7f2 TL |
328 | f->dump_string("pool", parent_image_spec.pool_name); |
329 | f->dump_string("pool_namespace", parent_image_spec.pool_namespace); | |
330 | f->dump_string("image", parent_image_spec.image_name); | |
331 | f->dump_string("id", parent_image_spec.image_id); | |
332 | f->dump_string("snapshot", parent_snap_spec.name); | |
333 | f->dump_bool("trash", parent_image_spec.trash); | |
7c673cae FG |
334 | f->dump_unsigned("overlap", overlap); |
335 | f->close_section(); | |
336 | } else { | |
11fdf7f2 TL |
337 | std::cout << "\tparent: " << parent_image_spec.pool_name << "/"; |
338 | if (!parent_image_spec.pool_namespace.empty()) { | |
339 | std::cout << parent_image_spec.pool_namespace << "/"; | |
340 | } | |
341 | std::cout << parent_image_spec.image_name << "@" | |
342 | << parent_snap_spec.name; | |
343 | if (parent_image_spec.trash) { | |
344 | std::cout << " (trash " << parent_image_spec.image_id << ")"; | |
7c673cae FG |
345 | } |
346 | std::cout << std::endl; | |
1adf2230 | 347 | std::cout << "\toverlap: " << byte_u_t(overlap) << std::endl; |
7c673cae FG |
348 | } |
349 | } | |
350 | ||
351 | // striping info, if feature is set | |
352 | if (features & RBD_FEATURE_STRIPINGV2) { | |
353 | if (f) { | |
354 | f->dump_unsigned("stripe_unit", image.get_stripe_unit()); | |
355 | f->dump_unsigned("stripe_count", image.get_stripe_count()); | |
356 | } else { | |
1adf2230 | 357 | std::cout << "\tstripe unit: " << byte_u_t(image.get_stripe_unit()) |
7c673cae FG |
358 | << std::endl |
359 | << "\tstripe count: " << image.get_stripe_count() << std::endl; | |
360 | } | |
361 | } | |
362 | ||
363 | if (features & RBD_FEATURE_JOURNALING) { | |
364 | if (f) { | |
365 | f->dump_string("journal", utils::image_id(image)); | |
366 | } else { | |
367 | std::cout << "\tjournal: " << utils::image_id(image) << std::endl; | |
368 | } | |
369 | } | |
370 | ||
9f95a23c TL |
371 | if (features & RBD_FEATURE_JOURNALING || |
372 | mirror_image.state != RBD_MIRROR_IMAGE_DISABLED) { | |
7c673cae FG |
373 | if (f) { |
374 | f->open_object_section("mirroring"); | |
9f95a23c TL |
375 | f->dump_string("mode", |
376 | utils::mirror_image_mode(mirror_mode)); | |
7c673cae FG |
377 | f->dump_string("state", |
378 | utils::mirror_image_state(mirror_image.state)); | |
379 | if (mirror_image.state != RBD_MIRROR_IMAGE_DISABLED) { | |
380 | f->dump_string("global_id", mirror_image.global_id); | |
381 | f->dump_bool("primary", mirror_image.primary); | |
382 | } | |
383 | f->close_section(); | |
384 | } else { | |
385 | std::cout << "\tmirroring state: " | |
386 | << utils::mirror_image_state(mirror_image.state) << std::endl; | |
387 | if (mirror_image.state != RBD_MIRROR_IMAGE_DISABLED) { | |
9f95a23c TL |
388 | std::cout << "\tmirroring mode: " |
389 | << utils::mirror_image_mode(mirror_mode) << std::endl | |
390 | << "\tmirroring global id: " << mirror_image.global_id | |
7c673cae FG |
391 | << std::endl |
392 | << "\tmirroring primary: " | |
393 | << (mirror_image.primary ? "true" : "false") <<std::endl; | |
394 | } | |
395 | } | |
396 | } | |
397 | ||
398 | if (f) { | |
399 | f->close_section(); | |
400 | f->flush(std::cout); | |
401 | } | |
402 | ||
403 | return 0; | |
404 | } | |
405 | ||
406 | void get_arguments(po::options_description *positional, | |
407 | po::options_description *options) { | |
408 | at::add_image_or_snap_spec_options(positional, options, | |
409 | at::ARGUMENT_MODIFIER_NONE); | |
410 | at::add_image_id_option(options); | |
411 | at::add_format_options(options); | |
412 | } | |
413 | ||
11fdf7f2 TL |
414 | int execute(const po::variables_map &vm, |
415 | const std::vector<std::string> &ceph_global_init_args) { | |
7c673cae FG |
416 | size_t arg_index = 0; |
417 | std::string pool_name; | |
11fdf7f2 | 418 | std::string namespace_name; |
7c673cae FG |
419 | std::string image_name; |
420 | std::string snap_name; | |
421 | std::string image_id; | |
422 | ||
423 | if (vm.count(at::IMAGE_ID)) { | |
424 | image_id = vm[at::IMAGE_ID].as<std::string>(); | |
425 | } | |
426 | ||
11fdf7f2 TL |
427 | int r = utils::get_pool_image_snapshot_names( |
428 | vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &namespace_name, | |
429 | &image_name, &snap_name, image_id.empty(), | |
430 | utils::SNAPSHOT_PRESENCE_PERMITTED, utils::SPEC_VALIDATION_NONE); | |
431 | if (r < 0) { | |
432 | return r; | |
433 | } | |
7c673cae | 434 | |
11fdf7f2 | 435 | if (!image_id.empty() && !image_name.empty()) { |
7c673cae FG |
436 | std::cerr << "rbd: trying to access image using both name and id. " |
437 | << std::endl; | |
438 | return -EINVAL; | |
439 | } | |
440 | ||
7c673cae FG |
441 | at::Format::Formatter formatter; |
442 | r = utils::get_formatter(vm, &formatter); | |
443 | if (r < 0) { | |
444 | return r; | |
445 | } | |
446 | ||
447 | librados::Rados rados; | |
448 | librados::IoCtx io_ctx; | |
449 | librbd::Image image; | |
11fdf7f2 TL |
450 | r = utils::init_and_open_image(pool_name, namespace_name, image_name, |
451 | image_id, snap_name, true, &rados, &io_ctx, | |
452 | &image); | |
7c673cae FG |
453 | if (r < 0) { |
454 | return r; | |
455 | } | |
456 | ||
11fdf7f2 | 457 | r = do_show_info(io_ctx, image, snap_name, formatter.get()); |
7c673cae FG |
458 | if (r < 0) { |
459 | std::cerr << "rbd: info: " << cpp_strerror(r) << std::endl; | |
460 | return r; | |
461 | } | |
462 | return 0; | |
463 | } | |
464 | ||
465 | Shell::Action action( | |
466 | {"info"}, {}, "Show information about image size, striping, etc.", "", | |
467 | &get_arguments, &execute); | |
468 | ||
469 | } // namespace info | |
470 | } // namespace action | |
471 | } // namespace rbd |