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 ""
44 ActivePyModules
*py_modules
;
45 ActivePyModule
*this_module
;
48 class MonCommandCompletion
: public Context
50 ActivePyModules
*py_modules
;
51 PyObject
*python_completion
;
52 const std::string tag
;
53 SafeThreadState pThreadState
;
60 ActivePyModules
*py_modules_
, PyObject
* ev
,
61 const std::string
&tag_
, PyThreadState
*ts_
)
62 : py_modules(py_modules_
), python_completion(ev
),
63 tag(tag_
), pThreadState(ts_
)
65 ceph_assert(python_completion
!= nullptr);
66 Py_INCREF(python_completion
);
69 ~MonCommandCompletion() override
71 if (python_completion
) {
72 // Usually do this in finish(): this path is only for if we're
73 // being destroyed without completing.
74 Gil
gil(pThreadState
, true);
75 Py_DECREF(python_completion
);
76 python_completion
= nullptr;
80 void finish(int r
) override
82 ceph_assert(python_completion
!= nullptr);
84 dout(10) << "MonCommandCompletion::finish()" << dendl
;
86 // Scoped so the Gil is released before calling notify_all()
87 // Create new thread state because this is called via the MonClient
88 // Finisher, not the PyModules finisher.
89 Gil
gil(pThreadState
, true);
91 auto set_fn
= PyObject_GetAttrString(python_completion
, "complete");
92 ceph_assert(set_fn
!= nullptr);
94 auto pyR
= PyLong_FromLong(r
);
95 auto pyOutBl
= PyUnicode_FromString(outbl
.to_str().c_str());
96 auto pyOutS
= PyUnicode_FromString(outs
.c_str());
97 auto args
= PyTuple_Pack(3, pyR
, pyOutBl
, pyOutS
);
102 auto rtn
= PyObject_CallObject(set_fn
, args
);
103 if (rtn
!= nullptr) {
109 Py_DECREF(python_completion
);
110 python_completion
= nullptr;
112 py_modules
->notify_all("command", tag
);
118 ceph_send_command(BaseMgrModule
*self
, PyObject
*args
)
120 // Like mon, osd, mds
121 char *type
= nullptr;
123 // Like "23" for an OSD or "myid" for an MDS
124 char *name
= nullptr;
126 char *cmd_json
= nullptr;
128 char *inbuf_ptr
= nullptr;
129 Py_ssize_t inbuf_len
= 0;
130 bufferlist inbuf
= {};
132 PyObject
*completion
= nullptr;
133 if (!PyArg_ParseTuple(args
, "Ossssz#:ceph_send_command",
134 &completion
, &type
, &name
, &cmd_json
, &tag
, &inbuf_ptr
, &inbuf_len
)) {
139 inbuf
.append(inbuf_ptr
, (unsigned)inbuf_len
);
142 auto set_fn
= PyObject_GetAttrString(completion
, "complete");
143 if (set_fn
== nullptr) {
144 ceph_abort(); // TODO raise python exception instead
146 ceph_assert(PyCallable_Check(set_fn
));
150 MonCommandCompletion
*command_c
= new MonCommandCompletion(self
->py_modules
,
151 completion
, tag
, PyThreadState_Get());
153 PyThreadState
*tstate
= PyEval_SaveThread();
155 if (std::string(type
) == "mon") {
157 // Wait for the latest OSDMap after each command we send to
158 // the mons. This is a heavy-handed hack to make life simpler
159 // for python module authors, so that they know whenever they
160 // run a command they've gt a fresh OSDMap afterwards.
161 // TODO: enhance MCommand interface so that it returns
162 // latest cluster map versions on completion, and callers
163 // can wait for those.
164 auto c
= new LambdaContext([command_c
, self
](int command_r
){
165 self
->py_modules
->get_objecter().wait_for_latest_osdmap(
166 [command_c
, command_r
](boost::system::error_code
) {
167 command_c
->complete(command_r
);
171 self
->py_modules
->get_monc().start_mon_command(
177 new C_OnFinisher(c
, &self
->py_modules
->cmd_finisher
));
178 } else if (std::string(type
) == "osd") {
180 uint64_t osd_id
= strict_strtoll(name
, 10, &err
);
183 string
msg("invalid osd_id: ");
184 msg
.append("\"").append(name
).append("\"");
185 PyEval_RestoreThread(tstate
);
186 PyErr_SetString(PyExc_ValueError
, msg
.c_str());
191 self
->py_modules
->get_objecter().osd_command(
196 [command_c
, f
= &self
->py_modules
->cmd_finisher
]
197 (boost::system::error_code ec
, std::string s
, ceph::buffer::list bl
) {
198 command_c
->outs
= std::move(s
);
199 command_c
->outbl
= std::move(bl
);
202 } else if (std::string(type
) == "mds") {
203 int r
= self
->py_modules
->get_client().mds_command(
209 new C_OnFinisher(command_c
, &self
->py_modules
->cmd_finisher
));
211 string
msg("failed to send command to mds: ");
212 msg
.append(cpp_strerror(r
));
213 PyEval_RestoreThread(tstate
);
214 PyErr_SetString(PyExc_RuntimeError
, msg
.c_str());
217 } else if (std::string(type
) == "pg") {
219 if (!pgid
.parse(name
)) {
221 string
msg("invalid pgid: ");
222 msg
.append("\"").append(name
).append("\"");
223 PyEval_RestoreThread(tstate
);
224 PyErr_SetString(PyExc_ValueError
, msg
.c_str());
229 self
->py_modules
->get_objecter().pg_command(
234 [command_c
, f
= &self
->py_modules
->cmd_finisher
]
235 (boost::system::error_code ec
, std::string s
, ceph::buffer::list bl
) {
236 command_c
->outs
= std::move(s
);
237 command_c
->outbl
= std::move(bl
);
240 PyEval_RestoreThread(tstate
);
244 string
msg("unknown service type: ");
246 PyEval_RestoreThread(tstate
);
247 PyErr_SetString(PyExc_ValueError
, msg
.c_str());
251 PyEval_RestoreThread(tstate
);
256 ceph_set_health_checks(BaseMgrModule
*self
, PyObject
*args
)
258 PyObject
*checks
= NULL
;
259 if (!PyArg_ParseTuple(args
, "O:ceph_set_health_checks", &checks
)) {
262 if (!PyDict_Check(checks
)) {
263 derr
<< __func__
<< " arg not a dict" << dendl
;
266 PyObject
*checksls
= PyDict_Items(checks
);
267 health_check_map_t out_checks
;
268 for (int i
= 0; i
< PyList_Size(checksls
); ++i
) {
269 PyObject
*kv
= PyList_GET_ITEM(checksls
, i
);
270 char *check_name
= nullptr;
271 PyObject
*check_info
= nullptr;
272 if (!PyArg_ParseTuple(kv
, "sO:pair", &check_name
, &check_info
)) {
273 derr
<< __func__
<< " dict item " << i
274 << " not a size 2 tuple" << dendl
;
277 if (!PyDict_Check(check_info
)) {
278 derr
<< __func__
<< " item " << i
<< " " << check_name
279 << " value not a dict" << dendl
;
282 health_status_t severity
= HEALTH_OK
;
286 PyObject
*infols
= PyDict_Items(check_info
);
287 for (int j
= 0; j
< PyList_Size(infols
); ++j
) {
288 PyObject
*pair
= PyList_GET_ITEM(infols
, j
);
289 if (!PyTuple_Check(pair
)) {
290 derr
<< __func__
<< " item " << i
<< " pair " << j
291 << " not a tuple" << dendl
;
295 PyObject
*v
= nullptr;
296 if (!PyArg_ParseTuple(pair
, "sO:pair", &k
, &v
)) {
297 derr
<< __func__
<< " item " << i
<< " pair " << j
298 << " not a size 2 tuple" << dendl
;
302 if (ks
== "severity") {
303 if (!PyUnicode_Check(v
)) {
304 derr
<< __func__
<< " check " << check_name
305 << " severity value not string" << dendl
;
308 if (const string vs
= PyUnicode_AsUTF8(v
); vs
== "warning") {
309 severity
= HEALTH_WARN
;
310 } else if (vs
== "error") {
311 severity
= HEALTH_ERR
;
313 } else if (ks
== "summary") {
314 if (!PyUnicode_Check(v
)) {
315 derr
<< __func__
<< " check " << check_name
316 << " summary value not [unicode] string" << dendl
;
319 summary
= PyUnicode_AsUTF8(v
);
321 } else if (ks
== "count") {
322 if (PyLong_Check(v
)) {
323 count
= PyLong_AsLong(v
);
325 derr
<< __func__
<< " check " << check_name
326 << " count value not int" << dendl
;
329 } else if (ks
== "detail") {
330 if (!PyList_Check(v
)) {
331 derr
<< __func__
<< " check " << check_name
332 << " detail value not list" << dendl
;
335 for (int k
= 0; k
< PyList_Size(v
); ++k
) {
336 PyObject
*di
= PyList_GET_ITEM(v
, k
);
337 if (!PyUnicode_Check(di
)) {
338 derr
<< __func__
<< " check " << check_name
339 << " detail item " << k
<< " not a [unicode] string" << dendl
;
342 detail
.push_back(PyUnicode_AsUTF8(di
));
346 derr
<< __func__
<< " check " << check_name
347 << " unexpected key " << k
<< dendl
;
350 auto& d
= out_checks
.add(check_name
, severity
, summary
, count
);
351 d
.detail
.swap(detail
);
354 JSONFormatter
jf(true);
355 dout(10) << "module " << self
->this_module
->get_name()
356 << " health checks:\n";
357 out_checks
.dump(&jf
);
361 PyThreadState
*tstate
= PyEval_SaveThread();
362 self
->py_modules
->set_health_checks(self
->this_module
->get_name(),
363 std::move(out_checks
));
364 PyEval_RestoreThread(tstate
);
371 ceph_state_get(BaseMgrModule
*self
, PyObject
*args
)
374 if (!PyArg_ParseTuple(args
, "s:ceph_state_get", &what
)) {
378 return self
->py_modules
->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 boost::optional
<string
> val
;
495 PyThreadState
*tstate
= PyEval_SaveThread();
496 self
->py_modules
->set_config(module
, key
, val
);
497 PyEval_RestoreThread(tstate
);
503 ceph_store_get(BaseMgrModule
*self
, PyObject
*args
)
505 char *what
= nullptr;
506 if (!PyArg_ParseTuple(args
, "s:ceph_store_get", &what
)) {
507 derr
<< "Invalid args!" << dendl
;
512 bool found
= self
->py_modules
->get_store(self
->this_module
->get_name(),
515 dout(10) << "ceph_store_get " << what
<< " found: " << value
.c_str() << dendl
;
516 return PyUnicode_FromString(value
.c_str());
518 dout(4) << "ceph_store_get " << what
<< " not found " << dendl
;
524 ceph_store_set(BaseMgrModule
*self
, PyObject
*args
)
527 char *value
= nullptr;
528 if (!PyArg_ParseTuple(args
, "sz:ceph_store_set", &key
, &value
)) {
531 boost::optional
<string
> val
;
535 PyThreadState
*tstate
= PyEval_SaveThread();
536 self
->py_modules
->set_store(self
->this_module
->get_name(), key
, val
);
537 PyEval_RestoreThread(tstate
);
543 get_metadata(BaseMgrModule
*self
, PyObject
*args
)
545 char *svc_name
= NULL
;
547 if (!PyArg_ParseTuple(args
, "ss:get_metadata", &svc_name
, &svc_id
)) {
550 return self
->py_modules
->get_metadata_python(svc_name
, svc_id
);
554 get_daemon_status(BaseMgrModule
*self
, PyObject
*args
)
556 char *svc_name
= NULL
;
558 if (!PyArg_ParseTuple(args
, "ss:get_daemon_status", &svc_name
,
562 return self
->py_modules
->get_daemon_status_python(svc_name
, svc_id
);
566 ceph_log(BaseMgrModule
*self
, PyObject
*args
)
568 char *record
= nullptr;
569 if (!PyArg_ParseTuple(args
, "s:log", &record
)) {
573 ceph_assert(self
->this_module
);
575 self
->this_module
->log(record
);
581 ceph_cluster_log(BaseMgrModule
*self
, PyObject
*args
)
584 char *channel
= nullptr;
585 char *message
= nullptr;
587 if (!PyArg_ParseTuple(args
, "sis:ceph_cluster_log", &channel
, &prio
, &message
)) {
591 PyThreadState
*tstate
= PyEval_SaveThread();
592 self
->py_modules
->cluster_log(channel
, (clog_type
)prio
, message
);
593 PyEval_RestoreThread(tstate
);
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_osdmap(BaseMgrModule
*self
, PyObject
*args
)
676 return self
->py_modules
->get_osdmap();
680 ceph_set_uri(BaseMgrModule
*self
, PyObject
*args
)
682 char *svc_str
= nullptr;
683 if (!PyArg_ParseTuple(args
, "s:ceph_advertize_service",
688 // We call down into PyModules even though we have a MgrPyModule
689 // reference here, because MgrPyModule's fields are protected
690 // by PyModules' lock.
691 PyThreadState
*tstate
= PyEval_SaveThread();
692 self
->py_modules
->set_uri(self
->this_module
->get_name(), svc_str
);
693 PyEval_RestoreThread(tstate
);
699 ceph_set_wear_level(BaseMgrModule
*self
, PyObject
*args
)
701 char *devid
= nullptr;
703 if (!PyArg_ParseTuple(args
, "sf:ceph_set_wear_level",
704 &devid
, &wear_level
)) {
708 PyThreadState
*tstate
= PyEval_SaveThread();
709 self
->py_modules
->set_device_wear_level(devid
, wear_level
);
710 PyEval_RestoreThread(tstate
);
716 ceph_have_mon_connection(BaseMgrModule
*self
, PyObject
*args
)
718 if (self
->py_modules
->get_monc().is_connected()) {
726 ceph_update_progress_event(BaseMgrModule
*self
, PyObject
*args
)
728 char *evid
= nullptr;
729 char *desc
= nullptr;
730 float progress
= 0.0;
731 bool add_to_ceph_s
= false;
732 if (!PyArg_ParseTuple(args
, "ssfb:ceph_update_progress_event",
733 &evid
, &desc
, &progress
, &add_to_ceph_s
)) {
737 PyThreadState
*tstate
= PyEval_SaveThread();
738 self
->py_modules
->update_progress_event(evid
, desc
, progress
, add_to_ceph_s
);
739 PyEval_RestoreThread(tstate
);
745 ceph_complete_progress_event(BaseMgrModule
*self
, PyObject
*args
)
747 char *evid
= nullptr;
748 if (!PyArg_ParseTuple(args
, "s:ceph_complete_progress_event",
753 PyThreadState
*tstate
= PyEval_SaveThread();
754 self
->py_modules
->complete_progress_event(evid
);
755 PyEval_RestoreThread(tstate
);
761 ceph_clear_all_progress_events(BaseMgrModule
*self
, PyObject
*args
)
763 PyThreadState
*tstate
= PyEval_SaveThread();
764 self
->py_modules
->clear_all_progress_events();
765 PyEval_RestoreThread(tstate
);
773 ceph_dispatch_remote(BaseMgrModule
*self
, PyObject
*args
)
775 char *other_module
= nullptr;
776 char *method
= nullptr;
777 PyObject
*remote_args
= nullptr;
778 PyObject
*remote_kwargs
= nullptr;
779 if (!PyArg_ParseTuple(args
, "ssOO:ceph_dispatch_remote",
780 &other_module
, &method
, &remote_args
, &remote_kwargs
)) {
784 // Early error handling, because if the module doesn't exist then we
785 // won't be able to use its thread state to set python error state
786 // inside dispatch_remote().
787 if (!self
->py_modules
->module_exists(other_module
)) {
788 derr
<< "no module '" << other_module
<< "'" << dendl
;
789 PyErr_SetString(PyExc_ImportError
, "Module not found");
793 // Drop GIL from calling python thread state, it will be taken
794 // both for checking for method existence and for executing method.
795 PyThreadState
*tstate
= PyEval_SaveThread();
797 if (!self
->py_modules
->method_exists(other_module
, method
)) {
798 PyEval_RestoreThread(tstate
);
799 PyErr_SetString(PyExc_NameError
, "Method not found");
804 auto result
= self
->py_modules
->dispatch_remote(other_module
, method
,
805 remote_args
, remote_kwargs
, &err
);
807 PyEval_RestoreThread(tstate
);
809 if (result
== nullptr) {
810 std::stringstream ss
;
811 ss
<< "Remote method threw exception: " << err
;
812 PyErr_SetString(PyExc_RuntimeError
, ss
.str().c_str());
813 derr
<< ss
.str() << dendl
;
820 ceph_add_osd_perf_query(BaseMgrModule
*self
, PyObject
*args
)
822 static const std::string NAME_KEY_DESCRIPTOR
= "key_descriptor";
823 static const std::string NAME_COUNTERS_DESCRIPTORS
=
824 "performance_counter_descriptors";
825 static const std::string NAME_LIMIT
= "limit";
826 static const std::string NAME_SUB_KEY_TYPE
= "type";
827 static const std::string NAME_SUB_KEY_REGEX
= "regex";
828 static const std::string NAME_LIMIT_ORDER_BY
= "order_by";
829 static const std::string NAME_LIMIT_MAX_COUNT
= "max_count";
830 static const std::map
<std::string
, OSDPerfMetricSubKeyType
> sub_key_types
= {
831 {"client_id", OSDPerfMetricSubKeyType::CLIENT_ID
},
832 {"client_address", OSDPerfMetricSubKeyType::CLIENT_ADDRESS
},
833 {"pool_id", OSDPerfMetricSubKeyType::POOL_ID
},
834 {"namespace", OSDPerfMetricSubKeyType::NAMESPACE
},
835 {"osd_id", OSDPerfMetricSubKeyType::OSD_ID
},
836 {"pg_id", OSDPerfMetricSubKeyType::PG_ID
},
837 {"object_name", OSDPerfMetricSubKeyType::OBJECT_NAME
},
838 {"snap_id", OSDPerfMetricSubKeyType::SNAP_ID
},
840 static const std::map
<std::string
, PerformanceCounterType
> counter_types
= {
841 {"ops", PerformanceCounterType::OPS
},
842 {"write_ops", PerformanceCounterType::WRITE_OPS
},
843 {"read_ops", PerformanceCounterType::READ_OPS
},
844 {"bytes", PerformanceCounterType::BYTES
},
845 {"write_bytes", PerformanceCounterType::WRITE_BYTES
},
846 {"read_bytes", PerformanceCounterType::READ_BYTES
},
847 {"latency", PerformanceCounterType::LATENCY
},
848 {"write_latency", PerformanceCounterType::WRITE_LATENCY
},
849 {"read_latency", PerformanceCounterType::READ_LATENCY
},
852 PyObject
*py_query
= nullptr;
853 if (!PyArg_ParseTuple(args
, "O:ceph_add_osd_perf_query", &py_query
)) {
854 derr
<< "Invalid args!" << dendl
;
857 if (!PyDict_Check(py_query
)) {
858 derr
<< __func__
<< " arg not a dict" << dendl
;
862 PyObject
*query_params
= PyDict_Items(py_query
);
863 OSDPerfMetricQuery query
;
864 std::optional
<OSDPerfMetricLimit
> limit
;
867 // 'key_descriptor': [
868 // {'type': subkey_type, 'regex': regex_pattern},
871 // 'performance_counter_descriptors': [
872 // list, of, descriptor, types
874 // 'limit': {'order_by': performance_counter_type, 'max_count': n},
877 for (int i
= 0; i
< PyList_Size(query_params
); ++i
) {
878 PyObject
*kv
= PyList_GET_ITEM(query_params
, i
);
879 char *query_param_name
= nullptr;
880 PyObject
*query_param_val
= nullptr;
881 if (!PyArg_ParseTuple(kv
, "sO:pair", &query_param_name
, &query_param_val
)) {
882 derr
<< __func__
<< " dict item " << i
<< " not a size 2 tuple" << dendl
;
885 if (query_param_name
== NAME_KEY_DESCRIPTOR
) {
886 if (!PyList_Check(query_param_val
)) {
887 derr
<< __func__
<< " " << query_param_name
<< " not a list" << dendl
;
890 for (int j
= 0; j
< PyList_Size(query_param_val
); j
++) {
891 PyObject
*sub_key
= PyList_GET_ITEM(query_param_val
, j
);
892 if (!PyDict_Check(sub_key
)) {
893 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
894 << " not a dict" << dendl
;
897 OSDPerfMetricSubKeyDescriptor d
;
898 PyObject
*sub_key_params
= PyDict_Items(sub_key
);
899 for (int k
= 0; k
< PyList_Size(sub_key_params
); ++k
) {
900 PyObject
*pair
= PyList_GET_ITEM(sub_key_params
, k
);
901 if (!PyTuple_Check(pair
)) {
902 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
903 << " pair " << k
<< " not a tuple" << dendl
;
906 char *param_name
= nullptr;
907 PyObject
*param_value
= nullptr;
908 if (!PyArg_ParseTuple(pair
, "sO:pair", ¶m_name
, ¶m_value
)) {
909 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
910 << " pair " << k
<< " not a size 2 tuple" << dendl
;
913 if (param_name
== NAME_SUB_KEY_TYPE
) {
914 if (!PyUnicode_Check(param_value
)) {
915 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
916 << " contains invalid param " << param_name
<< dendl
;
919 auto type
= PyUnicode_AsUTF8(param_value
);
920 auto it
= sub_key_types
.find(type
);
921 if (it
== sub_key_types
.end()) {
922 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
923 << " contains invalid type " << dendl
;
927 } else if (param_name
== NAME_SUB_KEY_REGEX
) {
928 if (!PyUnicode_Check(param_value
)) {
929 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
930 << " contains invalid param " << param_name
<< dendl
;
933 d
.regex_str
= PyUnicode_AsUTF8(param_value
);
935 d
.regex
= d
.regex_str
.c_str();
936 } catch (const std::regex_error
& e
) {
937 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
938 << " contains invalid regex " << d
.regex_str
<< dendl
;
941 if (d
.regex
.mark_count() == 0) {
942 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
943 << " regex " << d
.regex_str
<< ": no capturing groups"
948 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
949 << " contains invalid param " << param_name
<< dendl
;
953 if (d
.type
== static_cast<OSDPerfMetricSubKeyType
>(-1) ||
954 d
.regex_str
.empty()) {
955 derr
<< __func__
<< " query " << query_param_name
<< " item " << i
956 << " invalid" << dendl
;
959 query
.key_descriptor
.push_back(d
);
961 } else if (query_param_name
== NAME_COUNTERS_DESCRIPTORS
) {
962 if (!PyList_Check(query_param_val
)) {
963 derr
<< __func__
<< " " << query_param_name
<< " not a list" << dendl
;
966 for (int j
= 0; j
< PyList_Size(query_param_val
); j
++) {
967 PyObject
*py_type
= PyList_GET_ITEM(query_param_val
, j
);
968 if (!PyUnicode_Check(py_type
)) {
969 derr
<< __func__
<< " query " << query_param_name
<< " item " << j
970 << " not a string" << dendl
;
973 auto type
= PyUnicode_AsUTF8(py_type
);
974 auto it
= counter_types
.find(type
);
975 if (it
== counter_types
.end()) {
976 derr
<< __func__
<< " query " << query_param_name
<< " item " << type
977 << " is not valid type" << dendl
;
980 query
.performance_counter_descriptors
.push_back(it
->second
);
982 } else if (query_param_name
== NAME_LIMIT
) {
983 if (!PyDict_Check(query_param_val
)) {
984 derr
<< __func__
<< " query " << query_param_name
<< " not a dict"
989 limit
= OSDPerfMetricLimit();
990 PyObject
*limit_params
= PyDict_Items(query_param_val
);
992 for (int j
= 0; j
< PyList_Size(limit_params
); ++j
) {
993 PyObject
*kv
= PyList_GET_ITEM(limit_params
, j
);
994 char *limit_param_name
= nullptr;
995 PyObject
*limit_param_val
= nullptr;
996 if (!PyArg_ParseTuple(kv
, "sO:pair", &limit_param_name
,
998 derr
<< __func__
<< " limit item " << j
<< " not a size 2 tuple"
1003 if (limit_param_name
== NAME_LIMIT_ORDER_BY
) {
1004 if (!PyUnicode_Check(limit_param_val
)) {
1005 derr
<< __func__
<< " " << limit_param_name
<< " not a string"
1009 auto order_by
= PyUnicode_AsUTF8(limit_param_val
);
1010 auto it
= counter_types
.find(order_by
);
1011 if (it
== counter_types
.end()) {
1012 derr
<< __func__
<< " limit " << limit_param_name
1013 << " not a valid counter type" << dendl
;
1016 limit
->order_by
= it
->second
;
1017 } else if (limit_param_name
== NAME_LIMIT_MAX_COUNT
) {
1018 if (!PyLong_Check(limit_param_val
)) {
1019 derr
<< __func__
<< " " << limit_param_name
<< " not an int"
1023 limit
->max_count
= PyLong_AsLong(limit_param_val
);
1025 derr
<< __func__
<< " unknown limit param: " << limit_param_name
1031 derr
<< __func__
<< " unknown query param: " << query_param_name
<< dendl
;
1036 if (query
.key_descriptor
.empty() ||
1037 query
.performance_counter_descriptors
.empty()) {
1038 derr
<< __func__
<< " invalid query" << dendl
;
1043 auto &ds
= query
.performance_counter_descriptors
;
1044 if (std::find(ds
.begin(), ds
.end(), limit
->order_by
) == ds
.end()) {
1045 derr
<< __func__
<< " limit order_by " << limit
->order_by
1046 << " not in performance_counter_descriptors" << dendl
;
1051 auto query_id
= self
->py_modules
->add_osd_perf_query(query
, limit
);
1052 return PyLong_FromLong(query_id
);
1056 ceph_remove_osd_perf_query(BaseMgrModule
*self
, PyObject
*args
)
1058 MetricQueryID query_id
;
1059 if (!PyArg_ParseTuple(args
, "i:ceph_remove_osd_perf_query", &query_id
)) {
1060 derr
<< "Invalid args!" << dendl
;
1064 self
->py_modules
->remove_osd_perf_query(query_id
);
1069 ceph_get_osd_perf_counters(BaseMgrModule
*self
, PyObject
*args
)
1071 MetricQueryID query_id
;
1072 if (!PyArg_ParseTuple(args
, "i:ceph_get_osd_perf_counters", &query_id
)) {
1073 derr
<< "Invalid args!" << dendl
;
1077 return self
->py_modules
->get_osd_perf_counters(query_id
);
1080 // MDS perf query interface -- mostly follows ceph_add_osd_perf_query()
1084 ceph_add_mds_perf_query(BaseMgrModule
*self
, PyObject
*args
)
1086 static const std::string NAME_KEY_DESCRIPTOR
= "key_descriptor";
1087 static const std::string NAME_COUNTERS_DESCRIPTORS
=
1088 "performance_counter_descriptors";
1089 static const std::string NAME_LIMIT
= "limit";
1090 static const std::string NAME_SUB_KEY_TYPE
= "type";
1091 static const std::string NAME_SUB_KEY_REGEX
= "regex";
1092 static const std::string NAME_LIMIT_ORDER_BY
= "order_by";
1093 static const std::string NAME_LIMIT_MAX_COUNT
= "max_count";
1094 static const std::map
<std::string
, MDSPerfMetricSubKeyType
> sub_key_types
= {
1095 {"mds_rank", MDSPerfMetricSubKeyType::MDS_RANK
},
1096 {"client_id", MDSPerfMetricSubKeyType::CLIENT_ID
},
1098 static const std::map
<std::string
, MDSPerformanceCounterType
> counter_types
= {
1099 {"cap_hit", MDSPerformanceCounterType::CAP_HIT_METRIC
},
1100 {"read_latency", MDSPerformanceCounterType::READ_LATENCY_METRIC
},
1101 {"write_latency", MDSPerformanceCounterType::WRITE_LATENCY_METRIC
},
1102 {"metadata_latency", MDSPerformanceCounterType::METADATA_LATENCY_METRIC
},
1103 {"dentry_lease", MDSPerformanceCounterType::DENTRY_LEASE_METRIC
},
1104 {"opened_files", MDSPerformanceCounterType::OPENED_FILES_METRIC
},
1105 {"pinned_icaps", MDSPerformanceCounterType::PINNED_ICAPS_METRIC
},
1106 {"opened_inodes", MDSPerformanceCounterType::OPENED_INODES_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 PY_MAJOR_VERSION <= 2
1276 if (!PyInt_Check(limit_param_val
) && !PyLong_Check(limit_param_val
)) {
1278 if (!PyLong_Check(limit_param_val
)) {
1280 derr
<< __func__
<< " " << limit_param_name
<< " not an int"
1284 limit
->max_count
= PyLong_AsLong(limit_param_val
);
1286 derr
<< __func__
<< " unknown limit param: " << limit_param_name
1292 derr
<< __func__
<< " unknown query param: " << query_param_name
<< dendl
;
1297 if (query
.key_descriptor
.empty()) {
1298 derr
<< __func__
<< " invalid query" << dendl
;
1303 auto &ds
= query
.performance_counter_descriptors
;
1304 if (std::find(ds
.begin(), ds
.end(), limit
->order_by
) == ds
.end()) {
1305 derr
<< __func__
<< " limit order_by " << limit
->order_by
1306 << " not in performance_counter_descriptors" << dendl
;
1311 auto query_id
= self
->py_modules
->add_mds_perf_query(query
, limit
);
1312 return PyLong_FromLong(query_id
);
1316 ceph_remove_mds_perf_query(BaseMgrModule
*self
, PyObject
*args
)
1318 MetricQueryID query_id
;
1319 if (!PyArg_ParseTuple(args
, "i:ceph_remove_mds_perf_query", &query_id
)) {
1320 derr
<< "Invalid args!" << dendl
;
1324 self
->py_modules
->remove_mds_perf_query(query_id
);
1329 ceph_get_mds_perf_counters(BaseMgrModule
*self
, PyObject
*args
)
1331 MetricQueryID query_id
;
1332 if (!PyArg_ParseTuple(args
, "i:ceph_get_mds_perf_counters", &query_id
)) {
1333 derr
<< "Invalid args!" << dendl
;
1337 return self
->py_modules
->get_mds_perf_counters(query_id
);
1341 ceph_is_authorized(BaseMgrModule
*self
, PyObject
*args
)
1343 PyObject
*args_dict
= NULL
;
1344 if (!PyArg_ParseTuple(args
, "O:ceph_is_authorized", &args_dict
)) {
1348 if (!PyDict_Check(args_dict
)) {
1349 derr
<< __func__
<< " arg not a dict" << dendl
;
1353 std::map
<std::string
, std::string
> arguments
;
1355 PyObject
*args_list
= PyDict_Items(args_dict
);
1356 for (int i
= 0; i
< PyList_Size(args_list
); ++i
) {
1357 PyObject
*kv
= PyList_GET_ITEM(args_list
, i
);
1359 char *arg_key
= nullptr;
1360 char *arg_value
= nullptr;
1361 if (!PyArg_ParseTuple(kv
, "ss:pair", &arg_key
, &arg_value
)) {
1362 derr
<< __func__
<< " dict item " << i
<< " not a size 2 tuple" << dendl
;
1366 arguments
[arg_key
] = arg_value
;
1369 PyThreadState
*tstate
= PyEval_SaveThread();
1370 bool r
= self
->this_module
->is_authorized(arguments
);
1371 PyEval_RestoreThread(tstate
);
1380 ceph_register_client(BaseMgrModule
*self
, PyObject
*args
)
1382 char *addrs
= nullptr;
1383 if (!PyArg_ParseTuple(args
, "s:ceph_register_client", &addrs
)) {
1386 PyThreadState
*tstate
= PyEval_SaveThread();
1387 self
->py_modules
->register_client(self
->this_module
->get_name(), addrs
);
1388 PyEval_RestoreThread(tstate
);
1393 ceph_unregister_client(BaseMgrModule
*self
, PyObject
*args
)
1395 char *addrs
= nullptr;
1396 if (!PyArg_ParseTuple(args
, "s:ceph_unregister_client", &addrs
)) {
1399 PyThreadState
*tstate
= PyEval_SaveThread();
1400 self
->py_modules
->unregister_client(self
->this_module
->get_name(), addrs
);
1401 PyEval_RestoreThread(tstate
);
1405 PyMethodDef BaseMgrModule_methods
[] = {
1406 {"_ceph_get", (PyCFunction
)ceph_state_get
, METH_VARARGS
,
1407 "Get a cluster object"},
1409 {"_ceph_get_server", (PyCFunction
)ceph_get_server
, METH_VARARGS
,
1410 "Get a server object"},
1412 {"_ceph_get_metadata", (PyCFunction
)get_metadata
, METH_VARARGS
,
1413 "Get a service's metadata"},
1415 {"_ceph_get_daemon_status", (PyCFunction
)get_daemon_status
, METH_VARARGS
,
1416 "Get a service's status"},
1418 {"_ceph_send_command", (PyCFunction
)ceph_send_command
, METH_VARARGS
,
1419 "Send a mon command"},
1421 {"_ceph_set_health_checks", (PyCFunction
)ceph_set_health_checks
, METH_VARARGS
,
1422 "Set health checks for this module"},
1424 {"_ceph_get_mgr_id", (PyCFunction
)ceph_get_mgr_id
, METH_NOARGS
,
1425 "Get the name of the Mgr daemon where we are running"},
1427 {"_ceph_get_ceph_conf_path", (PyCFunction
)ceph_get_ceph_conf_path
, METH_NOARGS
,
1428 "Get path to ceph.conf"},
1430 {"_ceph_get_option", (PyCFunction
)ceph_option_get
, METH_VARARGS
,
1431 "Get a native configuration option value"},
1433 {"_ceph_get_foreign_option", (PyCFunction
)ceph_foreign_option_get
, METH_VARARGS
,
1434 "Get a native configuration option value for another entity"},
1436 {"_ceph_get_module_option", (PyCFunction
)ceph_get_module_option
, METH_VARARGS
,
1437 "Get a module configuration option value"},
1439 {"_ceph_get_store_prefix", (PyCFunction
)ceph_store_get_prefix
, METH_VARARGS
,
1440 "Get all KV store values with a given prefix"},
1442 {"_ceph_set_module_option", (PyCFunction
)ceph_set_module_option
, METH_VARARGS
,
1443 "Set a module configuration option value"},
1445 {"_ceph_get_store", (PyCFunction
)ceph_store_get
, METH_VARARGS
,
1446 "Get a stored field"},
1448 {"_ceph_set_store", (PyCFunction
)ceph_store_set
, METH_VARARGS
,
1449 "Set a stored field"},
1451 {"_ceph_get_counter", (PyCFunction
)get_counter
, METH_VARARGS
,
1452 "Get a performance counter"},
1454 {"_ceph_get_latest_counter", (PyCFunction
)get_latest_counter
, METH_VARARGS
,
1455 "Get the latest performance counter"},
1457 {"_ceph_get_perf_schema", (PyCFunction
)get_perf_schema
, METH_VARARGS
,
1458 "Get the performance counter schema"},
1460 {"_ceph_log", (PyCFunction
)ceph_log
, METH_VARARGS
,
1461 "Emit a (local) log message"},
1463 {"_ceph_cluster_log", (PyCFunction
)ceph_cluster_log
, METH_VARARGS
,
1464 "Emit a cluster log message"},
1466 {"_ceph_get_version", (PyCFunction
)ceph_get_version
, METH_NOARGS
,
1467 "Get the ceph version of this process"},
1469 {"_ceph_get_release_name", (PyCFunction
)ceph_get_release_name
, METH_NOARGS
,
1470 "Get the ceph release name of this process"},
1472 {"_ceph_lookup_release_name", (PyCFunction
)ceph_lookup_release_name
, METH_VARARGS
,
1473 "Get the ceph release name for a given major number"},
1475 {"_ceph_get_context", (PyCFunction
)ceph_get_context
, METH_NOARGS
,
1476 "Get a CephContext* in a python capsule"},
1478 {"_ceph_get_osdmap", (PyCFunction
)ceph_get_osdmap
, METH_NOARGS
,
1479 "Get an OSDMap* in a python capsule"},
1481 {"_ceph_set_uri", (PyCFunction
)ceph_set_uri
, METH_VARARGS
,
1482 "Advertize a service URI served by this module"},
1484 {"_ceph_set_device_wear_level", (PyCFunction
)ceph_set_wear_level
, METH_VARARGS
,
1485 "Set device wear_level value"},
1487 {"_ceph_have_mon_connection", (PyCFunction
)ceph_have_mon_connection
,
1488 METH_NOARGS
, "Find out whether this mgr daemon currently has "
1489 "a connection to a monitor"},
1491 {"_ceph_update_progress_event", (PyCFunction
)ceph_update_progress_event
,
1492 METH_VARARGS
, "Update status of a progress event"},
1493 {"_ceph_complete_progress_event", (PyCFunction
)ceph_complete_progress_event
,
1494 METH_VARARGS
, "Complete a progress event"},
1495 {"_ceph_clear_all_progress_events", (PyCFunction
)ceph_clear_all_progress_events
,
1496 METH_NOARGS
, "Clear all progress events"},
1498 {"_ceph_dispatch_remote", (PyCFunction
)ceph_dispatch_remote
,
1499 METH_VARARGS
, "Dispatch a call to another module"},
1501 {"_ceph_add_osd_perf_query", (PyCFunction
)ceph_add_osd_perf_query
,
1502 METH_VARARGS
, "Add an osd perf query"},
1504 {"_ceph_remove_osd_perf_query", (PyCFunction
)ceph_remove_osd_perf_query
,
1505 METH_VARARGS
, "Remove an osd perf query"},
1507 {"_ceph_get_osd_perf_counters", (PyCFunction
)ceph_get_osd_perf_counters
,
1508 METH_VARARGS
, "Get osd perf counters"},
1510 {"_ceph_add_mds_perf_query", (PyCFunction
)ceph_add_mds_perf_query
,
1511 METH_VARARGS
, "Add an osd perf query"},
1513 {"_ceph_remove_mds_perf_query", (PyCFunction
)ceph_remove_mds_perf_query
,
1514 METH_VARARGS
, "Remove an osd perf query"},
1516 {"_ceph_get_mds_perf_counters", (PyCFunction
)ceph_get_mds_perf_counters
,
1517 METH_VARARGS
, "Get osd perf counters"},
1519 {"_ceph_is_authorized", (PyCFunction
)ceph_is_authorized
,
1520 METH_VARARGS
, "Verify the current session caps are valid"},
1522 {"_ceph_register_client", (PyCFunction
)ceph_register_client
,
1523 METH_VARARGS
, "Register RADOS instance for potential blocklisting"},
1525 {"_ceph_unregister_client", (PyCFunction
)ceph_unregister_client
,
1526 METH_VARARGS
, "Unregister RADOS instance for potential blocklisting"},
1528 {NULL
, NULL
, 0, NULL
}
1533 BaseMgrModule_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwds
)
1535 BaseMgrModule
*self
;
1537 self
= (BaseMgrModule
*)type
->tp_alloc(type
, 0);
1539 return (PyObject
*)self
;
1543 BaseMgrModule_init(BaseMgrModule
*self
, PyObject
*args
, PyObject
*kwds
)
1545 PyObject
*py_modules_capsule
= nullptr;
1546 PyObject
*this_module_capsule
= nullptr;
1547 static const char *kwlist
[] = {"py_modules", "this_module", NULL
};
1549 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "OO",
1550 const_cast<char**>(kwlist
),
1551 &py_modules_capsule
,
1552 &this_module_capsule
)) {
1556 self
->py_modules
= static_cast<ActivePyModules
*>(PyCapsule_GetPointer(
1557 py_modules_capsule
, nullptr));
1558 ceph_assert(self
->py_modules
);
1559 self
->this_module
= static_cast<ActivePyModule
*>(PyCapsule_GetPointer(
1560 this_module_capsule
, nullptr));
1561 ceph_assert(self
->this_module
);
1566 PyTypeObject BaseMgrModuleType
= {
1567 PyVarObject_HEAD_INIT(NULL
, 0)
1568 "ceph_module.BaseMgrModule", /* tp_name */
1569 sizeof(BaseMgrModule
), /* tp_basicsize */
1570 0, /* tp_itemsize */
1577 0, /* tp_as_number */
1578 0, /* tp_as_sequence */
1579 0, /* tp_as_mapping */
1583 0, /* tp_getattro */
1584 0, /* tp_setattro */
1585 0, /* tp_as_buffer */
1586 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
1587 "ceph-mgr Python Plugin", /* tp_doc */
1588 0, /* tp_traverse */
1590 0, /* tp_richcompare */
1591 0, /* tp_weaklistoffset */
1593 0, /* tp_iternext */
1594 BaseMgrModule_methods
, /* tp_methods */
1599 0, /* tp_descr_get */
1600 0, /* tp_descr_set */
1601 0, /* tp_dictoffset */
1602 (initproc
)BaseMgrModule_init
, /* tp_init */
1604 BaseMgrModule_new
, /* tp_new */