]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/mgr/BaseMgrModule.cc
import ceph quincy 17.2.6
[ceph.git] / ceph / src / mgr / BaseMgrModule.cc
index 59bbe8f393edb39fe7d9f2d21cec2cc74203a7b3..4fb5b250b98b9cc79c404a8a27a454fae10f606a 100644 (file)
@@ -25,7 +25,9 @@
 #include "mon/MonClient.h"
 #include "common/errno.h"
 #include "common/version.h"
+#include "mgr/Types.h"
 
+#include "PyUtil.h"
 #include "BaseMgrModule.h"
 #include "Gil.h"
 
@@ -36,6 +38,8 @@
 
 #define PLACEHOLDER ""
 
+using std::list;
+using std::string;
 
 typedef struct {
   PyObject_HEAD
@@ -89,9 +93,9 @@ public:
       auto set_fn = PyObject_GetAttrString(python_completion, "complete");
       ceph_assert(set_fn != nullptr);
 
-      auto pyR = PyInt_FromLong(r);
-      auto pyOutBl = PyString_FromString(outbl.to_str().c_str());
-      auto pyOutS = PyString_FromString(outs.c_str());
+      auto pyR = PyLong_FromLong(r);
+      auto pyOutBl = PyUnicode_FromString(outbl.to_str().c_str());
+      auto pyOutS = PyUnicode_FromString(outs.c_str());
       auto args = PyTuple_Pack(3, pyR, pyOutBl, pyOutS);
       Py_DECREF(pyR);
       Py_DECREF(pyOutBl);
@@ -123,12 +127,20 @@ ceph_send_command(BaseMgrModule *self, PyObject *args)
 
   char *cmd_json = nullptr;
   char *tag = nullptr;
+  char *inbuf_ptr = nullptr;
+  Py_ssize_t inbuf_len = 0;
+  bufferlist inbuf = {};
+
   PyObject *completion = nullptr;
-  if (!PyArg_ParseTuple(args, "Ossss:ceph_send_command",
-        &completion, &type, &name, &cmd_json, &tag)) {
+  if (!PyArg_ParseTuple(args, "Ossssz#:ceph_send_command",
+        &completion, &type, &name, &cmd_json, &tag, &inbuf_ptr, &inbuf_len)) {
     return nullptr;
   }
 
+  if (inbuf_ptr) {
+    inbuf.append(inbuf_ptr, (unsigned)inbuf_len);
+  }
+
   auto set_fn = PyObject_GetAttrString(completion, "complete");
   if (set_fn == nullptr) {
     ceph_abort();  // TODO raise python exception instead
@@ -151,18 +163,17 @@ ceph_send_command(BaseMgrModule *self, PyObject *args)
     // TODO: enhance MCommand interface so that it returns
     // latest cluster map versions on completion, and callers
     // can wait for those.
-    auto c = new FunctionContext([command_c, self](int command_r){
+    auto c = new LambdaContext([command_c, self](int command_r){
       self->py_modules->get_objecter().wait_for_latest_osdmap(
-          new FunctionContext([command_c, command_r](int wait_r){
-            command_c->complete(command_r);
-          })
-      );
+       [command_c, command_r](boost::system::error_code) {
+         command_c->complete(command_r);
+       });
     });
 
     self->py_modules->get_monc().start_mon_command(
         name,
         {cmd_json},
-        {},
+        inbuf,
         &command_c->outbl,
         &command_c->outs,
         new C_OnFinisher(c, &self->py_modules->cmd_finisher));
@@ -182,16 +193,19 @@ ceph_send_command(BaseMgrModule *self, PyObject *args)
     self->py_modules->get_objecter().osd_command(
         osd_id,
         {cmd_json},
-        {},
+        inbuf,
         &tid,
-        &command_c->outbl,
-        &command_c->outs,
-        new C_OnFinisher(command_c, &self->py_modules->cmd_finisher));
+       [command_c, f = &self->py_modules->cmd_finisher]
+       (boost::system::error_code ec, std::string s, ceph::buffer::list bl) {
+         command_c->outs = std::move(s);
+         command_c->outbl = std::move(bl);
+         f->queue(command_c);
+       });
   } else if (std::string(type) == "mds") {
     int r = self->py_modules->get_client().mds_command(
         name,
         {cmd_json},
-        {},
+        inbuf,
         &command_c->outbl,
         &command_c->outs,
         new C_OnFinisher(command_c, &self->py_modules->cmd_finisher));
@@ -217,11 +231,14 @@ ceph_send_command(BaseMgrModule *self, PyObject *args)
     self->py_modules->get_objecter().pg_command(
         pgid,
         {cmd_json},
-        {},
+        inbuf,
         &tid,
-        &command_c->outbl,
-        &command_c->outs,
-        new C_OnFinisher(command_c, &self->py_modules->cmd_finisher));
+       [command_c, f = &self->py_modules->cmd_finisher]
+       (boost::system::error_code ec, std::string s, ceph::buffer::list bl) {
+         command_c->outs = std::move(s);
+         command_c->outbl = std::move(bl);
+         f->queue(command_c);
+       });
     PyEval_RestoreThread(tstate);
     return nullptr;
   } else {
@@ -267,6 +284,7 @@ ceph_set_health_checks(BaseMgrModule *self, PyObject *args)
     health_status_t severity = HEALTH_OK;
     string summary;
     list<string> detail;
+    int64_t count = 0;
     PyObject *infols = PyDict_Items(check_info);
     for (int j = 0; j < PyList_Size(infols); ++j) {
       PyObject *pair = PyList_GET_ITEM(infols, j);
@@ -284,24 +302,32 @@ ceph_set_health_checks(BaseMgrModule *self, PyObject *args)
       }
       string ks(k);
       if (ks == "severity") {
-       if (!PyString_Check(v)) {
+       if (!PyUnicode_Check(v)) {
          derr << __func__ << " check " << check_name
               << " severity value not string" << dendl;
          continue;
        }
-       string vs(PyString_AsString(v));
-       if (vs == "warning") {
+       if (const string vs = PyUnicode_AsUTF8(v); vs == "warning") {
          severity = HEALTH_WARN;
        } else if (vs == "error") {
          severity = HEALTH_ERR;
        }
       } else if (ks == "summary") {
-       if (!PyString_Check(v)) {
+       if (!PyUnicode_Check(v)) {
+         derr << __func__ << " check " << check_name
+              << " summary value not [unicode] string" << dendl;
+         continue;
+       } else {
+         summary = PyUnicode_AsUTF8(v);
+       }
+      } else if (ks == "count") {
+       if (PyLong_Check(v)) {
+         count = PyLong_AsLong(v);
+       } else {
          derr << __func__ << " check " << check_name
-              << " summary value not string" << dendl;
+              << " count value not int" << dendl;
          continue;
        }
-       summary = PyString_AsString(v);
       } else if (ks == "detail") {
        if (!PyList_Check(v)) {
          derr << __func__ << " check " << check_name
@@ -310,19 +336,20 @@ ceph_set_health_checks(BaseMgrModule *self, PyObject *args)
        }
        for (int k = 0; k < PyList_Size(v); ++k) {
          PyObject *di = PyList_GET_ITEM(v, k);
-         if (!PyString_Check(di)) {
+         if (!PyUnicode_Check(di)) {
            derr << __func__ << " check " << check_name
-                << " detail item " << k << " not a string" << dendl;
+                << " detail item " << k << " not a [unicode] string" << dendl;
            continue;
+         } else {
+           detail.push_back(PyUnicode_AsUTF8(di));
          }
-         detail.push_back(PyString_AsString(di));
        }
       } else {
        derr << __func__ << " check " << check_name
             << " unexpected key " << k << dendl;
       }
     }
-    auto& d = out_checks.add(check_name, severity, summary);
+    auto& d = out_checks.add(check_name, severity, summary, count);
     d.detail.swap(detail);
   }
 
@@ -332,12 +359,10 @@ ceph_set_health_checks(BaseMgrModule *self, PyObject *args)
   out_checks.dump(&jf);
   jf.flush(*_dout);
   *_dout << dendl;
-
-  PyThreadState *tstate = PyEval_SaveThread();
-  self->py_modules->set_health_checks(self->this_module->get_name(),
-                                      std::move(out_checks));
-  PyEval_RestoreThread(tstate);
-  
+  without_gil([&] {
+    self->py_modules->set_health_checks(self->this_module->get_name(),
+                                       std::move(out_checks));
+  });
   Py_RETURN_NONE;
 }
 
@@ -350,7 +375,7 @@ ceph_state_get(BaseMgrModule *self, PyObject *args)
     return NULL;
   }
 
-  return self->py_modules->get_python(what);
+  return self->py_modules->cacheable_get_python(what);
 }
 
 
@@ -372,7 +397,7 @@ ceph_get_server(BaseMgrModule *self, PyObject *args)
 static PyObject*
 ceph_get_mgr_id(BaseMgrModule *self, PyObject *args)
 {
-  return PyString_FromString(g_conf()->name.get_id().c_str());
+  return PyUnicode_FromString(g_conf()->name.get_id().c_str());
 }
 
 static PyObject*
@@ -384,17 +409,41 @@ ceph_option_get(BaseMgrModule *self, PyObject *args)
     return nullptr;
   }
 
-  std::string value;
-  int r = g_conf().get_val(string(what), &value);
-  if (r >= 0) {
+  const Option *opt = g_conf().find_option(string(what));
+  if (opt) {
+    std::string value;
+    switch (int r = g_conf().get_val(string(what), &value); r) {
+    case -ENOMEM:
+      PyErr_NoMemory();
+      return nullptr;
+    case -ENAMETOOLONG:
+      PyErr_SetString(PyExc_ValueError, "value too long");
+      return nullptr;
+    default:
+      ceph_assert(r == 0);
+      break;
+    }
     dout(10) << "ceph_option_get " << what << " found: " << value << dendl;
-    return PyString_FromString(value.c_str());
+    return get_python_typed_option_value(opt->type, value);
   } else {
     dout(4) << "ceph_option_get " << what << " not found " << dendl;
-    Py_RETURN_NONE;
+    PyErr_Format(PyExc_KeyError, "option not found: %s", what);
+    return nullptr;
   }
 }
 
+static PyObject*
+ceph_foreign_option_get(BaseMgrModule *self, PyObject *args)
+{
+  char *who = nullptr;
+  char *what = nullptr;
+  if (!PyArg_ParseTuple(args, "ss:ceph_foreign_option_get", &who, &what)) {
+    derr << "Invalid args!" << dendl;
+    return nullptr;
+  }
+  return self->py_modules->get_foreign_config(who, what);
+}
+
 static PyObject*
 ceph_get_module_option(BaseMgrModule *self, PyObject *args)
 {
@@ -439,14 +488,17 @@ ceph_set_module_option(BaseMgrModule *self, PyObject *args)
     derr << "Invalid args!" << dendl;
     return nullptr;
   }
-  boost::optional<string> val;
+  std::optional<string> val;
   if (value) {
     val = value;
   }
-  PyThreadState *tstate = PyEval_SaveThread();
-  self->py_modules->set_config(module, key, val);
-  PyEval_RestoreThread(tstate);
-
+  auto [ret, msg] = without_gil([&] {
+    return self->py_modules->set_config(module, key, val);
+  });
+  if (ret) {
+    PyErr_SetString(PyExc_ValueError, msg.c_str());
+    return nullptr;
+  }
   Py_RETURN_NONE;
 }
 
@@ -464,7 +516,7 @@ ceph_store_get(BaseMgrModule *self, PyObject *args)
       what, &value);
   if (found) {
     dout(10) << "ceph_store_get " << what << " found: " << value.c_str() << dendl;
-    return PyString_FromString(value.c_str());
+    return PyUnicode_FromString(value.c_str());
   } else {
     dout(4) << "ceph_store_get " << what << " not found " << dendl;
     Py_RETURN_NONE;
@@ -479,14 +531,13 @@ ceph_store_set(BaseMgrModule *self, PyObject *args)
   if (!PyArg_ParseTuple(args, "sz:ceph_store_set", &key, &value)) {
     return nullptr;
   }
-  boost::optional<string> val;
+  std::optional<string> val;
   if (value) {
     val = value;
   }
-  PyThreadState *tstate = PyEval_SaveThread();
-  self->py_modules->set_store(self->this_module->get_name(), key, val);
-  PyEval_RestoreThread(tstate);
-
+  without_gil([&] {
+    self->py_modules->set_store(self->this_module->get_name(), key, val);
+  });
   Py_RETURN_NONE;
 }
 
@@ -516,15 +567,14 @@ get_daemon_status(BaseMgrModule *self, PyObject *args)
 static PyObject*
 ceph_log(BaseMgrModule *self, PyObject *args)
 {
-  int level = 0;
   char *record = nullptr;
-  if (!PyArg_ParseTuple(args, "is:log", &level, &record)) {
+  if (!PyArg_ParseTuple(args, "s:log", &record)) {
     return nullptr;
   }
 
   ceph_assert(self->this_module);
 
-  self->this_module->log(level, record);
+  self->this_module->log(record);
 
   Py_RETURN_NONE;
 }
@@ -535,34 +585,46 @@ ceph_cluster_log(BaseMgrModule *self, PyObject *args)
   int prio = 0;
   char *channel = nullptr;
   char *message = nullptr;
-  std::vector<std::string> channels = { "audit", "cluster" };
 
   if (!PyArg_ParseTuple(args, "sis:ceph_cluster_log", &channel, &prio, &message)) {
     return nullptr;
   }
+  without_gil([&] {
+    self->py_modules->cluster_log(channel, (clog_type)prio, message);
+  });
+  Py_RETURN_NONE;
+}
 
-  if (std::find(channels.begin(), channels.end(), std::string(channel)) == channels.end()) {
-    std::string msg("Unknown channel: ");
-    msg.append(channel);
-    PyErr_SetString(PyExc_ValueError, msg.c_str());
-    return nullptr;
-  }
+static PyObject *
+ceph_get_version(BaseMgrModule *self, PyObject *args)
+{
+  return PyUnicode_FromString(pretty_version_to_str().c_str());
+}
 
-  PyThreadState *tstate = PyEval_SaveThread();
-  self->py_modules->cluster_log(channel, (clog_type)prio, message);
-  PyEval_RestoreThread(tstate);
+static PyObject *
+ceph_get_ceph_conf_path(BaseMgrModule *self, PyObject *args)
+{
+  return PyUnicode_FromString(g_conf().get_conf_path().c_str());
+}
 
-  Py_RETURN_NONE;
+static PyObject *
+ceph_get_release_name(BaseMgrModule *self, PyObject *args)
+{
+  return PyUnicode_FromString(ceph_release_to_str());
 }
 
 static PyObject *
-ceph_get_version(BaseMgrModule *self, PyObject *args)
+ceph_lookup_release_name(BaseMgrModule *self, PyObject *args)
 {
-  return PyString_FromString(pretty_version_to_str().c_str());
+  int major = 0;
+  if (!PyArg_ParseTuple(args, "i:ceph_lookup_release_name", &major)) {
+    return nullptr;
+  }
+  return PyUnicode_FromString(ceph_release_name(major));
 }
 
 static PyObject *
-ceph_get_context(BaseMgrModule *self, PyObject *args)
+ceph_get_context(BaseMgrModule *self)
 {
   return self->py_modules->get_context();
 }
@@ -608,6 +670,13 @@ get_perf_schema(BaseMgrModule *self, PyObject *args)
   return self->py_modules->get_perf_schema_python(type_str, svc_id);
 }
 
+static PyObject*
+ceph_get_rocksdb_version(BaseMgrModule *self)
+{
+  return self->py_modules->get_rocksdb_version();
+}
+
+
 static PyObject *
 ceph_get_osdmap(BaseMgrModule *self, PyObject *args)
 {
@@ -622,14 +691,27 @@ ceph_set_uri(BaseMgrModule *self, PyObject *args)
         &svc_str)) {
     return nullptr;
   }
-
   // We call down into PyModules even though we have a MgrPyModule
   // reference here, because MgrPyModule's fields are protected
   // by PyModules' lock.
-  PyThreadState *tstate = PyEval_SaveThread();
-  self->py_modules->set_uri(self->this_module->get_name(), svc_str);
-  PyEval_RestoreThread(tstate);
+  without_gil([&] {
+    self->py_modules->set_uri(self->this_module->get_name(), svc_str);
+  });
+  Py_RETURN_NONE;
+}
 
+static PyObject*
+ceph_set_wear_level(BaseMgrModule *self, PyObject *args)
+{
+  char *devid = nullptr;
+  float wear_level;
+  if (!PyArg_ParseTuple(args, "sf:ceph_set_wear_level",
+                       &devid, &wear_level)) {
+    return nullptr;
+  }
+  without_gil([&] {
+    self->py_modules->set_device_wear_level(devid, wear_level);
+  });
   Py_RETURN_NONE;
 }
 
@@ -649,15 +731,14 @@ ceph_update_progress_event(BaseMgrModule *self, PyObject *args)
   char *evid = nullptr;
   char *desc = nullptr;
   float progress = 0.0;
-  if (!PyArg_ParseTuple(args, "ssf:ceph_update_progress_event",
-                       &evid, &desc, &progress)) {
+  bool add_to_ceph_s = false;
+  if (!PyArg_ParseTuple(args, "ssfb:ceph_update_progress_event",
+                       &evid, &desc, &progress, &add_to_ceph_s)) {
     return nullptr;
   }
-
-  PyThreadState *tstate = PyEval_SaveThread();
-  self->py_modules->update_progress_event(evid, desc, progress);
-  PyEval_RestoreThread(tstate);
-
+  without_gil([&] {
+    self->py_modules->update_progress_event(evid, desc, progress, add_to_ceph_s);
+  });
   Py_RETURN_NONE;
 }
 
@@ -669,21 +750,18 @@ ceph_complete_progress_event(BaseMgrModule *self, PyObject *args)
                        &evid)) {
     return nullptr;
   }
-
-  PyThreadState *tstate = PyEval_SaveThread();
-  self->py_modules->complete_progress_event(evid);
-  PyEval_RestoreThread(tstate);
-
+  without_gil([&] {
+    self->py_modules->complete_progress_event(evid);
+  });
   Py_RETURN_NONE;
 }
 
 static PyObject*
 ceph_clear_all_progress_events(BaseMgrModule *self, PyObject *args)
 {
-  PyThreadState *tstate = PyEval_SaveThread();
-  self->py_modules->clear_all_progress_events();
-  PyEval_RestoreThread(tstate);
-
+  without_gil([&] {
+    self->py_modules->clear_all_progress_events();
+  });
   Py_RETURN_NONE;
 }
 
@@ -831,12 +909,12 @@ ceph_add_osd_perf_query(BaseMgrModule *self, PyObject *args)
             Py_RETURN_NONE;
           }
           if (param_name == NAME_SUB_KEY_TYPE) {
-            if (!PyString_Check(param_value)) {
+            if (!PyUnicode_Check(param_value)) {
               derr << __func__ << " query " << query_param_name << " item " << j
                    << " contains invalid param " << param_name << dendl;
               Py_RETURN_NONE;
             }
-            auto type = PyString_AsString(param_value);
+            auto type = PyUnicode_AsUTF8(param_value);
             auto it = sub_key_types.find(type);
             if (it == sub_key_types.end()) {
               derr << __func__ << " query " << query_param_name << " item " << j
@@ -845,14 +923,14 @@ ceph_add_osd_perf_query(BaseMgrModule *self, PyObject *args)
             }
             d.type = it->second;
           } else if (param_name == NAME_SUB_KEY_REGEX) {
-            if (!PyString_Check(param_value)) {
+            if (!PyUnicode_Check(param_value)) {
               derr << __func__ << " query " << query_param_name << " item " << j
                    << " contains invalid param " << param_name << dendl;
               Py_RETURN_NONE;
             }
-            d.regex_str = PyString_AsString(param_value);
+            d.regex_str = PyUnicode_AsUTF8(param_value);
             try {
-              d.regex = {d.regex_str.c_str()};
+              d.regex = d.regex_str.c_str();
             } catch (const std::regex_error& e) {
               derr << __func__ << " query " << query_param_name << " item " << j
                    << " contains invalid regex " << d.regex_str << dendl;
@@ -885,12 +963,12 @@ ceph_add_osd_perf_query(BaseMgrModule *self, PyObject *args)
       }
       for (int j = 0; j < PyList_Size(query_param_val); j++) {
         PyObject *py_type = PyList_GET_ITEM(query_param_val, j);
-        if (!PyString_Check(py_type)) {
+        if (!PyUnicode_Check(py_type)) {
           derr << __func__ << " query " << query_param_name << " item " << j
                << " not a string" << dendl;
           Py_RETURN_NONE;
         }
-        auto type = PyString_AsString(py_type);
+        auto type = PyUnicode_AsUTF8(py_type);
         auto it = counter_types.find(type);
         if (it == counter_types.end()) {
           derr << __func__ << " query " << query_param_name << " item " << type
@@ -921,12 +999,12 @@ ceph_add_osd_perf_query(BaseMgrModule *self, PyObject *args)
         }
 
         if (limit_param_name == NAME_LIMIT_ORDER_BY) {
-          if (!PyString_Check(limit_param_val)) {
+          if (!PyUnicode_Check(limit_param_val)) {
             derr << __func__ << " " << limit_param_name << " not a string"
                  << dendl;
             Py_RETURN_NONE;
           }
-          auto order_by = PyString_AsString(limit_param_val);
+          auto order_by = PyUnicode_AsUTF8(limit_param_val);
           auto it = counter_types.find(order_by);
           if (it == counter_types.end()) {
             derr << __func__ << " limit " << limit_param_name
@@ -935,11 +1013,7 @@ ceph_add_osd_perf_query(BaseMgrModule *self, PyObject *args)
           }
           limit->order_by = it->second;
         } else if (limit_param_name == NAME_LIMIT_MAX_COUNT) {
-#if PY_MAJOR_VERSION <= 2
-          if (!PyInt_Check(limit_param_val) && !PyLong_Check(limit_param_val)) {
-#else
           if (!PyLong_Check(limit_param_val)) {
-#endif
             derr << __func__ << " " << limit_param_name << " not an int"
                  << dendl;
             Py_RETURN_NONE;
@@ -979,7 +1053,7 @@ ceph_add_osd_perf_query(BaseMgrModule *self, PyObject *args)
 static PyObject*
 ceph_remove_osd_perf_query(BaseMgrModule *self, PyObject *args)
 {
-  OSDPerfMetricQueryID query_id;
+  MetricQueryID query_id;
   if (!PyArg_ParseTuple(args, "i:ceph_remove_osd_perf_query", &query_id)) {
     derr << "Invalid args!" << dendl;
     return nullptr;
@@ -992,7 +1066,7 @@ ceph_remove_osd_perf_query(BaseMgrModule *self, PyObject *args)
 static PyObject*
 ceph_get_osd_perf_counters(BaseMgrModule *self, PyObject *args)
 {
-  OSDPerfMetricQueryID query_id;
+  MetricQueryID query_id;
   if (!PyArg_ParseTuple(args, "i:ceph_get_osd_perf_counters", &query_id)) {
     derr << "Invalid args!" << dendl;
     return nullptr;
@@ -1001,6 +1075,348 @@ ceph_get_osd_perf_counters(BaseMgrModule *self, PyObject *args)
   return self->py_modules->get_osd_perf_counters(query_id);
 }
 
+// MDS perf query interface -- mostly follows ceph_add_osd_perf_query()
+// style
+
+static PyObject*
+ceph_add_mds_perf_query(BaseMgrModule *self, PyObject *args)
+{
+  static const std::string NAME_KEY_DESCRIPTOR = "key_descriptor";
+  static const std::string NAME_COUNTERS_DESCRIPTORS =
+      "performance_counter_descriptors";
+  static const std::string NAME_LIMIT = "limit";
+  static const std::string NAME_SUB_KEY_TYPE = "type";
+  static const std::string NAME_SUB_KEY_REGEX = "regex";
+  static const std::string NAME_LIMIT_ORDER_BY = "order_by";
+  static const std::string NAME_LIMIT_MAX_COUNT = "max_count";
+  static const std::map<std::string, MDSPerfMetricSubKeyType> sub_key_types = {
+    {"mds_rank", MDSPerfMetricSubKeyType::MDS_RANK},
+    {"client_id", MDSPerfMetricSubKeyType::CLIENT_ID},
+  };
+  static const std::map<std::string, MDSPerformanceCounterType> counter_types = {
+    {"cap_hit", MDSPerformanceCounterType::CAP_HIT_METRIC},
+    {"read_latency", MDSPerformanceCounterType::READ_LATENCY_METRIC},
+    {"write_latency", MDSPerformanceCounterType::WRITE_LATENCY_METRIC},
+    {"metadata_latency", MDSPerformanceCounterType::METADATA_LATENCY_METRIC},
+    {"dentry_lease", MDSPerformanceCounterType::DENTRY_LEASE_METRIC},
+    {"opened_files", MDSPerformanceCounterType::OPENED_FILES_METRIC},
+    {"pinned_icaps", MDSPerformanceCounterType::PINNED_ICAPS_METRIC},
+    {"opened_inodes", MDSPerformanceCounterType::OPENED_INODES_METRIC},
+    {"read_io_sizes", MDSPerformanceCounterType::READ_IO_SIZES_METRIC},
+    {"write_io_sizes", MDSPerformanceCounterType::WRITE_IO_SIZES_METRIC},
+    {"avg_read_latency", MDSPerformanceCounterType::AVG_READ_LATENCY_METRIC},
+    {"stdev_read_latency", MDSPerformanceCounterType::STDEV_READ_LATENCY_METRIC},
+    {"avg_write_latency", MDSPerformanceCounterType::AVG_WRITE_LATENCY_METRIC},
+    {"stdev_write_latency", MDSPerformanceCounterType::STDEV_WRITE_LATENCY_METRIC},
+    {"avg_metadata_latency", MDSPerformanceCounterType::AVG_METADATA_LATENCY_METRIC},
+    {"stdev_metadata_latency", MDSPerformanceCounterType::STDEV_METADATA_LATENCY_METRIC},
+  };
+
+  PyObject *py_query = nullptr;
+  if (!PyArg_ParseTuple(args, "O:ceph_add_mds_perf_query", &py_query)) {
+    derr << "Invalid args!" << dendl;
+    return nullptr;
+  }
+  if (!PyDict_Check(py_query)) {
+    derr << __func__ << " arg not a dict" << dendl;
+    Py_RETURN_NONE;
+  }
+
+  PyObject *query_params = PyDict_Items(py_query);
+  MDSPerfMetricQuery query;
+  std::optional<MDSPerfMetricLimit> limit;
+
+  // {
+  //   'key_descriptor': [
+  //     {'type': subkey_type, 'regex': regex_pattern},
+  //     ...
+  //   ],
+  //   'performance_counter_descriptors': [
+  //     list, of, descriptor, types
+  //   ],
+  //   'limit': {'order_by': performance_counter_type, 'max_count': n},
+  // }
+
+  for (int i = 0; i < PyList_Size(query_params); ++i) {
+    PyObject *kv = PyList_GET_ITEM(query_params, i);
+    char *query_param_name = nullptr;
+    PyObject *query_param_val = nullptr;
+    if (!PyArg_ParseTuple(kv, "sO:pair", &query_param_name, &query_param_val)) {
+      derr << __func__ << " dict item " << i << " not a size 2 tuple" << dendl;
+      Py_RETURN_NONE;
+    }
+    if (query_param_name == NAME_KEY_DESCRIPTOR) {
+      if (!PyList_Check(query_param_val)) {
+        derr << __func__ << " " << query_param_name << " not a list" << dendl;
+        Py_RETURN_NONE;
+      }
+      for (int j = 0; j < PyList_Size(query_param_val); j++) {
+        PyObject *sub_key = PyList_GET_ITEM(query_param_val, j);
+        if (!PyDict_Check(sub_key)) {
+          derr << __func__ << " query " << query_param_name << " item " << j
+               << " not a dict" << dendl;
+          Py_RETURN_NONE;
+        }
+        MDSPerfMetricSubKeyDescriptor d;
+        PyObject *sub_key_params = PyDict_Items(sub_key);
+        for (int k = 0; k < PyList_Size(sub_key_params); ++k) {
+          PyObject *pair = PyList_GET_ITEM(sub_key_params, k);
+          if (!PyTuple_Check(pair)) {
+            derr << __func__ << " query " << query_param_name << " item " << j
+                 << " pair " << k << " not a tuple" << dendl;
+            Py_RETURN_NONE;
+          }
+          char *param_name = nullptr;
+          PyObject *param_value = nullptr;
+          if (!PyArg_ParseTuple(pair, "sO:pair", &param_name, &param_value)) {
+            derr << __func__ << " query " << query_param_name << " item " << j
+                 << " pair " << k << " not a size 2 tuple" << dendl;
+            Py_RETURN_NONE;
+          }
+          if (param_name == NAME_SUB_KEY_TYPE) {
+            if (!PyUnicode_Check(param_value)) {
+              derr << __func__ << " query " << query_param_name << " item " << j
+                   << " contains invalid param " << param_name << dendl;
+              Py_RETURN_NONE;
+            }
+            auto type = PyUnicode_AsUTF8(param_value);
+            auto it = sub_key_types.find(type);
+            if (it == sub_key_types.end()) {
+              derr << __func__ << " query " << query_param_name << " item " << j
+                   << " contains invalid type " << dendl;
+              Py_RETURN_NONE;
+            }
+            d.type = it->second;
+          } else if (param_name == NAME_SUB_KEY_REGEX) {
+            if (!PyUnicode_Check(param_value)) {
+              derr << __func__ << " query " << query_param_name << " item " << j
+                   << " contains invalid param " << param_name << dendl;
+              Py_RETURN_NONE;
+            }
+            d.regex_str = PyUnicode_AsUTF8(param_value);
+            try {
+              d.regex = d.regex_str.c_str();
+            } catch (const std::regex_error& e) {
+              derr << __func__ << " query " << query_param_name << " item " << j
+                   << " contains invalid regex " << d.regex_str << dendl;
+              Py_RETURN_NONE;
+            }
+            if (d.regex.mark_count() == 0) {
+              derr << __func__ << " query " << query_param_name << " item " << j
+                   << " regex " << d.regex_str << ": no capturing groups"
+                   << dendl;
+              Py_RETURN_NONE;
+            }
+          } else {
+            derr << __func__ << " query " << query_param_name << " item " << j
+                 << " contains invalid param " << param_name << dendl;
+            Py_RETURN_NONE;
+          }
+        }
+        if (d.type == static_cast<MDSPerfMetricSubKeyType>(-1) ||
+            d.regex_str.empty()) {
+          derr << __func__ << " query " << query_param_name << " item " << i
+               << " invalid" << dendl;
+          Py_RETURN_NONE;
+        }
+        query.key_descriptor.push_back(d);
+      }
+    } else if (query_param_name == NAME_COUNTERS_DESCRIPTORS) {
+      if (!PyList_Check(query_param_val)) {
+        derr << __func__ << " " << query_param_name << " not a list" << dendl;
+        Py_RETURN_NONE;
+      }
+      for (int j = 0; j < PyList_Size(query_param_val); j++) {
+        PyObject *py_type = PyList_GET_ITEM(query_param_val, j);
+        if (!PyUnicode_Check(py_type)) {
+          derr << __func__ << " query " << query_param_name << " item " << j
+               << " not a string" << dendl;
+          Py_RETURN_NONE;
+        }
+        auto type = PyUnicode_AsUTF8(py_type);
+        auto it = counter_types.find(type);
+        if (it == counter_types.end()) {
+          derr << __func__ << " query " << query_param_name << " item " << type
+               << " is not valid type" << dendl;
+          Py_RETURN_NONE;
+        }
+        query.performance_counter_descriptors.push_back(it->second);
+      }
+    } else if (query_param_name == NAME_LIMIT) {
+      if (!PyDict_Check(query_param_val)) {
+        derr << __func__ << " query " << query_param_name << " not a dict"
+             << dendl;
+        Py_RETURN_NONE;
+      }
+
+      limit = MDSPerfMetricLimit();
+      PyObject *limit_params = PyDict_Items(query_param_val);
+
+      for (int j = 0; j < PyList_Size(limit_params); ++j) {
+        PyObject *kv = PyList_GET_ITEM(limit_params, j);
+        char *limit_param_name = nullptr;
+        PyObject *limit_param_val = nullptr;
+        if (!PyArg_ParseTuple(kv, "sO:pair", &limit_param_name,
+                              &limit_param_val)) {
+          derr << __func__ << " limit item " << j << " not a size 2 tuple"
+               << dendl;
+          Py_RETURN_NONE;
+        }
+
+        if (limit_param_name == NAME_LIMIT_ORDER_BY) {
+          if (!PyUnicode_Check(limit_param_val)) {
+            derr << __func__ << " " << limit_param_name << " not a string"
+                 << dendl;
+            Py_RETURN_NONE;
+          }
+          auto order_by = PyUnicode_AsUTF8(limit_param_val);
+          auto it = counter_types.find(order_by);
+          if (it == counter_types.end()) {
+            derr << __func__ << " limit " << limit_param_name
+                 << " not a valid counter type" << dendl;
+            Py_RETURN_NONE;
+          }
+          limit->order_by = it->second;
+        } else if (limit_param_name == NAME_LIMIT_MAX_COUNT) {
+          if (!PyLong_Check(limit_param_val)) {
+            derr << __func__ << " " << limit_param_name << " not an int"
+                 << dendl;
+            Py_RETURN_NONE;
+          }
+          limit->max_count = PyLong_AsLong(limit_param_val);
+        } else {
+          derr << __func__ << " unknown limit param: " << limit_param_name
+               << dendl;
+          Py_RETURN_NONE;
+        }
+      }
+    } else {
+      derr << __func__ << " unknown query param: " << query_param_name << dendl;
+      Py_RETURN_NONE;
+    }
+  }
+
+  if (query.key_descriptor.empty()) {
+    derr << __func__ << " invalid query" << dendl;
+    Py_RETURN_NONE;
+  }
+
+  if (limit) {
+    auto &ds = query.performance_counter_descriptors;
+    if (std::find(ds.begin(), ds.end(), limit->order_by) == ds.end()) {
+      derr << __func__ << " limit order_by " << limit->order_by
+           << " not in performance_counter_descriptors" << dendl;
+      Py_RETURN_NONE;
+    }
+  }
+
+  auto query_id = self->py_modules->add_mds_perf_query(query, limit);
+  return PyLong_FromLong(query_id);
+}
+
+static PyObject*
+ceph_remove_mds_perf_query(BaseMgrModule *self, PyObject *args)
+{
+  MetricQueryID query_id;
+  if (!PyArg_ParseTuple(args, "i:ceph_remove_mds_perf_query", &query_id)) {
+    derr << "Invalid args!" << dendl;
+    return nullptr;
+  }
+
+  self->py_modules->remove_mds_perf_query(query_id);
+  Py_RETURN_NONE;
+}
+
+static PyObject*
+ceph_reregister_mds_perf_queries(BaseMgrModule *self, PyObject *args)
+{
+  self->py_modules->reregister_mds_perf_queries();
+  Py_RETURN_NONE;
+}
+
+static PyObject*
+ceph_get_mds_perf_counters(BaseMgrModule *self, PyObject *args)
+{
+  MetricQueryID query_id;
+  if (!PyArg_ParseTuple(args, "i:ceph_get_mds_perf_counters", &query_id)) {
+    derr << "Invalid args!" << dendl;
+    return nullptr;
+  }
+
+  return self->py_modules->get_mds_perf_counters(query_id);
+}
+
+static PyObject*
+ceph_is_authorized(BaseMgrModule *self, PyObject *args)
+{
+  PyObject *args_dict = NULL;
+  if (!PyArg_ParseTuple(args, "O:ceph_is_authorized", &args_dict)) {
+    return nullptr;
+  }
+
+  if (!PyDict_Check(args_dict)) {
+    derr << __func__ << " arg not a dict" << dendl;
+    Py_RETURN_FALSE;
+  }
+
+  std::map<std::string, std::string> arguments;
+
+  PyObject *args_list = PyDict_Items(args_dict);
+  for (int i = 0; i < PyList_Size(args_list); ++i) {
+    PyObject *kv = PyList_GET_ITEM(args_list, i);
+
+    char *arg_key = nullptr;
+    char *arg_value = nullptr;
+    if (!PyArg_ParseTuple(kv, "ss:pair", &arg_key, &arg_value)) {
+      derr << __func__ << " dict item " << i << " not a size 2 tuple" << dendl;
+      continue;
+    }
+
+    arguments[arg_key] = arg_value;
+  }
+
+  bool r = without_gil([&] {
+    return self->this_module->is_authorized(arguments);
+  });
+
+  if (r) {
+    Py_RETURN_TRUE;
+  }
+  Py_RETURN_FALSE;
+}
+
+static PyObject*
+ceph_register_client(BaseMgrModule *self, PyObject *args)
+{
+  char *addrs = nullptr;
+  if (!PyArg_ParseTuple(args, "s:ceph_register_client", &addrs)) {
+    return nullptr;
+  }
+  without_gil([&] {
+    self->py_modules->register_client(self->this_module->get_name(), addrs);
+  });
+  Py_RETURN_NONE;
+}
+
+static PyObject*
+ceph_unregister_client(BaseMgrModule *self, PyObject *args)
+{
+  char *addrs = nullptr;
+  if (!PyArg_ParseTuple(args, "s:ceph_unregister_client", &addrs)) {
+    return nullptr;
+  }
+  without_gil([&] {
+    self->py_modules->unregister_client(self->this_module->get_name(), addrs);
+  });
+  Py_RETURN_NONE;
+}
+
+static PyObject*
+ceph_get_daemon_health_metrics(BaseMgrModule *self, PyObject *args)
+{
+  return self->py_modules->get_daemon_health_metrics();
+}
+
 PyMethodDef BaseMgrModule_methods[] = {
   {"_ceph_get", (PyCFunction)ceph_state_get, METH_VARARGS,
    "Get a cluster object"},
@@ -1023,9 +1439,15 @@ PyMethodDef BaseMgrModule_methods[] = {
   {"_ceph_get_mgr_id", (PyCFunction)ceph_get_mgr_id, METH_NOARGS,
    "Get the name of the Mgr daemon where we are running"},
 
+  {"_ceph_get_ceph_conf_path", (PyCFunction)ceph_get_ceph_conf_path, METH_NOARGS,
+   "Get path to ceph.conf"},
+
   {"_ceph_get_option", (PyCFunction)ceph_option_get, METH_VARARGS,
    "Get a native configuration option value"},
 
+  {"_ceph_get_foreign_option", (PyCFunction)ceph_foreign_option_get, METH_VARARGS,
+   "Get a native configuration option value for another entity"},
+
   {"_ceph_get_module_option", (PyCFunction)ceph_get_module_option, METH_VARARGS,
    "Get a module configuration option value"},
 
@@ -1050,15 +1472,24 @@ PyMethodDef BaseMgrModule_methods[] = {
   {"_ceph_get_perf_schema", (PyCFunction)get_perf_schema, METH_VARARGS,
     "Get the performance counter schema"},
 
+  {"_ceph_get_rocksdb_version", (PyCFunction)ceph_get_rocksdb_version, METH_NOARGS,
+    "Get the current RocksDB version number"},
+
   {"_ceph_log", (PyCFunction)ceph_log, METH_VARARGS,
    "Emit a (local) log message"},
 
   {"_ceph_cluster_log", (PyCFunction)ceph_cluster_log, METH_VARARGS,
    "Emit a cluster log message"},
 
-  {"_ceph_get_version", (PyCFunction)ceph_get_version, METH_VARARGS,
+  {"_ceph_get_version", (PyCFunction)ceph_get_version, METH_NOARGS,
    "Get the ceph version of this process"},
 
+  {"_ceph_get_release_name", (PyCFunction)ceph_get_release_name, METH_NOARGS,
+   "Get the ceph release name of this process"},
+
+  {"_ceph_lookup_release_name", (PyCFunction)ceph_lookup_release_name, METH_VARARGS,
+   "Get the ceph release name for a given major number"},
+
   {"_ceph_get_context", (PyCFunction)ceph_get_context, METH_NOARGS,
     "Get a CephContext* in a python capsule"},
 
@@ -1068,6 +1499,9 @@ PyMethodDef BaseMgrModule_methods[] = {
   {"_ceph_set_uri", (PyCFunction)ceph_set_uri, METH_VARARGS,
     "Advertize a service URI served by this module"},
 
+  {"_ceph_set_device_wear_level", (PyCFunction)ceph_set_wear_level, METH_VARARGS,
+   "Set device wear_level value"},
+
   {"_ceph_have_mon_connection", (PyCFunction)ceph_have_mon_connection,
     METH_NOARGS, "Find out whether this mgr daemon currently has "
                  "a connection to a monitor"},
@@ -1091,6 +1525,30 @@ PyMethodDef BaseMgrModule_methods[] = {
   {"_ceph_get_osd_perf_counters", (PyCFunction)ceph_get_osd_perf_counters,
     METH_VARARGS, "Get osd perf counters"},
 
+  {"_ceph_add_mds_perf_query", (PyCFunction)ceph_add_mds_perf_query,
+    METH_VARARGS, "Add an mds perf query"},
+
+  {"_ceph_remove_mds_perf_query", (PyCFunction)ceph_remove_mds_perf_query,
+    METH_VARARGS, "Remove an mds perf query"},
+
+  {"_ceph_reregister_mds_perf_queries", (PyCFunction)ceph_reregister_mds_perf_queries,
+    METH_NOARGS, "Re-register mds perf queries"},
+
+  {"_ceph_get_mds_perf_counters", (PyCFunction)ceph_get_mds_perf_counters,
+    METH_VARARGS, "Get mds perf counters"},
+
+  {"_ceph_is_authorized", (PyCFunction)ceph_is_authorized,
+    METH_VARARGS, "Verify the current session caps are valid"},
+
+  {"_ceph_register_client", (PyCFunction)ceph_register_client,
+    METH_VARARGS, "Register RADOS instance for potential blocklisting"},
+
+  {"_ceph_unregister_client", (PyCFunction)ceph_unregister_client,
+    METH_VARARGS, "Unregister RADOS instance for potential blocklisting"},
+
+  {"_ceph_get_daemon_health_metrics", (PyCFunction)ceph_get_daemon_health_metrics,
+    METH_VARARGS, "Get health metrics for all daemons"},
+
   {NULL, NULL, 0, NULL}
 };
 
@@ -1169,4 +1627,3 @@ PyTypeObject BaseMgrModuleType = {
   0,                         /* tp_alloc */
   BaseMgrModule_new,     /* tp_new */
 };
-