From 61b2e4d6acea36d1090567d77d10f69acd4ed603 Mon Sep 17 00:00:00 2001 From: Dan Mick Date: Thu, 4 Oct 2012 14:40:03 -0700 Subject: [PATCH] rbd: use TextTable to implement ls -l Signed-off-by: Dan Mick Reviewed-by: Josh Durgin --- doc/man/8/rbd.rst | 6 +- man/rbd.8 | 8 +- qa/workunits/rbd/copy.sh | 7 ++ src/Makefile.am | 2 +- src/rbd.cc | 106 ++++++++++++++++++++++---- src/test/cli/rbd/bad-map.t | 6 +- src/test/cli/rbd/help.t | 3 +- src/test/cli/rbd/invalid-snap-usage.t | 36 ++++++--- 8 files changed, 138 insertions(+), 36 deletions(-) diff --git a/doc/man/8/rbd.rst b/doc/man/8/rbd.rst index 92d77e61f7e86..b37c7e33d52ed 100644 --- a/doc/man/8/rbd.rst +++ b/doc/man/8/rbd.rst @@ -97,8 +97,10 @@ Commands .. TODO rst "option" directive seems to require --foo style options, parsing breaks on subcommands.. the args show up as bold too -:command:`ls` [*pool-name*] - Will list all rbd images listed in the rbd_directory object. +:command:`ls` [-l | --long] [pool-name] + Will list all rbd images listed in the rbd_directory object. With + -l, also show snapshots, and use longer-format output including + size, parent (if clone), format, etc. :command:`info` [*image-name*] Will dump information (such as size and order) about a specific rbd image. diff --git a/man/rbd.8 b/man/rbd.8 index 7a316214260e4..d88a003dd5315 100644 --- a/man/rbd.8 +++ b/man/rbd.8 @@ -1,4 +1,4 @@ -.TH "RBD" "8" "September 27, 2012" "dev" "Ceph" +.TH "RBD" "8" "October 03, 2012" "dev" "Ceph" .SH NAME rbd \- manage rados block device (RBD) images . @@ -124,8 +124,10 @@ a clustered filesystem. .SH COMMANDS .INDENT 0.0 .TP -.B \fBls\fP [\fIpool\-name\fP] -Will list all rbd images listed in the rbd_directory object. +.B \fBls\fP [\-l | \-\-long] [pool\-name] +Will list all rbd images listed in the rbd_directory object. With +\-l, also show snapshots, and use longer\-format output including +size, parent (if clone), format, etc. .TP .B \fBinfo\fP [\fIimage\-name\fP] Will dump information (such as size and order) about a specific rbd image. diff --git a/qa/workunits/rbd/copy.sh b/qa/workunits/rbd/copy.sh index 8ea4525b4a427..7878e78a6437c 100755 --- a/qa/workunits/rbd/copy.sh +++ b/qa/workunits/rbd/copy.sh @@ -88,6 +88,9 @@ test_ls() { rbd ls | grep test1 rbd ls | grep test2 rbd ls | wc -l | grep 2 + # look for fields in output of ls -l without worrying about space + rbd ls -l | grep 'test1.*image.*1024 KB.*1' + rbd ls -l | grep 'test2.*image.*1024 KB.*1' rbd rm test1 rbd rm test2 @@ -97,6 +100,8 @@ test_ls() { rbd ls | grep test1 rbd ls | grep test2 rbd ls | wc -l | grep 2 + rbd ls -l | grep 'test1.*image.*1024 KB.*2' + rbd ls -l | grep 'test2.*image.*1024 KB.*2' rbd rm test1 rbd rm test2 @@ -106,6 +111,8 @@ test_ls() { rbd ls | grep test1 rbd ls | grep test2 rbd ls | wc -l | grep 2 + rbd ls -l | grep 'test1.*image.*1024 KB.*2' + rbd ls -l | grep 'test2.*image.*1024 KB.*1' remove_images } diff --git a/src/Makefile.am b/src/Makefile.am index ab9bdf57c3773..2cba186904c6c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -411,7 +411,7 @@ radosacl_SOURCES = radosacl.cc radosacl_LDADD = librados.la $(PTHREAD_LIBS) -lm $(CRYPTO_LIBS) $(EXTRALIBS) bin_DEBUGPROGRAMS += scratchtool scratchtoolpp radosacl -rbd_SOURCES = rbd.cc common/fiemap.cc common/secret.c +rbd_SOURCES = rbd.cc common/fiemap.cc common/secret.c common/TextTable.cc rbd_CXXFLAGS = ${AM_CXXFLAGS} rbd_LDADD = libglobal.la librbd.la librados.la $(PTHREAD_LIBS) -lm -lkeyutils $(CRYPTO_LIBS) $(EXTRALIBS) if LINUX diff --git a/src/rbd.cc b/src/rbd.cc index 5f03e4f0280a2..cfd7f6b8a865c 100644 --- a/src/rbd.cc +++ b/src/rbd.cc @@ -22,6 +22,7 @@ #include "global/global_init.h" #include "common/safe_io.h" #include "common/secret.h" +#include "include/stringify.h" #include "include/rados/librados.hpp" #include "include/rbd/librbd.hpp" #include "include/byteorder.h" @@ -44,6 +45,7 @@ #include #include "include/rbd_types.h" +#include "common/TextTable.h" #if defined(__linux__) #include @@ -66,7 +68,8 @@ void usage() cout << "usage: rbd [-n ] [OPTIONS] ...\n" "where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of:\n" -" (ls | list) [pool-name] list rbd images\n" +" (ls | list) [-l | --long ] [pool-name] list rbd images\n" +" (-l includes snapshots/clones)\n" " info show information about image size,\n" " striping, etc.\n" " create [--order ] --size create an empty image\n" @@ -138,7 +141,7 @@ struct MyProgressContext : public librbd::ProgressContext { MyProgressContext(const char *o) : operation(o), last_pc(0) { } - + int update_progress(uint64_t offset, uint64_t total) { int pc = total ? (offset * 100ull / total) : 0; if (pc != last_pc) { @@ -158,15 +161,78 @@ struct MyProgressContext : public librbd::ProgressContext { } }; -static int do_list(librbd::RBD &rbd, librados::IoCtx& io_ctx) +static int do_list(librbd::RBD &rbd, librados::IoCtx& io_ctx, bool lflag) { std::vector names; int r = rbd.list(io_ctx, names); - if (r < 0) + if (r < 0 || (names.size() == 0)) return r; - for (std::vector::const_iterator i = names.begin(); i != names.end(); i++) - cout << *i << std::endl; + if (!lflag) { + for (std::vector::const_iterator i = names.begin(); + i != names.end(); ++i) { + cout << *i << std::endl; + } + return 0; + } + + TextTable tbl; + tbl.define_column("NAME", TextTable::LEFT, TextTable::LEFT); + tbl.define_column("TYPE", TextTable::LEFT, TextTable::LEFT); + tbl.define_column("SIZE", TextTable::RIGHT, TextTable::RIGHT); + tbl.define_column("PARENT", TextTable::LEFT, TextTable::LEFT); + tbl.define_column("FORMAT", TextTable::RIGHT, TextTable::RIGHT); + + string pool, image, snap, parent; + + for (std::vector::const_iterator i = names.begin(); + i != names.end(); ++i) { + librbd::image_info_t info; + librbd::Image im; + + rbd.open(io_ctx, im, i->c_str()); + + // handle second-nth trips through loop + parent.clear(); + r = im.parent_info(&pool, &image, &snap); + if (r < 0 && r != -ENOENT) + return r; + + if (r != -ENOENT) + parent = pool + "/" + image + "@" + snap; + + if (im.stat(info, sizeof(info)) < 0) + return -EINVAL; + + uint8_t old_format; + im.old_format(&old_format); + + tbl << *i + << ((parent.length()) ? "clone" : "image") + << stringify(prettybyte_t(info.size)) + << parent + << ((old_format) ? '1' : '2') + << TextTable::endrow; + + vector snaplist; + if (im.snap_list(snaplist) >= 0 && !snaplist.empty()) { + for (std::vector::iterator s = snaplist.begin(); + s != snaplist.end(); ++s) { + parent.clear(); + im.snap_set(s->name.c_str()); + if (im.parent_info(&pool, &image, &snap) >= 0) { + parent = pool + "/" + image + "@" + snap; + } + tbl << *i + "@" + s->name + << "snap" + << stringify(prettybyte_t(s->size)) + << parent + << ((old_format) ? '1' : '2') + << TextTable::endrow; + } + } + } + cout << tbl; return 0; } @@ -175,7 +241,7 @@ static int do_create(librbd::RBD &rbd, librados::IoCtx& io_ctx, int format, uint64_t features) { int r; - if (features == 0) + if (features == 0) features = RBD_FEATURES_ALL; if (format == 1) @@ -188,7 +254,7 @@ static int do_create(librbd::RBD &rbd, librados::IoCtx& io_ctx, } static int do_clone(librbd::RBD &rbd, librados::IoCtx &p_ioctx, - const char *p_name, const char *p_snapname, + const char *p_name, const char *p_snapname, librados::IoCtx &c_ioctx, const char *c_name, uint64_t features, int *c_order) { @@ -274,7 +340,7 @@ static int do_show_info(const char *imgname, librbd::Image& image, << std::endl; } - // parent info, if present + // parent info, if present if ((image.parent_info(&parent_pool, &parent_name, &parent_snapname) == 0) && parent_name.length() > 0) { @@ -313,13 +379,20 @@ static int do_list_snaps(librbd::Image& image) { std::vector snaps; int r = image.snap_list(snaps); - if (r < 0) + if (r < 0 || snaps.empty()) return r; - cout << "ID\tNAME\t\tSIZE" << std::endl; - for (std::vector::iterator i = snaps.begin(); i != snaps.end(); ++i) { - cout << i->id << '\t' << i->name << '\t' << i->size << std::endl; + 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); + + for (std::vector::iterator s = snaps.begin(); + s != snaps.end(); ++s) { + t << s->id << s->name << stringify(prettybyte_t(s->size)) + << TextTable::endrow; } + cout << t; return 0; } @@ -664,7 +737,7 @@ static int do_import(librbd::RBD &rbd, librados::IoCtx& io_ctx, extent++; if (extent == fiemap->fm_mapped_extents) break; - + } while (end_ofs == (off_t)fiemap->fm_extents[extent].fe_logical); //cerr << "rbd import file_pos=" << file_pos << " extent_len=" << extent_len << std::endl; @@ -1168,6 +1241,7 @@ int main(int argc, const char **argv) *dest_poolname = NULL, *dest_snapname = NULL, *path = NULL, *devpath = NULL, *lock_cookie = NULL, *lock_client = NULL, *lock_tag = NULL; + bool lflag = false; std::string val; std::ostringstream err; @@ -1206,6 +1280,8 @@ int main(int argc, const char **argv) return EXIT_FAILURE; } size = sizell << 20; // bytes to MB + } else if (ceph_argparse_flag(args, i, "-l", "--long", (char*)NULL)) { + lflag = true; } else if (ceph_argparse_withint(args, i, &order, &err, "--order", (char*)NULL)) { if (!err.str().empty()) { cerr << err.str() << std::endl; @@ -1508,7 +1584,7 @@ int main(int argc, const char **argv) switch (opt_cmd) { case OPT_LIST: - r = do_list(rbd, io_ctx); + r = do_list(rbd, io_ctx, lflag); if (r < 0) { switch (r) { case -ENOENT: diff --git a/src/test/cli/rbd/bad-map.t b/src/test/cli/rbd/bad-map.t index 590441eea22a5..9bef6ca65f912 100644 --- a/src/test/cli/rbd/bad-map.t +++ b/src/test/cli/rbd/bad-map.t @@ -2,7 +2,8 @@ error: image name was not specified usage: rbd [-n ] [OPTIONS] ... where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of: - (ls | list) [pool-name] list rbd images + (ls | list) [-l | --long ] [pool-name] list rbd images + (-l includes snapshots/clones) info show information about image size, striping, etc. create [--order ] --size create an empty image @@ -62,7 +63,8 @@ error: device path was not specified usage: rbd [-n ] [OPTIONS] ... where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of: - (ls | list) [pool-name] list rbd images + (ls | list) [-l | --long ] [pool-name] list rbd images + (-l includes snapshots/clones) info show information about image size, striping, etc. create [--order ] --size create an empty image diff --git a/src/test/cli/rbd/help.t b/src/test/cli/rbd/help.t index ea02c1210c070..ce5365ab91674 100644 --- a/src/test/cli/rbd/help.t +++ b/src/test/cli/rbd/help.t @@ -1,7 +1,8 @@ $ rbd --help usage: rbd [-n ] [OPTIONS] ... where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of: - (ls | list) [pool-name] list rbd images + (ls | list) [-l | --long ] [pool-name] list rbd images + (-l includes snapshots/clones) info show information about image size, striping, etc. create [--order ] --size create an empty image diff --git a/src/test/cli/rbd/invalid-snap-usage.t b/src/test/cli/rbd/invalid-snap-usage.t index 2f4e8cf24a76d..f34998f03ba11 100644 --- a/src/test/cli/rbd/invalid-snap-usage.t +++ b/src/test/cli/rbd/invalid-snap-usage.t @@ -2,7 +2,8 @@ error: snapname specified for a command that doesn't use it usage: rbd [-n ] [OPTIONS] ... where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of: - (ls | list) [pool-name] list rbd images + (ls | list) [-l | --long ] [pool-name] list rbd images + (-l includes snapshots/clones) info show information about image size, striping, etc. create [--order ] --size create an empty image @@ -62,7 +63,8 @@ error: snapname specified for a command that doesn't use it usage: rbd [-n ] [OPTIONS] ... where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of: - (ls | list) [pool-name] list rbd images + (ls | list) [-l | --long ] [pool-name] list rbd images + (-l includes snapshots/clones) info show information about image size, striping, etc. create [--order ] --size create an empty image @@ -122,7 +124,8 @@ error: snapname specified for a command that doesn't use it usage: rbd [-n ] [OPTIONS] ... where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of: - (ls | list) [pool-name] list rbd images + (ls | list) [-l | --long ] [pool-name] list rbd images + (-l includes snapshots/clones) info show information about image size, striping, etc. create [--order ] --size create an empty image @@ -182,7 +185,8 @@ error: snapname specified for a command that doesn't use it usage: rbd [-n ] [OPTIONS] ... where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of: - (ls | list) [pool-name] list rbd images + (ls | list) [-l | --long ] [pool-name] list rbd images + (-l includes snapshots/clones) info show information about image size, striping, etc. create [--order ] --size create an empty image @@ -242,7 +246,8 @@ error: snapname specified for a command that doesn't use it usage: rbd [-n ] [OPTIONS] ... where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of: - (ls | list) [pool-name] list rbd images + (ls | list) [-l | --long ] [pool-name] list rbd images + (-l includes snapshots/clones) info show information about image size, striping, etc. create [--order ] --size create an empty image @@ -302,7 +307,8 @@ error: snapname specified for a command that doesn't use it usage: rbd [-n ] [OPTIONS] ... where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of: - (ls | list) [pool-name] list rbd images + (ls | list) [-l | --long ] [pool-name] list rbd images + (-l includes snapshots/clones) info show information about image size, striping, etc. create [--order ] --size create an empty image @@ -362,7 +368,8 @@ error: snapname specified for a command that doesn't use it usage: rbd [-n ] [OPTIONS] ... where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of: - (ls | list) [pool-name] list rbd images + (ls | list) [-l | --long ] [pool-name] list rbd images + (-l includes snapshots/clones) info show information about image size, striping, etc. create [--order ] --size create an empty image @@ -422,7 +429,8 @@ error: snapname specified for a command that doesn't use it usage: rbd [-n ] [OPTIONS] ... where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of: - (ls | list) [pool-name] list rbd images + (ls | list) [-l | --long ] [pool-name] list rbd images + (-l includes snapshots/clones) info show information about image size, striping, etc. create [--order ] --size create an empty image @@ -482,7 +490,8 @@ error: snapname specified for a command that doesn't use it usage: rbd [-n ] [OPTIONS] ... where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of: - (ls | list) [pool-name] list rbd images + (ls | list) [-l | --long ] [pool-name] list rbd images + (-l includes snapshots/clones) info show information about image size, striping, etc. create [--order ] --size create an empty image @@ -542,7 +551,8 @@ error: snapname specified for a command that doesn't use it usage: rbd [-n ] [OPTIONS] ... where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of: - (ls | list) [pool-name] list rbd images + (ls | list) [-l | --long ] [pool-name] list rbd images + (-l includes snapshots/clones) info show information about image size, striping, etc. create [--order ] --size create an empty image @@ -602,7 +612,8 @@ error: snapname specified for a command that doesn't use it usage: rbd [-n ] [OPTIONS] ... where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of: - (ls | list) [pool-name] list rbd images + (ls | list) [-l | --long ] [pool-name] list rbd images + (-l includes snapshots/clones) info show information about image size, striping, etc. create [--order ] --size create an empty image @@ -662,7 +673,8 @@ error: snapname specified for a command that doesn't use it usage: rbd [-n ] [OPTIONS] ... where 'pool' is a rados pool name (default is 'rbd') and 'cmd' is one of: - (ls | list) [pool-name] list rbd images + (ls | list) [-l | --long ] [pool-name] list rbd images + (-l includes snapshots/clones) info show information about image size, striping, etc. create [--order ] --size create an empty image -- 2.39.5