]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/crimson/admin/osd_admin.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / crimson / admin / osd_admin.cc
index ce6b6695d2892bb5fb79afbbcdb7f3c1ef558e4d..e8320458834773f0eb04333a8903bb6632522cfb 100644 (file)
 #include "crimson/osd/exceptions.h"
 #include "crimson/osd/osd.h"
 
+namespace {
+seastar::logger& logger()
+{
+  return crimson::get_logger(ceph_subsys_osd);
+}
+}  // namespace
+
+using std::string_view;
+using std::unique_ptr;
 using crimson::osd::OSD;
+using crimson::common::local_conf;
 using namespace crimson::common;
 
 namespace crimson::admin {
 
-using crimson::common::local_conf;
-
 template <class Hook, class... Args>
 std::unique_ptr<AdminSocketHook> make_asok_hook(Args&&... args)
 {
@@ -132,6 +140,35 @@ private:
 };
 template std::unique_ptr<AdminSocketHook> make_asok_hook<DumpPGStateHistory>(const crimson::osd::OSD& osd);
 
+//dump the contents of perfcounters in osd and store
+class DumpPerfCountersHook final: public AdminSocketHook {
+public:
+  explicit DumpPerfCountersHook() :
+    AdminSocketHook{"perfcounters_dump",
+                    "name=logger,type=CephString,req=false "
+                    "name=counter,type=CephString,req=false",
+                    "dump perfcounters in osd and store"}
+  {}
+  seastar::future<tell_result_t> call(const cmdmap_t& cmdmap,
+                                      std::string_view format,
+                                      ceph::bufferlist&& input) const final
+  {
+    std::unique_ptr<Formatter> f{Formatter::create(format,
+                                                   "json-pretty",
+                                                   "json-pretty")};
+    std::string logger;
+    std::string counter;
+    cmd_getval(cmdmap, "logger", logger);
+    cmd_getval(cmdmap, "counter", counter);
+
+    crimson::common::local_perf_coll().dump_formatted(f.get(), false, logger, counter);
+    return seastar::make_ready_future<tell_result_t>(std::move(f));
+  }
+};
+template std::unique_ptr<AdminSocketHook> make_asok_hook<DumpPerfCountersHook>();
+
+
+
 /**
  * A CephContext admin hook: calling assert (if allowed by
  * 'debug_asok_assert_abort')
@@ -161,31 +198,230 @@ template std::unique_ptr<AdminSocketHook> make_asok_hook<AssertAlwaysHook>();
 /**
 * A Seastar admin hook: fetching the values of configured metrics
 */
-class SeastarMetricsHook : public AdminSocketHook {
+class DumpMetricsHook : public AdminSocketHook {
 public:
- SeastarMetricsHook()  :
-   AdminSocketHook("perf dump_seastar",
-      "",
-      "dump current configured seastar metrics and their values")
- {}
- seastar::future<tell_result_t> call(const cmdmap_t& cmdmap,
-             std::string_view format,
-             ceph::bufferlist&& input) const final
- {
-   std::unique_ptr<Formatter> f{Formatter::create(format, "json-pretty", "json-pretty")};
-   f->open_object_section("perf_dump_seastar");
-   for (const auto& mf : seastar::scollectd::get_value_map()) {
-     for (const auto& m : mf.second) {
-       if (m.second && m.second->is_enabled()) {
-         auto& metric_function = m.second->get_function();
-         f->dump_float(m.second->get_id().full_name(), metric_function().d());
-       }
-     }
-   }
-   f->close_section();
-   return seastar::make_ready_future<tell_result_t>(std::move(f));
- }
+  DumpMetricsHook() :
+    AdminSocketHook("dump_metrics",
+                    "name=group,type=CephString,req=false",
+                    "dump current configured seastar metrics and their values")
+  {}
+  seastar::future<tell_result_t> call(const cmdmap_t& cmdmap,
+                                      std::string_view format,
+                                      ceph::bufferlist&& input) const final
+  {
+    std::unique_ptr<Formatter> f{Formatter::create(format, "json-pretty", "json-pretty")};
+    std::string prefix;
+    cmd_getval(cmdmap, "group", prefix);
+    f->open_object_section("metrics");
+    for (const auto& [full_name, metric_family]: seastar::scollectd::get_value_map()) {
+      if (!prefix.empty() && full_name.compare(0, prefix.size(), prefix) != 0) {
+        continue;
+      }
+      for (const auto& [labels, metric] : metric_family) {
+        if (metric && metric->is_enabled()) {
+          dump_metric_value(f.get(), full_name, *metric, labels);
+        }
+      }
+    }
+    f->close_section();
+    return seastar::make_ready_future<tell_result_t>(std::move(f));
+  }
+private:
+  using registered_metric = seastar::metrics::impl::registered_metric;
+  using data_type = seastar::metrics::impl::data_type;
+
+  static void dump_metric_value(Formatter* f,
+                                string_view full_name,
+                                const registered_metric& metric,
+                                const seastar::metrics::impl::labels_type& labels)
+  {
+    f->open_object_section(full_name);
+    for (const auto& [key, value] : labels) {
+      f->dump_string(key, value);
+    }
+    auto value_name = "value";
+    switch (auto v = metric(); v.type()) {
+    case data_type::GAUGE:
+      f->dump_float(value_name, v.d());
+      break;
+    case data_type::COUNTER:
+      f->dump_unsigned(value_name, v.ui());
+      break;
+    case data_type::DERIVE:
+      f->dump_int(value_name, v.i());
+      break;
+    case data_type::HISTOGRAM: {
+      f->open_object_section(value_name);
+      auto&& h = v.get_histogram();
+      f->dump_float("sum", h.sample_sum);
+      f->dump_unsigned("count", h.sample_count);
+      f->open_array_section("buckets");
+      for (auto i : h.buckets) {
+        f->open_object_section("bucket");
+        f->dump_float("le", i.upper_bound);
+        f->dump_unsigned("count", i.count);
+        f->close_section(); // "bucket"
+      }
+      {
+        f->open_object_section("bucket");
+        f->dump_string("le", "+Inf");
+        f->dump_unsigned("count", h.sample_count);
+        f->close_section();
+      }
+      f->close_section(); // "buckets"
+      f->close_section(); // value_name
+    }
+      break;
+    default:
+      std::abort();
+      break;
+    }
+    f->close_section(); // full_name
+  }
+};
+template std::unique_ptr<AdminSocketHook> make_asok_hook<DumpMetricsHook>();
+
+
+static ghobject_t test_ops_get_object_name(
+  const OSDMap& osdmap,
+  const cmdmap_t& cmdmap)
+{
+  auto pool = [&] {
+    auto pool_arg = cmd_getval<std::string>(cmdmap, "pool");
+    if (!pool_arg) {
+      throw std::invalid_argument{"No 'pool' specified"};
+    }
+    int64_t pool = osdmap.lookup_pg_pool_name(*pool_arg);
+    if (pool < 0 && std::isdigit((*pool_arg)[0])) {
+      pool = std::atoll(pool_arg->c_str());
+    }
+    if (pool < 0) {
+      // the return type of `fmt::format` is `std::string`
+      using namespace fmt::literals;
+      throw std::invalid_argument{
+        "Invalid pool '{}'"_format(*pool_arg)
+      };
+    }
+    return pool;
+  }();
+
+  auto [ objname, nspace, raw_pg ] = [&] {
+    auto obj_arg = cmd_getval<std::string>(cmdmap, "objname");
+    if (!obj_arg) {
+      throw std::invalid_argument{"No 'objname' specified"};
+    }
+    std::string objname, nspace;
+    if (std::size_t sep_pos = obj_arg->find_first_of('/');
+        sep_pos != obj_arg->npos) {
+      nspace = obj_arg->substr(0, sep_pos);
+      objname = obj_arg->substr(sep_pos+1);
+    } else {
+      objname = *obj_arg;
+    }
+    pg_t raw_pg;
+    if (object_locator_t oloc(pool, nspace);
+        osdmap.object_locator_to_pg(object_t(objname), oloc,  raw_pg) < 0) {
+      throw std::invalid_argument{"Invalid namespace/objname"};
+    }
+    return std::make_tuple(std::move(objname),
+                           std::move(nspace),
+                           std::move(raw_pg));
+  }();
+
+  auto shard_id = cmd_getval_or<int64_t>(cmdmap,
+                                        "shardid",
+                                        shard_id_t::NO_SHARD);
+
+  return ghobject_t{
+    hobject_t{
+      object_t{objname}, std::string{}, CEPH_NOSNAP, raw_pg.ps(), pool, nspace
+    },
+    ghobject_t::NO_GEN,
+    shard_id_t{static_cast<int8_t>(shard_id)}
+  };
+}
+
+// Usage:
+//   injectdataerr <pool> [namespace/]<obj-name> [shardid]
+class InjectDataErrorHook : public AdminSocketHook {
+public:
+  InjectDataErrorHook(crimson::osd::ShardServices& shard_services)  :
+   AdminSocketHook("injectdataerr",
+    "name=pool,type=CephString " \
+    "name=objname,type=CephObjectname " \
+    "name=shardid,type=CephInt,req=false,range=0|255",
+    "inject data error to an object"),
+   shard_services(shard_services) {
+  }
+
+  seastar::future<tell_result_t> call(const cmdmap_t& cmdmap,
+                                     std::string_view format,
+                                     ceph::bufferlist&& input) const final
+  {
+    ghobject_t obj;
+    try {
+      obj = test_ops_get_object_name(*shard_services.get_osdmap(), cmdmap);
+    } catch (const std::invalid_argument& e) {
+      logger().info("error during data error injection: {}", e.what());
+      return seastar::make_ready_future<tell_result_t>(-EINVAL,
+                                                      e.what());
+    }
+    return shard_services.get_store().inject_data_error(obj).then([=] {
+      logger().info("successfully injected data error for obj={}", obj);
+      ceph::bufferlist bl;
+      bl.append("ok"sv);
+      return seastar::make_ready_future<tell_result_t>(0,
+                                                      std::string{}, // no err
+                                                      std::move(bl));
+    });
+  }
+
+private:
+  crimson::osd::ShardServices& shard_services;
+};
+template std::unique_ptr<AdminSocketHook> make_asok_hook<InjectDataErrorHook>(
+  crimson::osd::ShardServices&);
+
+
+// Usage:
+//   injectmdataerr <pool> [namespace/]<obj-name> [shardid]
+class InjectMDataErrorHook : public AdminSocketHook {
+public:
+  InjectMDataErrorHook(crimson::osd::ShardServices& shard_services)  :
+   AdminSocketHook("injectmdataerr",
+    "name=pool,type=CephString " \
+    "name=objname,type=CephObjectname " \
+    "name=shardid,type=CephInt,req=false,range=0|255",
+    "inject data error to an object"),
+   shard_services(shard_services) {
+  }
+
+  seastar::future<tell_result_t> call(const cmdmap_t& cmdmap,
+                                     std::string_view format,
+                                     ceph::bufferlist&& input) const final
+  {
+    ghobject_t obj;
+    try {
+      obj = test_ops_get_object_name(*shard_services.get_osdmap(), cmdmap);
+    } catch (const std::invalid_argument& e) {
+      logger().info("error during metadata error injection: {}", e.what());
+      return seastar::make_ready_future<tell_result_t>(-EINVAL,
+                                                      e.what());
+    }
+    return shard_services.get_store().inject_mdata_error(obj).then([=] {
+      logger().info("successfully injected metadata error for obj={}", obj);
+      ceph::bufferlist bl;
+      bl.append("ok"sv);
+      return seastar::make_ready_future<tell_result_t>(0,
+                                                      std::string{}, // no err
+                                                      std::move(bl));
+    });
+  }
+
+private:
+  crimson::osd::ShardServices& shard_services;
 };
-template std::unique_ptr<AdminSocketHook> make_asok_hook<SeastarMetricsHook>();
+template std::unique_ptr<AdminSocketHook> make_asok_hook<InjectMDataErrorHook>(
+  crimson::osd::ShardServices&);
 
 } // namespace crimson::admin