]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd-nbd: output format support for list-mapped command
authorMykola Golub <mgolub@suse.com>
Wed, 27 Dec 2017 18:50:40 +0000 (20:50 +0200)
committerMykola Golub <mgolub@suse.com>
Wed, 3 Jan 2018 12:44:10 +0000 (14:44 +0200)
Signed-off-by: Mykola Golub <mgolub@suse.com>
qa/workunits/rbd/rbd-nbd.sh
src/test/cli/rbd/help.t
src/tools/rbd/action/Nbd.cc
src/tools/rbd_nbd/rbd-nbd.cc

index 15b3d1706fa7f9ad4ca4bccf1a02564412af1bdb..900a6075644bb483705e662052b8bad1c30f5fce 100755 (executable)
@@ -75,6 +75,14 @@ function expect_false()
   if "$@"; then return 1; else return 0; fi
 }
 
+function get_pid()
+{
+    PID=$(rbd-nbd --format xml list-mapped | $XMLSTARLET sel -t -v \
+      "//devices/device[pool='${POOL}'][image='${IMAGE}'][device='${DEV}']/id")
+    test -n "${PID}"
+    ps -p ${PID} -o cmd | grep rbd-nbd
+}
+
 #
 # main
 #
@@ -91,12 +99,14 @@ fi
 expect_false _sudo rbd-nbd map INVALIDIMAGE
 expect_false _sudo rbd-nbd --device INVALIDDEV map ${IMAGE}
 
+# list format test
+expect_false rbd-nbd --format INVALID list-mapped
+rbd-nbd --format json --pretty-format list-mapped
+rbd-nbd --format xml list-mapped
+
 # map test using the first unused device
 DEV=`_sudo rbd-nbd map ${POOL}/${IMAGE}`
-PID=$(rbd-nbd list-mapped | awk -v pool=${POOL} -v img=${IMAGE} -v dev=${DEV} \
-    '$2 == pool && $3 == img && $5 == dev {print $1}')
-test -n "${PID}"
-ps -p ${PID} -o cmd | grep rbd-nbd
+get_pid
 # map test specifying the device
 expect_false _sudo rbd-nbd --device ${DEV} map ${POOL}/${IMAGE}
 dev1=${DEV}
@@ -107,10 +117,7 @@ DEV=
 DEV=`_sudo rbd-nbd --device ${dev1} map ${POOL}/${IMAGE}`
 [ "${DEV}" = "${dev1}" ]
 rbd-nbd list-mapped | grep "${IMAGE}"
-PID=$(rbd-nbd list-mapped | awk -v pool=${POOL} -v img=${IMAGE} -v dev=${DEV} \
-    '$2 == pool && $3 == img && $5 == dev {print $1}')
-test -n "${PID}"
-ps -p ${PID} -o cmd | grep rbd-nbd
+get_pid
 
 # read test
 [ "`dd if=${DATA} bs=1M | md5sum`" = "`_sudo dd if=${DEV} bs=1M | md5sum`" ]
@@ -162,10 +169,7 @@ _sudo rbd-nbd unmap ${DEV}
 
 # exclusive option test
 DEV=`_sudo rbd-nbd map --exclusive ${POOL}/${IMAGE}`
-PID=$(rbd-nbd list-mapped | awk -v pool=${POOL} -v img=${IMAGE} -v dev=${DEV} \
-    '$2 == pool && $3 == img && $5 == dev {print $1}')
-test -n "${PID}"
-ps -p ${PID} -o cmd | grep rbd-nbd
+get_pid
 
 _sudo dd if=${DATA} of=${DEV} bs=1M oflag=direct
 expect_false timeout 10 \
@@ -176,10 +180,7 @@ rbd bench ${IMAGE} --io-type write --io-size=1024 --io-total=1024
 
 # unmap by image name test
 DEV=`_sudo rbd-nbd map ${POOL}/${IMAGE}`
-PID=$(rbd-nbd list-mapped | awk -v pool=${POOL} -v img=${IMAGE} -v dev=${DEV} \
-    '$2 == pool && $3 == img && $5 == dev {print $1}')
-test -n "${PID}"
-ps -p ${PID} -o cmd | grep rbd-nbd
+get_pid
 _sudo rbd-nbd unmap "${IMAGE}"
 rbd-nbd list-mapped | expect_false grep "${DEV} $"
 DEV=
@@ -188,10 +189,7 @@ ps -p ${PID} -o cmd | expect_false grep rbd-nbd
 # map/unmap snap test
 rbd snap create ${POOL}/${IMAGE}@snap
 DEV=`_sudo rbd-nbd map ${POOL}/${IMAGE}@snap`
-PID=$(rbd-nbd list-mapped |
-      awk -v pool=${POOL} -v img=${IMAGE} -v snap=snap -v dev=${DEV} \
-          '$2 == pool && $3 == img && $4 == snap && $5 == dev {print $1}')
-test -n "${PID}"
+get_pid
 _sudo rbd-nbd unmap "${IMAGE}@snap"
 rbd-nbd list-mapped | expect_false grep "${DEV} $"
 DEV=
@@ -199,10 +197,7 @@ ps -p ${PID} -o cmd | expect_false grep rbd-nbd
 
 # auto unmap test
 DEV=`_sudo rbd-nbd map ${POOL}/${IMAGE}`
-PID=$(rbd-nbd list-mapped | awk -v pool=${POOL} -v img=${IMAGE} -v dev=${DEV} \
-    '$2 == pool && $3 == img && $5 == dev {print $1}')
-test -n "${PID}"
-ps -p ${PID} -o cmd | grep rbd-nbd
+get_pid
 _sudo kill ${PID}
 for i in `seq 10`; do
   rbd-nbd list-mapped | expect_false grep "^${PID} *${POOL} *${IMAGE}" && break
index f5440dba7d6633e74821a81487f610e725d428e5..b41d56c0e39ffd9173dc77bea65da454d04640ec 100644 (file)
@@ -1140,10 +1140,14 @@ Skip test on FreeBSD as it generates different output there.
     --verbose            be verbose
   
   rbd help nbd list
-  usage: rbd nbd list 
+  usage: rbd nbd list [--format <format>] [--pretty-format] 
   
   List the nbd devices already used.
   
+  Optional arguments
+    --format arg         output format (plain, json, or xml) [default: plain]
+    --pretty-format      pretty formatting (json and xml)
+  
   rbd help nbd map
   usage: rbd nbd map [--pool <pool>] [--image <image>] [--snap <snap>] 
                      [--read-only] [--exclusive] [--device <device>] 
index 43f547704e5fea40db58a17040f52ea3fb450f90..b599f525449ae18c5b777c9cc91c4813e5ba75a2 100644 (file)
@@ -105,8 +105,9 @@ int get_image_or_snap_spec(const po::variables_map &vm, std::string *spec) {
 }
 
 void get_show_arguments(po::options_description *positional,
-                        po::options_description *options)
-{ }
+                        po::options_description *options) {
+  at::add_format_options(options);
+}
 
 int execute_show(const po::variables_map &vm)
 {
@@ -114,6 +115,14 @@ int execute_show(const po::variables_map &vm)
 
   args.push_back("list-mapped");
 
+  if (vm.count("format")) {
+    args.push_back("--format");
+    args.push_back(vm["format"].as<at::Format>().value.c_str());
+  }
+  if (vm["pretty-format"].as<bool>()) {
+    args.push_back("--pretty-format");
+  }
+
   return call_nbd_cmd(vm, args);
 }
 
index e5006592e052a114452ff15de8e4298bc10867d8..647cbb1de722a6e16a868cbaf1f6c49a95b17b2e 100644 (file)
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 
-#include <iostream>
 #include <fstream>
+#include <iostream>
+#include <memory>
 #include <boost/regex.hpp>
 #include <boost/algorithm/string/predicate.hpp>
 
-#include "mon/MonClient.h"
+#include "common/Formatter.h"
+#include "common/Preforker.h"
+#include "common/TextTable.h"
+#include "common/ceph_argparse.h"
 #include "common/config.h"
 #include "common/dout.h"
-
 #include "common/errno.h"
 #include "common/module.h"
 #include "common/safe_io.h"
-#include "common/TextTable.h"
-#include "common/ceph_argparse.h"
-#include "common/Preforker.h"
 #include "common/version.h"
+
 #include "global/global_init.h"
 #include "global/signal_handler.h"
 
@@ -56,6 +57,8 @@
 #include "include/stringify.h"
 #include "include/xlist.h"
 
+#include "mon/MonClient.h"
+
 #define dout_context g_ceph_context
 #define dout_subsys ceph_subsys_rbd
 #undef dout_prefix
@@ -74,20 +77,27 @@ struct Config {
   std::string imgname;
   std::string snapname;
   std::string devpath;
+
+  std::string format;
+  bool pretty_format = false;
 };
 
 static void usage()
 {
   std::cout << "Usage: rbd-nbd [options] map <image-or-snap-spec>  Map an image to nbd device\n"
             << "               unmap <device|image-or-snap-spec>   Unmap nbd device\n"
-            << "               list-mapped                         List mapped nbd devices\n"
-            << "Options:\n"
+            << "               [options] list-mapped               List mapped nbd devices\n"
+            << "Map options:\n"
             << "  --device <device path>  Specify nbd device path\n"
             << "  --read-only             Map read-only\n"
             << "  --nbds_max <limit>      Override for module param nbds_max\n"
             << "  --max_part <limit>      Override for module param max_part\n"
             << "  --exclusive             Forbid writes by other clients\n"
             << "  --timeout <seconds>     Set nbd request timeout\n"
+            << "\n"
+            << "List options:\n"
+            << "  --format plain|json|xml Output format (default: plain)\n"
+            << "  --pretty-format         Pretty formatting (json and xml)\n"
             << std::endl;
   generic_server_usage();
 }
@@ -932,31 +942,59 @@ static int parse_imgpath(const std::string &imgpath, Config *cfg,
   return 0;
 }
 
-static int do_list_mapped_devices()
+static int do_list_mapped_devices(const std::string &format, bool pretty_format)
 {
   bool should_print = false;
+  std::unique_ptr<ceph::Formatter> f;
   TextTable tbl;
 
-  tbl.define_column("pid", 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 (format == "json") {
+    f.reset(new JSONFormatter(pretty_format));
+  } else if (format == "xml") {
+    f.reset(new XMLFormatter(pretty_format));
+  } else if (!format.empty() && format != "plain") {
+    std::cerr << "rbd-nbd: invalid output format: " << format << std::endl;
+    return -EINVAL;
+  }
+
+  if (f) {
+    f->open_array_section("devices");
+  } else {
+    tbl.define_column("pid", 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);
+  }
 
   int pid;
   Config cfg;
   NBDListIterator it;
   while (it.get(&pid, &cfg)) {
-    should_print = true;
-    if (cfg.snapname.empty()) {
-      cfg.snapname = "-";
+    if (f) {
+      f->open_object_section("device");
+      f->dump_int("id", pid);
+      f->dump_string("pool", cfg.poolname);
+      f->dump_string("image", cfg.imgname);
+      f->dump_string("snap", cfg.snapname);
+      f->dump_string("device", cfg.devpath);
+      f->close_section();
+    } else {
+      should_print = true;
+      if (cfg.snapname.empty()) {
+        cfg.snapname = "-";
+      }
+      tbl << pid << cfg.poolname << cfg.imgname << cfg.snapname << cfg.devpath
+          << TextTable::endrow;
     }
-    tbl << pid << cfg.poolname << cfg.imgname << cfg.snapname << cfg.devpath
-        << TextTable::endrow;
   }
 
+  if (f) {
+    f->close_section(); // devices
+    f->flush(std::cout);
+  }
   if (should_print) {
-    cout << tbl;
+    std::cout << tbl;
   }
   return 0;
 }
@@ -1038,6 +1076,10 @@ static int parse_args(vector<const char*>& args, std::ostream *err_msg,
         *err_msg << "rbd-nbd: Invalid argument for timeout!";
         return -EINVAL;
       }
+    } else if (ceph_argparse_witharg(args, i, &cfg->format, err, "--format",
+                                     (char *)NULL)) {
+    } else if (ceph_argparse_flag(args, i, "--pretty-format", (char *)NULL)) {
+      cfg->pretty_format = true;
     } else {
       ++i;
     }
@@ -1144,7 +1186,7 @@ static int rbd_nbd(int argc, const char *argv[])
         return -EINVAL;
       break;
     case List:
-      r = do_list_mapped_devices();
+      r = do_list_mapped_devices(cfg.format, cfg.pretty_format);
       if (r < 0)
         return -EINVAL;
       break;