This matches nbd and krbd drivers output.
Signed-off-by: Mykola Golub <to.my.trociny@gmail.com>
# 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`" ]
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))
# 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
# 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 \
}
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)
{
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);
}
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;
}
#ifndef CEPH_RBD_GGATE_DRIVER_H
#define CEPH_RBD_GGATE_DRIVER_H
-#include <list>
+#include <map>
#include <string>
#include "ggate_drv.h"
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);
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;
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++;
}
}
}
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]);
- }
-}
extern "C" {
#endif
+#include <sys/param.h>
+
#include <stdbool.h>
#include <stdint.h>
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);
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
}
#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"
#include "include/rados/librados.hpp"
#include "include/rbd/librbd.hpp"
+#include "include/stringify.h"
#include "Driver.h"
#include "Server.h"
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();
}
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;
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);
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)) {
}
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;
}
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(); ) {
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;
}
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:
return EXIT_FAILURE;
break;
case List:
- r = do_list();
+ r = do_list(format, pretty_format);
if (r < 0)
return EXIT_FAILURE;
break;