#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"
#define PLACEHOLDER ""
+using std::list;
+using std::string;
typedef struct {
PyObject_HEAD
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);
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
// 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));
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));
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 {
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);
}
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) && !PyUnicode_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
+ << " count value not int" << dendl;
+ continue;
}
- summary = PyString_AsString(v);
} else if (ks == "detail") {
if (!PyList_Check(v)) {
derr << __func__ << " check " << check_name
}
for (int k = 0; k < PyList_Size(v); ++k) {
PyObject *di = PyList_GET_ITEM(v, k);
- if (!PyString_Check(di) && !PyUnicode_Check(di)) {
+ if (!PyUnicode_Check(di)) {
derr << __func__ << " check " << check_name
<< " 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);
}
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;
}
return NULL;
}
- return self->py_modules->get_python(what);
+ return self->py_modules->cacheable_get_python(what);
}
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*
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)
{
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;
}
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;
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;
}
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;
}
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();
}
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)
{
&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;
}
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;
}
&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;
}
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
}
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;
}
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
}
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
}
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;
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;
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;
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", ¶m_name, ¶m_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)
+{
+ const char* _name = nullptr;
+ char* addrs = nullptr;
+ int replace = 0;
+ if (!PyArg_ParseTuple(args, "zsp:ceph_register_client", &_name, &addrs, &replace)) {
+ return nullptr;
+ }
+ auto name = _name ? std::string(_name) : std::string(self->this_module->get_name());
+ without_gil([&] {
+ self->py_modules->register_client(name, addrs, replace);
+ });
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+ceph_unregister_client(BaseMgrModule *self, PyObject *args)
+{
+ const char* _name = nullptr;
+ char* addrs = nullptr;
+ if (!PyArg_ParseTuple(args, "zs:ceph_unregister_client", &_name, &addrs)) {
+ return nullptr;
+ }
+ auto name = _name ? std::string(_name) : std::string(self->this_module->get_name());
+ without_gil([&] {
+ self->py_modules->unregister_client(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"},
{"_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"},
{"_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"},
{"_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"},
{"_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}
};
0, /* tp_alloc */
BaseMgrModule_new, /* tp_new */
};
-