]> git.proxmox.com Git - ceph.git/blob - ceph/src/mgr/PyOSDMap.cc
update sources to v12.2.5
[ceph.git] / ceph / src / mgr / PyOSDMap.cc
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
19 typedef struct {
20 PyObject_HEAD
21 OSDMap *osdmap;
22 } BasePyOSDMap;
23
24 typedef struct {
25 PyObject_HEAD
26 OSDMap::Incremental *inc;
27 } BasePyOSDMapIncremental;
28
29 typedef struct {
30 PyObject_HEAD
31 ceph::shared_ptr<CrushWrapper> crush;
32 } BasePyCRUSH;
33
34 // ----------
35
36 static PyObject *osdmap_get_epoch(BasePyOSDMap *self, PyObject *obj)
37 {
38 return PyInt_FromLong(self->osdmap->get_epoch());
39 }
40
41 static PyObject *osdmap_get_crush_version(BasePyOSDMap* self, PyObject *obj)
42 {
43 return PyInt_FromLong(self->osdmap->get_crush_version());
44 }
45
46 static PyObject *osdmap_dump(BasePyOSDMap* self, PyObject *obj)
47 {
48 PyFormatter f;
49 self->osdmap->dump(&f);
50 return f.get();
51 }
52
53 static 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
69 static 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
88 static PyObject *osdmap_get_crush(BasePyOSDMap* self, PyObject *obj)
89 {
90 return construct_with_capsule("mgr_module", "CRUSHMap",
91 (void*)(&(self->osdmap->crush)));
92 }
93
94 static 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
113 static 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 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 }
144
145 dout(10) << __func__ << " osdmap " << self->osdmap << " inc " << incobj->inc
146 << " max_deviation " << max_deviation
147 << " max_iterations " << max_iterations
148 << " pools " << pools
149 << dendl;
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
159 static 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
186 static int
187 BasePyOSDMap_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
208 static void
209 BasePyOSDMap_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
221 PyMethodDef 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
240 PyTypeObject 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
284 static int
285 BasePyOSDMapIncremental_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
306 static void
307 BasePyOSDMapIncremental_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
318 static PyObject *osdmap_inc_get_epoch(BasePyOSDMapIncremental *self,
319 PyObject *obj)
320 {
321 return PyInt_FromLong(self->inc->epoch);
322 }
323
324 static PyObject *osdmap_inc_dump(BasePyOSDMapIncremental *self,
325 PyObject *obj)
326 {
327 PyFormatter f;
328 self->inc->dump(&f);
329 return f.get();
330 }
331
332 static 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
356 static 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
370 static 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
396 PyMethodDef 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
409 PyTypeObject 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
453 static int
454 BasePyCRUSH_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
481 static void
482 BasePyCRUSH_dealloc(BasePyCRUSH *self)
483 {
484 self->crush.reset();
485 Py_TYPE(self)->tp_free(self);
486 }
487
488 static PyObject *crush_dump(BasePyCRUSH *self, PyObject *obj)
489 {
490 PyFormatter f;
491 self->crush->dump(&f);
492 return f.get();
493 }
494
495 static 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
507 static 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
519 static 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
532 static 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
556 PyMethodDef 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
569 PyTypeObject 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 };