]> git.proxmox.com Git - ceph.git/blame - ceph/src/mgr/PyState.cc
update sources to v12.1.1
[ceph.git] / ceph / src / mgr / PyState.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2016 John Spray <john.spray@redhat.com>
7 *
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.
12 */
13
14/**
15 * The interface we present to python code that runs within
16 * ceph-mgr.
17 */
18
19#include "Mgr.h"
20
21#include "mon/MonClient.h"
31f18b77 22#include "common/errno.h"
7c673cae
FG
23#include "common/version.h"
24
25#include "PyState.h"
31f18b77 26#include "Gil.h"
7c673cae
FG
27
28#define dout_context g_ceph_context
31f18b77 29#define dout_subsys ceph_subsys_mgr
7c673cae
FG
30
31PyModules *global_handle = NULL;
32
33
34class MonCommandCompletion : public Context
35{
36 PyObject *python_completion;
37 const std::string tag;
31f18b77 38 PyThreadState *pThreadState;
7c673cae
FG
39
40public:
41 std::string outs;
42 bufferlist outbl;
43
31f18b77
FG
44 MonCommandCompletion(PyObject* ev, const std::string &tag_, PyThreadState *ts_)
45 : python_completion(ev), tag(tag_), pThreadState(ts_)
7c673cae
FG
46 {
47 assert(python_completion != nullptr);
48 Py_INCREF(python_completion);
49 }
50
51 ~MonCommandCompletion() override
52 {
53 Py_DECREF(python_completion);
54 }
55
56 void finish(int r) override
57 {
31f18b77
FG
58 dout(10) << "MonCommandCompletion::finish()" << dendl;
59 {
60 // Scoped so the Gil is released before calling notify_all()
61 Gil gil(pThreadState);
62
63 auto set_fn = PyObject_GetAttrString(python_completion, "complete");
64 assert(set_fn != nullptr);
65
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);
70 Py_DECREF(pyR);
71 Py_DECREF(pyOutBl);
72 Py_DECREF(pyOutS);
73
74 auto rtn = PyObject_CallObject(set_fn, args);
75 if (rtn != nullptr) {
76 Py_DECREF(rtn);
77 }
78 Py_DECREF(args);
7c673cae 79 }
7c673cae
FG
80 global_handle->notify_all("command", tag);
81 }
82};
83
84
85static PyObject*
86ceph_send_command(PyObject *self, PyObject *args)
87{
88 char *handle = nullptr;
89
90 // Like mon, osd, mds
91 char *type = nullptr;
92
93 // Like "23" for an OSD or "myid" for an MDS
94 char *name = nullptr;
95
96 char *cmd_json = nullptr;
97 char *tag = nullptr;
98 PyObject *completion = nullptr;
99 if (!PyArg_ParseTuple(args, "sOssss:ceph_send_command",
100 &handle, &completion, &type, &name, &cmd_json, &tag)) {
101 return nullptr;
102 }
103
104 auto set_fn = PyObject_GetAttrString(completion, "complete");
105 if (set_fn == nullptr) {
106 ceph_abort(); // TODO raise python exception instead
107 } else {
108 assert(PyCallable_Check(set_fn));
109 }
110 Py_DECREF(set_fn);
111
31f18b77 112 auto c = new MonCommandCompletion(completion, tag, PyThreadState_Get());
7c673cae
FG
113 if (std::string(type) == "mon") {
114 global_handle->get_monc().start_mon_command(
115 {cmd_json},
116 {},
117 &c->outbl,
118 &c->outs,
119 c);
120 } else if (std::string(type) == "osd") {
121 std::string err;
122 uint64_t osd_id = strict_strtoll(name, 10, &err);
123 if (!err.empty()) {
31f18b77
FG
124 delete c;
125 string msg("invalid osd_id: ");
126 msg.append("\"").append(name).append("\"");
127 PyErr_SetString(PyExc_ValueError, msg.c_str());
7c673cae
FG
128 return nullptr;
129 }
130
131 ceph_tid_t tid;
132 global_handle->get_objecter().osd_command(
133 osd_id,
134 {cmd_json},
135 {},
136 &tid,
137 &c->outbl,
138 &c->outs,
139 c);
140 } else if (std::string(type) == "mds") {
141 int r = global_handle->get_client().mds_command(
142 name,
143 {cmd_json},
144 {},
145 &c->outbl,
146 &c->outs,
147 c);
148 if (r != 0) {
31f18b77
FG
149 string msg("failed to send command to mds: ");
150 msg.append(cpp_strerror(r));
151 PyErr_SetString(PyExc_RuntimeError, msg.c_str());
7c673cae
FG
152 return nullptr;
153 }
154 } else if (std::string(type) == "pg") {
224ce89b
WB
155 pg_t pgid;
156 if (!pgid.parse(name)) {
157 delete c;
158 string msg("invalid pgid: ");
159 msg.append("\"").append(name).append("\"");
160 PyErr_SetString(PyExc_ValueError, msg.c_str());
161 return nullptr;
162 }
163
164 ceph_tid_t tid;
165 global_handle->get_objecter().pg_command(
166 pgid,
167 {cmd_json},
168 {},
169 &tid,
170 &c->outbl,
171 &c->outs,
172 c);
7c673cae
FG
173 return nullptr;
174 } else {
224ce89b 175 delete c;
31f18b77
FG
176 string msg("unknown service type: ");
177 msg.append(type);
178 PyErr_SetString(PyExc_ValueError, msg.c_str());
7c673cae
FG
179 return nullptr;
180 }
181
182 Py_RETURN_NONE;
183}
184
185
186static PyObject*
187ceph_state_get(PyObject *self, PyObject *args)
188{
189 char *handle = nullptr;
190 char *what = NULL;
191 if (!PyArg_ParseTuple(args, "ss:ceph_state_get", &handle, &what)) {
192 return NULL;
193 }
194
195 return global_handle->get_python(what);
196}
197
198
199static PyObject*
200ceph_get_server(PyObject *self, PyObject *args)
201{
202 char *handle = nullptr;
203 char *hostname = NULL;
204 if (!PyArg_ParseTuple(args, "sz:ceph_get_server", &handle, &hostname)) {
205 return NULL;
206 }
207
208 if (hostname) {
209 return global_handle->get_server_python(hostname);
210 } else {
211 return global_handle->list_servers_python();
212 }
213}
214
31f18b77
FG
215static PyObject*
216ceph_get_mgr_id(PyObject *self, PyObject *args)
217{
218 return PyString_FromString(g_conf->name.get_id().c_str());
219}
220
7c673cae
FG
221static PyObject*
222ceph_config_get(PyObject *self, PyObject *args)
223{
224 char *handle = nullptr;
225 char *what = nullptr;
226 if (!PyArg_ParseTuple(args, "ss:ceph_config_get", &handle, &what)) {
227 derr << "Invalid args!" << dendl;
228 return nullptr;
229 }
230
231 std::string value;
232 bool found = global_handle->get_config(handle, what, &value);
233 if (found) {
31f18b77 234 dout(10) << "ceph_config_get " << what << " found: " << value.c_str() << dendl;
7c673cae
FG
235 return PyString_FromString(value.c_str());
236 } else {
31f18b77 237 derr << "ceph_config_get " << what << " not found " << dendl;
7c673cae
FG
238 Py_RETURN_NONE;
239 }
240}
241
31f18b77
FG
242static PyObject*
243ceph_config_get_prefix(PyObject *self, PyObject *args)
244{
245 char *handle = nullptr;
246 char *prefix = nullptr;
247 if (!PyArg_ParseTuple(args, "ss:ceph_config_get", &handle, &prefix)) {
248 derr << "Invalid args!" << dendl;
249 return nullptr;
250 }
251
252 return global_handle->get_config_prefix(handle, prefix);
253}
254
7c673cae
FG
255static PyObject*
256ceph_config_set(PyObject *self, PyObject *args)
257{
258 char *handle = nullptr;
259 char *key = nullptr;
260 char *value = nullptr;
261 if (!PyArg_ParseTuple(args, "sss:ceph_config_set", &handle, &key, &value)) {
262 return nullptr;
263 }
264
265 global_handle->set_config(handle, key, value);
266
267 Py_RETURN_NONE;
268}
269
7c673cae
FG
270static PyObject*
271get_metadata(PyObject *self, PyObject *args)
272{
273 char *handle = nullptr;
224ce89b 274 char *svc_name = NULL;
7c673cae 275 char *svc_id = NULL;
224ce89b 276 if (!PyArg_ParseTuple(args, "sss:get_metadata", &handle, &svc_name, &svc_id)) {
7c673cae
FG
277 return nullptr;
278 }
224ce89b
WB
279 return global_handle->get_metadata_python(handle, svc_name, svc_id);
280}
7c673cae 281
224ce89b
WB
282static PyObject*
283get_daemon_status(PyObject *self, PyObject *args)
284{
285 char *handle = nullptr;
286 char *svc_name = NULL;
287 char *svc_id = NULL;
288 if (!PyArg_ParseTuple(args, "sss:get_daemon_status", &handle, &svc_name,
289 &svc_id)) {
7c673cae
FG
290 return nullptr;
291 }
224ce89b 292 return global_handle->get_daemon_status_python(handle, svc_name, svc_id);
7c673cae
FG
293}
294
295static PyObject*
296ceph_log(PyObject *self, PyObject *args)
297{
298 int level = 0;
299 char *record = nullptr;
300 char *handle = nullptr;
301 if (!PyArg_ParseTuple(args, "sis:log", &handle, &level, &record)) {
302 return nullptr;
303 }
304
305 global_handle->log(handle, level, record);
306
307 Py_RETURN_NONE;
308}
309
310static PyObject *
311ceph_get_version(PyObject *self, PyObject *args)
312{
313 return PyString_FromString(pretty_version_to_str().c_str());
314}
315
316static PyObject *
317ceph_get_context(PyObject *self, PyObject *args)
318{
319 return global_handle->get_context();
320}
321
322static PyObject*
323get_counter(PyObject *self, PyObject *args)
324{
325 char *handle = nullptr;
224ce89b 326 char *svc_name = nullptr;
7c673cae
FG
327 char *svc_id = nullptr;
328 char *counter_path = nullptr;
224ce89b 329 if (!PyArg_ParseTuple(args, "ssss:get_counter", &handle, &svc_name,
7c673cae
FG
330 &svc_id, &counter_path)) {
331 return nullptr;
332 }
7c673cae 333 return global_handle->get_counter_python(
224ce89b 334 handle, svc_name, svc_id, counter_path);
7c673cae
FG
335}
336
337PyMethodDef CephStateMethods[] = {
338 {"get", ceph_state_get, METH_VARARGS,
339 "Get a cluster object"},
340 {"get_server", ceph_get_server, METH_VARARGS,
341 "Get a server object"},
342 {"get_metadata", get_metadata, METH_VARARGS,
343 "Get a service's metadata"},
224ce89b
WB
344 {"get_daemon_status", get_daemon_status, METH_VARARGS,
345 "Get a service's status"},
7c673cae
FG
346 {"send_command", ceph_send_command, METH_VARARGS,
347 "Send a mon command"},
31f18b77
FG
348 {"get_mgr_id", ceph_get_mgr_id, METH_NOARGS,
349 "Get the mgr id"},
7c673cae
FG
350 {"get_config", ceph_config_get, METH_VARARGS,
351 "Get a configuration value"},
31f18b77
FG
352 {"get_config_prefix", ceph_config_get_prefix, METH_VARARGS,
353 "Get all configuration values with a given prefix"},
7c673cae
FG
354 {"set_config", ceph_config_set, METH_VARARGS,
355 "Set a configuration value"},
356 {"get_counter", get_counter, METH_VARARGS,
357 "Get a performance counter"},
358 {"log", ceph_log, METH_VARARGS,
359 "Emit a (local) log message"},
360 {"get_version", ceph_get_version, METH_VARARGS,
361 "Get the ceph version of this process"},
362 {"get_context", ceph_get_context, METH_NOARGS,
363 "Get a CephContext* in a python capsule"},
364 {NULL, NULL, 0, NULL}
365};
366