]> git.proxmox.com Git - ceph.git/blame - ceph/src/mgr/PyOSDMap.cc
update sources to v12.2.5
[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 }
94b18763
FG
124 if (!PyList_CheckExact(pool_list)) {
125 derr << __func__ << " pool_list not a list" << dendl;
126 return nullptr;
127 }
128 set<int64_t> pools;
129 for (auto i = 0; i < PyList_Size(pool_list); ++i) {
130 PyObject *pool_name = PyList_GET_ITEM(pool_list, i);
131 if (!PyString_Check(pool_name)) {
132 derr << __func__ << " " << pool_name << " not a string" << dendl;
133 return nullptr;
134 }
135 auto pool_id = self->osdmap->lookup_pg_pool_name(
136 PyString_AsString(pool_name));
137 if (pool_id < 0) {
138 derr << __func__ << " pool '" << PyString_AsString(pool_name)
139 << "' does not exist" << dendl;
140 return nullptr;
141 }
142 pools.insert(pool_id);
143 }
3efd9988
FG
144
145 dout(10) << __func__ << " osdmap " << self->osdmap << " inc " << incobj->inc
146 << " max_deviation " << max_deviation
147 << " max_iterations " << max_iterations
94b18763 148 << " pools " << pools
3efd9988 149 << dendl;
3efd9988
FG
150 int r = self->osdmap->calc_pg_upmaps(g_ceph_context,
151 max_deviation,
152 max_iterations,
153 pools,
154 incobj->inc);
155 dout(10) << __func__ << " r = " << r << dendl;
156 return PyInt_FromLong(r);
157}
158
159static PyObject *osdmap_map_pool_pgs_up(BasePyOSDMap* self, PyObject *args)
160{
161 int poolid;
162 if (!PyArg_ParseTuple(args, "i:map_pool_pgs_up",
163 &poolid)) {
164 return nullptr;
165 }
166 auto pi = self->osdmap->get_pg_pool(poolid);
167 if (!pi)
168 return nullptr;
169 map<pg_t,vector<int>> pm;
170 for (unsigned ps = 0; ps < pi->get_pg_num(); ++ps) {
171 pg_t pgid(ps, poolid);
172 self->osdmap->pg_to_up_acting_osds(pgid, &pm[pgid], nullptr, nullptr, nullptr);
173 }
174 PyFormatter f;
175 for (auto p : pm) {
176 string pg = stringify(p.first);
177 f.open_array_section(pg.c_str());
178 for (auto o : p.second) {
179 f.dump_int("osd", o);
180 }
181 f.close_section();
182 }
183 return f.get();
184}
185
186static int
187BasePyOSDMap_init(BasePyOSDMap *self, PyObject *args, PyObject *kwds)
188{
189 PyObject *osdmap_capsule = nullptr;
190 static const char *kwlist[] = {"osdmap_capsule", NULL};
191
192 if (! PyArg_ParseTupleAndKeywords(args, kwds, "O",
193 const_cast<char**>(kwlist),
194 &osdmap_capsule)) {
195 assert(0);
196 return -1;
197 }
198 assert(PyObject_TypeCheck(osdmap_capsule, &PyCapsule_Type));
199
200 self->osdmap = (OSDMap*)PyCapsule_GetPointer(
201 osdmap_capsule, nullptr);
202 assert(self->osdmap);
203
204 return 0;
205}
206
207
208static void
209BasePyOSDMap_dealloc(BasePyOSDMap *self)
210{
211 if (self->osdmap) {
212 delete self->osdmap;
213 self->osdmap = nullptr;
214 } else {
215 derr << "Destroying improperly initialized BasePyOSDMap " << self << dendl;
216 }
217 Py_TYPE(self)->tp_free(self);
218}
219
220
221PyMethodDef BasePyOSDMap_methods[] = {
222 {"_get_epoch", (PyCFunction)osdmap_get_epoch, METH_NOARGS, "Get OSDMap epoch"},
223 {"_get_crush_version", (PyCFunction)osdmap_get_crush_version, METH_NOARGS,
224 "Get CRUSH version"},
225 {"_dump", (PyCFunction)osdmap_dump, METH_NOARGS, "Dump OSDMap::Incremental"},
226 {"_new_incremental", (PyCFunction)osdmap_new_incremental, METH_NOARGS,
227 "Create OSDMap::Incremental"},
228 {"_apply_incremental", (PyCFunction)osdmap_apply_incremental, METH_O,
229 "Apply OSDMap::Incremental and return the resulting OSDMap"},
230 {"_get_crush", (PyCFunction)osdmap_get_crush, METH_NOARGS, "Get CrushWrapper"},
231 {"_get_pools_by_take", (PyCFunction)osdmap_get_pools_by_take, METH_VARARGS,
232 "Get pools that have CRUSH rules that TAKE the given root"},
233 {"_calc_pg_upmaps", (PyCFunction)osdmap_calc_pg_upmaps, METH_VARARGS,
234 "Calculate new pg-upmap values"},
235 {"_map_pool_pgs_up", (PyCFunction)osdmap_map_pool_pgs_up, METH_VARARGS,
236 "Calculate up set mappings for all PGs in a pool"},
237 {NULL, NULL, 0, NULL}
238};
239
240PyTypeObject BasePyOSDMapType = {
241 PyVarObject_HEAD_INIT(NULL, 0)
242 "ceph_module.BasePyOSDMap", /* tp_name */
243 sizeof(BasePyOSDMap), /* tp_basicsize */
244 0, /* tp_itemsize */
245 (destructor)BasePyOSDMap_dealloc, /* tp_dealloc */
246 0, /* tp_print */
247 0, /* tp_getattr */
248 0, /* tp_setattr */
249 0, /* tp_compare */
250 0, /* tp_repr */
251 0, /* tp_as_number */
252 0, /* tp_as_sequence */
253 0, /* tp_as_mapping */
254 0, /* tp_hash */
255 0, /* tp_call */
256 0, /* tp_str */
257 0, /* tp_getattro */
258 0, /* tp_setattro */
259 0, /* tp_as_buffer */
260 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
261 "Ceph OSDMap", /* tp_doc */
262 0, /* tp_traverse */
263 0, /* tp_clear */
264 0, /* tp_richcompare */
265 0, /* tp_weaklistoffset */
266 0, /* tp_iter */
267 0, /* tp_iternext */
268 BasePyOSDMap_methods, /* tp_methods */
269 0, /* tp_members */
270 0, /* tp_getset */
271 0, /* tp_base */
272 0, /* tp_dict */
273 0, /* tp_descr_get */
274 0, /* tp_descr_set */
275 0, /* tp_dictoffset */
276 (initproc)BasePyOSDMap_init, /* tp_init */
277 0, /* tp_alloc */
278 0, /* tp_new */
279};
280
281// ----------
282
283
284static int
285BasePyOSDMapIncremental_init(BasePyOSDMapIncremental *self,
286 PyObject *args, PyObject *kwds)
287{
288 PyObject *inc_capsule = nullptr;
289 static const char *kwlist[] = {"inc_capsule", NULL};
290
291 if (! PyArg_ParseTupleAndKeywords(args, kwds, "O",
292 const_cast<char**>(kwlist),
293 &inc_capsule)) {
294 assert(0);
295 return -1;
296 }
297 assert(PyObject_TypeCheck(inc_capsule, &PyCapsule_Type));
298
299 self->inc = (OSDMap::Incremental*)PyCapsule_GetPointer(
300 inc_capsule, nullptr);
301 assert(self->inc);
302
303 return 0;
304}
305
306static void
307BasePyOSDMapIncremental_dealloc(BasePyOSDMapIncremental *self)
308{
309 if (self->inc) {
310 delete self->inc;
311 self->inc = nullptr;
312 } else {
313 derr << "Destroying improperly initialized BasePyOSDMap " << self << dendl;
314 }
315 Py_TYPE(self)->tp_free(self);
316}
317
318static PyObject *osdmap_inc_get_epoch(BasePyOSDMapIncremental *self,
319 PyObject *obj)
320{
321 return PyInt_FromLong(self->inc->epoch);
322}
323
324static PyObject *osdmap_inc_dump(BasePyOSDMapIncremental *self,
325 PyObject *obj)
326{
327 PyFormatter f;
328 self->inc->dump(&f);
329 return f.get();
330}
331
332static int get_int_float_map(PyObject *obj, map<int,double> *out)
333{
334 PyObject *ls = PyDict_Items(obj);
335 for (int j = 0; j < PyList_Size(ls); ++j) {
336 PyObject *pair = PyList_GET_ITEM(ls, j);
337 if (!PyTuple_Check(pair)) {
338 derr << __func__ << " item " << j << " not a tuple" << dendl;
339 Py_DECREF(ls);
340 return -1;
341 }
342 int k;
343 double v;
344 if (!PyArg_ParseTuple(pair, "id:pair", &k, &v)) {
345 derr << __func__ << " item " << j << " not a size 2 tuple" << dendl;
346 Py_DECREF(ls);
347 return -1;
348 }
349 (*out)[k] = v;
350 }
351
352 Py_DECREF(ls);
353 return 0;
354}
355
356static PyObject *osdmap_inc_set_osd_reweights(BasePyOSDMapIncremental *self,
357 PyObject *weightobj)
358{
359 map<int,double> wm;
360 if (get_int_float_map(weightobj, &wm) < 0) {
361 return nullptr;
362 }
363
364 for (auto i : wm) {
365 self->inc->new_weight[i.first] = std::max(0.0, std::min(1.0, i.second)) * 0x10000;
366 }
367 Py_RETURN_NONE;
368}
369
370static PyObject *osdmap_inc_set_compat_weight_set_weights(
371 BasePyOSDMapIncremental *self, PyObject *weightobj)
372{
373 map<int,double> wm;
374 if (get_int_float_map(weightobj, &wm) < 0) {
375 return nullptr;
376 }
377
378 CrushWrapper crush;
379 assert(self->inc->crush.length()); // see new_incremental
380 auto p = self->inc->crush.begin();
381 ::decode(crush, p);
382 crush.create_choose_args(CrushWrapper::DEFAULT_CHOOSE_ARGS, 1);
383 for (auto i : wm) {
384 crush.choose_args_adjust_item_weightf(
385 g_ceph_context,
386 crush.choose_args_get(CrushWrapper::DEFAULT_CHOOSE_ARGS),
387 i.first,
388 { i.second },
389 nullptr);
390 }
391 self->inc->crush.clear();
392 crush.encode(self->inc->crush, CEPH_FEATURES_ALL);
393 Py_RETURN_NONE;
394}
395
396PyMethodDef BasePyOSDMapIncremental_methods[] = {
397 {"_get_epoch", (PyCFunction)osdmap_inc_get_epoch, METH_NOARGS,
398 "Get OSDMap::Incremental epoch"},
399 {"_dump", (PyCFunction)osdmap_inc_dump, METH_NOARGS,
400 "Dump OSDMap::Incremental"},
401 {"_set_osd_reweights", (PyCFunction)osdmap_inc_set_osd_reweights,
402 METH_O, "Set osd reweight values"},
403 {"_set_crush_compat_weight_set_weights",
404 (PyCFunction)osdmap_inc_set_compat_weight_set_weights, METH_O,
405 "Set weight values in the pending CRUSH compat weight-set"},
406 {NULL, NULL, 0, NULL}
407};
408
409PyTypeObject BasePyOSDMapIncrementalType = {
410 PyVarObject_HEAD_INIT(NULL, 0)
411 "ceph_module.BasePyOSDMapIncremental", /* tp_name */
412 sizeof(BasePyOSDMapIncremental), /* tp_basicsize */
413 0, /* tp_itemsize */
414 (destructor)BasePyOSDMapIncremental_dealloc, /* tp_dealloc */
415 0, /* tp_print */
416 0, /* tp_getattr */
417 0, /* tp_setattr */
418 0, /* tp_compare */
419 0, /* tp_repr */
420 0, /* tp_as_number */
421 0, /* tp_as_sequence */
422 0, /* tp_as_mapping */
423 0, /* tp_hash */
424 0, /* tp_call */
425 0, /* tp_str */
426 0, /* tp_getattro */
427 0, /* tp_setattro */
428 0, /* tp_as_buffer */
429 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
430 "Ceph OSDMapIncremental", /* tp_doc */
431 0, /* tp_traverse */
432 0, /* tp_clear */
433 0, /* tp_richcompare */
434 0, /* tp_weaklistoffset */
435 0, /* tp_iter */
436 0, /* tp_iternext */
437 BasePyOSDMapIncremental_methods, /* tp_methods */
438 0, /* tp_members */
439 0, /* tp_getset */
440 0, /* tp_base */
441 0, /* tp_dict */
442 0, /* tp_descr_get */
443 0, /* tp_descr_set */
444 0, /* tp_dictoffset */
445 (initproc)BasePyOSDMapIncremental_init, /* tp_init */
446 0, /* tp_alloc */
447 0, /* tp_new */
448};
449
450
451// ----------
452
453static int
454BasePyCRUSH_init(BasePyCRUSH *self,
455 PyObject *args, PyObject *kwds)
456{
457 PyObject *crush_capsule = nullptr;
458 static const char *kwlist[] = {"crush_capsule", NULL};
459
460 if (! PyArg_ParseTupleAndKeywords(args, kwds, "O",
461 const_cast<char**>(kwlist),
462 &crush_capsule)) {
463 assert(0);
464 return -1;
465 }
466 assert(PyObject_TypeCheck(crush_capsule, &PyCapsule_Type));
467
468 auto ptr_ref = (ceph::shared_ptr<CrushWrapper>*)(
469 PyCapsule_GetPointer(crush_capsule, nullptr));
470
471 // We passed a pointer to a shared pointer, which is weird, but
472 // just enough to get it into the constructor: this is a real shared
473 // pointer construction now, and then we throw away that pointer to
474 // the shared pointer.
475 self->crush = *ptr_ref;
476 assert(self->crush);
477
478 return 0;
479}
480
481static void
482BasePyCRUSH_dealloc(BasePyCRUSH *self)
483{
484 self->crush.reset();
485 Py_TYPE(self)->tp_free(self);
486}
487
488static PyObject *crush_dump(BasePyCRUSH *self, PyObject *obj)
489{
490 PyFormatter f;
491 self->crush->dump(&f);
492 return f.get();
493}
494
495static PyObject *crush_get_item_name(BasePyCRUSH *self, PyObject *args)
496{
497 int item;
498 if (!PyArg_ParseTuple(args, "i:get_item_name", &item)) {
499 return nullptr;
500 }
501 if (!self->crush->item_exists(item)) {
502 Py_RETURN_NONE;
503 }
504 return PyString_FromString(self->crush->get_item_name(item));
505}
506
507static PyObject *crush_get_item_weight(BasePyCRUSH *self, PyObject *args)
508{
509 int item;
510 if (!PyArg_ParseTuple(args, "i:get_item_weight", &item)) {
511 return nullptr;
512 }
513 if (!self->crush->item_exists(item)) {
514 Py_RETURN_NONE;
515 }
516 return PyFloat_FromDouble(self->crush->get_item_weightf(item));
517}
518
519static PyObject *crush_find_takes(BasePyCRUSH *self, PyObject *obj)
520{
521 set<int> takes;
522 self->crush->find_takes(&takes);
523 PyFormatter f;
524 f.open_array_section("takes");
525 for (auto root : takes) {
526 f.dump_int("root", root);
527 }
528 f.close_section();
529 return f.get();
530}
531
532static PyObject *crush_get_take_weight_osd_map(BasePyCRUSH *self, PyObject *args)
533{
534 int root;
535 if (!PyArg_ParseTuple(args, "i:get_take_weight_osd_map",
536 &root)) {
537 return nullptr;
538 }
539 map<int,float> wmap;
540
541 if (!self->crush->item_exists(root)) {
542 return nullptr;
543 }
544
545 self->crush->get_take_weight_osd_map(root, &wmap);
546 PyFormatter f;
547 f.open_object_section("weights");
548 for (auto& p : wmap) {
549 string n = stringify(p.first); // ick
550 f.dump_float(n.c_str(), p.second);
551 }
552 f.close_section();
553 return f.get();
554}
555
556PyMethodDef BasePyCRUSH_methods[] = {
557 {"_dump", (PyCFunction)crush_dump, METH_NOARGS, "Dump map"},
558 {"_get_item_name", (PyCFunction)crush_get_item_name, METH_VARARGS,
559 "Get item name"},
560 {"_get_item_weight", (PyCFunction)crush_get_item_weight, METH_VARARGS,
561 "Get item weight"},
562 {"_find_takes", (PyCFunction)crush_find_takes, METH_NOARGS,
563 "Find distinct TAKE roots"},
564 {"_get_take_weight_osd_map", (PyCFunction)crush_get_take_weight_osd_map,
565 METH_VARARGS, "Get OSD weight map for a given TAKE root node"},
566 {NULL, NULL, 0, NULL}
567};
568
569PyTypeObject BasePyCRUSHType = {
570 PyVarObject_HEAD_INIT(NULL, 0)
571 "ceph_module.BasePyCRUSH", /* tp_name */
572 sizeof(BasePyCRUSH), /* tp_basicsize */
573 0, /* tp_itemsize */
574 (destructor)BasePyCRUSH_dealloc, /* tp_dealloc */
575 0, /* tp_print */
576 0, /* tp_getattr */
577 0, /* tp_setattr */
578 0, /* tp_compare */
579 0, /* tp_repr */
580 0, /* tp_as_number */
581 0, /* tp_as_sequence */
582 0, /* tp_as_mapping */
583 0, /* tp_hash */
584 0, /* tp_call */
585 0, /* tp_str */
586 0, /* tp_getattro */
587 0, /* tp_setattro */
588 0, /* tp_as_buffer */
589 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
590 "Ceph OSDMapIncremental", /* tp_doc */
591 0, /* tp_traverse */
592 0, /* tp_clear */
593 0, /* tp_richcompare */
594 0, /* tp_weaklistoffset */
595 0, /* tp_iter */
596 0, /* tp_iternext */
597 BasePyCRUSH_methods, /* tp_methods */
598 0, /* tp_members */
599 0, /* tp_getset */
600 0, /* tp_base */
601 0, /* tp_dict */
602 0, /* tp_descr_get */
603 0, /* tp_descr_set */
604 0, /* tp_dictoffset */
605 (initproc)BasePyCRUSH_init, /* tp_init */
606 0, /* tp_alloc */
607 0, /* tp_new */
608};