]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd-ggate: extended info when listing devices
authorMykola Golub <to.my.trociny@gmail.com>
Mon, 25 Dec 2017 09:15:08 +0000 (09:15 +0000)
committerMykola Golub <to.my.trociny@gmail.com>
Wed, 27 Dec 2017 20:29:58 +0000 (20:29 +0000)
This matches nbd and krbd drivers output.

Signed-off-by: Mykola Golub <to.my.trociny@gmail.com>
qa/workunits/rbd/rbd-ggate.sh
src/tools/rbd/action/Ggate.cc
src/tools/rbd_ggate/Driver.cc
src/tools/rbd_ggate/Driver.h
src/tools/rbd_ggate/ggate_drv.c
src/tools/rbd_ggate/ggate_drv.h
src/tools/rbd_ggate/main.cc

index 97a7d89c4ec9ee29643cff024ead5817e05bfefd..1cc78d12f08f9dd280a81381acc1cc790447b6aa 100755 (executable)
@@ -92,18 +92,23 @@ expect_false _sudo rbd-ggate map INVALIDIMAGE
 
 # map test using the first unused device
 DEV=`_sudo rbd-ggate map ${POOL}/${IMAGE}`
-_sudo rbd-ggate list | grep "^${DEV}$"
+_sudo rbd-ggate list | grep " ${DEV} *$"
 
 # map test specifying the device
 expect_false _sudo rbd-ggate --device ${DEV} map ${POOL}/${IMAGE}
 dev1=${DEV}
 _sudo rbd-ggate unmap ${DEV}
-_sudo rbd-ggate list | expect_false grep "^${DEV}$"
+_sudo rbd-ggate list | expect_false grep " ${DEV} *$"
 DEV=
 # XXX: race possible when the device is reused by other process
 DEV=`_sudo rbd-ggate --device ${dev1} map ${POOL}/${IMAGE}`
 [ "${DEV}" = "${dev1}" ]
-_sudo rbd-ggate list | grep "^${DEV}$"
+_sudo rbd-ggate list | grep " ${DEV} *$"
+
+# list format test
+expect_false _sudo rbd-ggate --format INVALID list
+_sudo rbd-ggate --format json --pretty-format list
+_sudo rbd-ggate --format xml list
 
 # read test
 [ "`dd if=${DATA} bs=1M | md5`" = "`_sudo dd if=${DEV} bs=1M | md5`" ]
@@ -137,9 +142,9 @@ rbd info ${POOL}/${IMAGE}
 if [ -z "$RBD_GGATE_RESIZE_SUPPORTED" ]; then
     # XXX: ggate device resize is not supported by vanila kernel.
     # rbd-ggate should terminate when detecting resize.
-    _sudo rbd-ggate list | expect_false grep "^${DEV}$"
+    _sudo rbd-ggate list | expect_false grep " ${DEV} *$"
 else
-    _sudo rbd-ggate list | grep "^${DEV}$"
+    _sudo rbd-ggate list | grep " ${DEV} *$"
     size2=$(geom gate list ${devname} | awk '$1 ~ /Mediasize:/ {print $2}')
     test -n "${size2}"
     test ${size2} -eq $((size * 2))
@@ -161,7 +166,7 @@ DEV=
 # read-only option test
 DEV=`_sudo rbd-ggate map --read-only ${POOL}/${IMAGE}`
 devname=$(basename ${DEV})
-_sudo rbd-ggate list | grep "^${DEV}$"
+_sudo rbd-ggate list | grep " ${DEV} *$"
 access=$(geom gate list ${devname} | awk '$1 == "access:" {print $2}')
 test "${access}" = "read-only"
 _sudo dd if=${DEV} of=/dev/null bs=1M
@@ -170,7 +175,7 @@ _sudo rbd-ggate unmap ${DEV}
 
 # exclusive option test
 DEV=`_sudo rbd-ggate map --exclusive ${POOL}/${IMAGE}`
-_sudo rbd-ggate list | grep "^${DEV}$"
+_sudo rbd-ggate list | grep " ${DEV} *$"
 _sudo dd if=${DATA} of=${DEV} bs=1M
 _sudo sync
 expect_false timeout 10 \
index a87751bd35b0b7394682280444101ad2cdd2f0b1..24ffdfc07a2e5e7209635c6112f142684ce05939 100644 (file)
@@ -77,8 +77,9 @@ static int call_ggate_cmd(const po::variables_map &vm,
 }
 
 void get_list_arguments(po::options_description *positional,
-                        po::options_description *options)
-{ }
+                        po::options_description *options) {
+  at::add_format_options(options);
+}
 
 int execute_list(const po::variables_map &vm)
 {
@@ -86,6 +87,14 @@ int execute_list(const po::variables_map &vm)
 
   args.push_back("list");
 
+  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_ggate_cmd(vm, args);
 }
 
index cf63fc66024653fdfcbcba4c0d582f874ce97a61..e2b3e3a110317401d5bfc8cbaad71c74661eaf4f 100644 (file)
@@ -29,32 +29,31 @@ int Driver::kill(const std::string &devname) {
   return r;
 }
 
-int Driver::list(std::list<std::string> &devs) {
+int Driver::list(std::map<std::string, DevInfo> *devices) {
   size_t size = 1024;
-  char **devs_ = nullptr;
+  ggate_drv_info *devs = nullptr;
   int r;
 
   while (size <= 1024 * 1024) {
-    devs_ = static_cast<char **>(
-        realloc(static_cast<void *>(devs_), size * sizeof(*devs_)));
-    r = ggate_drv_list(devs_, &size);
+    devs = static_cast<ggate_drv_info *>(
+        realloc(static_cast<void *>(devs), size * sizeof(*devs)));
+    r = ggate_drv_list(devs, &size);
     if (r != -ERANGE) {
       break;
     }
-    size *= 2;
   }
   if (r < 0) {
     goto free;
   }
 
-  devs.clear();
+  devices->clear();
   for (size_t i = 0; i < size; i++) {
-    devs.push_back(devs_[i]);
+    auto &dev = devs[i];
+    (*devices)[dev.id] = {dev.name, dev.info};
   }
 
-  ggate_drv_list_free(devs_, size);
 free:
-  free(devs_);
+  free(devs);
 
   return r;
 }
index b52b48ab1129b35e39161e7f3b10e90a365a8047..50be72b9cb9a1970330be33797a74fe68cb4d670 100644 (file)
@@ -4,7 +4,7 @@
 #ifndef CEPH_RBD_GGATE_DRIVER_H
 #define CEPH_RBD_GGATE_DRIVER_H
 
-#include <list>
+#include <map>
 #include <string>
 
 #include "ggate_drv.h"
@@ -16,9 +16,10 @@ struct Request;
 
 class Driver {
 public:
+  typedef std::pair<std::string, std::string> DevInfo;
   static int load();
   static int kill(const std::string &devname);
-  static int list(std::list<std::string> &devs);
+  static int list(std::map<std::string, DevInfo> *devices);
 
   Driver(const std::string &devname, size_t sectorsize, size_t mediasize,
          bool readonly, const std::string &info);
index 8b02b1bef423a1ec370905b3cea5127949d70453..b1faccd25e19adf63386a53cfe2045191b5f2b5b 100644 (file)
@@ -330,7 +330,17 @@ int ggate_drv_send(ggate_drv_t drv_, ggate_drv_req_t req) {
   return r;
 }
 
-int ggate_drv_list(char **devs, size_t *size) {
+static const char * get_conf(struct ggeom *gp, const char *name) {
+       struct gconfig *conf;
+
+       LIST_FOREACH(conf, &gp->lg_config, lg_config) {
+               if (strcmp(conf->lg_name, name) == 0)
+                       return (conf->lg_val);
+       }
+       return "";
+}
+
+int ggate_drv_list(struct ggate_drv_info *info, size_t *size) {
   struct gmesh mesh;
   struct gclass *class;
   struct ggeom *gp;
@@ -355,8 +365,10 @@ int ggate_drv_list(char **devs, size_t *size) {
         goto done;
       }
       LIST_FOREACH(gp, &class->lg_geom, lg_geom) {
-        *devs = strdup(gp->lg_name);
-        devs++;
+        strlcpy(info->id, get_conf(gp, "unit"), sizeof(info->id));
+        strlcpy(info->name, gp->lg_name, sizeof(info->name));
+        strlcpy(info->info, get_conf(gp, "info"), sizeof(info->info));
+        info++;
       }
     }
   }
@@ -365,11 +377,3 @@ done:
   geom_deletetree(&mesh);
   return r;
 }
-
-void ggate_drv_list_free(char **devs, size_t size) {
-  size_t i;
-
-  for (i = 0; i < size; i++) {
-    free(devs[i]);
-  }
-}
index 5ea5f32b93e181a50b2b81d52a99dbfeb967246d..a32f511386efb23d53c6bb1cba34508a1fa1098b 100644 (file)
@@ -8,6 +8,8 @@
 extern "C" {
 #endif
 
+#include <sys/param.h>
+
 #include <stdbool.h>
 #include <stdint.h>
 
@@ -25,6 +27,12 @@ enum {
   GGATE_DRV_CMD_DISCARD = 4,
 };
 
+struct ggate_drv_info {
+  char id[16];
+  char name[NAME_MAX];
+  char info[2048]; /* G_GATE_INFOSIZE */
+};
+
 uint64_t ggate_drv_req_id(ggate_drv_req_t req);
 int ggate_drv_req_cmd(ggate_drv_req_t req);
 void *ggate_drv_req_buf(ggate_drv_req_t req);
@@ -47,8 +55,7 @@ int ggate_drv_send(ggate_drv_t drv, ggate_drv_req_t req);
 int ggate_drv_resize(ggate_drv_t drv, size_t newsize);
 
 int ggate_drv_kill(const char *devname);
-int ggate_drv_list(char **devs, size_t *size);
-void ggate_drv_list_free(char **devs, size_t size);
+int ggate_drv_list(struct ggate_drv_info *info, size_t *size);
 
 #ifdef __cplusplus
 }
index e2d132c9bb8a436cad0b02e17421a2c8a20de849..d1c4fba93ba35ba3a8785d1e99f58ff92e361c92 100644 (file)
 #include <assert.h>
 
 #include <iostream>
+#include <memory>
+#include <boost/algorithm/string/predicate.hpp>
 #include <boost/regex.hpp>
 
+#include "common/Formatter.h"
 #include "common/Preforker.h"
+#include "common/TextTable.h"
 #include "common/ceph_argparse.h"
 #include "common/config.h"
 #include "common/debug.h"
@@ -25,6 +29,7 @@
 
 #include "include/rados/librados.hpp"
 #include "include/rbd/librbd.hpp"
+#include "include/stringify.h"
 
 #include "Driver.h"
 #include "Server.h"
@@ -39,10 +44,15 @@ static void usage() {
   std::cout << "Usage: rbd-ggate [options] map <image-or-snap-spec>  Map an image to ggate device\n"
             << "                           unmap <device path>       Unmap ggate device\n"
             << "                           list                      List mapped ggate devices\n"
-            << "Options:\n"
+            << "\n"
+            << "Map options:\n"
             << "  --device <device path>  Specify ggate device path\n"
             << "  --read-only             Map readonly\n"
             << "  --exclusive             Forbid writes by other clients\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();
 }
@@ -110,7 +120,7 @@ static int do_map(int argc, const char *argv[])
     poolname = g_ceph_context->_conf->get_val<std::string>("rbd_default_pool");
   }
 
-  std::string devname = (devpath.compare(0, 5, "/dev/") == 0) ?
+  std::string devname = boost::starts_with(devpath, "/dev/") ?
     devpath.substr(5) : devpath;
   std::unique_ptr<rbd::ggate::Watcher> watcher;
   uint64_t handle;
@@ -228,7 +238,7 @@ done:
 
 static int do_unmap()
 {
-  std::string devname = (devpath.compare(0, 5, "/dev/") == 0) ?
+  std::string devname = boost::starts_with(devpath, "/dev/") ?
     devpath.substr(5) : devpath;
 
   int r = rbd::ggate::Driver::kill(devname);
@@ -241,8 +251,8 @@ static int do_unmap()
   return 0;
 }
 
-static int parse_imgpath(const std::string &imgpath)
-{
+static int parse_imgpath(const std::string &imgpath, std::string *poolname,
+                         std::string *imgname, std::string *snapname) {
   boost::regex pattern("^(?:([^/@]+)/)?([^/@]+)(?:@([^/@]+))?$");
   boost::smatch match;
   if (!boost::regex_match(imgpath, match, pattern)) {
@@ -251,31 +261,86 @@ static int parse_imgpath(const std::string &imgpath)
   }
 
   if (match[1].matched) {
-    poolname = match[1];
+    *poolname = match[1];
   }
 
-  imgname = match[2];
+  *imgname = match[2];
 
   if (match[3].matched) {
-    snapname = match[3];
+    *snapname = match[3];
   }
 
   return 0;
 }
 
-static int do_list()
+static int do_list(const std::string &format, bool pretty_format)
 {
   rbd::ggate::Driver::load();
 
-  std::list<std::string> devs;
-  int r = rbd::ggate::Driver::list(devs);
+  std::map<std::string, rbd::ggate::Driver::DevInfo> devs;
+  int r = rbd::ggate::Driver::list(&devs);
   if (r < 0) {
     return -r;
   }
 
-  for (auto &devname : devs) {
-    cout << "/dev/" << devname << std::endl;
+  std::unique_ptr<ceph::Formatter> f;
+  TextTable tbl;
+
+  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-ggate: invalid output format: " << format << std::endl;
+    return -EINVAL;
+  }
+
+  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);
   }
+
+  int count = 0;
+
+  for (auto &it : devs) {
+    auto &id = it.first;
+    auto &name = it.second.first;
+    auto &info = it.second.second;
+    if (!boost::starts_with(info, "RBD ")) {
+      continue;
+    }
+
+    std::string poolname;
+    std::string imgname;
+    std::string snapname(f ? "" : "-");
+    parse_imgpath(info.substr(4), &poolname, &imgname, &snapname);
+
+    if (f) {
+      f->open_object_section(stringify(id).c_str());
+      f->dump_string("pool", poolname);
+      f->dump_string("image", imgname);
+      f->dump_string("snap", snapname);
+      f->dump_string("device", "/dev/" + name);
+      f->close_section();
+    } else {
+      tbl << id << poolname << imgname << snapname << "/dev/" + name
+          << TextTable::endrow;
+    }
+    count++;
+  }
+
+  if (f) {
+    f->close_section(); // devices
+    f->flush(std::cout);
+  } else if (count > 0) {
+    std::cout << tbl;
+  }
+
   return 0;
 }
 
@@ -293,6 +358,8 @@ int main(int argc, const char *argv[]) {
   argv_to_vec(argc, argv, args);
   md_config_t().parse_argv(args);
 
+  std::string format;
+  bool pretty_format = false;
   std::vector<const char*>::iterator i;
 
   for (i = args.begin(); i != args.end(); ) {
@@ -305,6 +372,10 @@ int main(int argc, const char *argv[]) {
       readonly = true;
     } else if (ceph_argparse_flag(args, i, "--exclusive", (char *)NULL)) {
       exclusive = true;
+    } else if (ceph_argparse_witharg(args, i, &format, "--format",
+                                     (char *)NULL)) {
+    } else if (ceph_argparse_flag(args, i, "--pretty-format", (char *)NULL)) {
+      pretty_format = true;
     } else {
       ++i;
     }
@@ -335,8 +406,9 @@ int main(int argc, const char *argv[]) {
         cerr << "rbd-ggate: must specify image-or-snap-spec" << std::endl;
         return EXIT_FAILURE;
       }
-      if (parse_imgpath(string(*args.begin())) < 0)
+      if (parse_imgpath(*args.begin(), &poolname, &imgname, &snapname) < 0) {
         return EXIT_FAILURE;
+      }
       args.erase(args.begin());
       break;
     case Disconnect:
@@ -373,7 +445,7 @@ int main(int argc, const char *argv[]) {
         return EXIT_FAILURE;
       break;
     case List:
-      r = do_list();
+      r = do_list(format, pretty_format);
       if (r < 0)
         return EXIT_FAILURE;
       break;