From 833a09e8aedbf54ef71d578898a0b9aa1053b808 Mon Sep 17 00:00:00 2001 From: Lucian Petrut Date: Thu, 30 Apr 2020 07:11:16 +0000 Subject: [PATCH] rbd: Use the right device type on Windows "wnbd" will be the only supported device type on Windows, for now. We'll update the "rbd" wrapper accordingly. Signed-off-by: Lucian Petrut --- src/common/compat.cc | 9 ++ src/include/compat.h | 3 + src/tools/rbd/CMakeLists.txt | 3 +- src/tools/rbd/action/Device.cc | 30 +++++- src/tools/rbd/action/Wnbd.cc | 192 +++++++++++++++++++++++++++++++++ 5 files changed, 233 insertions(+), 4 deletions(-) create mode 100644 src/tools/rbd/action/Wnbd.cc diff --git a/src/common/compat.cc b/src/common/compat.cc index bac0cb81bc70e..0e8d944a73cc2 100644 --- a/src/common/compat.cc +++ b/src/common/compat.cc @@ -487,10 +487,19 @@ int setenv(const char *name, const char *value, int overwrite) { return _putenv_s(name, value); } +ssize_t get_self_exe_path(char* path, int buff_length) { + return GetModuleFileName(NULL, path, buff_length - 1); +} + #else unsigned get_page_size() { return sysconf(_SC_PAGESIZE); } +ssize_t get_self_exe_path(char* path, int buff_length) { + return readlink("/proc/self/exe", path, + sizeof(buff_length) - 1); +} + #endif /* _WIN32 */ diff --git a/src/include/compat.h b/src/include/compat.h index b454fc6a3f981..6147c5c0a19f9 100644 --- a/src/include/compat.h +++ b/src/include/compat.h @@ -202,6 +202,9 @@ extern "C" { int pipe_cloexec(int pipefd[2], int flags); char *ceph_strerror_r(int errnum, char *buf, size_t buflen); unsigned get_page_size(); +// On success, returns the number of bytes written to the buffer. On +// failure, returns -1. +ssize_t get_self_exe_path(char* path, int buff_length); int ceph_memzero_s(void *dest, size_t destsz, size_t count); diff --git a/src/tools/rbd/CMakeLists.txt b/src/tools/rbd/CMakeLists.txt index eda58e6b8a831..8ab1db3d2a82b 100644 --- a/src/tools/rbd/CMakeLists.txt +++ b/src/tools/rbd/CMakeLists.txt @@ -51,7 +51,8 @@ set(rbd_srcs action/Status.cc action/TrashPurgeSchedule.cc action/Trash.cc - action/Watch.cc) + action/Watch.cc + action/Wnbd.cc) add_executable(rbd ${rbd_srcs} $) diff --git a/src/tools/rbd/action/Device.cc b/src/tools/rbd/action/Device.cc index fd0249b2031a7..9ab906311628b 100644 --- a/src/tools/rbd/action/Device.cc +++ b/src/tools/rbd/action/Device.cc @@ -28,6 +28,7 @@ namespace po = boost::program_options; DECLARE_DEVICE_OPERATIONS(ggate); DECLARE_DEVICE_OPERATIONS(kernel); DECLARE_DEVICE_OPERATIONS(nbd); +DECLARE_DEVICE_OPERATIONS(wnbd); namespace device { @@ -60,10 +61,17 @@ const DeviceOperations nbd_operations = { nbd::execute_unmap, }; +const DeviceOperations wnbd_operations = { + wnbd::execute_list, + wnbd::execute_map, + wnbd::execute_unmap, +}; + enum device_type_t { DEVICE_TYPE_GGATE, DEVICE_TYPE_KRBD, DEVICE_TYPE_NBD, + DEVICE_TYPE_WNBD, }; struct DeviceType {}; @@ -72,12 +80,18 @@ void validate(boost::any& v, const std::vector& values, DeviceType *target_type, int) { po::validators::check_first_occurrence(v); const std::string &s = po::validators::get_single_string(values); - if (s == "ggate") { + + #ifdef _WIN32 + if (s == "wnbd") { + v = boost::any(DEVICE_TYPE_WNBD); + #else + if (s == "nbd") { + v = boost::any(DEVICE_TYPE_NBD); + } else if (s == "ggate") { v = boost::any(DEVICE_TYPE_GGATE); } else if (s == "krbd") { v = boost::any(DEVICE_TYPE_KRBD); - } else if (s == "nbd") { - v = boost::any(DEVICE_TYPE_NBD); + #endif /* _WIN32 */ } else { throw po::validation_error(po::validation_error::invalid_option_value); } @@ -86,7 +100,11 @@ void validate(boost::any& v, const std::vector& values, void add_device_type_option(po::options_description *options) { options->add_options() ("device-type,t", po::value(), +#ifdef _WIN32 + "device type [wnbd]"); +#else "device type [ggate, krbd (default), nbd]"); +#endif } void add_device_specific_options(po::options_description *options) { @@ -99,7 +117,11 @@ device_type_t get_device_type(const po::variables_map &vm) { if (vm.count("device-type")) { return vm["device-type"].as(); } + #ifndef _WIN32 return DEVICE_TYPE_KRBD; + #else + return DEVICE_TYPE_WNBD; + #endif } const DeviceOperations *get_device_operations(const po::variables_map &vm) { @@ -110,6 +132,8 @@ const DeviceOperations *get_device_operations(const po::variables_map &vm) { return &krbd_operations; case DEVICE_TYPE_NBD: return &nbd_operations; + case DEVICE_TYPE_WNBD: + return &wnbd_operations; default: ceph_abort(); return nullptr; diff --git a/src/tools/rbd/action/Wnbd.cc b/src/tools/rbd/action/Wnbd.cc new file mode 100644 index 0000000000000..41b331a9e3c04 --- /dev/null +++ b/src/tools/rbd/action/Wnbd.cc @@ -0,0 +1,192 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "tools/rbd/ArgumentTypes.h" +#include "tools/rbd/Shell.h" +#include "tools/rbd/Utils.h" +#include "include/stringify.h" +#include "common/SubProcess.h" +#include +#include +#include +#include + +namespace rbd { +namespace action { +namespace wnbd { + +namespace at = argument_types; +namespace po = boost::program_options; + +static int call_wnbd_cmd(const po::variables_map &vm, + const std::vector &args, + const std::vector &ceph_global_init_args) { + char exe_path[PATH_MAX]; + ssize_t exe_path_bytes = get_self_exe_path(exe_path, PATH_MAX); + + if (exe_path_bytes > 4) { + // Drop .exe suffix as we're going to add the "-wnbd" suffix. + exe_path[strlen(exe_path) - 4] = '\0'; + exe_path_bytes -= 4; + } + + if (exe_path_bytes < 0) { + strcpy(exe_path, "rbd-wnbd"); + } else { + if (snprintf(exe_path + exe_path_bytes, + sizeof(exe_path) - exe_path_bytes, + "-wnbd") < 0) { + return -EOVERFLOW; + } + } + + SubProcess process(exe_path, SubProcess::KEEP, SubProcess::KEEP, SubProcess::KEEP); + + for (auto &arg : ceph_global_init_args) { + process.add_cmd_arg(arg.c_str()); + } + + for (auto &arg : args) { + process.add_cmd_arg(arg.c_str()); + } + + if (process.spawn()) { + std::cerr << "rbd: failed to run rbd-wnbd: " << process.err() << std::endl; + return -EINVAL; + } else if (process.join()) { + std::cerr << "rbd: rbd-wnbd failed with error: " << process.err() << std::endl; + return -EINVAL; + } + + return 0; +} + +int get_image_or_snap_spec(const po::variables_map &vm, std::string *spec) { + size_t arg_index = 0; + std::string pool_name; + std::string nspace_name; + std::string image_name; + std::string snap_name; + int r = utils::get_pool_image_snapshot_names( + vm, at::ARGUMENT_MODIFIER_NONE, &arg_index, &pool_name, &nspace_name, + &image_name, &snap_name, true, utils::SNAPSHOT_PRESENCE_PERMITTED, + utils::SPEC_VALIDATION_NONE); + if (r < 0) { + return r; + } + + if (!pool_name.empty()) { + spec->append(pool_name); + spec->append("/"); + } + if (!nspace_name.empty()) { + spec->append(nspace_name); + spec->append("/"); + } + spec->append(image_name); + if (!snap_name.empty()) { + spec->append("@"); + spec->append(snap_name); + } + + return 0; +} + +int parse_options(const std::vector &options, + std::vector *args) { + for (auto &opts : options) { + std::vector args_; + boost::split(args_, opts, boost::is_any_of(",")); + for (auto &o : args_) { + args->push_back("--" + o); + } + } + + return 0; +} + +int execute_list(const po::variables_map &vm, + const std::vector &ceph_global_init_args) { + std::vector args; + + args.push_back("list"); + + if (vm.count("format")) { + args.push_back("--format"); + args.push_back(vm["format"].as().value); + } + if (vm["pretty-format"].as()) { + args.push_back("--pretty-format"); + } + + return call_wnbd_cmd(vm, args, ceph_global_init_args); +} + +int execute_map(const po::variables_map &vm, + const std::vector &ceph_global_init_args) { + std::vector args; + + args.push_back("map"); + std::string img; + int r = get_image_or_snap_spec(vm, &img); + if (r < 0) { + return r; + } + args.push_back(img); + + if (vm["read-only"].as()) { + args.push_back("--read-only"); + } + + if (vm["exclusive"].as()) { + args.push_back("--exclusive"); + } + + if (vm.count("options")) { + r = parse_options(vm["options"].as>(), &args); + if (r < 0) { + return r; + } + } + + return call_wnbd_cmd(vm, args, ceph_global_init_args); +} + +int execute_unmap(const po::variables_map &vm, + const std::vector &ceph_global_init_args) { + std::string device_name = utils::get_positional_argument(vm, 0); + + std::string image_name; + if (device_name.empty()) { + int r = get_image_or_snap_spec(vm, &image_name); + if (r < 0) { + return r; + } + } + + if (device_name.empty() && image_name.empty()) { + std::cerr << "rbd: unmap requires either image name or device path" + << std::endl; + return -EINVAL; + } + + std::vector args; + + args.push_back("unmap"); + args.push_back(device_name.empty() ? image_name : device_name); + + if (vm.count("options")) { + int r = parse_options(vm["options"].as>(), &args); + if (r < 0) { + return r; + } + } + + return call_wnbd_cmd(vm, args, ceph_global_init_args); +} + +Shell::SwitchArguments switched_arguments({"read-only", "exclusive"}); + +} // namespace wnbd +} // namespace action +} // namespace rbd -- 2.39.5