1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
6 #include "osd/OSDMap.h"
7 #include "common/errno.h"
8 #include "common/version.h"
9 #include "include/stringify.h"
12 #include "PyFormatter.h"
15 #define dout_context g_ceph_context
16 #define dout_subsys ceph_subsys_mgr
26 OSDMap::Incremental
*inc
;
27 } BasePyOSDMapIncremental
;
31 ceph::shared_ptr
<CrushWrapper
> crush
;
36 static PyObject
*osdmap_get_epoch(BasePyOSDMap
*self
, PyObject
*obj
)
38 return PyInt_FromLong(self
->osdmap
->get_epoch());
41 static PyObject
*osdmap_get_crush_version(BasePyOSDMap
* self
, PyObject
*obj
)
43 return PyInt_FromLong(self
->osdmap
->get_crush_version());
46 static PyObject
*osdmap_dump(BasePyOSDMap
* self
, PyObject
*obj
)
49 self
->osdmap
->dump(&f
);
53 static PyObject
*osdmap_new_incremental(BasePyOSDMap
*self
, PyObject
*obj
)
55 OSDMap::Incremental
*inc
= new OSDMap::Incremental
;
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
62 self
->osdmap
->crush
->encode(inc
->crush
, CEPH_FEATURES_ALL
);
63 dout(10) << __func__
<< " " << inc
<< dendl
;
65 return construct_with_capsule("mgr_module", "OSDMapIncremental",
69 static PyObject
*osdmap_apply_incremental(BasePyOSDMap
*self
,
70 BasePyOSDMapIncremental
*incobj
)
72 if (!PyObject_TypeCheck(incobj
, &BasePyOSDMapIncrementalType
)) {
73 derr
<< "Wrong type in osdmap_apply_incremental!" << dendl
;
78 self
->osdmap
->encode(bl
, CEPH_FEATURES_ALL
|CEPH_FEATURE_RESERVED
);
79 OSDMap
*next
= new OSDMap
;
81 next
->apply_incremental(*(incobj
->inc
));
82 dout(10) << __func__
<< " map " << self
->osdmap
<< " inc " << incobj
->inc
83 << " next " << next
<< dendl
;
85 return construct_with_capsule("mgr_module", "OSDMap", (void*)next
);
88 static PyObject
*osdmap_get_crush(BasePyOSDMap
* self
, PyObject
*obj
)
90 return construct_with_capsule("mgr_module", "CRUSHMap",
91 (void*)(&(self
->osdmap
->crush
)));
94 static PyObject
*osdmap_get_pools_by_take(BasePyOSDMap
* self
, PyObject
*args
)
97 if (!PyArg_ParseTuple(args
, "i:get_pools_by_take",
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
);
113 static PyObject
*osdmap_calc_pg_upmaps(BasePyOSDMap
* self
, PyObject
*args
)
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
)) {
124 if (!PyList_CheckExact(pool_list
)) {
125 derr
<< __func__
<< " pool_list not a list" << dendl
;
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
;
135 auto pool_id
= self
->osdmap
->lookup_pg_pool_name(
136 PyString_AsString(pool_name
));
138 derr
<< __func__
<< " pool '" << PyString_AsString(pool_name
)
139 << "' does not exist" << dendl
;
142 pools
.insert(pool_id
);
145 dout(10) << __func__
<< " osdmap " << self
->osdmap
<< " inc " << incobj
->inc
146 << " max_deviation " << max_deviation
147 << " max_iterations " << max_iterations
148 << " pools " << pools
150 int r
= self
->osdmap
->calc_pg_upmaps(g_ceph_context
,
155 dout(10) << __func__
<< " r = " << r
<< dendl
;
156 return PyInt_FromLong(r
);
159 static PyObject
*osdmap_map_pool_pgs_up(BasePyOSDMap
* self
, PyObject
*args
)
162 if (!PyArg_ParseTuple(args
, "i:map_pool_pgs_up",
166 auto pi
= self
->osdmap
->get_pg_pool(poolid
);
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);
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
);
187 BasePyOSDMap_init(BasePyOSDMap
*self
, PyObject
*args
, PyObject
*kwds
)
189 PyObject
*osdmap_capsule
= nullptr;
190 static const char *kwlist
[] = {"osdmap_capsule", NULL
};
192 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "O",
193 const_cast<char**>(kwlist
),
198 assert(PyObject_TypeCheck(osdmap_capsule
, &PyCapsule_Type
));
200 self
->osdmap
= (OSDMap
*)PyCapsule_GetPointer(
201 osdmap_capsule
, nullptr);
202 assert(self
->osdmap
);
209 BasePyOSDMap_dealloc(BasePyOSDMap
*self
)
213 self
->osdmap
= nullptr;
215 derr
<< "Destroying improperly initialized BasePyOSDMap " << self
<< dendl
;
217 Py_TYPE(self
)->tp_free(self
);
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
}
240 PyTypeObject BasePyOSDMapType
= {
241 PyVarObject_HEAD_INIT(NULL
, 0)
242 "ceph_module.BasePyOSDMap", /* tp_name */
243 sizeof(BasePyOSDMap
), /* tp_basicsize */
245 (destructor
)BasePyOSDMap_dealloc
, /* tp_dealloc */
251 0, /* tp_as_number */
252 0, /* tp_as_sequence */
253 0, /* tp_as_mapping */
259 0, /* tp_as_buffer */
260 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
261 "Ceph OSDMap", /* tp_doc */
264 0, /* tp_richcompare */
265 0, /* tp_weaklistoffset */
268 BasePyOSDMap_methods
, /* tp_methods */
273 0, /* tp_descr_get */
274 0, /* tp_descr_set */
275 0, /* tp_dictoffset */
276 (initproc
)BasePyOSDMap_init
, /* tp_init */
285 BasePyOSDMapIncremental_init(BasePyOSDMapIncremental
*self
,
286 PyObject
*args
, PyObject
*kwds
)
288 PyObject
*inc_capsule
= nullptr;
289 static const char *kwlist
[] = {"inc_capsule", NULL
};
291 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "O",
292 const_cast<char**>(kwlist
),
297 assert(PyObject_TypeCheck(inc_capsule
, &PyCapsule_Type
));
299 self
->inc
= (OSDMap::Incremental
*)PyCapsule_GetPointer(
300 inc_capsule
, nullptr);
307 BasePyOSDMapIncremental_dealloc(BasePyOSDMapIncremental
*self
)
313 derr
<< "Destroying improperly initialized BasePyOSDMap " << self
<< dendl
;
315 Py_TYPE(self
)->tp_free(self
);
318 static PyObject
*osdmap_inc_get_epoch(BasePyOSDMapIncremental
*self
,
321 return PyInt_FromLong(self
->inc
->epoch
);
324 static PyObject
*osdmap_inc_dump(BasePyOSDMapIncremental
*self
,
332 static int get_int_float_map(PyObject
*obj
, map
<int,double> *out
)
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
;
344 if (!PyArg_ParseTuple(pair
, "id:pair", &k
, &v
)) {
345 derr
<< __func__
<< " item " << j
<< " not a size 2 tuple" << dendl
;
356 static PyObject
*osdmap_inc_set_osd_reweights(BasePyOSDMapIncremental
*self
,
360 if (get_int_float_map(weightobj
, &wm
) < 0) {
365 self
->inc
->new_weight
[i
.first
] = std::max(0.0, std::min(1.0, i
.second
)) * 0x10000;
370 static PyObject
*osdmap_inc_set_compat_weight_set_weights(
371 BasePyOSDMapIncremental
*self
, PyObject
*weightobj
)
374 if (get_int_float_map(weightobj
, &wm
) < 0) {
379 assert(self
->inc
->crush
.length()); // see new_incremental
380 auto p
= self
->inc
->crush
.begin();
382 crush
.create_choose_args(CrushWrapper::DEFAULT_CHOOSE_ARGS
, 1);
384 crush
.choose_args_adjust_item_weightf(
386 crush
.choose_args_get(CrushWrapper::DEFAULT_CHOOSE_ARGS
),
391 self
->inc
->crush
.clear();
392 crush
.encode(self
->inc
->crush
, CEPH_FEATURES_ALL
);
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
}
409 PyTypeObject BasePyOSDMapIncrementalType
= {
410 PyVarObject_HEAD_INIT(NULL
, 0)
411 "ceph_module.BasePyOSDMapIncremental", /* tp_name */
412 sizeof(BasePyOSDMapIncremental
), /* tp_basicsize */
414 (destructor
)BasePyOSDMapIncremental_dealloc
, /* tp_dealloc */
420 0, /* tp_as_number */
421 0, /* tp_as_sequence */
422 0, /* tp_as_mapping */
428 0, /* tp_as_buffer */
429 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
430 "Ceph OSDMapIncremental", /* tp_doc */
433 0, /* tp_richcompare */
434 0, /* tp_weaklistoffset */
437 BasePyOSDMapIncremental_methods
, /* tp_methods */
442 0, /* tp_descr_get */
443 0, /* tp_descr_set */
444 0, /* tp_dictoffset */
445 (initproc
)BasePyOSDMapIncremental_init
, /* tp_init */
454 BasePyCRUSH_init(BasePyCRUSH
*self
,
455 PyObject
*args
, PyObject
*kwds
)
457 PyObject
*crush_capsule
= nullptr;
458 static const char *kwlist
[] = {"crush_capsule", NULL
};
460 if (! PyArg_ParseTupleAndKeywords(args
, kwds
, "O",
461 const_cast<char**>(kwlist
),
466 assert(PyObject_TypeCheck(crush_capsule
, &PyCapsule_Type
));
468 auto ptr_ref
= (ceph::shared_ptr
<CrushWrapper
>*)(
469 PyCapsule_GetPointer(crush_capsule
, nullptr));
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
;
482 BasePyCRUSH_dealloc(BasePyCRUSH
*self
)
485 Py_TYPE(self
)->tp_free(self
);
488 static PyObject
*crush_dump(BasePyCRUSH
*self
, PyObject
*obj
)
491 self
->crush
->dump(&f
);
495 static PyObject
*crush_get_item_name(BasePyCRUSH
*self
, PyObject
*args
)
498 if (!PyArg_ParseTuple(args
, "i:get_item_name", &item
)) {
501 if (!self
->crush
->item_exists(item
)) {
504 return PyString_FromString(self
->crush
->get_item_name(item
));
507 static PyObject
*crush_get_item_weight(BasePyCRUSH
*self
, PyObject
*args
)
510 if (!PyArg_ParseTuple(args
, "i:get_item_weight", &item
)) {
513 if (!self
->crush
->item_exists(item
)) {
516 return PyFloat_FromDouble(self
->crush
->get_item_weightf(item
));
519 static PyObject
*crush_find_takes(BasePyCRUSH
*self
, PyObject
*obj
)
522 self
->crush
->find_takes(&takes
);
524 f
.open_array_section("takes");
525 for (auto root
: takes
) {
526 f
.dump_int("root", root
);
532 static PyObject
*crush_get_take_weight_osd_map(BasePyCRUSH
*self
, PyObject
*args
)
535 if (!PyArg_ParseTuple(args
, "i:get_take_weight_osd_map",
541 if (!self
->crush
->item_exists(root
)) {
545 self
->crush
->get_take_weight_osd_map(root
, &wmap
);
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
);
556 PyMethodDef BasePyCRUSH_methods
[] = {
557 {"_dump", (PyCFunction
)crush_dump
, METH_NOARGS
, "Dump map"},
558 {"_get_item_name", (PyCFunction
)crush_get_item_name
, METH_VARARGS
,
560 {"_get_item_weight", (PyCFunction
)crush_get_item_weight
, METH_VARARGS
,
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
}
569 PyTypeObject BasePyCRUSHType
= {
570 PyVarObject_HEAD_INIT(NULL
, 0)
571 "ceph_module.BasePyCRUSH", /* tp_name */
572 sizeof(BasePyCRUSH
), /* tp_basicsize */
574 (destructor
)BasePyCRUSH_dealloc
, /* tp_dealloc */
580 0, /* tp_as_number */
581 0, /* tp_as_sequence */
582 0, /* tp_as_mapping */
588 0, /* tp_as_buffer */
589 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
590 "Ceph OSDMapIncremental", /* tp_doc */
593 0, /* tp_richcompare */
594 0, /* tp_weaklistoffset */
597 BasePyCRUSH_methods
, /* tp_methods */
602 0, /* tp_descr_get */
603 0, /* tp_descr_set */
604 0, /* tp_dictoffset */
605 (initproc
)BasePyCRUSH_init
, /* tp_init */