]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd/action/Info.cc
d415c9a5859603e7c0e501b301aa626bf5cf7f4e
[ceph.git] / ceph / src / tools / rbd / action / Info.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 <iostream>
12 #include <boost/program_options.hpp>
13
14 namespace rbd {
15 namespace action {
16 namespace info {
17
18 namespace at = argument_types;
19 namespace po = boost::program_options;
20
21 static void format_bitmask(Formatter *f, const std::string &name,
22 const std::map<uint64_t, std::string>& mapping,
23 uint64_t bitmask)
24 {
25 int count = 0;
26 std::string group_name(name + "s");
27 if (f == NULL) {
28 std::cout << "\t" << group_name << ": ";
29 } else {
30 f->open_array_section(group_name.c_str());
31 }
32 for (std::map<uint64_t, std::string>::const_iterator it = mapping.begin();
33 it != mapping.end(); ++it) {
34 if ((it->first & bitmask) == 0) {
35 continue;
36 }
37
38 if (f == NULL) {
39 if (count++ > 0) {
40 std::cout << ", ";
41 }
42 std::cout << it->second;
43 } else {
44 f->dump_string(name.c_str(), it->second);
45 }
46 }
47 if (f == NULL) {
48 std::cout << std::endl;
49 } else {
50 f->close_section();
51 }
52 }
53
54 static void format_features(Formatter *f, uint64_t features)
55 {
56 format_bitmask(f, "feature", at::ImageFeatures::FEATURE_MAPPING, features);
57 }
58
59 static void format_flags(Formatter *f, uint64_t flags)
60 {
61 std::map<uint64_t, std::string> mapping = {
62 {RBD_FLAG_OBJECT_MAP_INVALID, "object map invalid"},
63 {RBD_FLAG_FAST_DIFF_INVALID, "fast diff invalid"}};
64 format_bitmask(f, "flag", mapping, flags);
65 }
66
67 static int do_show_info(librados::IoCtx &io_ctx, librbd::Image& image,
68 const std::string &imgname, const std::string &imgid,
69 const std::string &snapname, Formatter *f)
70 {
71 librbd::image_info_t info;
72 uint8_t old_format;
73 uint64_t overlap, features, flags, snap_limit;
74 bool snap_protected = false;
75 librbd::mirror_image_info_t mirror_image;
76 int r;
77
78 r = image.stat(info, sizeof(info));
79 if (r < 0)
80 return r;
81
82 r = image.old_format(&old_format);
83 if (r < 0)
84 return r;
85
86 std::string data_pool;
87 if (!old_format) {
88 int64_t data_pool_id = image.get_data_pool_id();
89 if (data_pool_id != io_ctx.get_id()) {
90 librados::Rados rados(io_ctx);
91 librados::IoCtx data_io_ctx;
92 r = rados.ioctx_create2(data_pool_id, data_io_ctx);
93 if (r < 0) {
94 data_pool = "<missing data pool " + stringify(data_pool_id) + ">";
95 } else {
96 data_pool = data_io_ctx.get_pool_name();
97 }
98 }
99 }
100
101 r = image.overlap(&overlap);
102 if (r < 0)
103 return r;
104
105 r = image.features(&features);
106 if (r < 0)
107 return r;
108
109 r = image.get_flags(&flags);
110 if (r < 0) {
111 return r;
112 }
113
114 if (!snapname.empty()) {
115 r = image.snap_is_protected(snapname.c_str(), &snap_protected);
116 if (r < 0)
117 return r;
118 }
119
120 if (features & RBD_FEATURE_JOURNALING) {
121 r = image.mirror_image_get_info(&mirror_image, sizeof(mirror_image));
122 if (r < 0) {
123 return r;
124 }
125 }
126
127 r = image.snap_get_limit(&snap_limit);
128 if (r < 0)
129 return r;
130
131 std::string prefix = image.get_block_name_prefix();
132
133 librbd::group_spec_t group_spec;
134 r = image.get_group(&group_spec);
135 if (r < 0) {
136 return r;
137 }
138
139 std::string group_string = "";
140 if (-1 != group_spec.pool)
141 group_string = stringify(group_spec.pool) + "." + group_spec.name;
142
143 struct timespec create_timestamp;
144 image.get_create_timestamp(&create_timestamp);
145
146 string create_timestamp_str = "";
147 if(create_timestamp.tv_sec != 0) {
148 time_t timestamp = create_timestamp.tv_sec;
149 create_timestamp_str = ctime(&timestamp);
150 create_timestamp_str = create_timestamp_str.substr(0,
151 create_timestamp_str.length() - 1);
152 }
153
154 if (f) {
155 f->open_object_section("image");
156 if (!imgname.empty()) {
157 f->dump_string("name", imgname);
158 } else {
159 f->dump_string("id", imgid);
160 }
161 f->dump_unsigned("size", info.size);
162 f->dump_unsigned("objects", info.num_objs);
163 f->dump_int("order", info.order);
164 f->dump_unsigned("object_size", info.obj_size);
165 if (!data_pool.empty()) {
166 f->dump_string("data_pool", data_pool);
167 }
168 f->dump_string("block_name_prefix", prefix);
169 f->dump_int("format", (old_format ? 1 : 2));
170 } else {
171 std::cout << "rbd image '" << (imgname.empty() ? imgid : imgname) << "':\n"
172 << "\tsize " << prettybyte_t(info.size) << " in "
173 << info.num_objs << " objects"
174 << std::endl
175 << "\torder " << info.order
176 << " (" << prettybyte_t(info.obj_size) << " objects)"
177 << std::endl;
178 if (!data_pool.empty()) {
179 std::cout << "\tdata_pool: " << data_pool << std::endl;
180 }
181 std::cout << "\tblock_name_prefix: " << prefix
182 << std::endl
183 << "\tformat: " << (old_format ? "1" : "2")
184 << std::endl;
185 }
186
187 if (!old_format) {
188 format_features(f, features);
189 format_flags(f, flags);
190 }
191
192 if (!group_string.empty()) {
193 if (f) {
194 f->dump_string("group", group_string);
195 } else {
196 std::cout << "\tconsistency group: " << group_string
197 << std::endl;
198 }
199 }
200
201 if (!create_timestamp_str.empty()) {
202 if (f) {
203 f->dump_string("create_timestamp", create_timestamp_str);
204 } else {
205 std::cout << "\tcreate_timestamp: " << create_timestamp_str
206 << std::endl;
207 }
208 }
209
210 // snapshot info, if present
211 if (!snapname.empty()) {
212 if (f) {
213 f->dump_string("protected", snap_protected ? "true" : "false");
214 } else {
215 std::cout << "\tprotected: " << (snap_protected ? "True" : "False")
216 << std::endl;
217 }
218 }
219
220 if (snap_limit < UINT64_MAX) {
221 if (f) {
222 f->dump_unsigned("snapshot_limit", snap_limit);
223 } else {
224 std::cout << "\tsnapshot_limit: " << snap_limit << std::endl;
225 }
226 }
227
228 // parent info, if present
229 std::string parent_pool, parent_name, parent_id, parent_snapname;
230 if ((image.parent_info2(&parent_pool, &parent_name, &parent_id,
231 &parent_snapname) == 0) &&
232 parent_name.length() > 0) {
233
234 librbd::trash_image_info_t trash_image_info;
235 librbd::RBD rbd;
236 r = rbd.trash_get(io_ctx, parent_id.c_str(), &trash_image_info);
237 bool trash_image_info_valid = (r == 0);
238
239 if (f) {
240 f->open_object_section("parent");
241 f->dump_string("pool", parent_pool);
242 f->dump_string("image", parent_name);
243 f->dump_string("snapshot", parent_snapname);
244 if (trash_image_info_valid) {
245 f->dump_string("trash", parent_id);
246 }
247 f->dump_unsigned("overlap", overlap);
248 f->close_section();
249 } else {
250 std::cout << "\tparent: " << parent_pool << "/" << parent_name
251 << "@" << parent_snapname;
252 if (trash_image_info_valid) {
253 std::cout << " (trash " << parent_id << ")";
254 }
255 std::cout << std::endl;
256 std::cout << "\toverlap: " << prettybyte_t(overlap) << std::endl;
257 }
258 }
259
260 // striping info, if feature is set
261 if (features & RBD_FEATURE_STRIPINGV2) {
262 if (f) {
263 f->dump_unsigned("stripe_unit", image.get_stripe_unit());
264 f->dump_unsigned("stripe_count", image.get_stripe_count());
265 } else {
266 std::cout << "\tstripe unit: " << prettybyte_t(image.get_stripe_unit())
267 << std::endl
268 << "\tstripe count: " << image.get_stripe_count() << std::endl;
269 }
270 }
271
272 if (features & RBD_FEATURE_JOURNALING) {
273 if (f) {
274 f->dump_string("journal", utils::image_id(image));
275 } else {
276 std::cout << "\tjournal: " << utils::image_id(image) << std::endl;
277 }
278 }
279
280 if (features & RBD_FEATURE_JOURNALING) {
281 if (f) {
282 f->open_object_section("mirroring");
283 f->dump_string("state",
284 utils::mirror_image_state(mirror_image.state));
285 if (mirror_image.state != RBD_MIRROR_IMAGE_DISABLED) {
286 f->dump_string("global_id", mirror_image.global_id);
287 f->dump_bool("primary", mirror_image.primary);
288 }
289 f->close_section();
290 } else {
291 std::cout << "\tmirroring state: "
292 << utils::mirror_image_state(mirror_image.state) << std::endl;
293 if (mirror_image.state != RBD_MIRROR_IMAGE_DISABLED) {
294 std::cout << "\tmirroring global id: " << mirror_image.global_id
295 << std::endl
296 << "\tmirroring primary: "
297 << (mirror_image.primary ? "true" : "false") <<std::endl;
298 }
299 }
300 }
301
302 if (f) {
303 f->close_section();
304 f->flush(std::cout);
305 }
306
307 return 0;
308 }
309
310 void get_arguments(po::options_description *positional,
311 po::options_description *options) {
312 at::add_image_or_snap_spec_options(positional, options,
313 at::ARGUMENT_MODIFIER_NONE);
314 at::add_image_id_option(options);
315 at::add_format_options(options);
316 }
317
318 int execute(const po::variables_map &vm) {
319 size_t arg_index = 0;
320 std::string pool_name;
321 std::string image_name;
322 std::string snap_name;
323 std::string image_id;
324
325 if (vm.count(at::IMAGE_ID)) {
326 image_id = vm[at::IMAGE_ID].as<std::string>();
327 }
328
329 bool has_image_spec = utils::check_if_image_spec_present(
330 vm, at::ARGUMENT_MODIFIER_NONE, arg_index);
331
332 if (!image_id.empty() && has_image_spec) {
333 std::cerr << "rbd: trying to access image using both name and id. "
334 << std::endl;
335 return -EINVAL;
336 }
337
338 int r;
339 if (image_id.empty()) {
340 r = utils::get_pool_image_snapshot_names(vm, at::ARGUMENT_MODIFIER_NONE,
341 &arg_index, &pool_name,
342 &image_name, &snap_name,
343 utils::SNAPSHOT_PRESENCE_PERMITTED,
344 utils::SPEC_VALIDATION_NONE);
345 } else {
346 r = utils::get_pool_snapshot_names(vm, at::ARGUMENT_MODIFIER_NONE,
347 &arg_index, &pool_name, &snap_name,
348 utils::SNAPSHOT_PRESENCE_PERMITTED,
349 utils::SPEC_VALIDATION_NONE);
350 }
351 if (r < 0) {
352 return r;
353 }
354
355 at::Format::Formatter formatter;
356 r = utils::get_formatter(vm, &formatter);
357 if (r < 0) {
358 return r;
359 }
360
361 librados::Rados rados;
362 librados::IoCtx io_ctx;
363 librbd::Image image;
364 r = utils::init_and_open_image(pool_name, image_name, image_id, snap_name,
365 true, &rados, &io_ctx, &image);
366 if (r < 0) {
367 return r;
368 }
369
370 r = do_show_info(io_ctx, image, image_name, image_id, snap_name,
371 formatter.get());
372 if (r < 0) {
373 std::cerr << "rbd: info: " << cpp_strerror(r) << std::endl;
374 return r;
375 }
376 return 0;
377 }
378
379 Shell::Action action(
380 {"info"}, {}, "Show information about image size, striping, etc.", "",
381 &get_arguments, &execute);
382
383 } // namespace info
384 } // namespace action
385 } // namespace rbd