From 8e0f40aae1be3eba86f1cce87bdce275d94c8a31 Mon Sep 17 00:00:00 2001 From: Mykola Golub Date: Mon, 25 Dec 2017 09:15:08 +0000 Subject: [PATCH] rbd-ggate: extended info when listing devices This matches nbd and krbd drivers output. Signed-off-by: Mykola Golub --- qa/workunits/rbd/rbd-ggate.sh | 19 +++--- src/tools/rbd/action/Ggate.cc | 13 +++- src/tools/rbd_ggate/Driver.cc | 19 +++--- src/tools/rbd_ggate/Driver.h | 5 +- src/tools/rbd_ggate/ggate_drv.c | 26 ++++---- src/tools/rbd_ggate/ggate_drv.h | 11 +++- src/tools/rbd_ggate/main.cc | 102 +++++++++++++++++++++++++++----- 7 files changed, 146 insertions(+), 49 deletions(-) diff --git a/qa/workunits/rbd/rbd-ggate.sh b/qa/workunits/rbd/rbd-ggate.sh index 97a7d89c4ec9e..1cc78d12f08f9 100755 --- a/qa/workunits/rbd/rbd-ggate.sh +++ b/qa/workunits/rbd/rbd-ggate.sh @@ -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 \ diff --git a/src/tools/rbd/action/Ggate.cc b/src/tools/rbd/action/Ggate.cc index a87751bd35b0b..24ffdfc07a2e5 100644 --- a/src/tools/rbd/action/Ggate.cc +++ b/src/tools/rbd/action/Ggate.cc @@ -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().value.c_str()); + } + if (vm["pretty-format"].as()) { + args.push_back("--pretty-format"); + } + return call_ggate_cmd(vm, args); } diff --git a/src/tools/rbd_ggate/Driver.cc b/src/tools/rbd_ggate/Driver.cc index cf63fc6602465..e2b3e3a110317 100644 --- a/src/tools/rbd_ggate/Driver.cc +++ b/src/tools/rbd_ggate/Driver.cc @@ -29,32 +29,31 @@ int Driver::kill(const std::string &devname) { return r; } -int Driver::list(std::list &devs) { +int Driver::list(std::map *devices) { size_t size = 1024; - char **devs_ = nullptr; + ggate_drv_info *devs = nullptr; int r; while (size <= 1024 * 1024) { - devs_ = static_cast( - realloc(static_cast(devs_), size * sizeof(*devs_))); - r = ggate_drv_list(devs_, &size); + devs = static_cast( + realloc(static_cast(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; } diff --git a/src/tools/rbd_ggate/Driver.h b/src/tools/rbd_ggate/Driver.h index b52b48ab1129b..50be72b9cb9a1 100644 --- a/src/tools/rbd_ggate/Driver.h +++ b/src/tools/rbd_ggate/Driver.h @@ -4,7 +4,7 @@ #ifndef CEPH_RBD_GGATE_DRIVER_H #define CEPH_RBD_GGATE_DRIVER_H -#include +#include #include #include "ggate_drv.h" @@ -16,9 +16,10 @@ struct Request; class Driver { public: + typedef std::pair DevInfo; static int load(); static int kill(const std::string &devname); - static int list(std::list &devs); + static int list(std::map *devices); Driver(const std::string &devname, size_t sectorsize, size_t mediasize, bool readonly, const std::string &info); diff --git a/src/tools/rbd_ggate/ggate_drv.c b/src/tools/rbd_ggate/ggate_drv.c index 8b02b1bef423a..b1faccd25e19a 100644 --- a/src/tools/rbd_ggate/ggate_drv.c +++ b/src/tools/rbd_ggate/ggate_drv.c @@ -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]); - } -} diff --git a/src/tools/rbd_ggate/ggate_drv.h b/src/tools/rbd_ggate/ggate_drv.h index 5ea5f32b93e18..a32f511386efb 100644 --- a/src/tools/rbd_ggate/ggate_drv.h +++ b/src/tools/rbd_ggate/ggate_drv.h @@ -8,6 +8,8 @@ extern "C" { #endif +#include + #include #include @@ -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 } diff --git a/src/tools/rbd_ggate/main.cc b/src/tools/rbd_ggate/main.cc index e2d132c9bb8a4..d1c4fba93ba35 100644 --- a/src/tools/rbd_ggate/main.cc +++ b/src/tools/rbd_ggate/main.cc @@ -13,9 +13,13 @@ #include #include +#include +#include #include +#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 Map an image to ggate device\n" << " unmap Unmap ggate device\n" << " list List mapped ggate devices\n" - << "Options:\n" + << "\n" + << "Map options:\n" << " --device 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("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 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 devs; - int r = rbd::ggate::Driver::list(devs); + std::map 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 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::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; -- 2.39.5