Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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   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(&timestamp);
140     create_timestamp_str = create_timestamp_str.substr(0,
141         create_timestamp_str.length() - 1);
142   }
143
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
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
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