]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd: use TextTable to implement ls -l
authorDan Mick <dan.mick@inktank.com>
Thu, 4 Oct 2012 21:40:03 +0000 (14:40 -0700)
committerDan Mick <dan.mick@inktank.com>
Thu, 4 Oct 2012 22:20:29 +0000 (15:20 -0700)
Signed-off-by: Dan Mick <dan.mick@inktank.com>
Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
doc/man/8/rbd.rst
man/rbd.8
qa/workunits/rbd/copy.sh
src/Makefile.am
src/rbd.cc
src/test/cli/rbd/bad-map.t
src/test/cli/rbd/help.t
src/test/cli/rbd/invalid-snap-usage.t

index 92d77e61f7e86fca4e6970b346660a5968d1a0ce..b37c7e33d52ed352ff1c6d796856968c22b22cec 100644 (file)
@@ -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.
index 7a316214260e4ca4302c42b4b731f12a451dc3c1..d88a003dd5315d3963a00adc2a9f944146650999 100644 (file)
--- 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.
index 8ea4525b4a4273db62fe7d6262bcbcb4bd70746e..7878e78a6437c4aa4436ccf2d0bfea434da50011 100755 (executable)
@@ -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
 }
index ab9bdf57c377333053683dcf88951990b64ac677..2cba186904c6c2269d219360b30939e3d57d2b00 100644 (file)
@@ -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
index 5f03e4f0280a20134a0381905e84ba3b60e44a80..cfd7f6b8a865c537a8a9b10d139ec24b37bbf569 100644 (file)
@@ -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 <sys/ioctl.h>
 
 #include "include/rbd_types.h"
+#include "common/TextTable.h"
 
 #if defined(__linux__)
 #include <linux/fs.h>
@@ -66,7 +68,8 @@ void usage()
   cout << 
 "usage: rbd [-n <auth user>] [OPTIONS] <cmd> ...\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 <image-name>                           show information about image size,\n"
 "                                              striping, etc.\n"
 "  create [--order <bits>] --size <MB> <name>  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<string> names;
   int r = rbd.list(io_ctx, names);
-  if (r < 0)
+  if (r < 0 || (names.size() == 0))
     return r;
 
-  for (std::vector<string>::const_iterator i = names.begin(); i != names.end(); i++)
-    cout << *i << std::endl;
+  if (!lflag) {
+    for (std::vector<string>::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<string>::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<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) {
+       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<librbd::snap_info_t> 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<librbd::snap_info_t>::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<librbd::snap_info_t>::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:
index 590441eea22a523c9cf17dda8bca4dec0c80872f..9bef6ca65f912b72dd56c0b03d184c85369d6c4f 100644 (file)
@@ -2,7 +2,8 @@
   error: image name was not specified
   usage: rbd [-n <auth user>] [OPTIONS] <cmd> ...
   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 <image-name>                           show information about image size,
                                                 striping, etc.
     create [--order <bits>] --size <MB> <name>  create an empty image
@@ -62,7 +63,8 @@
   error: device path was not specified
   usage: rbd [-n <auth user>] [OPTIONS] <cmd> ...
   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 <image-name>                           show information about image size,
                                                 striping, etc.
     create [--order <bits>] --size <MB> <name>  create an empty image
index ea02c1210c070e1e3118b94c29feae53c5e4a9b4..ce5365ab9167403063e11b9366f3f7ade428e2a3 100644 (file)
@@ -1,7 +1,8 @@
   $ rbd --help
   usage: rbd [-n <auth user>] [OPTIONS] <cmd> ...
   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 <image-name>                           show information about image size,
                                                 striping, etc.
     create [--order <bits>] --size <MB> <name>  create an empty image
index 2f4e8cf24a76dffd899c5a817051bb5850cb6cdb..f34998f03ba11b8981aca2c9b974810d1cefa4ed 100644 (file)
@@ -2,7 +2,8 @@
   error: snapname specified for a command that doesn't use it
   usage: rbd [-n <auth user>] [OPTIONS] <cmd> ...
   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 <image-name>                           show information about image size,
                                                 striping, etc.
     create [--order <bits>] --size <MB> <name>  create an empty image
@@ -62,7 +63,8 @@
   error: snapname specified for a command that doesn't use it
   usage: rbd [-n <auth user>] [OPTIONS] <cmd> ...
   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 <image-name>                           show information about image size,
                                                 striping, etc.
     create [--order <bits>] --size <MB> <name>  create an empty image
   error: snapname specified for a command that doesn't use it
   usage: rbd [-n <auth user>] [OPTIONS] <cmd> ...
   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 <image-name>                           show information about image size,
                                                 striping, etc.
     create [--order <bits>] --size <MB> <name>  create an empty image
   error: snapname specified for a command that doesn't use it
   usage: rbd [-n <auth user>] [OPTIONS] <cmd> ...
   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 <image-name>                           show information about image size,
                                                 striping, etc.
     create [--order <bits>] --size <MB> <name>  create an empty image
   error: snapname specified for a command that doesn't use it
   usage: rbd [-n <auth user>] [OPTIONS] <cmd> ...
   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 <image-name>                           show information about image size,
                                                 striping, etc.
     create [--order <bits>] --size <MB> <name>  create an empty image
   error: snapname specified for a command that doesn't use it
   usage: rbd [-n <auth user>] [OPTIONS] <cmd> ...
   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 <image-name>                           show information about image size,
                                                 striping, etc.
     create [--order <bits>] --size <MB> <name>  create an empty image
   error: snapname specified for a command that doesn't use it
   usage: rbd [-n <auth user>] [OPTIONS] <cmd> ...
   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 <image-name>                           show information about image size,
                                                 striping, etc.
     create [--order <bits>] --size <MB> <name>  create an empty image
   error: snapname specified for a command that doesn't use it
   usage: rbd [-n <auth user>] [OPTIONS] <cmd> ...
   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 <image-name>                           show information about image size,
                                                 striping, etc.
     create [--order <bits>] --size <MB> <name>  create an empty image
   error: snapname specified for a command that doesn't use it
   usage: rbd [-n <auth user>] [OPTIONS] <cmd> ...
   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 <image-name>                           show information about image size,
                                                 striping, etc.
     create [--order <bits>] --size <MB> <name>  create an empty image
   error: snapname specified for a command that doesn't use it
   usage: rbd [-n <auth user>] [OPTIONS] <cmd> ...
   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 <image-name>                           show information about image size,
                                                 striping, etc.
     create [--order <bits>] --size <MB> <name>  create an empty image
   error: snapname specified for a command that doesn't use it
   usage: rbd [-n <auth user>] [OPTIONS] <cmd> ...
   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 <image-name>                           show information about image size,
                                                 striping, etc.
     create [--order <bits>] --size <MB> <name>  create an empty image
   error: snapname specified for a command that doesn't use it
   usage: rbd [-n <auth user>] [OPTIONS] <cmd> ...
   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 <image-name>                           show information about image size,
                                                 striping, etc.
     create [--order <bits>] --size <MB> <name>  create an empty image