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
21 #include "mon/MonClient.h"
22 #include "common/errno.h"
23 #include "common/version.h"
28 #define dout_context g_ceph_context
29 #define dout_subsys ceph_subsys_mgr
31 PyModules
*global_handle
= NULL
;
34 class MonCommandCompletion
: public Context
36 PyObject
*python_completion
;
37 const std::string tag
;
38 PyThreadState
*pThreadState
;
44 MonCommandCompletion(PyObject
* ev
, const std::string
&tag_
, PyThreadState
*ts_
)
45 : python_completion(ev
), tag(tag_
), pThreadState(ts_
)
47 assert(python_completion
!= nullptr);
48 Py_INCREF(python_completion
);
51 ~MonCommandCompletion() override
53 Py_DECREF(python_completion
);
56 void finish(int r
) override
58 dout(10) << "MonCommandCompletion::finish()" << dendl
;
60 // Scoped so the Gil is released before calling notify_all()
61 Gil
gil(pThreadState
);
63 auto set_fn
= PyObject_GetAttrString(python_completion
, "complete");
64 assert(set_fn
!= nullptr);
66 auto pyR
= PyInt_FromLong(r
);
67 auto pyOutBl
= PyString_FromString(outbl
.to_str().c_str());
68 auto pyOutS
= PyString_FromString(outs
.c_str());
69 auto args
= PyTuple_Pack(3, pyR
, pyOutBl
, pyOutS
);
74 auto rtn
= PyObject_CallObject(set_fn
, args
);
80 global_handle
->notify_all("command", tag
);
86 ceph_send_command(PyObject
*self
, PyObject
*args
)
88 char *handle
= nullptr;
93 // Like "23" for an OSD or "myid" for an MDS
96 char *cmd_json
= nullptr;
98 PyObject
*completion
= nullptr;
99 if (!PyArg_ParseTuple(args
, "sOssss:ceph_send_command",
100 &handle
, &completion
, &type
, &name
, &cmd_json
, &tag
)) {
104 auto set_fn
= PyObject_GetAttrString(completion
, "complete");
105 if (set_fn
== nullptr) {
106 ceph_abort(); // TODO raise python exception instead
108 assert(PyCallable_Check(set_fn
));
112 auto c
= new MonCommandCompletion(completion
, tag
, PyThreadState_Get());
113 if (std::string(type
) == "mon") {
114 global_handle
->get_monc().start_mon_command(
120 } else if (std::string(type
) == "osd") {
122 uint64_t osd_id
= strict_strtoll(name
, 10, &err
);
125 string
msg("invalid osd_id: ");
126 msg
.append("\"").append(name
).append("\"");
127 PyErr_SetString(PyExc_ValueError
, msg
.c_str());
132 global_handle
->get_objecter().osd_command(
140 } else if (std::string(type
) == "mds") {
141 int r
= global_handle
->get_client().mds_command(
149 string
msg("failed to send command to mds: ");
150 msg
.append(cpp_strerror(r
));
151 PyErr_SetString(PyExc_RuntimeError
, msg
.c_str());
154 } else if (std::string(type
) == "pg") {
155 // TODO: expose objecter::pg_command
158 string
msg("unknown service type: ");
160 PyErr_SetString(PyExc_ValueError
, msg
.c_str());
169 ceph_state_get(PyObject
*self
, PyObject
*args
)
171 char *handle
= nullptr;
173 if (!PyArg_ParseTuple(args
, "ss:ceph_state_get", &handle
, &what
)) {
177 return global_handle
->get_python(what
);
182 ceph_get_server(PyObject
*self
, PyObject
*args
)
184 char *handle
= nullptr;
185 char *hostname
= NULL
;
186 if (!PyArg_ParseTuple(args
, "sz:ceph_get_server", &handle
, &hostname
)) {
191 return global_handle
->get_server_python(hostname
);
193 return global_handle
->list_servers_python();
198 ceph_get_mgr_id(PyObject
*self
, PyObject
*args
)
200 return PyString_FromString(g_conf
->name
.get_id().c_str());
204 ceph_config_get(PyObject
*self
, PyObject
*args
)
206 char *handle
= nullptr;
207 char *what
= nullptr;
208 if (!PyArg_ParseTuple(args
, "ss:ceph_config_get", &handle
, &what
)) {
209 derr
<< "Invalid args!" << dendl
;
214 bool found
= global_handle
->get_config(handle
, what
, &value
);
216 dout(10) << "ceph_config_get " << what
<< " found: " << value
.c_str() << dendl
;
217 return PyString_FromString(value
.c_str());
219 derr
<< "ceph_config_get " << what
<< " not found " << dendl
;
225 ceph_config_get_prefix(PyObject
*self
, PyObject
*args
)
227 char *handle
= nullptr;
228 char *prefix
= nullptr;
229 if (!PyArg_ParseTuple(args
, "ss:ceph_config_get", &handle
, &prefix
)) {
230 derr
<< "Invalid args!" << dendl
;
234 return global_handle
->get_config_prefix(handle
, prefix
);
238 ceph_config_set(PyObject
*self
, PyObject
*args
)
240 char *handle
= nullptr;
242 char *value
= nullptr;
243 if (!PyArg_ParseTuple(args
, "sss:ceph_config_set", &handle
, &key
, &value
)) {
247 global_handle
->set_config(handle
, key
, value
);
252 static entity_type_t
svc_type_from_str(const std::string
&type_str
)
254 if (type_str
== std::string("mds")) {
255 return CEPH_ENTITY_TYPE_MDS
;
256 } else if (type_str
== std::string("osd")) {
257 return CEPH_ENTITY_TYPE_OSD
;
258 } else if (type_str
== std::string("mon")) {
259 return CEPH_ENTITY_TYPE_MON
;
261 return CEPH_ENTITY_TYPE_ANY
;
266 get_metadata(PyObject
*self
, PyObject
*args
)
268 char *handle
= nullptr;
269 char *type_str
= NULL
;
271 if (!PyArg_ParseTuple(args
, "sss:get_metadata", &handle
, &type_str
, &svc_id
)) {
275 entity_type_t svc_type
= svc_type_from_str(type_str
);
276 if (svc_type
== CEPH_ENTITY_TYPE_ANY
) {
277 // FIXME: form a proper exception
282 return global_handle
->get_metadata_python(handle
, svc_type
, svc_id
);
286 ceph_log(PyObject
*self
, PyObject
*args
)
289 char *record
= nullptr;
290 char *handle
= nullptr;
291 if (!PyArg_ParseTuple(args
, "sis:log", &handle
, &level
, &record
)) {
295 global_handle
->log(handle
, level
, record
);
301 ceph_get_version(PyObject
*self
, PyObject
*args
)
303 return PyString_FromString(pretty_version_to_str().c_str());
307 ceph_get_context(PyObject
*self
, PyObject
*args
)
309 return global_handle
->get_context();
313 get_counter(PyObject
*self
, PyObject
*args
)
315 char *handle
= nullptr;
316 char *type_str
= nullptr;
317 char *svc_id
= nullptr;
318 char *counter_path
= nullptr;
319 if (!PyArg_ParseTuple(args
, "ssss:get_counter", &handle
, &type_str
,
320 &svc_id
, &counter_path
)) {
324 entity_type_t svc_type
= svc_type_from_str(type_str
);
325 if (svc_type
== CEPH_ENTITY_TYPE_ANY
) {
326 // FIXME: form a proper exception
330 return global_handle
->get_counter_python(
331 handle
, svc_type
, svc_id
, counter_path
);
334 PyMethodDef CephStateMethods
[] = {
335 {"get", ceph_state_get
, METH_VARARGS
,
336 "Get a cluster object"},
337 {"get_server", ceph_get_server
, METH_VARARGS
,
338 "Get a server object"},
339 {"get_metadata", get_metadata
, METH_VARARGS
,
340 "Get a service's metadata"},
341 {"send_command", ceph_send_command
, METH_VARARGS
,
342 "Send a mon command"},
343 {"get_mgr_id", ceph_get_mgr_id
, METH_NOARGS
,
345 {"get_config", ceph_config_get
, METH_VARARGS
,
346 "Get a configuration value"},
347 {"get_config_prefix", ceph_config_get_prefix
, METH_VARARGS
,
348 "Get all configuration values with a given prefix"},
349 {"set_config", ceph_config_set
, METH_VARARGS
,
350 "Set a configuration value"},
351 {"get_counter", get_counter
, METH_VARARGS
,
352 "Get a performance counter"},
353 {"log", ceph_log
, METH_VARARGS
,
354 "Emit a (local) log message"},
355 {"get_version", ceph_get_version
, METH_VARARGS
,
356 "Get the ceph version of this process"},
357 {"get_context", ceph_get_context
, METH_NOARGS
,
358 "Get a CephContext* in a python capsule"},
359 {NULL
, NULL
, 0, NULL
}