#include "auth/KeyRing.h"
#include "common/errno.h"
#include "common/ceph_argparse.h"
+#include "common/strtol.h"
#include "global/global_init.h"
#include "common/safe_io.h"
#include "common/secret.h"
#include "common/TextTable.h"
#include "include/util.h"
+#include "common/Formatter.h"
+
#if defined(__linux__)
#include <linux/fs.h>
#endif
"individual pieces of names with -p/--pool, --image, and/or --snap.\n"
"\n"
"Other input options:\n"
-" -p, --pool <pool> source pool name\n"
-" --image <image-name> image name\n"
-" --dest <image-name> destination [pool and] image name\n"
-" --snap <snap-name> snapshot name\n"
-" --dest-pool <name> destination pool name\n"
-" --path <path-name> path name for import/export\n"
-" --size <size in MB> size of image for create and resize\n"
-" --order <bits> the object size in bits; object size will be\n"
-" (1 << order) bytes. Default is 22 (4 MB).\n"
-" --format <format-number> format to use when creating an image\n"
-" format 1 is the original format (default)\n"
-" format 2 supports cloning\n"
-" --id <username> rados user (without 'client.' prefix) to authenticate as\n"
-" --keyfile <path> file containing secret key for use with cephx\n"
-" --shared <tag> take a shared (rather than exclusive) lock\n";
+" -p, --pool <pool> source pool name\n"
+" --image <image-name> image name\n"
+" --dest <image-name> destination [pool and] image name\n"
+" --snap <snap-name> snapshot name\n"
+" --dest-pool <name> destination pool name\n"
+" --path <path-name> path name for import/export\n"
+" --size <size in MB> size of image for create and resize\n"
+" --order <bits> the object size in bits; object size will be\n"
+" (1 << order) bytes. Default is 22 (4 MB).\n"
+" --image-format <format-number> format to use when creating an image\n"
+" format 1 is the original format (default)\n"
+" format 2 supports cloning\n"
+" --id <username> rados user (without 'client.' prefix) to authenticate as\n"
+" --keyfile <path> file containing secret key for use with cephx\n"
+" --shared <tag> take a shared (rather than exclusive) lock\n"
+" --format <output-format> output format (default: plain, json, xml)\n";
}
static string feature_str(uint64_t features)
}
};
-static int do_list(librbd::RBD &rbd, librados::IoCtx& io_ctx, bool lflag)
+static int get_outfmt(const char *output_format, Formatter **f)
+{
+ if (!strcmp(output_format, "json"))
+ *f = new JSONFormatter(false);
+ else if (!strcmp(output_format, "xml"))
+ *f = new XMLFormatter(false);
+ else if (strcmp(output_format, "plain")) {
+ cerr << "rbd unknown format '" << output_format << "'" << std::endl;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int do_list(librbd::RBD &rbd, librados::IoCtx& io_ctx, bool lflag, const char *output_format)
{
std::vector<string> names;
int r = rbd.list(io_ctx, names);
if (r < 0 || (names.size() == 0))
return r;
+ Formatter *f = 0;
+
+ r = get_outfmt(output_format, &f);
+ if (r < 0)
+ return r;
+
if (!lflag) {
+ if (f)
+ f->open_array_section("images");
for (std::vector<string>::const_iterator i = names.begin();
i != names.end(); ++i) {
- cout << *i << std::endl;
+ if (f)
+ f->dump_string("name", *i);
+ else
+ cout << *i << std::endl;
+ }
+ if (f) {
+ f->close_section();
+ f->flush(cout);
}
return 0;
}
TextTable tbl;
- tbl.define_column("NAME", TextTable::LEFT, TextTable::LEFT);
- tbl.define_column("SIZE", TextTable::RIGHT, TextTable::RIGHT);
- tbl.define_column("PARENT", TextTable::LEFT, TextTable::LEFT);
- tbl.define_column("FMT", TextTable::RIGHT, TextTable::RIGHT);
- tbl.define_column("PROT", TextTable::LEFT, TextTable::LEFT);
- tbl.define_column("LOCK", TextTable::LEFT, TextTable::LEFT);
+
+ if (f) {
+ f->open_object_section("images");
+ } else {
+ tbl.define_column("NAME", TextTable::LEFT, TextTable::LEFT);
+ tbl.define_column("SIZE", TextTable::RIGHT, TextTable::RIGHT);
+ tbl.define_column("PARENT", TextTable::LEFT, TextTable::LEFT);
+ tbl.define_column("FMT", TextTable::RIGHT, TextTable::RIGHT);
+ tbl.define_column("PROT", TextTable::LEFT, TextTable::LEFT);
+ tbl.define_column("LOCK", TextTable::LEFT, TextTable::LEFT);
+ }
string pool, image, snap, parent;
lockstr = (exclusive) ? "excl" : "shr";
}
- tbl << *i
- << stringify(si_t(info.size))
- << parent
- << ((old_format) ? '1' : '2')
- << "" // protect doesn't apply to images
- << lockstr
- << TextTable::endrow;
+ if (f) {
+ f->open_object_section(i->c_str());
+ f->dump_string("size", stringify(si_t(info.size)));
+ f->dump_string("parent", parent);
+ f->dump_string("fmt", (old_format) ? "1" : "2");
+ f->dump_string("prot", ""); // protect doesn't apply to images
+ f->dump_string("lock", lockstr);
+ f->close_section();
+ } else {
+ tbl << *i
+ << stringify(si_t(info.size))
+ << parent
+ << ((old_format) ? '1' : '2')
+ << "" // protect doesn't apply to images
+ << lockstr
+ << TextTable::endrow;
+ }
vector<librbd::snap_info_t> snaplist;
if (im.snap_list(snaplist) >= 0 && !snaplist.empty()) {
for (std::vector<librbd::snap_info_t>::iterator s = snaplist.begin();
- s != snaplist.end(); ++s) {
+ s != snaplist.end(); ++s) {
bool is_protected;
parent.clear();
im.snap_set(s->name.c_str());
- r = im.snap_is_protected(s->name.c_str(), &is_protected);
+ r = im.snap_is_protected(s->name.c_str(), &is_protected);
if (r < 0)
return r;
if (im.parent_info(&pool, &image, &snap) >= 0) {
parent = pool + "/" + image + "@" + snap;
}
- tbl << *i + "@" + s->name
- << stringify(si_t(s->size))
- << parent
- << ((old_format) ? '1' : '2')
- << (is_protected ? "yes" : "")
- << "" // locks don't apply to snaps
- << TextTable::endrow;
+ if (f) {
+ f->open_object_section((*i + "@" + s->name).c_str());
+ f->dump_string("size", stringify(si_t(s->size)));
+ f->dump_string("parent", parent);
+ f->dump_string("fmt", (old_format) ? "1" : "2");
+ f->dump_string("prot", is_protected ? "yes" : "");
+ f->dump_string("lock", ""); // locks don't apply to snaps
+ f->close_section();
+ } else {
+ tbl << *i + "@" + s->name
+ << stringify(si_t(s->size))
+ << parent
+ << ((old_format) ? '1' : '2')
+ << (is_protected ? "yes" : "")
+ << "" // locks don't apply to snaps
+ << TextTable::endrow;
+ }
}
}
}
- cout << tbl;
+ if (f) {
+ f->close_section();
+ f->flush(cout);
+ } else {
+ cout << tbl;
+ }
+
return 0;
}
}
static int do_show_info(const char *imgname, librbd::Image& image,
- const char *snapname)
+ const char *snapname, const char *output_format)
{
librbd::image_info_t info;
string parent_pool, parent_name, parent_snapname;
uint8_t old_format;
uint64_t overlap, features;
bool snap_protected;
+ Formatter *f = 0;
+ int r;
+
+ r = get_outfmt(output_format, &f);
+ if (r < 0)
+ return r;
- int r = image.stat(info, sizeof(info));
+ r = image.stat(info, sizeof(info));
if (r < 0)
return r;
return r;
}
- cout << "rbd image '" << imgname << "':\n"
- << "\tsize " << prettybyte_t(info.size) << " in "
- << info.num_objs << " objects"
- << std::endl
- << "\torder " << info.order
- << " (" << prettybyte_t(info.obj_size) << " objects)"
- << std::endl
- << "\tblock_name_prefix: " << info.block_name_prefix
- << std::endl
- << "\tformat: " << (old_format ? "1" : "2")
- << std::endl;
+ if (f) {
+ f->open_object_section("image");
+ f->dump_string("name", imgname);
+ f->dump_string("size", stringify(prettybyte_t(info.size)));
+ f->dump_int("objects", info.num_objs);
+ f->dump_int("order", info.order);
+ f->dump_string("obj_size", stringify(prettybyte_t(info.obj_size)));
+ f->dump_string("block_name_prefix", info.block_name_prefix);
+ f->dump_string("format", (old_format ? "1" : "2"));
+ } else {
+ cout << "rbd image '" << imgname << "':\n"
+ << "\tsize " << prettybyte_t(info.size) << " in "
+ << info.num_objs << " objects"
+ << std::endl
+ << "\torder " << info.order
+ << " (" << prettybyte_t(info.obj_size) << " objects)"
+ << std::endl
+ << "\tblock_name_prefix: " << info.block_name_prefix
+ << std::endl
+ << "\tformat: " << (old_format ? "1" : "2")
+ << std::endl;
+ }
+
if (!old_format) {
- cout << "\tfeatures: " << feature_str(features) << std::endl;
+ if (f)
+ f->dump_string("features", feature_str(features));
+ else
+ cout << "\tfeatures: " << feature_str(features) << std::endl;
}
// snapshot info, if present
if (snapname) {
- cout << "\tprotected: " << (snap_protected ? "True" : "False")
- << std::endl;
+ if (f) {
+ f->dump_string("protected", stringify(snap_protected));
+ } else {
+ cout << "\tprotected: " << (snap_protected ? "True" : "False")
+ << std::endl;
+ }
}
// parent info, if present
if ((image.parent_info(&parent_pool, &parent_name, &parent_snapname) == 0) &&
parent_name.length() > 0) {
-
- cout << "\tparent: " << parent_pool << "/" << parent_name
- << "@" << parent_snapname << std::endl;
- cout << "\toverlap: " << prettybyte_t(overlap) << std::endl;
+ if (f) {
+ f->dump_string("parent", parent_pool + "/" + parent_name);
+ f->dump_string("overlap", stringify(prettybyte_t(overlap)));
+ } else {
+ cout << "\tparent: " << parent_pool << "/" << parent_name
+ << "@" << parent_snapname << std::endl;
+ cout << "\toverlap: " << prettybyte_t(overlap) << std::endl;
+ }
}
// striping info, if feature is set
if (features & RBD_FEATURE_STRIPINGV2) {
- cout << "\tstripe unit: " << prettybyte_t(image.get_stripe_unit()) << std::endl
- << "\tstripe count: " << image.get_stripe_count() << std::endl;
+ if (f) {
+ f->dump_string("stripe_unit", stringify(prettybyte_t(image.get_stripe_unit())));
+ f->dump_string("stripe_count", stringify(image.get_stripe_count()));
+ } else {
+ cout << "\tstripe unit: " << prettybyte_t(image.get_stripe_unit()) << std::endl
+ << "\tstripe count: " << image.get_stripe_count() << std::endl;
+ }
+ }
+
+ if (f) {
+ f->close_section();
+ f->flush(cout);
}
+
return 0;
}
return 0;
}
-static int do_list_snaps(librbd::Image& image)
+static int do_list_snaps(librbd::Image& image, const char *output_format)
{
std::vector<librbd::snap_info_t> snaps;
- int r = image.snap_list(snaps);
+ Formatter *f = 0;
+ TextTable t;
+ int r;
+
+ r = get_outfmt(output_format, &f);
+ if (r < 0)
+ return r;
+
+ r = image.snap_list(snaps);
if (r < 0 || snaps.empty())
return r;
- TextTable t;
- t.define_column("SNAPID", TextTable::RIGHT, TextTable::RIGHT);
- t.define_column("NAME", TextTable::LEFT, TextTable::LEFT);
- t.define_column("SIZE", TextTable::RIGHT, TextTable::RIGHT);
+ if (f) {
+ f->open_object_section("snaps");
+ } else {
+ t.define_column("SNAPID", TextTable::RIGHT, TextTable::RIGHT);
+ t.define_column("NAME", TextTable::LEFT, TextTable::LEFT);
+ t.define_column("SIZE", TextTable::RIGHT, TextTable::RIGHT);
+ }
for (std::vector<librbd::snap_info_t>::iterator s = snaps.begin();
s != snaps.end(); ++s) {
- t << s->id << s->name << stringify(prettybyte_t(s->size))
- << TextTable::endrow;
+ if (f) {
+ f->open_object_section(stringify(s->id).c_str());
+ f->dump_string("name", s->name);
+ f->dump_string("size", stringify(prettybyte_t(s->size)));
+ f->close_section();
+ } else {
+ t << s->id << s->name << stringify(prettybyte_t(s->size))
+ << TextTable::endrow;
+ }
+ }
+
+ if (f) {
+ f->close_section();
+ f->flush(cout);
+ } else {
+ cout << t;
}
- cout << t;
+
return 0;
}
return 0;
}
-static int do_list_children(librbd::Image &image)
+static int do_list_children(librbd::Image &image, const char *output_format)
{
set<pair<string, string> > children;
- int r = image.list_children(&children);
+ Formatter *f = 0;
+ int r;
+
+ r = get_outfmt(output_format, &f);
if (r < 0)
return r;
+ r = image.list_children(&children);
+ if (r < 0)
+ return r;
+
+ if (f)
+ f->open_array_section("children");
+
for (set<pair<string, string> >::const_iterator child_it = children.begin();
child_it != children.end(); child_it++) {
- cout << child_it->first << "/" << child_it->second << std::endl;
+ if (f)
+ f->dump_string("child", child_it->first + "/" + child_it->second);
+ else
+ cout << child_it->first << "/" << child_it->second << std::endl;
}
+
+ if (f) {
+ f->close_section();
+ f->flush(cout);
+ }
+
return 0;
}
-static int do_lock_list(librbd::Image& image)
+static int do_lock_list(librbd::Image& image, const char *output_format)
{
list<librbd::locker_t> lockers;
bool exclusive;
string tag;
- int r = image.list_lockers(&lockers, &exclusive, &tag);
+ Formatter *f = 0;
+ TextTable tbl;
+ int r;
+
+ r = get_outfmt(output_format, &f);
+ if (r < 0)
+ return r;
+
+ r = image.list_lockers(&lockers, &exclusive, &tag);
if (r < 0)
return r;
if (lockers.size()) {
bool one = (lockers.size() == 1);
- cout << "There " << (one ? "is " : "are ") << lockers.size()
- << (exclusive ? " exclusive" : " shared")
- << " lock" << (one ? "" : "s") << " on this image.\n";
- if (!exclusive)
- cout << "Lock tag: " << tag << "\n";
- TextTable tbl;
- tbl.define_column("Locker", TextTable::LEFT, TextTable::LEFT);
- tbl.define_column("ID", TextTable::LEFT, TextTable::LEFT);
- tbl.define_column("Address", TextTable::LEFT, TextTable::LEFT);
+ if (!f) {
+ cout << "There " << (one ? "is " : "are ") << lockers.size()
+ << (exclusive ? " exclusive" : " shared")
+ << " lock" << (one ? "" : "s") << " on this image.\n";
+ if (!exclusive)
+ cout << "Lock tag: " << tag << "\n";
+ }
+
+ if (f) {
+ f->open_object_section("locks");
+ } else {
+ tbl.define_column("Locker", TextTable::LEFT, TextTable::LEFT);
+ tbl.define_column("ID", TextTable::LEFT, TextTable::LEFT);
+ tbl.define_column("Address", TextTable::LEFT, TextTable::LEFT);
+ }
for (list<librbd::locker_t>::const_iterator it = lockers.begin();
it != lockers.end(); ++it) {
- tbl << it->client << it->cookie << it->address << TextTable::endrow;
+ if (f) {
+ f->open_object_section(it->cookie.c_str());
+ f->dump_string("locker", it->client);
+ f->dump_string("address", it->address);
+ f->close_section();
+ } else {
+ tbl << it->client << it->cookie << it->address << TextTable::endrow;
+ }
+ }
+
+ if (f) {
+ f->close_section();
+ f->flush(cout);
+ } else {
+ cout << tbl;
}
- cout << tbl;
}
return 0;
}
closedir(dp);
}
-static int do_kernel_showmapped()
+static int do_kernel_showmapped(const char *output_format)
{
int r;
bool have_output = false;
+ Formatter *f = 0;
+ TextTable tbl;
+
+ r = get_outfmt(output_format, &f);
+ if (r < 0)
+ return r;
+
const char *devices_path = "/sys/bus/rbd/devices";
std::tr1::shared_ptr<DIR> device_dir(opendir(devices_path), do_closedir);
if (!device_dir.get()) {
return r;
}
- TextTable tbl;
- tbl.define_column("id", TextTable::LEFT, TextTable::LEFT);
- tbl.define_column("pool", TextTable::LEFT, TextTable::LEFT);
- tbl.define_column("image", TextTable::LEFT, TextTable::LEFT);
- tbl.define_column("snap", TextTable::LEFT, TextTable::LEFT);
- tbl.define_column("device", TextTable::LEFT, TextTable::LEFT);
+ if (f) {
+ f->open_object_section("devices");
+ } else {
+ tbl.define_column("id", TextTable::LEFT, TextTable::LEFT);
+ tbl.define_column("pool", TextTable::LEFT, TextTable::LEFT);
+ tbl.define_column("image", TextTable::LEFT, TextTable::LEFT);
+ tbl.define_column("snap", TextTable::LEFT, TextTable::LEFT);
+ tbl.define_column("device", TextTable::LEFT, TextTable::LEFT);
+ }
do {
if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
continue;
}
- tbl << dent->d_name << pool << name << snap << dev << TextTable::endrow;
+ if (f) {
+ f->open_object_section(dent->d_name);
+ f->dump_string("pool", pool);
+ f->dump_string("name", name);
+ f->dump_string("snap", snap);
+ f->dump_string("device", dev);
+ f->close_section();
+ } else {
+ tbl << dent->d_name << pool << name << snap << dev << TextTable::endrow;
+ }
have_output = true;
} while ((dent = readdir(device_dir.get())));
- if (have_output)
- cout << tbl;
+
+ if (f) {
+ f->close_section();
+ f->flush(cout);
+ } else {
+ if (have_output)
+ cout << tbl;
+ }
return 0;
}
const char *poolname = NULL;
uint64_t size = 0; // in bytes
int order = 0;
- bool format_specified = false;
+ bool format_specified = false, output_format_specified = false;
int format = 1;
uint64_t features = RBD_FEATURE_LAYERING;
const char *imgname = NULL, *snapname = NULL, *destname = NULL,
*dest_poolname = NULL, *dest_snapname = NULL, *path = NULL,
*devpath = NULL, *lock_cookie = NULL, *lock_client = NULL,
- *lock_tag = NULL;
+ *lock_tag = NULL, *output_format = "plain";
bool lflag = false;
long long stripe_unit = 0, stripe_count = 0;
long long bench_io_size = 4096, bench_io_threads = 16, bench_bytes = 1 << 30;
} else if (ceph_argparse_flag(args, i, "--new-format", (char*)NULL)) {
format = 2;
format_specified = true;
- } else if (ceph_argparse_withint(args, i, &format, &err, "--format",
+ } else if (ceph_argparse_withint(args, i, &format, &err, "--image-format",
(char*)NULL)) {
if (!err.str().empty()) {
cerr << "rbd: " << err.str() << std::endl;
imgname = strdup(val.c_str());
} else if (ceph_argparse_witharg(args, i, &val, "--shared", (char *)NULL)) {
lock_tag = strdup(val.c_str());
+ } else if (ceph_argparse_witharg(args, i, &val, "--format", (char *) NULL)) {
+ std::string err;
+ long long ret = strict_strtoll(val.c_str(), 10, &err);
+ if (err.empty()) {
+ format = ret;
+ format_specified = true;
+ cerr << "rbd: using --format for specifying the rbd image format is deprecated,"
+ << " use --image-format instead"
+ << std::endl;
+ } else {
+ output_format = strdup(val.c_str());
+ output_format_specified = true;
+ }
} else {
++i;
}
}
if (format_specified && opt_cmd != OPT_IMPORT && opt_cmd != OPT_CREATE) {
- cerr << "rbd: format can only be set when "
+ cerr << "rbd: image format can only be set when "
<< "creating or importing an image" << std::endl;
return EXIT_FAILURE;
}
+ if (output_format_specified && opt_cmd != OPT_SHOWMAPPED && opt_cmd != OPT_INFO &&
+ opt_cmd != OPT_LIST && opt_cmd != OPT_SNAP_LIST && opt_cmd != OPT_LOCK_LIST &&
+ opt_cmd != OPT_CHILDREN) {
+ cerr << "rbd: command doesn't use output formatting"
+ << std::endl;
+ return EXIT_FAILURE;
+ }
+
if (format_specified) {
if (format < 1 || format > 2) {
- cerr << "rbd: format must be 1 or 2" << std::endl;
+ cerr << "rbd: image format must be 1 or 2" << std::endl;
return EXIT_FAILURE;
}
}
switch (opt_cmd) {
case OPT_LIST:
- r = do_list(rbd, io_ctx, lflag);
+ r = do_list(rbd, io_ctx, lflag, output_format);
if (r < 0) {
switch (r) {
case -ENOENT:
break;
case OPT_INFO:
- r = do_show_info(imgname, image, snapname);
+ r = do_show_info(imgname, image, snapname, output_format);
if (r < 0) {
cerr << "rbd: info: " << cpp_strerror(-r) << std::endl;
return EXIT_FAILURE;
cerr << "rbd: snap list requires an image parameter" << std::endl;
return EXIT_FAILURE;
}
- r = do_list_snaps(image);
+ r = do_list_snaps(image, output_format);
if (r < 0) {
cerr << "rbd: failed to list snapshots: " << cpp_strerror(-r)
<< std::endl;
break;
case OPT_CHILDREN:
- r = do_list_children(image);
+ r = do_list_children(image, output_format);
if (r < 0) {
cerr << "rbd: listing children failed: " << cpp_strerror(-r) << std::endl;
return EXIT_FAILURE;
break;
case OPT_SHOWMAPPED:
- r = do_kernel_showmapped();
+ r = do_kernel_showmapped(output_format);
if (r < 0) {
cerr << "rbd: showmapped failed: " << cpp_strerror(-r) << std::endl;
return EXIT_FAILURE;
break;
case OPT_LOCK_LIST:
- r = do_lock_list(image);
+ r = do_lock_list(image, output_format);
if (r < 0) {
cerr << "rbd: listing locks failed: " << cpp_strerror(r) << std::endl;
return EXIT_FAILURE;