1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "common/ceph_json.h"
5 #include "common/errno.h"
6 #include "common/Formatter.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"
13 #include <boost/program_options.hpp>
19 namespace at
= argument_types
;
20 namespace po
= boost::program_options
;
24 const std::string IMAGE_CACHE_STATE
= ".librbd/image_cache_state";
26 struct ImageCacheState
{
34 bool image_cache_parse(const std::string
& s
, ImageCacheState
&cache_state
) {
37 bool success
= p
.parse(s
.c_str(), s
.size());
39 decode_json_obj(f
, &p
);
40 if ((success
= f
.exists("present"))) {
41 cache_state
.present
= (bool)f
["present"];
43 if (success
&& (success
= f
.exists("clean"))) {
44 cache_state
.present
= (bool)f
["clean"];
46 if (success
&& (success
= f
.exists("pwl_size"))) {
47 cache_state
.size
= (int)f
["pwl_size"];
49 if (success
&& (success
= f
.exists("pwl_host"))) {
50 cache_state
.host
= (std::string
)f
["pwl_host"];
52 if (success
&& (success
= f
.exists("pwl_path"))) {
53 cache_state
.path
= (std::string
)f
["pwl_path"];
59 } // anonymous namespace
61 static int do_show_status(librados::IoCtx
& io_ctx
, const std::string
&image_name
,
62 librbd::Image
&image
, Formatter
*f
)
65 std::list
<librbd::image_watcher_t
> watchers
;
67 r
= image
.list_watchers(watchers
);
72 r
= image
.features(&features
);
77 librbd::image_migration_status_t migration_status
;
78 std::string source_spec
;
79 std::string source_pool_name
;
80 std::string dest_pool_name
;
81 std::string migration_state
;
82 if ((features
& RBD_FEATURE_MIGRATING
) != 0) {
83 r
= librbd::RBD().migration_status(io_ctx
, image_name
.c_str(),
85 sizeof(migration_status
));
87 std::cerr
<< "rbd: getting migration status failed: " << cpp_strerror(r
)
91 if (migration_status
.source_pool_id
>= 0) {
92 librados::IoCtx src_io_ctx
;
93 r
= librados::Rados(io_ctx
).ioctx_create2(migration_status
.source_pool_id
, src_io_ctx
);
95 source_pool_name
= stringify(migration_status
.source_pool_id
);
97 source_pool_name
= src_io_ctx
.get_pool_name();
100 r
= image
.get_migration_source_spec(&source_spec
);
102 std::cerr
<< "rbd: getting migration source spec failed: "
103 << cpp_strerror(r
) << std::endl
;
107 librados::IoCtx dst_io_ctx
;
108 r
= librados::Rados(io_ctx
).ioctx_create2(migration_status
.dest_pool_id
, dst_io_ctx
);
110 dest_pool_name
= stringify(migration_status
.dest_pool_id
);
112 dest_pool_name
= dst_io_ctx
.get_pool_name();
115 switch (migration_status
.state
) {
116 case RBD_IMAGE_MIGRATION_STATE_ERROR
:
117 migration_state
= "error";
119 case RBD_IMAGE_MIGRATION_STATE_PREPARING
:
120 migration_state
= "preparing";
122 case RBD_IMAGE_MIGRATION_STATE_PREPARED
:
123 migration_state
= "prepared";
125 case RBD_IMAGE_MIGRATION_STATE_EXECUTING
:
126 migration_state
= "executing";
128 case RBD_IMAGE_MIGRATION_STATE_EXECUTED
:
129 migration_state
= "executed";
131 case RBD_IMAGE_MIGRATION_STATE_ABORTING
:
132 migration_state
= "aborting";
135 migration_state
= "unknown";
140 ImageCacheState cache_state
;
141 if (features
& RBD_FEATURE_DIRTY_CACHE
) {
142 std::string image_cache_str
;
143 r
= image
.metadata_get(IMAGE_CACHE_STATE
, &image_cache_str
);
145 std::cerr
<< "rbd: getting image cache status failed: " << cpp_strerror(r
)
148 r
= image_cache_parse(image_cache_str
, cache_state
);
150 std::cerr
<< "rbd: image cache metadata is corrupted: " << cpp_strerror(r
)
157 f
->open_object_section("status");
160 f
->open_array_section("watchers");
161 for (auto &watcher
: watchers
) {
162 f
->open_object_section("watcher");
163 f
->dump_string("address", watcher
.addr
);
164 f
->dump_unsigned("client", watcher
.id
);
165 f
->dump_unsigned("cookie", watcher
.cookie
);
168 f
->close_section(); // watchers
169 if (!migration_state
.empty()) {
170 f
->open_object_section("migration");
171 if (!source_spec
.empty()) {
172 f
->dump_string("source_spec", source_spec
);
174 f
->dump_string("source_pool_name", source_pool_name
);
175 f
->dump_string("source_pool_namespace",
176 migration_status
.source_pool_namespace
);
177 f
->dump_string("source_image_name", migration_status
.source_image_name
);
178 f
->dump_string("source_image_id", migration_status
.source_image_id
);
180 f
->dump_string("dest_pool_name", dest_pool_name
);
181 f
->dump_string("dest_pool_namespace",
182 migration_status
.dest_pool_namespace
);
183 f
->dump_string("dest_image_name", migration_status
.dest_image_name
);
184 f
->dump_string("dest_image_id", migration_status
.dest_image_id
);
185 f
->dump_string("state", migration_state
);
186 f
->dump_string("state_description", migration_status
.state_description
);
187 f
->close_section(); // migration
189 if (cache_state
.present
) {
190 f
->open_object_section("image_cache_state");
191 f
->dump_bool("clean", cache_state
.clean
);
192 f
->dump_int("size", cache_state
.size
);
193 f
->dump_string("host", cache_state
.host
);
194 f
->dump_string("path", cache_state
.path
);
195 f
->close_section(); // image_cache_state
198 if (watchers
.size()) {
199 std::cout
<< "Watchers:" << std::endl
;
200 for (auto &watcher
: watchers
) {
201 std::cout
<< "\twatcher=" << watcher
.addr
<< " client." << watcher
.id
202 << " cookie=" << watcher
.cookie
<< std::endl
;
205 std::cout
<< "Watchers: none" << std::endl
;
207 if (!migration_state
.empty()) {
208 if (!migration_status
.source_pool_namespace
.empty()) {
209 source_pool_name
+= ("/" + migration_status
.source_pool_namespace
);
211 if (!migration_status
.dest_pool_namespace
.empty()) {
212 dest_pool_name
+= ("/" + migration_status
.dest_pool_namespace
);
215 std::cout
<< "Migration:" << std::endl
;
216 std::cout
<< "\tsource: ";
217 if (!source_spec
.empty()) {
218 std::cout
<< source_spec
;
220 std::cout
<< source_pool_name
<< "/"
221 << migration_status
.source_image_name
;
222 if (!migration_status
.source_image_id
.empty()) {
223 std::cout
<< " (" << migration_status
.source_image_id
<< ")";
226 std::cout
<< std::endl
;
227 std::cout
<< "\tdestination: " << dest_pool_name
<< "/"
228 << migration_status
.dest_image_name
<< " ("
229 << migration_status
.dest_image_id
<< ")" << std::endl
;
230 std::cout
<< "\tstate: " << migration_state
;
231 if (!migration_status
.state_description
.empty()) {
232 std::cout
<< " (" << migration_status
.state_description
<< ")";
234 std::cout
<< std::endl
;
237 if (cache_state
.present
) {
238 std::cout
<< "Image cache state:" << std::endl
;
239 std::cout
<< "\tclean: " << (cache_state
.clean
? "true" : "false")
241 << "\tsize: " << byte_u_t(cache_state
.size
) << std::endl
242 << "\thost: " << cache_state
.host
<< std::endl
243 << "\tpath: " << cache_state
.path
<< std::endl
;
248 f
->close_section(); // status
255 void get_arguments(po::options_description
*positional
,
256 po::options_description
*options
) {
257 at::add_image_spec_options(positional
, options
, at::ARGUMENT_MODIFIER_NONE
);
258 at::add_format_options(options
);
261 int execute(const po::variables_map
&vm
,
262 const std::vector
<std::string
> &ceph_global_init_args
) {
263 size_t arg_index
= 0;
264 std::string pool_name
;
265 std::string namespace_name
;
266 std::string image_name
;
267 std::string snap_name
;
268 int r
= utils::get_pool_image_snapshot_names(
269 vm
, at::ARGUMENT_MODIFIER_NONE
, &arg_index
, &pool_name
, &namespace_name
,
270 &image_name
, &snap_name
, true, utils::SNAPSHOT_PRESENCE_NONE
,
271 utils::SPEC_VALIDATION_NONE
);
276 at::Format::Formatter formatter
;
277 r
= utils::get_formatter(vm
, &formatter
);
282 librados::Rados rados
;
283 librados::IoCtx io_ctx
;
285 r
= utils::init_and_open_image(pool_name
, namespace_name
, image_name
, "", "",
286 true, &rados
, &io_ctx
, &image
);
291 r
= do_show_status(io_ctx
, image_name
, image
, formatter
.get());
293 std::cerr
<< "rbd: show status failed: " << cpp_strerror(r
) << std::endl
;
299 Shell::Action
action(
300 {"status"}, {}, "Show the status of this image.", "", &get_arguments
,
303 } // namespace status
304 } // namespace action