]> git.proxmox.com Git - ceph.git/blame - ceph/src/mgr/PyOSDMap.cc
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / mgr / PyOSDMap.cc
CommitLineData
3efd9988
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "Mgr.h"
5
6#include "osd/OSDMap.h"
7#include "common/errno.h"
8#include "common/version.h"
9#include "include/stringify.h"
10
11#include "PyOSDMap.h"
12#include "PyFormatter.h"
13#include "Gil.h"
14
15#define dout_context g_ceph_context
16#define dout_subsys ceph_subsys_mgr
17
18
19typedef struct {
20 PyObject_HEAD
21 OSDMap *osdmap;
22} BasePyOSDMap;
23
24typedef struct {
25 PyObject_HEAD
26 OSDMap::Incremental *inc;
27} BasePyOSDMapIncremental;
28
29typedef struct {
30 PyObject_HEAD
31 ceph::shared_ptr<CrushWrapper> crush;
32} BasePyCRUSH;
33
34// ----------
35
36static PyObject *osdmap_get_epoch(BasePyOSDMap *self, PyObject *obj)
37{
38 return PyInt_FromLong(self->osdmap->get_epoch());
39}
40
41static PyObject *osdmap_get_crush_version(BasePyOSDMap* self, PyObject *obj)
42{
43 return PyInt_FromLong(self->osdmap->get_crush_version());
44}
45
46static PyObject *osdmap_dump(BasePyOSDMap* self, PyObject *obj)
47{
48 PyFormatter f;
49 self->osdmap->dump(&f);
50 return f.get();
51}
52
53static PyObject *osdmap_new_incremental(BasePyOSDMap *self, PyObject *obj)
54{
55 OSDMap::Incremental *inc = new OSDMap::Incremental;
56
57 inc->fsid = self->osdmap->get_fsid();
58 inc->epoch = self->osdmap->get_epoch() + 1;
59 // always include latest crush map here... this is okay since we never
60 // actually use this map in the real world (and even if we did it would
61 // be a no-op).
62 self->osdmap->crush->encode(inc->crush, CEPH_FEATURES_ALL);
63 dout(10) << __func__ << " " << inc << dendl;
64
65 return construct_with_capsule("mgr_module", "OSDMapIncremental",
66 (void*)(inc));
67}
68
69static PyObject *osdmap_apply_incremental(BasePyOSDMap *self,
70 BasePyOSDMapIncremental *incobj)
71{
72 if (!PyObject_TypeCheck(incobj, &BasePyOSDMapIncrementalType)) {
73 derr << "Wrong type in osdmap_apply_incremental!" << dendl;
74 return nullptr;
75 }
76
77 bufferlist bl;
78 self->osdmap->encode(bl, CEPH_FEATURES_ALL|CEPH_FEATURE_RESERVED);
79 OSDMap *next = new OSDMap;
80 next->decode(bl);
81 next->apply_incremental(*(incobj->inc));
82 dout(10) << __func__ << " map " << self->osdmap << " inc " << incobj->inc
83 << " next " << next << dendl;
84
85 return construct_with_capsule("mgr_module", "OSDMap", (void*)next);
86}
87
88static PyObject *osdmap_get_crush(BasePyOSDMap* self, PyObject *obj)
89{
90 return construct_with_capsule("mgr_module", "CRUSHMap",
91 (void*)(&(self->osdmap->crush)));
92}
93
94static PyObject *osdmap_get_pools_by_take(BasePyOSDMap* self, PyObject *args)
95{
96 int take;
97 if (!PyArg_ParseTuple(args, "i:get_pools_by_take",
98 &take)) {
99 return nullptr;
100 }
101
102 PyFormatter f;
103 f.open_array_section("pools");
104 for (auto& p : self->osdmap->get_pools()) {
105 if (self->osdmap->crush->rule_has_take(p.second.crush_rule, take)) {
106 f.dump_int("pool", p.first);
107 }
108 }
109 f.close_section();
110 return f.get();
111}
112
113static PyObject *osdmap_calc_pg_upmaps(BasePyOSDMap* self, PyObject *args)
114{
115 PyObject *pool_list;
116 BasePyOSDMapIncremental *incobj;
117 double max_deviation = 0;
118 int max_iterations = 0;
119 if (!PyArg_ParseTuple(args, "OdiO:calc_pg_upmaps",
120 &incobj, &max_deviation,
121 &max_iterations, &pool_list)) {
122 return nullptr;
123 }
124
125 dout(10) << __func__ << " osdmap " << self->osdmap << " inc " << incobj->inc
126 << " max_deviation " << max_deviation
127 << " max_iterations " << max_iterations
128 << dendl;
129 set<int64_t> pools;
130 // FIXME: unpack pool_list and translate to pools set
131 int r = self->osdmap->calc_pg_upmaps(g_ceph_context,
132 max_deviation,
133 max_iterations,
134 pools,
135 incobj->inc);
136 dout(10) << __func__ << " r = " << r << dendl;
137 return PyInt_FromLong(r);
138}
139
140static PyObject *osdmap_map_pool_pgs_up(BasePyOSDMap* self, PyObject *args)
141{
142 int poolid;
143 if (!PyArg_ParseTuple(args, "i:map_pool_pgs_up",
144 &poolid)) {
145 return nullptr;
146 }
147 auto pi = self->osdmap->get_pg_pool(poolid);
148 if (!pi)
149 return nullptr;
150 map<pg_t,vector<int>> pm;
151 for (unsigned ps = 0; ps < pi->get_pg_num(); ++ps) {
152 pg_t pgid(ps, poolid);
153 self->osdmap->pg_to_up_acting_osds(pgid, &pm[pgid], nullptr, nullptr, nullptr);
154 }
155 PyFormatter f;
156 for (auto p : pm) {
157 string pg = stringify(p.first);
158 f.open_array_section(pg.c_str());
159 for (auto o : p.second) {
160 f.dump_int("osd", o);
161 }
162 f.close_section();
163 }
164 return f.get();
165}
166
167static int
168BasePyOSDMap_init(BasePyOSDMap *self, PyObject *args, PyObject *kwds)
169{
170 PyObject *osdmap_capsule = nullptr;
171 static const char *kwlist[] = {"osdmap_capsule", NULL};
172
173 if (! PyArg_ParseTupleAndKeywords(args, kwds, "O",
174 const_cast<char**>(kwlist),
175 &osdmap_capsule)) {
176 assert(0);
177 return -1;
178 }
179 assert(PyObject_TypeCheck(osdmap_capsule, &PyCapsule_Type));
180
181 self->osdmap = (OSDMap*)PyCapsule_GetPointer(
182 osdmap_capsule, nullptr);
183 assert(self->osdmap);
184
185 return 0;
186}
187
188
189static void
190BasePyOSDMap_dealloc(BasePyOSDMap *self)
191{
192 if (self->osdmap) {
193 delete self->osdmap;
194 self->osdmap = nullptr;
195 } else {
196 derr << "Destroying improperly initialized BasePyOSDMap " << self << dendl;
197 }
198 Py_TYPE(self)->tp_free(self);
199}
200
201
202PyMethodDef BasePyOSDMap_methods[] = {
203 {"_get_epoch", (PyCFunction)osdmap_get_epoch, METH_NOARGS, "Get OSDMap epoch"},
204 {"_get_crush_version", (PyCFunction)osdmap_get_crush_version, METH_NOARGS,
205 "Get CRUSH version"},
206 {"_dump", (PyCFunction)osdmap_dump, METH_NOARGS, "Dump OSDMap::Incremental"},
207 {"_new_incremental", (PyCFunction)osdmap_new_incremental, METH_NOARGS,
208 "Create OSDMap::Incremental"},
209 {"_apply_incremental", (PyCFunction)osdmap_apply_incremental, METH_O,
210 "Apply OSDMap::Incremental and return the resulting OSDMap"},
211 {"_get_crush", (PyCFunction)osdmap_get_crush, METH_NOARGS, "Get CrushWrapper"},
212 {"_get_pools_by_take", (PyCFunction)osdmap_get_pools_by_take, METH_VARARGS,
213 "Get pools that have CRUSH rules that TAKE the given root"},
214 {"_calc_pg_upmaps", (PyCFunction)osdmap_calc_pg_upmaps, METH_VARARGS,
215 "Calculate new pg-upmap values"},
216 {"_map_pool_pgs_up", (PyCFunction)osdmap_map_pool_pgs_up, METH_VARARGS,
217 "Calculate up set mappings for all PGs in a pool"},
218 {NULL, NULL, 0, NULL}
219};
220
221PyTypeObject BasePyOSDMapType = {
222 PyVarObject_HEAD_INIT(NULL, 0)
223 "ceph_module.BasePyOSDMap", /* tp_name */
224 sizeof(BasePyOSDMap), /* tp_basicsize */
225 0, /* tp_itemsize */
226 (destructor)BasePyOSDMap_dealloc, /* tp_dealloc */
227 0, /* tp_print */
228 0, /* tp_getattr */
229 0, /* tp_setattr */
230 0, /* tp_compare */
231 0, /* tp_repr */
232 0, /* tp_as_number */
233 0, /* tp_as_sequence */
234 0, /* tp_as_mapping */
235 0, /* tp_hash */
236 0, /* tp_call */
237 0, /* tp_str */
238 0, /* tp_getattro */
239 0, /* tp_setattro */
240 0, /* tp_as_buffer */
241 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
242 "Ceph OSDMap", /* tp_doc */
243 0, /* tp_traverse */
244 0, /* tp_clear */
245 0, /* tp_richcompare */
246 0, /* tp_weaklistoffset */
247 0, /* tp_iter */
248 0, /* tp_iternext */
249 BasePyOSDMap_methods, /* tp_methods */
250 0, /* tp_members */
251 0, /* tp_getset */
252 0, /* tp_base */
253 0, /* tp_dict */
254 0, /* tp_descr_get */
255 0, /* tp_descr_set */
256 0, /* tp_dictoffset */
257 (initproc)BasePyOSDMap_init, /* tp_init */
258 0, /* tp_alloc */
259 0, /* tp_new */
260};
261
262// ----------
263
264
265static int
266BasePyOSDMapIncremental_init(BasePyOSDMapIncremental *self,
267 PyObject *args, PyObject *kwds)
268{
269 PyObject *inc_capsule = nullptr;
270 static const char *kwlist[] = {"inc_capsule", NULL};
271
272 if (! PyArg_ParseTupleAndKeywords(args, kwds, "O",
273 const_cast<char**>(kwlist),
274 &inc_capsule)) {
275 assert(0);
276 return -1;
277 }
278 assert(PyObject_TypeCheck(inc_capsule, &PyCapsule_Type));
279
280 self->inc = (OSDMap::Incremental*)PyCapsule_GetPointer(
281 inc_capsule, nullptr);
282 assert(self->inc);
283
284 return 0;
285}
286
287static void
288BasePyOSDMapIncremental_dealloc(BasePyOSDMapIncremental *self)
289{
290 if (self->inc) {
291 delete self->inc;
292 self->inc = nullptr;
293 } else {
294 derr << "Destroying improperly initialized BasePyOSDMap " << self << dendl;
295 }
296 Py_TYPE(self)->tp_free(self);
297}
298
299static PyObject *osdmap_inc_get_epoch(BasePyOSDMapIncremental *self,
300 PyObject *obj)
301{
302 return PyInt_FromLong(self->inc->epoch);
303}
304
305static PyObject *osdmap_inc_dump(BasePyOSDMapIncremental *self,
306 PyObject *obj)
307{
308 PyFormatter f;
309 self->inc->dump(&f);
310 return f.get();
311}
312
313static int get_int_float_map(PyObject *obj, map<int,double> *out)
314{
315 PyObject *ls = PyDict_Items(obj);
316 for (int j = 0; j < PyList_Size(ls); ++j) {
317 PyObject *pair = PyList_GET_ITEM(ls, j);
318 if (!PyTuple_Check(pair)) {
319 derr << __func__ << " item " << j << " not a tuple" << dendl;
320 Py_DECREF(ls);
321 return -1;
322 }
323 int k;
324 double v;
325 if (!PyArg_ParseTuple(pair, "id:pair", &k, &v)) {
326 derr << __func__ << " item " << j << " not a size 2 tuple" << dendl;
327 Py_DECREF(ls);
328 return -1;
329 }
330 (*out)[k] = v;
331 }
332
333 Py_DECREF(ls);
334 return 0;
335}
336
337static PyObject *osdmap_inc_set_osd_reweights(BasePyOSDMapIncremental *self,
338 PyObject *weightobj)
339{
340 map<int,double> wm;
341 if (get_int_float_map(weightobj, &wm) < 0) {
342 return nullptr;
343 }
344
345 for (auto i : wm) {
346 self->inc->new_weight[i.first] = std::max(0.0, std::min(1.0, i.second)) * 0x10000;
347 }
348 Py_RETURN_NONE;
349}
350
351static PyObject *osdmap_inc_set_compat_weight_set_weights(
352 BasePyOSDMapIncremental *self, PyObject *weightobj)
353{
354 map<int,double> wm;
355 if (get_int_float_map(weightobj, &wm) < 0) {
356 return nullptr;
357 }
358
359 CrushWrapper crush;
360 assert(self->inc->crush.length()); // see new_incremental
361 auto p = self->inc->crush.begin();
362 ::decode(crush, p);
363 crush.create_choose_args(CrushWrapper::DEFAULT_CHOOSE_ARGS, 1);
364 for (auto i : wm) {
365 crush.choose_args_adjust_item_weightf(
366 g_ceph_context,
367 crush.choose_args_get(CrushWrapper::DEFAULT_CHOOSE_ARGS),
368 i.first,
369 { i.second },
370 nullptr);
371 }
372 self->inc->crush.clear();
373 crush.encode(self->inc->crush, CEPH_FEATURES_ALL);
374 Py_RETURN_NONE;
375}
376
377PyMethodDef BasePyOSDMapIncremental_methods[] = {
378 {"_get_epoch", (PyCFunction)osdmap_inc_get_epoch, METH_NOARGS,
379 "Get OSDMap::Incremental epoch"},
380 {"_dump", (PyCFunction)osdmap_inc_dump, METH_NOARGS,
381 "Dump OSDMap::Incremental"},
382 {"_set_osd_reweights", (PyCFunction)osdmap_inc_set_osd_reweights,
383 METH_O, "Set osd reweight values"},
384 {"_set_crush_compat_weight_set_weights",
385 (PyCFunction)osdmap_inc_set_compat_weight_set_weights, METH_O,
386 "Set weight values in the pending CRUSH compat weight-set"},
387 {NULL, NULL, 0, NULL}
388};
389
390PyTypeObject BasePyOSDMapIncrementalType = {
391 PyVarObject_HEAD_INIT(NULL, 0)
392 "ceph_module.BasePyOSDMapIncremental", /* tp_name */
393 sizeof(BasePyOSDMapIncremental), /* tp_basicsize */
394 0, /* tp_itemsize */
395 (destructor)BasePyOSDMapIncremental_dealloc, /* tp_dealloc */
396 0, /* tp_print */
397 0, /* tp_getattr */
398 0, /* tp_setattr */
399 0, /* tp_compare */
400 0, /* tp_repr */
401 0, /* tp_as_number */
402 0, /* tp_as_sequence */
403 0, /* tp_as_mapping */
404 0, /* tp_hash */
405 0, /* tp_call */
406 0, /* tp_str */
407 0, /* tp_getattro */
408 0, /* tp_setattro */
409 0, /* tp_as_buffer */
410 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
411 "Ceph OSDMapIncremental", /* tp_doc */
412 0, /* tp_traverse */
413 0, /* tp_clear */
414 0, /* tp_richcompare */
415 0, /* tp_weaklistoffset */
416 0, /* tp_iter */
417 0, /* tp_iternext */
418 BasePyOSDMapIncremental_methods, /* tp_methods */
419 0, /* tp_members */
420 0, /* tp_getset */
421 0, /* tp_base */
422 0, /* tp_dict */
423 0, /* tp_descr_get */
424 0, /* tp_descr_set */
425 0, /* tp_dictoffset */
426 (initproc)BasePyOSDMapIncremental_init, /* tp_init */
427 0, /* tp_alloc */
428 0, /* tp_new */
429};
430
431
432// ----------
433
434static int
435BasePyCRUSH_init(BasePyCRUSH *self,
436 PyObject *args, PyObject *kwds)
437{
438 PyObject *crush_capsule = nullptr;
439 static const char *kwlist[] = {"crush_capsule", NULL};
440
441 if (! PyArg_ParseTupleAndKeywords(args, kwds, "O",
442 const_cast<char**>(kwlist),
443 &crush_capsule)) {
444 assert(0);
445 return -1;
446 }
447 assert(PyObject_TypeCheck(crush_capsule, &PyCapsule_Type));
448
449 auto ptr_ref = (ceph::shared_ptr<CrushWrapper>*)(
450 PyCapsule_GetPointer(crush_capsule, nullptr));
451
452 // We passed a pointer to a shared pointer, which is weird, but
453 // just enough to get it into the constructor: this is a real shared
454 // pointer construction now, and then we throw away that pointer to
455 // the shared pointer.
456 self->crush = *ptr_ref;
457 assert(self->crush);
458
459 return 0;
460}
461
462static void
463BasePyCRUSH_dealloc(BasePyCRUSH *self)
464{
465 self->crush.reset();
466 Py_TYPE(self)->tp_free(self);
467}
468
469static PyObject *crush_dump(BasePyCRUSH *self, PyObject *obj)
470{
471 PyFormatter f;
472 self->crush->dump(&f);
473 return f.get();
474}
475
476static PyObject *crush_get_item_name(BasePyCRUSH *self, PyObject *args)
477{
478 int item;
479 if (!PyArg_ParseTuple(args, "i:get_item_name", &item)) {
480 return nullptr;
481 }
482 if (!self->crush->item_exists(item)) {
483 Py_RETURN_NONE;
484 }
485 return PyString_FromString(self->crush->get_item_name(item));
486}
487
488static PyObject *crush_get_item_weight(BasePyCRUSH *self, PyObject *args)
489{
490 int item;
491 if (!PyArg_ParseTuple(args, "i:get_item_weight", &item)) {
492 return nullptr;
493 }
494 if (!self->crush->item_exists(item)) {
495 Py_RETURN_NONE;
496 }
497 return PyFloat_FromDouble(self->crush->get_item_weightf(item));
498}
499
500static PyObject *crush_find_takes(BasePyCRUSH *self, PyObject *obj)
501{
502 set<int> takes;
503 self->crush->find_takes(&takes);
504 PyFormatter f;
505 f.open_array_section("takes");
506 for (auto root : takes) {
507 f.dump_int("root", root);
508 }
509 f.close_section();
510 return f.get();
511}
512
513static PyObject *crush_get_take_weight_osd_map(BasePyCRUSH *self, PyObject *args)
514{
515 int root;
516 if (!PyArg_ParseTuple(args, "i:get_take_weight_osd_map",
517 &root)) {
518 return nullptr;
519 }
520 map<int,float> wmap;
521
522 if (!self->crush->item_exists(root)) {
523 return nullptr;
524 }
525
526 self->crush->get_take_weight_osd_map(root, &wmap);
527 PyFormatter f;
528 f.open_object_section("weights");
529 for (auto& p : wmap) {
530 string n = stringify(p.first); // ick
531 f.dump_float(n.c_str(), p.second);
532 }
533 f.close_section();
534 return f.get();
535}
536
537PyMethodDef BasePyCRUSH_methods[] = {
538 {"_dump", (PyCFunction)crush_dump, METH_NOARGS, "Dump map"},
539 {"_get_item_name", (PyCFunction)crush_get_item_name, METH_VARARGS,
540 "Get item name"},
541 {"_get_item_weight", (PyCFunction)crush_get_item_weight, METH_VARARGS,
542 "Get item weight"},
543 {"_find_takes", (PyCFunction)crush_find_takes, METH_NOARGS,
544 "Find distinct TAKE roots"},
545 {"_get_take_weight_osd_map", (PyCFunction)crush_get_take_weight_osd_map,
546 METH_VARARGS, "Get OSD weight map for a given TAKE root node"},
547 {NULL, NULL, 0, NULL}
548};
549
550PyTypeObject BasePyCRUSHType = {
551 PyVarObject_HEAD_INIT(NULL, 0)
552 "ceph_module.BasePyCRUSH", /* tp_name */
553 sizeof(BasePyCRUSH), /* tp_basicsize */
554 0, /* tp_itemsize */
555 (destructor)BasePyCRUSH_dealloc, /* tp_dealloc */
556 0, /* tp_print */
557 0, /* tp_getattr */
558 0, /* tp_setattr */
559 0, /* tp_compare */
560 0, /* tp_repr */
561 0, /* tp_as_number */
562 0, /* tp_as_sequence */
563 0, /* tp_as_mapping */
564 0, /* tp_hash */
565 0, /* tp_call */
566 0, /* tp_str */
567 0, /* tp_getattro */
568 0, /* tp_setattro */
569 0, /* tp_as_buffer */
570 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
571 "Ceph OSDMapIncremental", /* tp_doc */
572 0, /* tp_traverse */
573 0, /* tp_clear */
574 0, /* tp_richcompare */
575 0, /* tp_weaklistoffset */
576 0, /* tp_iter */
577 0, /* tp_iternext */
578 BasePyCRUSH_methods, /* tp_methods */
579 0, /* tp_members */
580 0, /* tp_getset */
581 0, /* tp_base */
582 0, /* tp_dict */
583 0, /* tp_descr_get */
584 0, /* tp_descr_set */
585 0, /* tp_dictoffset */
586 (initproc)BasePyCRUSH_init, /* tp_init */
587 0, /* tp_alloc */
588 0, /* tp_new */
589};