]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rbd: Use the right device type on Windows
authorLucian Petrut <lpetrut@cloudbasesolutions.com>
Thu, 30 Apr 2020 07:11:16 +0000 (07:11 +0000)
committerLucian Petrut <lpetrut@cloudbasesolutions.com>
Wed, 18 Nov 2020 10:31:24 +0000 (10:31 +0000)
"wnbd" will be the only supported device type on Windows, for now.
We'll update the "rbd" wrapper accordingly.

Signed-off-by: Lucian Petrut <lpetrut@cloudbasesolutions.com>
src/common/compat.cc
src/include/compat.h
src/tools/rbd/CMakeLists.txt
src/tools/rbd/action/Device.cc
src/tools/rbd/action/Wnbd.cc [new file with mode: 0644]

index bac0cb81bc70e5ed93bf2c3854f9c1385e326d2f..0e8d944a73cc2114e1eb121e4de103f95e3cd4fc 100644 (file)
@@ -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 */
index b454fc6a3f98182bf1fe6769b2d0a9a7adac82fb..6147c5c0a19f933717b3e0e7f552071cb4275755 100644 (file)
@@ -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);
 
index eda58e6b8a8312f2e61192f8e23e9a63c634c506..8ab1db3d2a82b6d91fbd6c6815979370095f33b8 100644 (file)
@@ -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}
   $<TARGET_OBJECTS:common_texttable_obj>)
index fd0249b2031a7467ecebb4c0aedb1b8aee94e4bc..9ab906311628b223af8d145f3a2a22bbc4a36554 100644 (file)
@@ -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<std::string>& 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<std::string>& values,
 void add_device_type_option(po::options_description *options) {
   options->add_options()
     ("device-type,t", po::value<DeviceType>(),
+#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<device_type_t>();
   }
+  #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 (file)
index 0000000..41b331a
--- /dev/null
@@ -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 <iostream>
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/program_options.hpp>
+
+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<std::string> &args,
+                        const std::vector<std::string> &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<std::string> &options,
+                  std::vector<std::string> *args) {
+  for (auto &opts : options) {
+    std::vector<std::string> 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<std::string> &ceph_global_init_args) {
+  std::vector<std::string> args;
+
+  args.push_back("list");
+
+  if (vm.count("format")) {
+    args.push_back("--format");
+    args.push_back(vm["format"].as<at::Format>().value);
+  }
+  if (vm["pretty-format"].as<bool>()) {
+    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<std::string> &ceph_global_init_args) {
+  std::vector<std::string> 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<bool>()) {
+    args.push_back("--read-only");
+  }
+
+  if (vm["exclusive"].as<bool>()) {
+    args.push_back("--exclusive");
+  }
+
+  if (vm.count("options")) {
+    r = parse_options(vm["options"].as<std::vector<std::string>>(), &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<std::string> &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<std::string> 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<std::vector<std::string>>(), &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