1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2016 John Spray <john.spray@redhat.com>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
15 * The interface we present to python code that runs within
16 * ceph-mgr. This is implemented as a Python class from which
17 * all modules must inherit -- access to the Ceph state is then
18 * available as methods on that object.
25 #include "mon/MonClient.h"
26 #include "common/errno.h"
27 #include "common/version.h"
28 #include "mgr/Types.h"
31 #include "BaseMgrModule.h"
36 #define dout_context g_ceph_context
37 #define dout_subsys ceph_subsys_mgr
39 #define PLACEHOLDER ""
46 ActivePyModules
*py_modules
;
47 ActivePyModule
*this_module
;
50 class MonCommandCompletion
: public Context
52 ActivePyModules
*py_modules
;
53 PyObject
*python_completion
;
54 const std::string tag
;
55 SafeThreadState pThreadState
;
62 ActivePyModules
*py_modules_
, PyObject
* ev
,
63 const std::string
&tag_
, PyThreadState
*ts_
)
64 : py_modules(py_modules_
), python_completion(ev
),
65 tag(tag_
), pThreadState(ts_
)
67 ceph_assert(python_completion
!= nullptr);
68 Py_INCREF(python_completion
);
71 ~MonCommandCompletion() override
73 if (python_completion
) {
74 // Usually do this in finish(): this path is only for if we're
75 // being destroyed without completing.
76 Gil
gil(pThreadState
, true);
77 Py_DECREF(python_completion
);
78 python_completion
= nullptr;
82 void finish(int r
) override
84 ceph_assert(python_completion
!= nullptr);
86 dout(10) << "MonCommandCompletion::finish()" << dendl
;
88 // Scoped so the Gil is released before calling notify_all()
89 // Create new thread state because this is called via the MonClient
90 // Finisher, not the PyModules finisher.
91 Gil
gil(pThreadState
, true);
93 auto set_fn
= PyObject_GetAttrString(python_completion
, "complete");
94 ceph_assert(set_fn
!= nullptr);
96 auto pyR
= PyLong_FromLong(r
);
97 auto pyOutBl
= PyUnicode_FromString(outbl
.to_str().c_str());
98 auto pyOutS
= PyUnicode_FromString(outs
.c_str());
99 auto args
= PyTuple_Pack(3, pyR
, pyOutBl
, pyOutS
);
104 auto rtn
= PyObject_CallObject(set_fn
, args
);
105 if (rtn
!= nullptr) {
111 Py_DECREF(python_completion
);
112 python_completion
= nullptr;
114 py_modules
->notify_all("command", tag
);
120 ceph_send_command(BaseMgrModule
*self
, PyObject
*args
)
122 // Like mon, osd, mds
123 char *type
= nullptr;
125 // Like "23" for an OSD or "myid" for an MDS
126 char *name
= nullptr;
128 char *cmd_json
= nullptr;
130 char *inbuf_ptr
= nullptr;
131 Py_ssize_t inbuf_len
= 0;
132 bufferlist inbuf
= {};
134 PyObject
*completion
= nullptr;
135 if (!PyArg_ParseTuple(args
, "Ossssz#:ceph_send_command",
136 &completion
, &type
, &name
, &cmd_json
, &tag
, &inbuf_ptr
, &inbuf_len
)) {
141 inbuf
.append(inbuf_ptr
, (unsigned)inbuf_len
);
144 auto set_fn
= PyObject_GetAttrString(completion
, "complete");
145 if (set_fn
== nullptr) {
146 ceph_abort(); // TODO raise python exception instead
148 ceph_assert(PyCallable_Check(set_fn
));
152 MonCommandCompletion
*command_c
= new MonCommandCompletion(self
->py_modules
,
153 completion
, tag
, PyThreadState_Get());
155 PyThreadState
*tstate
= PyEval_SaveThread();
157 if (std::string(type
) == "mon") {
159 // Wait for the latest OSDMap after each command we send to
160 // the mons. This is a heavy-handed hack to make life simpler
161 // for python module authors, so that they know whenever they
162 // run a command they've gt a fresh OSDMap afterwards.
163 // TODO: enhance MCommand interface so that it returns
164 // latest cluster map versions on completion, and callers
165 // can wait for those.
166 auto c
= new LambdaContext([command_c
, self
](int command_r
){
167 self
->py_modules
->get_objecter().wait_for_latest_osdmap(
168 [command_c
, command_r
](boost::system::error_code
) {
169 command_c
->complete(command_r
);
173 self
->py_modules
->get_monc().start_mon_command(
179 new C_OnFinisher(c
, &self
->py_modules
->cmd_finisher
));
180 } else if (std::string(type
) == "osd") {
182 uint64_t osd_id
= strict_strtoll(name
, 10, &err
);
185 string
msg("invalid osd_id: ");
186 msg
.append("\"").append(name
).append("\"");
187 PyEval_RestoreThread(tstate
);
188 PyErr_SetString(PyExc_ValueError
, msg
.c_str());
193 self
->py_modules
->get_objecter().osd_command(
198 [command_c
, f
= &self
->py_modules
->cmd_finisher
]
199 (boost::system::error_code ec
, std::string s
, ceph::buffer::list bl
) {
200 command_c
->outs
= std::move(s
);
201 command_c
->outbl
= std::move(bl
);
204 } else if (std::string(type
) == "mds") {
205 int r
= self
->py_modules
->get_client().mds_command(
211 new C_OnFinisher(command_c
, &self
->py_modules
->cmd_finisher
));
213 string
msg("failed to send command to mds: ");
214 msg
.append(cpp_strerror(r
));
215 PyEval_RestoreThread(tstate
);
216 PyErr_SetString(PyExc_RuntimeError
, msg
.c_str());
219 } else if (std::string(type
) == "pg") {
221 if (!pgid
.parse(name
)) {
223 string
msg("invalid pgid: ");
224 msg
.append("\"").append(name
).append("\"");
225 PyEval_RestoreThread(tstate
);
226 PyErr_SetString(PyExc_ValueError
, msg
.c_str());
231 self
->py_modules
->get_objecter().pg_command(
236 [command_c
, f
= &self
->py_modules
->cmd_finisher
]
237 (boost::system::error_code ec
, std::string s
, ceph::buffer::list bl
) {
238 command_c
->outs
= std::move(s
);
239 command_c
->outbl
= std::move(bl
);
242 PyEval_RestoreThread(tstate
);
246 string
msg("unknown service type: ");
248 PyEval_RestoreThread(tstate
);
249 PyErr_SetString(PyExc_ValueError
, msg
.c_str());
253 PyEval_RestoreThread(tstate
);
258 ceph_set_health_checks(BaseMgrModule
*self
, PyObject
*args
)
260 PyObject
*checks
= NULL
;
261 if (!PyArg_ParseTuple(args
, "O:ceph_set_health_checks", &checks
)) {
264 if (!PyDict_Check(checks
)) {
265 derr
<< __func__
<< " arg not a dict" << dendl
;
268 PyObject
*checksls
= PyDict_Items(checks
);
269 health_check_map_t out_checks
;
270 for (int i
= 0; i
< PyList_Size(checksls
); ++i
) {
271 PyObject
*kv
= PyList_GET_ITEM(checksls
, i
);
272 char *check_name
= nullptr;
273 PyObject
*check_info
= nullptr;
274 if (!PyArg_ParseTuple(kv
, "sO:pair", &check_name
, &check_info
)) {
275 derr
<< __func__
<< " dict item " << i
276 << " not a size 2 tuple" << dendl
;
279 if (!PyDict_Check(check_info
)) {
280 derr
<< __func__
<< " item " << i
<< " " << check_name
281 << " value not a dict" << dendl
;
284 health_status_t severity
= HEALTH_OK
;
288 PyObject
*infols
= PyDict_Items(check_info
);
289 for (int j
= 0; j
< PyList_Size(infols
); ++j
) {
290 PyObject
*pair
= PyList_GET_ITEM(infols
, j
);
291 if (!PyTuple_Check(pair
)) {
292 derr
<< __func__
<< " item " << i
<< " pair " << j
293 << " not a tuple" << dendl
;
297 PyObject
*v
= nullptr;
298 if (!PyArg_ParseTuple(pair
, "sO:pair", &k
, &v
)) {
299 derr
<< __func__
<< " item " << i
<< " pair " << j
300 << " not a size 2 tuple" << dendl
;
304 if (ks
== "severity") {
305 if (!PyUnicode_Check(v
)) {
306 derr
<< __func__
<< " check " << check_name
307 << " severity value not string" << dendl
;
310 if (const string vs
= PyUnicode_AsUTF8(v
); vs
== "warning") {
311 severity
= HEALTH_WARN
;
312 } else if (vs
== "error") {
313 severity
= HEALTH_ERR
;
315 } else if (ks
== "summary") {
316 if (!PyUnicode_Check(v
)) {
317 derr
<< __func__
<< " check " << check_name
318 << " summary value not [unicode] string" << dendl
;
321 summary
= PyUnicode_AsUTF8(v
);
323 } else if (ks
== "count") {
324 if (PyLong_Check(v
)) {
325 count
= PyLong_AsLong(v
);
327 derr
<< __func__
<< " check " << check_name
328 << " count value not int" << dendl
;
331 } else if (ks
== "detail") {
332 if (!PyList_Check(v
)) {
333 derr
<< __func__
<< " check " << check_name
334 << " detail value not list" << dendl
;
337 for (int k
= 0; k
< PyList_Size(v
); ++k
) {
338 PyObject
*di
= PyList_GET_ITEM(v
, k
);
339 if (!PyUnicode_Check(di
)) {
340 derr
<< __func__
<< " check " << check_name
341 << " detail item " << k
<< " not a [unicode] string" << dendl
;
344 detail
.push_back(PyUnicode_AsUTF8(di
));
348 derr
<< __func__
<< " check " << check_name
349 << " unexpected key " << k
<< dendl
;
352 auto& d
= out_checks
.add(check_name
, severity
, summary
, count
);
353 d
.detail
.swap(detail
);
356 JSONFormatter
jf(true);
357 dout(10) << "module " << self
->this_module
->get_name()
358 << " health checks:\n";
359 out_checks
.dump(&jf
);
363 self
->py_modules
->set_health_checks(self
->this_module
->get_name(),
364 std::move(out_checks
));
371 ceph_state_get(BaseMgrModule
*self
, PyObject
*args
)
374 if (!PyArg_ParseTuple(args
, "s:ceph_state_get", &what
)) {
378 return self
->py_modules
->cacheable_get_python(what
);
383 ceph_get_server(BaseMgrModule
*self
, PyObject
*args
)
385 char *hostname
= NULL
;
386 if (!PyArg_ParseTuple(args
, "z:ceph_get_server", &hostname
)) {
391 return self
->py_modules
->get_server_python(hostname
);
393 return self
->py_modules
->list_servers_python();
398 ceph_get_mgr_id(BaseMgrModule
*self
, PyObject
*args
)
400 return PyUnicode_FromString(g_conf()->name
.get_id().c_str());
404 ceph_option_get(BaseMgrModule
*self
, PyObject
*args
)
406 char *what
= nullptr;
407 if (!PyArg_ParseTuple(args
, "s:ceph_option_get", &what
)) {
408 derr
<< "Invalid args!" << dendl
;
412 const Option
*opt
= g_conf().find_option(string(what
));
415 switch (int r
= g_conf().get_val(string(what
), &value
); r
) {
420 PyErr_SetString(PyExc_ValueError
, "value too long");
426 dout(10) << "ceph_option_get " << what
<< " found: " << value
<< dendl
;
427 return get_python_typed_option_value(opt
->type
, value
);
429 dout(4) << "ceph_option_get " << what
<< " not found " << dendl
;
430 PyErr_Format(PyExc_KeyError
, "option not found: %s", what
);
436 ceph_foreign_option_get(BaseMgrModule
*self
, PyObject
*args
)
439 char *what
= nullptr;
440 if (!PyArg_ParseTuple(args
, "ss:ceph_foreign_option_get", &who
, &what
)) {
441 derr
<< "Invalid args!" << dendl
;
444 return self
->py_modules
->get_foreign_config(who
, what
);
448 ceph_get_module_option(BaseMgrModule
*self
, PyObject
*args
)
450 char *module
= nullptr;
452 char *prefix
= nullptr;
453 if (!PyArg_ParseTuple(args
, "ss|s:ceph_get_module_option", &module
, &key
,
455 derr
<< "Invalid args!" << dendl
;
458 std::string str_prefix
;
462 assert(self
->this_module
->py_module
);
463 auto pResult
= self
->py_modules
->get_typed_config(module
, key
, str_prefix
);
468 ceph_store_get_prefix(BaseMgrModule
*self
, PyObject
*args
)
470 char *prefix
= nullptr;
471 if (!PyArg_ParseTuple(args
, "s:ceph_store_get_prefix", &prefix
)) {
472 derr
<< "Invalid args!" << dendl
;
476 return self
->py_modules
->get_store_prefix(self
->this_module
->get_name(),
481 ceph_set_module_option(BaseMgrModule
*self
, PyObject
*args
)
483 char *module
= nullptr;
485 char *value
= nullptr;
486 if (!PyArg_ParseTuple(args
, "ssz:ceph_set_module_option",
487 &module
, &key
, &value
)) {
488 derr
<< "Invalid args!" << dendl
;
491 std::optional
<string
> val
;
495 auto [ret
, msg
] = without_gil([&] {
496 return self
->py_modules
->set_config(module
, key
, val
);
499 PyErr_SetString(PyExc_ValueError
, msg
.c_str());
506 ceph_store_get(BaseMgrModule
*self
, PyObject
*args
)
508 char *what
= nullptr;
509 if (!PyArg_ParseTuple(args
, "s:ceph_store_get", &what
)) {
510 derr
<< "Invalid args!" << dendl
;
515 bool found
= self
->py_modules
->get_store(self
->this_module
->get_name(),
518 dout(10) << "ceph_store_get " << what
<< " found: " << value
.c_str() << dendl
;
519 return PyUnicode_FromString(value
.c_str());
521 dout(4) << "ceph_store_get " << what
<< " not found " << dendl
;
527 ceph_store_set(BaseMgrModule
*self
, PyObject
*args
)
530 char *value
= nullptr;
531 if (!PyArg_ParseTuple(args
, "sz:ceph_store_set", &key
, &value
)) {
534 std::optional
<string
> val
;
539 self
->py_modules
->set_store(self
->this_module
->get_name(), key
, val
);
545 get_metadata(BaseMgrModule
*self
, PyObject
*args
)
547 char *svc_name
= NULL
;
549 if (!PyArg_ParseTuple(args
, "ss:get_metadata", &svc_name
, &svc_id
)) {
552 return self
->py_modules
->get_metadata_python(svc_name
, svc_id
);
556 get_daemon_status(BaseMgrModule
*self
, PyObject
*args
)
558 char *svc_name
= NULL
;
560 if (!PyArg_ParseTuple(args
, "ss:get_daemon_status", &svc_name
,
564 return self
->py_modules
->get_daemon_status_python(svc_name
, svc_id
);
568 ceph_log(BaseMgrModule
*self
, PyObject
*args
)
570 char *record
= nullptr;
571 if (!PyArg_ParseTuple(args
, "s:log", &record
)) {
575 ceph_assert(self
->this_module
);
577 self
->this_module
->log(record
);
583 ceph_cluster_log(BaseMgrModule
*self
, PyObject
*args
)
586 char *channel
= nullptr;
587 char *message
= nullptr;
589 if (!PyArg_ParseTuple(args
, "sis:ceph_cluster_log", &channel
, &prio
, &message
)) {
593 self
->py_modules
->cluster_log(channel
, (clog_type
)prio
, message
);
599 ceph_get_version(BaseMgrModule
*self
, PyObject
*args
)
601 return PyUnicode_FromString(pretty_version_to_str().c_str());
605 ceph_get_ceph_conf_path(BaseMgrModule
*self
, PyObject
*args
)
607 return PyUnicode_FromString(g_conf().get_conf_path().c_str());
611 ceph_get_release_name(BaseMgrModule
*self
, PyObject
*args
)
613 return PyUnicode_FromString(ceph_release_to_str());
617 ceph_lookup_release_name(BaseMgrModule
*self
, PyObject
*args
)
620 if (!PyArg_ParseTuple(args
, "i:ceph_lookup_release_name", &major
)) {
623 return PyUnicode_FromString(ceph_release_name(major
));
627 ceph_get_context(BaseMgrModule
*self
)
629 return self
->py_modules
->get_context();
633 get_counter(BaseMgrModule
*self
, PyObject
*args
)
635 char *svc_name
= nullptr;
636 char *svc_id
= nullptr;
637 char *counter_path
= nullptr;
638 if (!PyArg_ParseTuple(args
, "sss:get_counter", &svc_name
,
639 &svc_id
, &counter_path
)) {
642 return self
->py_modules
->get_counter_python(
643 svc_name
, svc_id
, counter_path
);
647 get_latest_counter(BaseMgrModule
*self
, PyObject
*args
)
649 char *svc_name
= nullptr;
650 char *svc_id
= nullptr;
651 char *counter_path
= nullptr;
652 if (!PyArg_ParseTuple(args
, "sss:get_counter", &svc_name
,
653 &svc_id
, &counter_path
)) {
656 return self
->py_modules
->get_latest_counter_python(
657 svc_name
, svc_id
, counter_path
);
661 get_perf_schema(BaseMgrModule
*self
, PyObject
*args
)
663 char *type_str
= nullptr;
664 char *svc_id
= nullptr;
665 if (!PyArg_ParseTuple(args
, "ss:get_perf_schema", &type_str
,
670 return self
->py_modules
->get_perf_schema_python(type_str
, svc_id
);
674 ceph_get_rocksdb_version(BaseMgrModule
*self
)
676 return self
->py_modules
->get_rocksdb_version();
681 ceph_get_osdmap(BaseMgrModule
*self
, PyObject
*args
)
683 return self
->py_modules
->get_osdmap();
687 ceph_set_uri(BaseMgrModule
*self
, PyObject
*args
)
689 char *svc_str
= nullptr;
690 if (!PyArg_ParseTuple(args
, "s:ceph_advertize_service",
694 // We call down into PyModules even though we have a MgrPyModule
695 // reference here, because MgrPyModule's fields are protected
696 // by PyModules' lock.
698 self
->py_modules
->set_uri(self
->this_module
->get_name(), svc_str
);
704 ceph_set_wear_level(BaseMgrModule
*self
, PyObject
*args
)
706 char *devid
= nullptr;
708 if (!PyArg_ParseTuple(args
, "sf:ceph_set_wear_level",
709 &devid
, &wear_level
)) {
713 self
->py_modules
->set_device_wear_level(devid
, wear_level
);
719 ceph_have_mon_connection(BaseMgrModule
*self
, PyObject
*args
)
721 if (self
->py_modules
->get_monc().is_connected()) {
729 ceph_update_progress_event(BaseMgrModule
*self
, PyObject
*args
)
731 char *evid
= nullptr;
732 char *desc
= nullptr;
733 float progress
= 0.0;
734 bool add_to_ceph_s
= false;
735 if (!PyArg_ParseTuple(args
, "ssfb:ceph_update_progress_event",
736 &evid
, &desc
, &progress
, &add_to_ceph_s
)) {
740 self
->py_modules
->update_progress_event(evid
, desc
, progress
, add_to_ceph_s
);
746 ceph_complete_progress_event(BaseMgrModule
*self
, PyObject
*args
)
748 char *evid
= nullptr;
749 if (!PyArg_ParseTuple(args
, "s:ceph_complete_progress_event",
754 self
->py_modules
->complete_progress_event(evid
);
760 ceph_clear_all_progress_events(BaseMgrModule
*self
, PyObject
*args
)
763 self
->py_modules
->clear_all_progress_events();
771 ceph_dispatch_remote(BaseMgrModule
*self
, PyObject
*args
)
773 char *other_module
= nullptr;
774 char *method
= nullptr;
775 PyObject
*remote_args
= nullptr;
776 PyObject
*remote_kwargs
= nullptr;
777 if (!PyArg_ParseTuple(args
, "ssOO:ceph_dispatch_remote",
778 &other_module
, &method
, &remote_args
, &remote_kwargs
)) {
782 // Early error handling, because if the module doesn't exist then we
783 // won't be able to use its thread state to set python error state
784 // inside dispatch_remote().
785 if (!self
->py_modules
->module_exists(other_module
)) {
786 derr
<< "no module '" << other_module
<< "'" << dendl
;
787 PyErr_SetString(PyExc_ImportError
, "Module not found");
791 // Drop GIL from calling python thread state, it will be taken
792 // both for checking for method existence and for executing method.
793 PyThreadState
*tstate
= PyEval_SaveThread();
795 if (!self
->py_modules
->method_exists(other_module
, method
)) {
796 PyEval_RestoreThread(tstate
);
797 PyErr_SetString(PyExc_NameError
, "Method not found");
802 auto result
= self
->py_modules
->dispatch_remote(other_module
, method
,
803 remote_args
, remote_kwargs
, &err
);
805 PyEval_RestoreThread(tstate
);
807 if (result
== nullptr) {
808 std::stringstream ss
;
809 ss
<< "Remote method threw exception: " << err
;
810 PyErr_SetString(PyExc_RuntimeError
, ss
.str().c_str());
811 derr
<< ss
.str() << dendl
;
818 ceph_add_osd_perf_query(BaseMgrModule
*self
, PyObject
*args
)
820 static const std::string NAME_KEY_DESCRIPTOR
= "key_descriptor";
821 static const std::string NAME_COUNTERS_DESCRIPTORS
=
822 "performance_counter_descriptors";
823 static const std::string NAME_LIMIT
= "limit";
824 static const std::string NAME_SUB_KEY_TYPE
= "type";
825 static const std::string NAME_SUB_KEY_REGEX
= "regex";
826 static const std::string NAME_LIMIT_ORDER_BY
= "order_by";
827 static const std::string NAME_LIMIT_MAX_COUNT
= "max_count";
828 static const std::map
<std::string
, OSDPerfMetricSubKeyType
> sub_key_types
= {
829 {"client_id", OSDPerfMetricSubKeyType::CLIENT_ID
},
830 {"client_address", OSDPerfMetricSubKeyType::CLIENT_ADDRESS
},
831 {"pool_id", OSDPerfMetricSubKeyType::POOL_ID
},
832 {"namespace", OSDPerfMetricSubKeyType::NAMESPACE
},
833 {"osd_id", OSDPerfMetricSubKeyType::OSD_ID
},
834 {"pg_id", OSDPerfMetricSubKeyType::PG_ID
},
835 {"object_name", OSDPerfMetricSubKeyType::OBJECT_NAME
},
836 {"snap_id", OSDPerfMetricSubKeyType::SNAP_ID
},
838 static const std::map
<std::string
, PerformanceCounterType
> counter_types
= {
839 {"ops", PerformanceCounterType::OPS
},
840 {"write_ops", PerformanceCounterType::WRITE_OPS
},
841 {"read_ops", PerformanceCounterType::READ_OPS
},
842 {"bytes", PerformanceCounterType::BYTES
},
843 {"write_bytes", PerformanceCounterType::WRITE_BYTES
},
844 {"read_bytes", PerformanceCounterType::READ_BYTES
},
845 {"latency", PerformanceCounterType::LATENCY
},
846 {"write_latency", PerformanceCounterType::WRITE_LATENCY
},
847 {"read_latency", PerformanceCounterType::READ_LATENCY
},
850 PyObject
*py_query
= nullptr;
851 if (!PyArg_ParseTuple(args
, "O:ceph_add_osd_perf_query", &py_query
)) {
852 derr
<< "Invalid args!" << dendl
;
855 if (!PyDict_Check(py_query
)) {
856 derr
<< __func__
<< " arg not a dict" << dendl
;
860 PyObject
*query_params
= PyDict_Items(py_query
);
861 OSDPerfMetricQuery query
;
862 std::optional
<OSDPerfMetricLimit
> limit
;
865 // 'key_descriptor': [
866 // {'type': subkey_type, 'regex': regex_pattern},
869 // 'performance_counter_descriptors': [
870 // list, of, descriptor, types
872 // 'limit': {'order_by': performance_counter_type, 'max_count': n},
875 for (int i
= 0; i
< PyList_Size(query_params
); ++i
) {
876 PyObject
*kv
= PyList_GET_ITEM(query_params
, i
);
877 char *query_param_name
= nullptr;
878 PyObject
*query_param_val
= nullptr;
879 if (!PyArg_ParseTuple(kv
, "sO:pair", &query_param_name
, &query_param_val
)) {
880 derr
<< __func__
<< " dict item " << i
<< " not a size 2 tuple" << dendl
;
883 if (query_param_name
== NAME_KEY_DESCRIPTOR
) {
884 if (!PyList_Check(query_param_val
)) {
885 derr
<< __func__
<< " " << query_param_name
<< " not a list" << dendl
;
888 for (int j
= 0; j
< PyList_Size(query_param_val
); j
++) {
889 PyObject
*sub_key
= PyList_GET_ITEM(query_param_val
, j
);
890 if (!PyDict_Check(sub_key
)) {
891 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
892 << " not a dict" << dendl
;
895 OSDPerfMetricSubKeyDescriptor d
;
896 PyObject
*sub_key_params
= PyDict_Items(sub_key
);
897 for (int k
= 0; k
< PyList_Size(sub_key_params
); ++k
) {
898 PyObject
*pair
= PyList_GET_ITEM(sub_key_params
, k
);
899 if (!PyTuple_Check(pair
)) {
900 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
901 << " pair " << k
<< " not a tuple" << dendl
;
904 char *param_name
= nullptr;
905 PyObject
*param_value
= nullptr;
906 if (!PyArg_ParseTuple(pair
, "sO:pair", ¶m_name
, ¶m_value
)) {
907 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
908 << " pair " << k
<< " not a size 2 tuple" << dendl
;
911 if (param_name
== NAME_SUB_KEY_TYPE
) {
912 if (!PyUnicode_Check(param_value
)) {
913 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
914 << " contains invalid param " << param_name
<< dendl
;
917 auto type
= PyUnicode_AsUTF8(param_value
);
918 auto it
= sub_key_types
.find(type
);
919 if (it
== sub_key_types
.end()) {
920 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
921 << " contains invalid type " << dendl
;
925 } else if (param_name
== NAME_SUB_KEY_REGEX
) {
926 if (!PyUnicode_Check(param_value
)) {
927 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
928 << " contains invalid param " << param_name
<< dendl
;
931 d
.regex_str
= PyUnicode_AsUTF8(param_value
);
933 d
.regex
= d
.regex_str
.c_str();
934 } catch (const std::regex_error
& e
) {
935 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
936 << " contains invalid regex " << d
.regex_str
<< dendl
;
939 if (d
.regex
.mark_count() == 0) {
940 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
941 << " regex " << d
.regex_str
<< ": no capturing groups"
946 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
947 << " contains invalid param " << param_name
<< dendl
;
951 if (d
.type
== static_cast<OSDPerfMetricSubKeyType
>(-1) ||
952 d
.regex_str
.empty()) {
953 derr
<< __func__
<< " query " << query_param_name
<< " item " << i
954 << " invalid" << dendl
;
957 query
.key_descriptor
.push_back(d
);
959 } else if (query_param_name
== NAME_COUNTERS_DESCRIPTORS
) {
960 if (!PyList_Check(query_param_val
)) {
961 derr
<< __func__
<< " " << query_param_name
<< " not a list" << dendl
;
964 for (int j
= 0; j
< PyList_Size(query_param_val
); j
++) {
965 PyObject
*py_type
= PyList_GET_ITEM(query_param_val
, j
);
966 if (!PyUnicode_Check(py_type
)) {
967 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
968 << " not a string" << dendl
;
971 auto type
= PyUnicode_AsUTF8(py_type
);
972 auto it
= counter_types
.find(type
);
973 if (it
== counter_types
.end()) {
974 derr
<< __func__
<< " query " << query_param_name
<< " item " << type
975 << " is not valid type" << dendl
;
978 query
.performance_counter_descriptors
.push_back(it
->second
);
980 } else if (query_param_name
== NAME_LIMIT
) {
981 if (!PyDict_Check(query_param_val
)) {
982 derr
<< __func__
<< " query " << query_param_name
<< " not a dict"
987 limit
= OSDPerfMetricLimit();
988 PyObject
*limit_params
= PyDict_Items(query_param_val
);
990 for (int j
= 0; j
< PyList_Size(limit_params
); ++j
) {
991 PyObject
*kv
= PyList_GET_ITEM(limit_params
, j
);
992 char *limit_param_name
= nullptr;
993 PyObject
*limit_param_val
= nullptr;
994 if (!PyArg_ParseTuple(kv
, "sO:pair", &limit_param_name
,
996 derr
<< __func__
<< " limit item " << j
<< " not a size 2 tuple"
1001 if (limit_param_name
== NAME_LIMIT_ORDER_BY
) {
1002 if (!PyUnicode_Check(limit_param_val
)) {
1003 derr
<< __func__
<< " " << limit_param_name
<< " not a string"
1007 auto order_by
= PyUnicode_AsUTF8(limit_param_val
);
1008 auto it
= counter_types
.find(order_by
);
1009 if (it
== counter_types
.end()) {
1010 derr
<< __func__
<< " limit " << limit_param_name
1011 << " not a valid counter type" << dendl
;
1014 limit
->order_by
= it
->second
;
1015 } else if (limit_param_name
== NAME_LIMIT_MAX_COUNT
) {
1016 if (!PyLong_Check(limit_param_val
)) {
1017 derr
<< __func__
<< " " << limit_param_name
<< " not an int"
1021 limit
->max_count
= PyLong_AsLong(limit_param_val
);
1023 derr
<< __func__
<< " unknown limit param: " << limit_param_name
1029 derr
<< __func__
<< " unknown query param: " << query_param_name
<< dendl
;
1034 if (query
.key_descriptor
.empty() ||
1035 query
.performance_counter_descriptors
.empty()) {
1036 derr
<< __func__
<< " invalid query" << dendl
;
1041 auto &ds
= query
.performance_counter_descriptors
;
1042 if (std::find(ds
.begin(), ds
.end(), limit
->order_by
) == ds
.end()) {
1043 derr
<< __func__
<< " limit order_by " << limit
->order_by
1044 << " not in performance_counter_descriptors" << dendl
;
1049 auto query_id
= self
->py_modules
->add_osd_perf_query(query
, limit
);
1050 return PyLong_FromLong(query_id
);
1054 ceph_remove_osd_perf_query(BaseMgrModule
*self
, PyObject
*args
)
1056 MetricQueryID query_id
;
1057 if (!PyArg_ParseTuple(args
, "i:ceph_remove_osd_perf_query", &query_id
)) {
1058 derr
<< "Invalid args!" << dendl
;
1062 self
->py_modules
->remove_osd_perf_query(query_id
);
1067 ceph_get_osd_perf_counters(BaseMgrModule
*self
, PyObject
*args
)
1069 MetricQueryID query_id
;
1070 if (!PyArg_ParseTuple(args
, "i:ceph_get_osd_perf_counters", &query_id
)) {
1071 derr
<< "Invalid args!" << dendl
;
1075 return self
->py_modules
->get_osd_perf_counters(query_id
);
1078 // MDS perf query interface -- mostly follows ceph_add_osd_perf_query()
1082 ceph_add_mds_perf_query(BaseMgrModule
*self
, PyObject
*args
)
1084 static const std::string NAME_KEY_DESCRIPTOR
= "key_descriptor";
1085 static const std::string NAME_COUNTERS_DESCRIPTORS
=
1086 "performance_counter_descriptors";
1087 static const std::string NAME_LIMIT
= "limit";
1088 static const std::string NAME_SUB_KEY_TYPE
= "type";
1089 static const std::string NAME_SUB_KEY_REGEX
= "regex";
1090 static const std::string NAME_LIMIT_ORDER_BY
= "order_by";
1091 static const std::string NAME_LIMIT_MAX_COUNT
= "max_count";
1092 static const std::map
<std::string
, MDSPerfMetricSubKeyType
> sub_key_types
= {
1093 {"mds_rank", MDSPerfMetricSubKeyType::MDS_RANK
},
1094 {"client_id", MDSPerfMetricSubKeyType::CLIENT_ID
},
1096 static const std::map
<std::string
, MDSPerformanceCounterType
> counter_types
= {
1097 {"cap_hit", MDSPerformanceCounterType::CAP_HIT_METRIC
},
1098 {"read_latency", MDSPerformanceCounterType::READ_LATENCY_METRIC
},
1099 {"write_latency", MDSPerformanceCounterType::WRITE_LATENCY_METRIC
},
1100 {"metadata_latency", MDSPerformanceCounterType::METADATA_LATENCY_METRIC
},
1101 {"dentry_lease", MDSPerformanceCounterType::DENTRY_LEASE_METRIC
},
1102 {"opened_files", MDSPerformanceCounterType::OPENED_FILES_METRIC
},
1103 {"pinned_icaps", MDSPerformanceCounterType::PINNED_ICAPS_METRIC
},
1104 {"opened_inodes", MDSPerformanceCounterType::OPENED_INODES_METRIC
},
1105 {"read_io_sizes", MDSPerformanceCounterType::READ_IO_SIZES_METRIC
},
1106 {"write_io_sizes", MDSPerformanceCounterType::WRITE_IO_SIZES_METRIC
},
1109 PyObject
*py_query
= nullptr;
1110 if (!PyArg_ParseTuple(args
, "O:ceph_add_mds_perf_query", &py_query
)) {
1111 derr
<< "Invalid args!" << dendl
;
1114 if (!PyDict_Check(py_query
)) {
1115 derr
<< __func__
<< " arg not a dict" << dendl
;
1119 PyObject
*query_params
= PyDict_Items(py_query
);
1120 MDSPerfMetricQuery query
;
1121 std::optional
<MDSPerfMetricLimit
> limit
;
1124 // 'key_descriptor': [
1125 // {'type': subkey_type, 'regex': regex_pattern},
1128 // 'performance_counter_descriptors': [
1129 // list, of, descriptor, types
1131 // 'limit': {'order_by': performance_counter_type, 'max_count': n},
1134 for (int i
= 0; i
< PyList_Size(query_params
); ++i
) {
1135 PyObject
*kv
= PyList_GET_ITEM(query_params
, i
);
1136 char *query_param_name
= nullptr;
1137 PyObject
*query_param_val
= nullptr;
1138 if (!PyArg_ParseTuple(kv
, "sO:pair", &query_param_name
, &query_param_val
)) {
1139 derr
<< __func__
<< " dict item " << i
<< " not a size 2 tuple" << dendl
;
1142 if (query_param_name
== NAME_KEY_DESCRIPTOR
) {
1143 if (!PyList_Check(query_param_val
)) {
1144 derr
<< __func__
<< " " << query_param_name
<< " not a list" << dendl
;
1147 for (int j
= 0; j
< PyList_Size(query_param_val
); j
++) {
1148 PyObject
*sub_key
= PyList_GET_ITEM(query_param_val
, j
);
1149 if (!PyDict_Check(sub_key
)) {
1150 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
1151 << " not a dict" << dendl
;
1154 MDSPerfMetricSubKeyDescriptor d
;
1155 PyObject
*sub_key_params
= PyDict_Items(sub_key
);
1156 for (int k
= 0; k
< PyList_Size(sub_key_params
); ++k
) {
1157 PyObject
*pair
= PyList_GET_ITEM(sub_key_params
, k
);
1158 if (!PyTuple_Check(pair
)) {
1159 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
1160 << " pair " << k
<< " not a tuple" << dendl
;
1163 char *param_name
= nullptr;
1164 PyObject
*param_value
= nullptr;
1165 if (!PyArg_ParseTuple(pair
, "sO:pair", ¶m_name
, ¶m_value
)) {
1166 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
1167 << " pair " << k
<< " not a size 2 tuple" << dendl
;
1170 if (param_name
== NAME_SUB_KEY_TYPE
) {
1171 if (!PyUnicode_Check(param_value
)) {
1172 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
1173 << " contains invalid param " << param_name
<< dendl
;
1176 auto type
= PyUnicode_AsUTF8(param_value
);
1177 auto it
= sub_key_types
.find(type
);
1178 if (it
== sub_key_types
.end()) {
1179 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
1180 << " contains invalid type " << dendl
;
1183 d
.type
= it
->second
;
1184 } else if (param_name
== NAME_SUB_KEY_REGEX
) {
1185 if (!PyUnicode_Check(param_value
)) {
1186 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
1187 << " contains invalid param " << param_name
<< dendl
;
1190 d
.regex_str
= PyUnicode_AsUTF8(param_value
);
1192 d
.regex
= d
.regex_str
.c_str();
1193 } catch (const std::regex_error
& e
) {
1194 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
1195 << " contains invalid regex " << d
.regex_str
<< dendl
;
1198 if (d
.regex
.mark_count() == 0) {
1199 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
1200 << " regex " << d
.regex_str
<< ": no capturing groups"
1205 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
1206 << " contains invalid param " << param_name
<< dendl
;
1210 if (d
.type
== static_cast<MDSPerfMetricSubKeyType
>(-1) ||
1211 d
.regex_str
.empty()) {
1212 derr
<< __func__
<< " query " << query_param_name
<< " item " << i
1213 << " invalid" << dendl
;
1216 query
.key_descriptor
.push_back(d
);
1218 } else if (query_param_name
== NAME_COUNTERS_DESCRIPTORS
) {
1219 if (!PyList_Check(query_param_val
)) {
1220 derr
<< __func__
<< " " << query_param_name
<< " not a list" << dendl
;
1223 for (int j
= 0; j
< PyList_Size(query_param_val
); j
++) {
1224 PyObject
*py_type
= PyList_GET_ITEM(query_param_val
, j
);
1225 if (!PyUnicode_Check(py_type
)) {
1226 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
1227 << " not a string" << dendl
;
1230 auto type
= PyUnicode_AsUTF8(py_type
);
1231 auto it
= counter_types
.find(type
);
1232 if (it
== counter_types
.end()) {
1233 derr
<< __func__
<< " query " << query_param_name
<< " item " << type
1234 << " is not valid type" << dendl
;
1237 query
.performance_counter_descriptors
.push_back(it
->second
);
1239 } else if (query_param_name
== NAME_LIMIT
) {
1240 if (!PyDict_Check(query_param_val
)) {
1241 derr
<< __func__
<< " query " << query_param_name
<< " not a dict"
1246 limit
= MDSPerfMetricLimit();
1247 PyObject
*limit_params
= PyDict_Items(query_param_val
);
1249 for (int j
= 0; j
< PyList_Size(limit_params
); ++j
) {
1250 PyObject
*kv
= PyList_GET_ITEM(limit_params
, j
);
1251 char *limit_param_name
= nullptr;
1252 PyObject
*limit_param_val
= nullptr;
1253 if (!PyArg_ParseTuple(kv
, "sO:pair", &limit_param_name
,
1254 &limit_param_val
)) {
1255 derr
<< __func__
<< " limit item " << j
<< " not a size 2 tuple"
1260 if (limit_param_name
== NAME_LIMIT_ORDER_BY
) {
1261 if (!PyUnicode_Check(limit_param_val
)) {
1262 derr
<< __func__
<< " " << limit_param_name
<< " not a string"
1266 auto order_by
= PyUnicode_AsUTF8(limit_param_val
);
1267 auto it
= counter_types
.find(order_by
);
1268 if (it
== counter_types
.end()) {
1269 derr
<< __func__
<< " limit " << limit_param_name
1270 << " not a valid counter type" << dendl
;
1273 limit
->order_by
= it
->second
;
1274 } else if (limit_param_name
== NAME_LIMIT_MAX_COUNT
) {
1275 if (!PyLong_Check(limit_param_val
)) {
1276 derr
<< __func__
<< " " << limit_param_name
<< " not an int"
1280 limit
->max_count
= PyLong_AsLong(limit_param_val
);
1282 derr
<< __func__
<< " unknown limit param: " << limit_param_name
1288 derr
<< __func__
<< " unknown query param: " << query_param_name
<< dendl
;
1293 if (query
.key_descriptor
.empty()) {
1294 derr
<< __func__
<< " invalid query" << dendl
;
1299 auto &ds
= query
.performance_counter_descriptors
;
1300 if (std::find(ds
.begin(), ds
.end(), limit
->order_by
) == ds
.end()) {
1301 derr
<< __func__
<< " limit order_by " << limit
->order_by
1302 << " not in performance_counter_descriptors" << dendl
;
1307 auto query_id
= self
->py_modules
->add_mds_perf_query(query
, limit
);
1308 return PyLong_FromLong(query_id
);
1312 ceph_remove_mds_perf_query(BaseMgrModule
*self
, PyObject
*args
)
1314 MetricQueryID query_id
;
1315 if (!PyArg_ParseTuple(args
, "i:ceph_remove_mds_perf_query", &query_id
)) {
1316 derr
<< "Invalid args!" << dendl
;
1320 self
->py_modules
->remove_mds_perf_query(query_id
);
1325 ceph_reregister_mds_perf_queries(BaseMgrModule
*self
, PyObject
*args
)
1327 self
->py_modules
->reregister_mds_perf_queries();
1332 ceph_get_mds_perf_counters(BaseMgrModule
*self
, PyObject
*args
)
1334 MetricQueryID query_id
;
1335 if (!PyArg_ParseTuple(args
, "i:ceph_get_mds_perf_counters", &query_id
)) {
1336 derr
<< "Invalid args!" << dendl
;
1340 return self
->py_modules
->get_mds_perf_counters(query_id
);
1344 ceph_is_authorized(BaseMgrModule
*self
, PyObject
*args
)
1346 PyObject
*args_dict
= NULL
;
1347 if (!PyArg_ParseTuple(args
, "O:ceph_is_authorized", &args_dict
)) {
1351 if (!PyDict_Check(args_dict
)) {
1352 derr
<< __func__
<< " arg not a dict" << dendl
;
1356 std::map
<std::string
, std::string
> arguments
;
1358 PyObject
*args_list
= PyDict_Items(args_dict
);
1359 for (int i
= 0; i
< PyList_Size(args_list
); ++i
) {
1360 PyObject
*kv
= PyList_GET_ITEM(args_list
, i
);
1362 char *arg_key
= nullptr;
1363 char *arg_value
= nullptr;
1364 if (!PyArg_ParseTuple(kv
, "ss:pair", &arg_key
, &arg_value
)) {
1365 derr
<< __func__
<< " dict item " << i
<< " not a size 2 tuple" << dendl
;
1369 arguments
[arg_key
] = arg_value
;
1372 bool r
= without_gil([&] {
1373 return self
->this_module
->is_authorized(arguments
);
1383 ceph_register_client(BaseMgrModule
*self
, PyObject
*args
)
1385 char *addrs
= nullptr;
1386 if (!PyArg_ParseTuple(args
, "s:ceph_register_client", &addrs
)) {
1390 self
->py_modules
->register_client(self
->this_module
->get_name(), addrs
);
1396 ceph_unregister_client(BaseMgrModule
*self
, PyObject
*args
)
1398 char *addrs
= nullptr;
1399 if (!PyArg_ParseTuple(args
, "s:ceph_unregister_client", &addrs
)) {
1403 self
->py_modules
->unregister_client(self
->this_module
->get_name(), addrs
);
1408 PyMethodDef BaseMgrModule_methods
[] = {
1409 {"_ceph_get", (PyCFunction
)ceph_state_get
, METH_VARARGS
,
1410 "Get a cluster object"},
1412 {"_ceph_get_server", (PyCFunction
)ceph_get_server
, METH_VARARGS
,
1413 "Get a server object"},
1415 {"_ceph_get_metadata", (PyCFunction
)get_metadata
, METH_VARARGS
,
1416 "Get a service's metadata"},
1418 {"_ceph_get_daemon_status", (PyCFunction
)get_daemon_status
, METH_VARARGS
,
1419 "Get a service's status"},
1421 {"_ceph_send_command", (PyCFunction
)ceph_send_command
, METH_VARARGS
,
1422 "Send a mon command"},
1424 {"_ceph_set_health_checks", (PyCFunction
)ceph_set_health_checks
, METH_VARARGS
,
1425 "Set health checks for this module"},
1427 {"_ceph_get_mgr_id", (PyCFunction
)ceph_get_mgr_id
, METH_NOARGS
,
1428 "Get the name of the Mgr daemon where we are running"},
1430 {"_ceph_get_ceph_conf_path", (PyCFunction
)ceph_get_ceph_conf_path
, METH_NOARGS
,
1431 "Get path to ceph.conf"},
1433 {"_ceph_get_option", (PyCFunction
)ceph_option_get
, METH_VARARGS
,
1434 "Get a native configuration option value"},
1436 {"_ceph_get_foreign_option", (PyCFunction
)ceph_foreign_option_get
, METH_VARARGS
,
1437 "Get a native configuration option value for another entity"},
1439 {"_ceph_get_module_option", (PyCFunction
)ceph_get_module_option
, METH_VARARGS
,
1440 "Get a module configuration option value"},
1442 {"_ceph_get_store_prefix", (PyCFunction
)ceph_store_get_prefix
, METH_VARARGS
,
1443 "Get all KV store values with a given prefix"},
1445 {"_ceph_set_module_option", (PyCFunction
)ceph_set_module_option
, METH_VARARGS
,
1446 "Set a module configuration option value"},
1448 {"_ceph_get_store", (PyCFunction
)ceph_store_get
, METH_VARARGS
,
1449 "Get a stored field"},
1451 {"_ceph_set_store", (PyCFunction
)ceph_store_set
, METH_VARARGS
,
1452 "Set a stored field"},
1454 {"_ceph_get_counter", (PyCFunction
)get_counter
, METH_VARARGS
,
1455 "Get a performance counter"},
1457 {"_ceph_get_latest_counter", (PyCFunction
)get_latest_counter
, METH_VARARGS
,
1458 "Get the latest performance counter"},
1460 {"_ceph_get_perf_schema", (PyCFunction
)get_perf_schema
, METH_VARARGS
,
1461 "Get the performance counter schema"},
1463 {"_ceph_get_rocksdb_version", (PyCFunction
)ceph_get_rocksdb_version
, METH_NOARGS
,
1464 "Get the current RocksDB version number"},
1466 {"_ceph_log", (PyCFunction
)ceph_log
, METH_VARARGS
,
1467 "Emit a (local) log message"},
1469 {"_ceph_cluster_log", (PyCFunction
)ceph_cluster_log
, METH_VARARGS
,
1470 "Emit a cluster log message"},
1472 {"_ceph_get_version", (PyCFunction
)ceph_get_version
, METH_NOARGS
,
1473 "Get the ceph version of this process"},
1475 {"_ceph_get_release_name", (PyCFunction
)ceph_get_release_name
, METH_NOARGS
,
1476 "Get the ceph release name of this process"},
1478 {"_ceph_lookup_release_name", (PyCFunction
)ceph_lookup_release_name
, METH_VARARGS
,
1479 "Get the ceph release name for a given major number"},
1481 {"_ceph_get_context", (PyCFunction
)ceph_get_context
, METH_NOARGS
,
1482 "Get a CephContext* in a python capsule"},
1484 {"_ceph_get_osdmap", (PyCFunction
)ceph_get_osdmap
, METH_NOARGS
,
1485 "Get an OSDMap* in a python capsule"},
1487 {"_ceph_set_uri", (PyCFunction
)ceph_set_uri
, METH_VARARGS
,
1488 "Advertize a service URI served by this module"},
1490 {"_ceph_set_device_wear_level", (PyCFunction
)ceph_set_wear_level
, METH_VARARGS
,
1491 "Set device wear_level value"},
1493 {"_ceph_have_mon_connection", (PyCFunction
)ceph_have_mon_connection
,
1494 METH_NOARGS
, "Find out whether this mgr daemon currently has "
1495 "a connection to a monitor"},
1497 {"_ceph_update_progress_event", (PyCFunction
)ceph_update_progress_event
,
1498 METH_VARARGS
, "Update status of a progress event"},
1499 {"_ceph_complete_progress_event", (PyCFunction
)ceph_complete_progress_event
,
1500 METH_VARARGS
, "Complete a progress event"},
1501 {"_ceph_clear_all_progress_events", (PyCFunction
)ceph_clear_all_progress_events
,
1502 METH_NOARGS
, "Clear all progress events"},
1504 {"_ceph_dispatch_remote", (PyCFunction
)ceph_dispatch_remote
,
1505 METH_VARARGS
, "Dispatch a call to another module"},
1507 {"_ceph_add_osd_perf_query", (PyCFunction
)ceph_add_osd_perf_query
,
1508 METH_VARARGS
, "Add an osd perf query"},
1510 {"_ceph_remove_osd_perf_query", (PyCFunction
)ceph_remove_osd_perf_query
,
1511 METH_VARARGS
, "Remove an osd perf query"},
1513 {"_ceph_get_osd_perf_counters", (PyCFunction
)ceph_get_osd_perf_counters
,
1514 METH_VARARGS
, "Get osd perf counters"},
1516 {"_ceph_add_mds_perf_query", (PyCFunction
)ceph_add_mds_perf_query
,
1517 METH_VARARGS
, "Add an mds perf query"},
1519 {"_ceph_remove_mds_perf_query", (PyCFunction
)ceph_remove_mds_perf_query
,
1520 METH_VARARGS
, "Remove an mds perf query"},
1522 {"_ceph_reregister_mds_perf_queries", (PyCFunction
)ceph_reregister_mds_perf_queries
,
1523 METH_NOARGS
, "Re-register mds perf queries"},
1525 {"_ceph_get_mds_perf_counters", (PyCFunction
)ceph_get_mds_perf_counters
,
1526 METH_VARARGS
, "Get mds perf counters"},
1528 {"_ceph_is_authorized", (PyCFunction
)ceph_is_authorized
,
1529 METH_VARARGS
, "Verify the current session caps are valid"},
1531 {"_ceph_register_client", (PyCFunction
)ceph_register_client
,
1532 METH_VARARGS
, "Register RADOS instance for potential blocklisting"},
1534 {"_ceph_unregister_client", (PyCFunction
)ceph_unregister_client
,
1535 METH_VARARGS
, "Unregister RADOS instance for potential blocklisting"},
1537 {NULL
, NULL
, 0, NULL
}
1542 BaseMgrModule_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwds
)
1544 BaseMgrModule
*self
;
1546 self
= (BaseMgrModule
*)type
->tp_alloc(type
, 0);
1548 return (PyObject
*)self
;
1552 BaseMgrModule_init(BaseMgrModule
*self
, PyObject
*args
, PyObject
*kwds
)
1554 PyObject
*py_modules_capsule
= nullptr;
1555 PyObject
*this_module_capsule
= nullptr;
1556 static const char *kwlist
[] = {"py_modules", "this_module", NULL
};
1558 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "OO",
1559 const_cast<char**>(kwlist
),
1560 &py_modules_capsule
,
1561 &this_module_capsule
)) {
1565 self
->py_modules
= static_cast<ActivePyModules
*>(PyCapsule_GetPointer(
1566 py_modules_capsule
, nullptr));
1567 ceph_assert(self
->py_modules
);
1568 self
->this_module
= static_cast<ActivePyModule
*>(PyCapsule_GetPointer(
1569 this_module_capsule
, nullptr));
1570 ceph_assert(self
->this_module
);
1575 PyTypeObject BaseMgrModuleType
= {
1576 PyVarObject_HEAD_INIT(NULL
, 0)
1577 "ceph_module.BaseMgrModule", /* tp_name */
1578 sizeof(BaseMgrModule
), /* tp_basicsize */
1579 0, /* tp_itemsize */
1586 0, /* tp_as_number */
1587 0, /* tp_as_sequence */
1588 0, /* tp_as_mapping */
1592 0, /* tp_getattro */
1593 0, /* tp_setattro */
1594 0, /* tp_as_buffer */
1595 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
1596 "ceph-mgr Python Plugin", /* tp_doc */
1597 0, /* tp_traverse */
1599 0, /* tp_richcompare */
1600 0, /* tp_weaklistoffset */
1602 0, /* tp_iternext */
1603 BaseMgrModule_methods
, /* tp_methods */
1608 0, /* tp_descr_get */
1609 0, /* tp_descr_set */
1610 0, /* tp_dictoffset */
1611 (initproc
)BaseMgrModule_init
, /* tp_init */
1613 BaseMgrModule_new
, /* tp_new */