]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/crush/CrushLocation: add crimson::cruch::CrushLocation
authorluo rixin <luorixin@huawei.com>
Wed, 10 May 2023 11:45:15 +0000 (19:45 +0800)
committerluo rixin <luorixin@huawei.com>
Tue, 30 May 2023 02:14:45 +0000 (10:14 +0800)
Signed-off-by: luo rixin <luorixin@huawei.com>
(cherry picked from commit 7b7adb0dc6d6934286095ecbd69103250525ec6a)

src/crimson/CMakeLists.txt
src/crimson/crush/CrushLocation.cc [new file with mode: 0644]
src/crimson/crush/CrushLocation.h [new file with mode: 0644]

index 563c20921bdff72a38871183f12d74e611cae307..e2b37fac9cbf0335eec80381d444caee710d728a 100644 (file)
@@ -23,7 +23,8 @@ set(crimson_common_srcs
   common/operation.cc
   common/throttle.cc
   common/tmap_helpers.cc
-  common/tri_mutex.cc)
+  common/tri_mutex.cc
+  crush/CrushLocation.cc)
 
 # the specialized version of ceph-common, where
 #  - the logging is sent to Seastar backend
@@ -98,7 +99,6 @@ add_library(crimson-common STATIC
   ${PROJECT_SOURCE_DIR}/src/crush/CrushWrapper.cc
   ${PROJECT_SOURCE_DIR}/src/crush/CrushCompiler.cc
   ${PROJECT_SOURCE_DIR}/src/crush/CrushTester.cc
-  ${PROJECT_SOURCE_DIR}/src/crush/CrushLocation.cc
   ${PROJECT_SOURCE_DIR}/src/global/global_context.cc
   ${PROJECT_SOURCE_DIR}/src/global/pidfile.cc
   ${PROJECT_SOURCE_DIR}/src/librbd/Features.cc
diff --git a/src/crimson/crush/CrushLocation.cc b/src/crimson/crush/CrushLocation.cc
new file mode 100644 (file)
index 0000000..d452640
--- /dev/null
@@ -0,0 +1,186 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+#include "CrushLocation.h"
+
+#include <vector>
+#include <boost/algorithm/string/trim.hpp>
+#include <seastar/util/process.hh>
+#include <seastar/util/later.hh>
+
+#include "crush/CrushWrapper.h"
+#include "crimson/common/log.h"
+#include "crimson/common/config_proxy.h"
+
+static seastar::logger& logger() {
+  return crimson::get_logger(ceph_subsys_crush);
+}
+
+using namespace crimson::common;
+
+namespace crimson::crush {
+
+seastar::future<> CrushLocation::update_from_conf()
+{
+  auto crush_location = local_conf().get_val<std::string>("crush_location");
+  if (crush_location.length()) {
+    _parse(crush_location);
+  }
+
+  return seastar::now();
+}
+
+void CrushLocation::_parse(const std::string& s)
+{
+  std::multimap<std::string, std::string> new_crush_location;
+  std::vector<std::string> lvec;
+  get_str_vec(s, ";, \t", lvec);
+  int r = CrushWrapper::parse_loc_multimap(lvec, &new_crush_location);
+  if (r < 0) {
+    logger().error("CrushWrapper::parse_loc_multimap error, keeping original\
+      crush_location {}", *this);
+    return;
+  }
+
+  loc.swap(new_crush_location);
+  logger().info("{}: crush_location is {}", __func__, *this);
+  return;
+}
+
+seastar::future<> CrushLocation::update_from_hook()
+{
+  auto crush_location_hook = local_conf().get_val<std::string>("crush_location_hook");
+  if (crush_location_hook.length() == 0)
+    return seastar::now();
+
+  return seastar::file_exists(
+    crush_location_hook
+  ).then([this] (bool result) {
+    if (!result) {
+      std::stringstream errmsg;
+      errmsg << "the user define crush location hook: "
+             << local_conf().get_val<std::string>("crush_location_hook")
+             << " is not exists.";
+      logger().error("{}", errmsg.str());
+      throw std::runtime_error(errmsg.str());
+    }
+
+    return seastar::file_accessible(
+      local_conf().get_val<std::string>("crush_location_hook"),
+      seastar::access_flags::execute
+    ).then([this] (bool result) {
+      if (!result) {
+        std::stringstream errmsg;
+        errmsg << "the user define crush location hook: "
+               << local_conf().get_val<std::string>("crush_location_hook")
+               << " is not executable.";
+        logger().error("{}", errmsg.str());
+        throw std::runtime_error(errmsg.str());
+      }
+
+      seastar::experimental::spawn_parameters params = {
+        .argv = {
+          local_conf().get_val<std::string>("crush_location_hook"),
+          "--cluster",
+          local_conf()->cluster,
+          "--id",
+          local_conf()->name.get_id(),
+          "--type",
+          local_conf()->name.get_type_str()
+        }
+      };
+      return seastar::experimental::spawn_process(
+        local_conf().get_val<std::string>("crush_location_hook"),
+        std::move(params)
+      ).then([this] (auto process) {
+        auto stdout = process.stdout();
+        return do_with(
+          std::move(process),
+          std::move(stdout),
+          [this](auto& process, auto& stdout)
+        {
+          return stdout.read().then([] (seastar::temporary_buffer<char> buf) {
+            auto out = std::string(buf.get(), buf.size());
+            boost::algorithm::trim_if(out, boost::algorithm::is_any_of(" \n\r\t"));
+            return seastar::make_ready_future<std::string>(std::move(out));
+          }).then([&process, this] (auto out) {
+            return process.wait(
+            ).then([out = std::move(out), this] (auto wstatus) {
+              auto* exit_signal = std::get_if<seastar::experimental::process::wait_signaled>(&wstatus);
+              if (exit_signal != nullptr) {
+                std::stringstream errmsg;
+                errmsg << "the user define crush location hook: "
+                       << local_conf().get_val<std::string>("crush_location_hook")
+                       << " terminated, terminated signal is "
+                       << exit_signal->terminating_signal;
+                logger().error("{}", errmsg.str());
+                throw std::runtime_error(errmsg.str());
+              }
+
+              auto* exit_status = std::get_if<seastar::experimental::process::wait_exited>(&wstatus);
+              if (exit_status->exit_code != 0) {
+                std::stringstream errmsg;
+                errmsg << "the user define crush location hook: "
+                       << local_conf().get_val<std::string>("crush_location_hook")
+                       << " execute failed, exit_code is " << exit_status->exit_code;
+                logger().error("{}", errmsg.str());
+                throw std::runtime_error(errmsg.str());
+              } else {
+                _parse(out);
+              }
+              return seastar::now();
+            });
+          });
+        });
+      });
+    });
+  });
+}
+
+seastar::future<> CrushLocation::init_on_startup()
+{
+  if (local_conf().get_val<std::string>("crush_location").length()) {
+    return update_from_conf();
+  }
+  if (local_conf().get_val<std::string>("crush_location_hook").length()) {
+    return update_from_hook();
+  }
+
+  // start with a sane default
+  char hostname[HOST_NAME_MAX + 1];
+  int r = gethostname(hostname, sizeof(hostname));
+  if (r < 0)
+    strcpy(hostname, "unknown_host");
+  // use short hostname
+  for (unsigned i=0; hostname[i]; ++i) {
+    if (hostname[i] == '.') {
+      hostname[i] = '\0';
+      break;
+    }
+  }
+
+  loc.clear();
+  loc.insert(std::make_pair<std::string, std::string>("host", hostname));
+  loc.insert(std::make_pair<std::string, std::string>("root", "default"));
+  return seastar::now();
+}
+
+std::multimap<std::string,std::string> CrushLocation::get_location() const
+{
+  return loc;
+}
+
+std::ostream& operator<<(std::ostream& os, const CrushLocation& loc)
+{
+  bool first = true;
+  for (auto& [type, pos] : loc.get_location()) {
+    if (first) {
+      first = false;
+    } else {
+      os << ", ";
+    }
+    os << '"' << type << '=' << pos << '"';
+  }
+  return os;
+}
+
+}
diff --git a/src/crimson/crush/CrushLocation.h b/src/crimson/crush/CrushLocation.h
new file mode 100644 (file)
index 0000000..9dc9546
--- /dev/null
@@ -0,0 +1,37 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+#pragma once
+
+#include <iosfwd>
+#include <map>
+#include <string>
+#if FMT_VERSION >= 90000
+#include <fmt/ostream.h>
+#endif
+
+#include <seastar/core/seastar.hh>
+
+namespace crimson::crush {
+
+class CrushLocation {
+public:
+  explicit CrushLocation() {
+  }
+
+  seastar::future<> update_from_conf();  ///< refresh from config
+  seastar::future<> init_on_startup();
+  seastar::future<> update_from_hook();  ///< call hook, if present
+
+  std::multimap<std::string, std::string> get_location() const;
+
+private:
+  void _parse(const std::string& s);
+  std::multimap<std::string, std::string> loc;
+};
+
+std::ostream& operator<<(std::ostream& os, const CrushLocation& loc);
+}
+
+#if FMT_VERSION >= 90000
+template <> struct fmt::formatter<crimson::crush::CrushLocation> : fmt::ostream_formatter {};
+#endif