1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "common/errno.h"
5 #include "common/Formatter.h"
6 #include "json_spirit/json_spirit.h"
7 #include "tools/rbd/ArgumentTypes.h"
8 #include "tools/rbd/Shell.h"
9 #include "tools/rbd/Utils.h"
10 #include "include/rbd_types.h"
11 #include "include/stringify.h"
12 #include "librbd/cache/Types.h"
14 #include <boost/program_options.hpp>
20 namespace at
= argument_types
;
21 namespace po
= boost::program_options
;
23 static int do_show_status(librados::IoCtx
& io_ctx
, const std::string
&image_name
,
24 librbd::Image
&image
, Formatter
*f
)
27 std::list
<librbd::image_watcher_t
> watchers
;
29 r
= image
.list_watchers(watchers
);
34 r
= image
.features(&features
);
39 librbd::image_migration_status_t migration_status
;
40 std::string source_spec
;
41 std::string source_pool_name
;
42 std::string dest_pool_name
;
43 std::string migration_state
;
44 if ((features
& RBD_FEATURE_MIGRATING
) != 0) {
45 r
= librbd::RBD().migration_status(io_ctx
, image_name
.c_str(),
47 sizeof(migration_status
));
49 std::cerr
<< "rbd: getting migration status failed: " << cpp_strerror(r
)
53 if (migration_status
.source_pool_id
>= 0) {
54 librados::IoCtx src_io_ctx
;
55 r
= librados::Rados(io_ctx
).ioctx_create2(migration_status
.source_pool_id
, src_io_ctx
);
57 source_pool_name
= stringify(migration_status
.source_pool_id
);
59 source_pool_name
= src_io_ctx
.get_pool_name();
62 r
= image
.get_migration_source_spec(&source_spec
);
64 std::cerr
<< "rbd: getting migration source spec failed: "
65 << cpp_strerror(r
) << std::endl
;
69 librados::IoCtx dst_io_ctx
;
70 r
= librados::Rados(io_ctx
).ioctx_create2(migration_status
.dest_pool_id
, dst_io_ctx
);
72 dest_pool_name
= stringify(migration_status
.dest_pool_id
);
74 dest_pool_name
= dst_io_ctx
.get_pool_name();
77 switch (migration_status
.state
) {
78 case RBD_IMAGE_MIGRATION_STATE_ERROR
:
79 migration_state
= "error";
81 case RBD_IMAGE_MIGRATION_STATE_PREPARING
:
82 migration_state
= "preparing";
84 case RBD_IMAGE_MIGRATION_STATE_PREPARED
:
85 migration_state
= "prepared";
87 case RBD_IMAGE_MIGRATION_STATE_EXECUTING
:
88 migration_state
= "executing";
90 case RBD_IMAGE_MIGRATION_STATE_EXECUTED
:
91 migration_state
= "executed";
93 case RBD_IMAGE_MIGRATION_STATE_ABORTING
:
94 migration_state
= "aborting";
97 migration_state
= "unknown";
108 std::string stats_timestamp
;
112 uint64_t allocated_bytes
;
113 uint64_t cached_bytes
;
114 uint64_t dirty_bytes
;
117 uint64_t hits_partial
;
123 uint64_t total_read_ops
;
124 uint64_t total_read_bytes
;
125 int hits_full_percent
;
126 int hits_partial_percent
;
127 int hit_bytes_percent
;
129 std::string cache_str
;
130 if (features
& RBD_FEATURE_DIRTY_CACHE
) {
131 r
= image
.metadata_get(librbd::cache::PERSISTENT_CACHE_STATE
, &cache_str
);
133 std::cerr
<< "rbd: getting persistent cache state failed: " << cpp_strerror(r
)
137 json_spirit::mValue json_root
;
138 if (!json_spirit::read(cache_str
.c_str(), json_root
)) {
139 std::cerr
<< "rbd: parsing persistent cache state failed" << std::endl
;
143 auto& o
= json_root
.get_obj();
144 cache_state
.host
= o
["host"].get_str();
145 cache_state
.path
= o
["path"].get_str();
146 cache_state
.size
= o
["size"].get_uint64();
147 cache_state
.mode
= o
["mode"].get_str();
148 time_t stats_timestamp_sec
= o
["stats_timestamp"].get_uint64();
149 cache_state
.stats_timestamp
= ctime(&stats_timestamp_sec
);
150 cache_state
.stats_timestamp
.pop_back();
151 cache_state
.present
= o
["present"].get_bool();
152 cache_state
.empty
= o
["empty"].get_bool();
153 cache_state
.clean
= o
["clean"].get_bool();
154 cache_state
.allocated_bytes
= o
["allocated_bytes"].get_uint64();
155 cache_state
.cached_bytes
= o
["cached_bytes"].get_uint64();
156 cache_state
.dirty_bytes
= o
["dirty_bytes"].get_uint64();
157 cache_state
.free_bytes
= o
["free_bytes"].get_uint64();
158 cache_state
.hits_full
= o
["hits_full"].get_uint64();
159 cache_state
.hits_partial
= o
["hits_partial"].get_uint64();
160 cache_state
.misses
= o
["misses"].get_uint64();
161 cache_state
.hit_bytes
= o
["hit_bytes"].get_uint64();
162 cache_state
.miss_bytes
= o
["miss_bytes"].get_uint64();
163 } catch (std::runtime_error
&e
) {
164 std::cerr
<< "rbd: parsing persistent cache state failed: " << e
.what()
168 cache_state
.total_read_ops
= cache_state
.hits_full
+
169 cache_state
.hits_partial
+ cache_state
.misses
;
170 cache_state
.total_read_bytes
= cache_state
.hit_bytes
+
171 cache_state
.miss_bytes
;
172 cache_state
.hits_full_percent
= utils::get_percentage(
173 cache_state
.hits_full
, cache_state
.total_read_ops
);
174 cache_state
.hits_partial_percent
= utils::get_percentage(
175 cache_state
.hits_partial
, cache_state
.total_read_ops
);
176 cache_state
.hit_bytes_percent
= utils::get_percentage(
177 cache_state
.hit_bytes
, cache_state
.total_read_bytes
);
182 f
->open_object_section("status");
185 f
->open_array_section("watchers");
186 for (auto &watcher
: watchers
) {
187 f
->open_object_section("watcher");
188 f
->dump_string("address", watcher
.addr
);
189 f
->dump_unsigned("client", watcher
.id
);
190 f
->dump_unsigned("cookie", watcher
.cookie
);
193 f
->close_section(); // watchers
194 if (!migration_state
.empty()) {
195 f
->open_object_section("migration");
196 if (!source_spec
.empty()) {
197 f
->dump_string("source_spec", source_spec
);
199 f
->dump_string("source_pool_name", source_pool_name
);
200 f
->dump_string("source_pool_namespace",
201 migration_status
.source_pool_namespace
);
202 f
->dump_string("source_image_name", migration_status
.source_image_name
);
203 f
->dump_string("source_image_id", migration_status
.source_image_id
);
205 f
->dump_string("dest_pool_name", dest_pool_name
);
206 f
->dump_string("dest_pool_namespace",
207 migration_status
.dest_pool_namespace
);
208 f
->dump_string("dest_image_name", migration_status
.dest_image_name
);
209 f
->dump_string("dest_image_id", migration_status
.dest_image_id
);
210 f
->dump_string("state", migration_state
);
211 f
->dump_string("state_description", migration_status
.state_description
);
212 f
->close_section(); // migration
214 if (!cache_str
.empty()) {
215 f
->open_object_section("persistent_cache");
216 f
->dump_string("host", cache_state
.host
);
217 f
->dump_string("path", cache_state
.path
);
218 f
->dump_unsigned("size", cache_state
.size
);
219 f
->dump_string("mode", cache_state
.mode
);
220 f
->dump_string("stats_timestamp", cache_state
.stats_timestamp
);
221 f
->dump_bool("present", cache_state
.present
);
222 f
->dump_bool("empty", cache_state
.empty
);
223 f
->dump_bool("clean", cache_state
.clean
);
224 f
->dump_unsigned("allocated_bytes", cache_state
.allocated_bytes
);
225 f
->dump_unsigned("cached_bytes", cache_state
.cached_bytes
);
226 f
->dump_unsigned("dirty_bytes", cache_state
.dirty_bytes
);
227 f
->dump_unsigned("free_bytes", cache_state
.free_bytes
);
228 f
->dump_unsigned("hits_full", cache_state
.hits_full
);
229 f
->dump_int("hits_full_percent", cache_state
.hits_full_percent
);
230 f
->dump_unsigned("hits_partial", cache_state
.hits_partial
);
231 f
->dump_int("hits_partial_percent", cache_state
.hits_partial_percent
);
232 f
->dump_unsigned("misses", cache_state
.misses
);
233 f
->dump_unsigned("hit_bytes", cache_state
.hit_bytes
);
234 f
->dump_int("hit_bytes_percent", cache_state
.hit_bytes_percent
);
235 f
->dump_unsigned("miss_bytes", cache_state
.miss_bytes
);
236 f
->close_section(); // persistent_cache
239 if (watchers
.size()) {
240 std::cout
<< "Watchers:" << std::endl
;
241 for (auto &watcher
: watchers
) {
242 std::cout
<< "\twatcher=" << watcher
.addr
<< " client." << watcher
.id
243 << " cookie=" << watcher
.cookie
<< std::endl
;
246 std::cout
<< "Watchers: none" << std::endl
;
248 if (!migration_state
.empty()) {
249 if (!migration_status
.source_pool_namespace
.empty()) {
250 source_pool_name
+= ("/" + migration_status
.source_pool_namespace
);
252 if (!migration_status
.dest_pool_namespace
.empty()) {
253 dest_pool_name
+= ("/" + migration_status
.dest_pool_namespace
);
256 std::cout
<< "Migration:" << std::endl
;
257 std::cout
<< "\tsource: ";
258 if (!source_spec
.empty()) {
259 std::cout
<< source_spec
;
261 std::cout
<< source_pool_name
<< "/"
262 << migration_status
.source_image_name
;
263 if (!migration_status
.source_image_id
.empty()) {
264 std::cout
<< " (" << migration_status
.source_image_id
<< ")";
267 std::cout
<< std::endl
;
268 std::cout
<< "\tdestination: " << dest_pool_name
<< "/"
269 << migration_status
.dest_image_name
<< " ("
270 << migration_status
.dest_image_id
<< ")" << std::endl
;
271 std::cout
<< "\tstate: " << migration_state
;
272 if (!migration_status
.state_description
.empty()) {
273 std::cout
<< " (" << migration_status
.state_description
<< ")";
275 std::cout
<< std::endl
;
277 if (!cache_str
.empty()) {
278 std::cout
<< "Persistent cache state:" << std::endl
;
279 std::cout
<< "\thost: " << cache_state
.host
<< std::endl
;
280 std::cout
<< "\tpath: " << cache_state
.path
<< std::endl
;
281 std::cout
<< "\tsize: " << byte_u_t(cache_state
.size
) << std::endl
;
282 std::cout
<< "\tmode: " << cache_state
.mode
<< std::endl
;
283 std::cout
<< "\tstats_timestamp: " << cache_state
.stats_timestamp
285 std::cout
<< "\tpresent: " << (cache_state
.present
? "true" : "false")
286 << "\tempty: " << (cache_state
.empty
? "true" : "false")
287 << "\tclean: " << (cache_state
.clean
? "true" : "false")
289 std::cout
<< "\tallocated: " << byte_u_t(cache_state
.allocated_bytes
)
291 std::cout
<< "\tcached: " << byte_u_t(cache_state
.cached_bytes
)
293 std::cout
<< "\tdirty: " << byte_u_t(cache_state
.dirty_bytes
) << std::endl
;
294 std::cout
<< "\tfree: " << byte_u_t(cache_state
.free_bytes
) << std::endl
;
295 std::cout
<< "\thits_full: " << cache_state
.hits_full
<< " / "
296 << cache_state
.hits_full_percent
<< "%" << std::endl
;
297 std::cout
<< "\thits_partial: " << cache_state
.hits_partial
<< " / "
298 << cache_state
.hits_partial_percent
<< "%" << std::endl
;
299 std::cout
<< "\tmisses: " << cache_state
.misses
<< std::endl
;
300 std::cout
<< "\thit_bytes: " << byte_u_t(cache_state
.hit_bytes
) << " / "
301 << cache_state
.hit_bytes_percent
<< "%" << std::endl
;
302 std::cout
<< "\tmiss_bytes: " << byte_u_t(cache_state
.miss_bytes
)
308 f
->close_section(); // status
315 void get_arguments(po::options_description
*positional
,
316 po::options_description
*options
) {
317 at::add_image_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_NONE
);
318 at::add_format_options(options
);
321 int execute(const po::variables_map
&vm
,
322 const std::vector
<std::string
> &ceph_global_init_args
) {
323 size_t arg_index
= 0;
324 std::string pool_name
;
325 std::string namespace_name
;
326 std::string image_name
;
327 std::string snap_name
;
328 int r
= utils::get_pool_image_snapshot_names(
329 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
330 &image_name
, &snap_name
, true, utils::SNAPSHOT_PRESENCE_NONE
,
331 utils::SPEC_VALIDATION_NONE
);
336 at::Format::Formatter formatter
;
337 r
= utils::get_formatter(vm
, &formatter
);
342 librados::Rados rados
;
343 librados::IoCtx io_ctx
;
345 r
= utils::init_and_open_image(pool_name
, namespace_name
, image_name
, "", "",
346 true, &rados
, &io_ctx
, &image
);
351 r
= do_show_status(io_ctx
, image_name
, image
, formatter
.get());
353 std::cerr
<< "rbd: show status failed: " << cpp_strerror(r
) << std::endl
;
359 Shell::Action
action(
360 {"status"}, {}, "Show the status of this image.", "", &get_arguments
,
363 } // namespace status
364 } // namespace action