]>
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 | ||
31f18b77 FG |
133 | struct timespec create_timestamp; |
134 | image.get_create_timestamp(&create_timestamp); | |
135 | ||
136 | string create_timestamp_str = ""; | |
137 | if(create_timestamp.tv_sec != 0) { | |
138 | time_t timestamp = create_timestamp.tv_sec; | |
139 | create_timestamp_str = ctime(×tamp); | |
140 | create_timestamp_str = create_timestamp_str.substr(0, | |
141 | create_timestamp_str.length() - 1); | |
142 | } | |
143 | ||
7c673cae FG |
144 | if (f) { |
145 | f->open_object_section("image"); | |
146 | if (!imgname.empty()) { | |
147 | f->dump_string("name", imgname); | |
148 | } else { | |
149 | f->dump_string("id", imgid); | |
150 | } | |
151 | f->dump_unsigned("size", info.size); | |
152 | f->dump_unsigned("objects", info.num_objs); | |
153 | f->dump_int("order", info.order); | |
154 | f->dump_unsigned("object_size", info.obj_size); | |
155 | if (!data_pool.empty()) { | |
156 | f->dump_string("data_pool", data_pool); | |
157 | } | |
158 | f->dump_string("block_name_prefix", prefix); | |
159 | f->dump_int("format", (old_format ? 1 : 2)); | |
160 | } else { | |
161 | std::cout << "rbd image '" << (imgname.empty() ? imgid : imgname) << "':\n" | |
162 | << "\tsize " << prettybyte_t(info.size) << " in " | |
163 | << info.num_objs << " objects" | |
164 | << std::endl | |
165 | << "\torder " << info.order | |
166 | << " (" << prettybyte_t(info.obj_size) << " objects)" | |
167 | << std::endl; | |
168 | if (!data_pool.empty()) { | |
169 | std::cout << "\tdata_pool: " << data_pool << std::endl; | |
170 | } | |
171 | std::cout << "\tblock_name_prefix: " << prefix | |
172 | << std::endl | |
173 | << "\tformat: " << (old_format ? "1" : "2") | |
174 | << std::endl; | |
175 | } | |
176 | ||
177 | if (!old_format) { | |
178 | format_features(f, features); | |
179 | format_flags(f, flags); | |
180 | } | |
181 | ||
31f18b77 FG |
182 | if (!create_timestamp_str.empty()) { |
183 | if (f) { | |
184 | f->dump_string("create_timestamp", create_timestamp_str); | |
185 | } else { | |
186 | std::cout << "\tcreate_timestamp: " << create_timestamp_str | |
187 | << std::endl; | |
188 | } | |
189 | } | |
190 | ||
7c673cae FG |
191 | // snapshot info, if present |
192 | if (!snapname.empty()) { | |
193 | if (f) { | |
194 | f->dump_string("protected", snap_protected ? "true" : "false"); | |
195 | } else { | |
196 | std::cout << "\tprotected: " << (snap_protected ? "True" : "False") | |
197 | << std::endl; | |
198 | } | |
199 | } | |
200 | ||
201 | if (snap_limit < UINT64_MAX) { | |
202 | if (f) { | |
203 | f->dump_unsigned("snapshot_limit", snap_limit); | |
204 | } else { | |
205 | std::cout << "\tsnapshot_limit: " << snap_limit << std::endl; | |
206 | } | |
207 | } | |
208 | ||
209 | // parent info, if present | |
210 | std::string parent_pool, parent_name, parent_id, parent_snapname; | |
211 | if ((image.parent_info2(&parent_pool, &parent_name, &parent_id, | |
212 | &parent_snapname) == 0) && | |
213 | parent_name.length() > 0) { | |
214 | ||
215 | librbd::trash_image_info_t trash_image_info; | |
216 | librbd::RBD rbd; | |
217 | r = rbd.trash_get(io_ctx, parent_id.c_str(), &trash_image_info); | |
218 | bool trash_image_info_valid = (r == 0); | |
219 | ||
220 | if (f) { | |
221 | f->open_object_section("parent"); | |
222 | f->dump_string("pool", parent_pool); | |
223 | f->dump_string("image", parent_name); | |
224 | f->dump_string("snapshot", parent_snapname); | |
225 | if (trash_image_info_valid) { | |
226 | f->dump_string("trash", parent_id); | |
227 | } | |
228 | f->dump_unsigned("overlap", overlap); | |
229 | f->close_section(); | |
230 | } else { | |
231 | std::cout << "\tparent: " << parent_pool << "/" << parent_name | |
232 | << "@" << parent_snapname; | |
233 | if (trash_image_info_valid) { | |
234 | std::cout << " (trash " << parent_id << ")"; | |
235 | } | |
236 | std::cout << std::endl; | |
237 | std::cout << "\toverlap: " << prettybyte_t(overlap) << std::endl; | |
238 | } | |
239 | } | |
240 | ||
241 | // striping info, if feature is set | |
242 | if (features & RBD_FEATURE_STRIPINGV2) { | |
243 | if (f) { | |
244 | f->dump_unsigned("stripe_unit", image.get_stripe_unit()); | |
245 | f->dump_unsigned("stripe_count", image.get_stripe_count()); | |
246 | } else { | |
247 | std::cout << "\tstripe unit: " << prettybyte_t(image.get_stripe_unit()) | |
248 | << std::endl | |
249 | << "\tstripe count: " << image.get_stripe_count() << std::endl; | |
250 | } | |
251 | } | |
252 | ||
253 | if (features & RBD_FEATURE_JOURNALING) { | |
254 | if (f) { | |
255 | f->dump_string("journal", utils::image_id(image)); | |
256 | } else { | |
257 | std::cout << "\tjournal: " << utils::image_id(image) << std::endl; | |
258 | } | |
259 | } | |
260 | ||
261 | if (features & RBD_FEATURE_JOURNALING) { | |
262 | if (f) { | |
263 | f->open_object_section("mirroring"); | |
264 | f->dump_string("state", | |
265 | utils::mirror_image_state(mirror_image.state)); | |
266 | if (mirror_image.state != RBD_MIRROR_IMAGE_DISABLED) { | |
267 | f->dump_string("global_id", mirror_image.global_id); | |
268 | f->dump_bool("primary", mirror_image.primary); | |
269 | } | |
270 | f->close_section(); | |
271 | } else { | |
272 | std::cout << "\tmirroring state: " | |
273 | << utils::mirror_image_state(mirror_image.state) << std::endl; | |
274 | if (mirror_image.state != RBD_MIRROR_IMAGE_DISABLED) { | |
275 | std::cout << "\tmirroring global id: " << mirror_image.global_id | |
276 | << std::endl | |
277 | << "\tmirroring primary: " | |
278 | << (mirror_image.primary ? "true" : "false") <<std::endl; | |
279 | } | |
280 | } | |
281 | } | |
282 | ||
283 | if (f) { | |
284 | f->close_section(); | |
285 | f->flush(std::cout); | |
286 | } | |
287 | ||
288 | return 0; | |
289 | } | |
290 | ||
291 | void get_arguments(po::options_description *positional, | |
292 | po::options_description *options) { | |
293 | at::add_image_or_snap_spec_options(positional, options, | |
294 | at::ARGUMENT_MODIFIER_NONE); | |
295 | at::add_image_id_option(options); | |
296 | at::add_format_options(options); | |
297 | } | |
298 | ||
299 | int execute(const po::variables_map &vm) { | |
300 | size_t arg_index = 0; | |
301 | std::string pool_name; | |
302 | std::string image_name; | |
303 | std::string snap_name; | |
304 | std::string image_id; | |
305 | ||
306 | if (vm.count(at::IMAGE_ID)) { | |
307 | image_id = vm[at::IMAGE_ID].as<std::string>(); | |
308 | } | |
309 | ||
310 | bool has_image_spec = utils::check_if_image_spec_present( | |
311 | vm, at::ARGUMENT_MODIFIER_NONE, arg_index); | |
312 | ||
313 | if (!image_id.empty() && has_image_spec) { | |
314 | std::cerr << "rbd: trying to access image using both name and id. " | |
315 | << std::endl; | |
316 | return -EINVAL; | |
317 | } | |
318 | ||
319 | int r; | |
320 | if (image_id.empty()) { | |
321 | r = utils::get_pool_image_snapshot_names(vm, at::ARGUMENT_MODIFIER_NONE, | |
322 | &arg_index, &pool_name, | |
323 | &image_name, &snap_name, | |
324 | utils::SNAPSHOT_PRESENCE_PERMITTED, | |
325 | utils::SPEC_VALIDATION_NONE); | |
326 | } else { | |
327 | r = utils::get_pool_snapshot_names(vm, at::ARGUMENT_MODIFIER_NONE, | |
328 | &arg_index, &pool_name, &snap_name, | |
329 | utils::SNAPSHOT_PRESENCE_PERMITTED, | |
330 | utils::SPEC_VALIDATION_NONE); | |
331 | } | |
332 | if (r < 0) { | |
333 | return r; | |
334 | } | |
335 | ||
336 | at::Format::Formatter formatter; | |
337 | r = utils::get_formatter(vm, &formatter); | |
338 | if (r < 0) { | |
339 | return r; | |
340 | } | |
341 | ||
342 | librados::Rados rados; | |
343 | librados::IoCtx io_ctx; | |
344 | librbd::Image image; | |
345 | r = utils::init_and_open_image(pool_name, image_name, image_id, snap_name, | |
346 | true, &rados, &io_ctx, &image); | |
347 | if (r < 0) { | |
348 | return r; | |
349 | } | |
350 | ||
351 | r = do_show_info(io_ctx, image, image_name, image_id, snap_name, | |
352 | formatter.get()); | |
353 | if (r < 0) { | |
354 | std::cerr << "rbd: info: " << cpp_strerror(r) << std::endl; | |
355 | return r; | |
356 | } | |
357 | return 0; | |
358 | } | |
359 | ||
360 | Shell::Action action( | |
361 | {"info"}, {}, "Show information about image size, striping, etc.", "", | |
362 | &get_arguments, &execute); | |
363 | ||
364 | } // namespace info | |
365 | } // namespace action | |
366 | } // namespace rbd |