]>
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 | ||
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 | ||
31f18b77 FG |
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(×tamp); | |
150 | create_timestamp_str = create_timestamp_str.substr(0, | |
151 | create_timestamp_str.length() - 1); | |
152 | } | |
153 | ||
7c673cae FG |
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 | ||
31f18b77 FG |
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 | ||
7c673cae FG |
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 |