]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
crimson/osd: add "ceph tell <pgid> <command>" support
authorKefu Chai <kchai@redhat.com>
Sun, 6 Sep 2020 06:53:22 +0000 (14:53 +0800)
committerKefu Chai <kchai@redhat.com>
Sun, 6 Sep 2020 13:49:34 +0000 (21:49 +0800)
* add an abstract class of `PGCommand` for `ceph tell <pgid> <command>`
* add two sample implementations for the pg tell commands.
  - "query"
  - "mark_unfound_lost"

Signed-off-by: Kefu Chai <kchai@redhat.com>
src/crimson/CMakeLists.txt
src/crimson/admin/pg_commands.cc [new file with mode: 0644]
src/crimson/admin/pg_commands.h [new file with mode: 0644]
src/crimson/osd/osd.cc

index 4a32540a12f7907c4714dab392fa31c142213db8..35ff74498a5f658d11f11eaee26d38543933e8ed 100644 (file)
@@ -14,6 +14,7 @@ set_target_properties(crimson::cflags PROPERTIES
 set(crimson_common_srcs
   admin/admin_socket.cc
   admin/osd_admin.cc
+  admin/pg_commands.cc
   common/assert.cc
   common/buffer_io.cc
   common/config_proxy.cc
diff --git a/src/crimson/admin/pg_commands.cc b/src/crimson/admin/pg_commands.cc
new file mode 100644 (file)
index 0000000..dacfd51
--- /dev/null
@@ -0,0 +1,159 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "crimson/admin/pg_commands.h"
+
+#include <memory>
+#include <string>
+#include <string_view>
+
+#include <fmt/format.h>
+#include <seastar/core/future.hh>
+
+#include "crimson/admin/admin_socket.h"
+#include "crimson/osd/osd.h"
+#include "crimson/osd/pg.h"
+
+
+using crimson::osd::OSD;
+using crimson::osd::PG;
+using namespace crimson::common;
+
+
+namespace crimson::admin::pg {
+
+class PGCommand : public AdminSocketHook {
+public:
+  // TODO: const correctness of osd
+  PGCommand(crimson::osd::OSD& osd,
+            std::string_view prefix,
+            std::string_view desc,
+            std::string_view help)
+      : AdminSocketHook{prefix, desc, help}, osd {osd}
+  {}
+  seastar::future<tell_result_t> call(const cmdmap_t& cmdmap,
+                                      std::string_view format,
+                                      ceph::bufferlist&& input) const final
+  {
+    // we have "ceph tell <pgid> <cmd>". and it is the ceph cli's responsibility
+    // to add "pgid" to the cmd dict. as rados_pg_command() does not set it for
+    // us. moreover, and "pgid" is not listed in the command description, as user
+    // command format does not follow the convention of "<prefix> [<args>,...]"
+    // so we have to verify it on the server side.
+    std::string pgid_str;
+    pg_t pgid;
+    if (!cmd_getval(cmdmap, "pgid", pgid_str)) {
+      return seastar::make_ready_future<tell_result_t>(
+        tell_result_t{-EINVAL, "no pgid specified"});
+    } else if (!pgid.parse(pgid_str.c_str())) {
+      return seastar::make_ready_future<tell_result_t>(
+        tell_result_t{-EINVAL, fmt::format("couldn't parse pgid '{}'", pgid_str)});
+    }
+    // am i the primary for this pg?
+    const auto osdmap = osd.get_shard_services().get_osdmap();
+    spg_t spg_id;
+    if (!osdmap->get_primary_shard(pgid, &spg_id)) {
+      return seastar::make_ready_future<tell_result_t>(tell_result_t{
+          -ENOENT, fmt::format("pgid '{}' does not exist", pgid_str)});
+    }
+    Ref<PG> pg = osd.get_pg(spg_id);
+    if (!pg) {
+      return seastar::make_ready_future<tell_result_t>(tell_result_t{
+        -ENOENT, fmt::format("i don't have pgid '{}'", spg_id)});
+    }
+    if (!pg->is_primary()) {
+      return seastar::make_ready_future<tell_result_t>(tell_result_t{
+        -EAGAIN, fmt::format("not primary for pgid '{}'", spg_id)});
+    }
+    return this->do_command(pg, cmdmap, format, std::move(input));
+  }
+
+private:
+  virtual seastar::future<tell_result_t>
+  do_command(Ref<PG> pg,
+             const cmdmap_t& cmdmap,
+             std::string_view format,
+             ceph::bufferlist&& input) const = 0;
+
+  OSD& osd;
+};
+
+class QueryCommand final : public PGCommand {
+public:
+  // TODO: const correctness of osd
+  explicit QueryCommand(crimson::osd::OSD& osd) :
+    PGCommand{osd,
+              "query",
+              "",
+              "show details of a specific pg"}
+  {}
+private:
+  seastar::future<tell_result_t>
+  do_command(Ref<PG> pg,
+             const cmdmap_t&,
+             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("pg");
+    pg->dump_primary(f.get());
+    f->close_section();
+    return seastar::make_ready_future<tell_result_t>(std::move(f));
+  }
+};
+
+class MarkUnfoundLostCommand final : public PGCommand {
+public:
+  explicit MarkUnfoundLostCommand(crimson::osd::OSD& osd) :
+    PGCommand{osd,
+              "mark_unfound_lost",
+              "name=pgid,type=CephPgid,req=false"
+              " name=mulcmd,type=CephChoices,strings=revert|delete",
+              "mark all unfound objects in this pg as lost, either"
+              " removing or reverting to a prior version if one is"
+              " available"}
+  {}
+  seastar::future<tell_result_t>
+  do_command(Ref<PG> pg,
+             const cmdmap_t& cmdmap,
+             std::string_view,
+             ceph::bufferlist&&) const final
+  {
+    // what to do with the unfound object specifically.
+    std::string cmd;
+    int op = -1;
+    cmd_getval(cmdmap, "mulcmd", cmd);
+    if (cmd == "revert") {
+      op = pg_log_entry_t::LOST_REVERT;
+    } else if (cmd == "delete") {
+      op = pg_log_entry_t::LOST_DELETE;
+    } else {
+      return seastar::make_ready_future<tell_result_t>(tell_result_t{
+        -EINVAL, "mode must be 'revert' or 'delete'; mark not yet implemented"});
+    }
+    return pg->mark_unfound_lost(op).then([] {
+      // TODO
+      return seastar::make_ready_future<tell_result_t>();
+    });
+  }
+};
+
+} // namespace crimson::admin::pg
+
+namespace crimson::admin {
+
+template <class Hook, class... Args>
+std::unique_ptr<AdminSocketHook> make_asok_hook(Args&&... args)
+{
+  return std::make_unique<Hook>(std::forward<Args>(args)...);
+}
+
+template std::unique_ptr<AdminSocketHook>
+make_asok_hook<crimson::admin::pg::QueryCommand>(crimson::osd::OSD& osd);
+
+template std::unique_ptr<AdminSocketHook>
+make_asok_hook<crimson::admin::pg::MarkUnfoundLostCommand>(crimson::osd::OSD& osd);
+
+} // namespace crimson::admin
diff --git a/src/crimson/admin/pg_commands.h b/src/crimson/admin/pg_commands.h
new file mode 100644 (file)
index 0000000..873b3c9
--- /dev/null
@@ -0,0 +1,10 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+#pragma once
+
+namespace crimson::admin::pg {
+
+class QueryCommand;
+class MarkUnfoundLostCommand;
+
+}  // namespace crimson::admin::pg
index 38fddaa987c8966221b53150a822ab1e85bc4eb4..a170d7ccf77993b4a9edd48a83e605e28507ecd9 100644 (file)
@@ -38,6 +38,7 @@
 #include "osd/PeeringState.h"
 
 #include "crimson/admin/osd_admin.h"
+#include "crimson/admin/pg_commands.h"
 #include "crimson/common/exception.h"
 #include "crimson/mon/MonClient.h"
 #include "crimson/net/Connection.h"
@@ -432,7 +433,10 @@ seastar::future<> OSD::start_asok_admin()
       asok->register_command(make_asok_hook<SendBeaconHook>(*this)),
       asok->register_command(make_asok_hook<FlushPgStatsHook>(*this)),
       asok->register_command(make_asok_hook<DumpPGStateHistory>(std::as_const(*this))),
-      asok->register_command(make_asok_hook<SeastarMetricsHook>()));
+      asok->register_command(make_asok_hook<SeastarMetricsHook>()),
+      // PG commands
+      asok->register_command(make_asok_hook<pg::QueryCommand>(*this)),
+      asok->register_command(make_asok_hook<pg::MarkUnfoundLostCommand>(*this)));
   }).then_unpack([] {
     return seastar::now();
   });