mirror of
https://github.com/ceph/ceph
synced 2025-03-25 11:48:05 +00:00
mgr: In plugins 'module' classes need not to be called "Module" anymore.
Fixes: http://tracker.ceph.com/issues/17454 Signed-off-by: Kefu Chai <kchai@redhat.com> Signed-off-by: bhavishyagopesh <bhavishyagopesh@gmail.com>
This commit is contained in:
parent
540b4cf575
commit
345c14438e
@ -6,7 +6,7 @@ Creating a plugin
|
||||
-----------------
|
||||
|
||||
In pybind/mgr/, create a python module. Within your module, create a class
|
||||
named ``Module`` that inherits from ``MgrModule``.
|
||||
that inherits from ``MgrModule``.
|
||||
|
||||
The most important methods to override are:
|
||||
|
||||
@ -33,7 +33,7 @@ or older versions of Ceph.
|
||||
Logging
|
||||
-------
|
||||
|
||||
MgrModule instances have a ``log`` property which is a logger instance that
|
||||
``MgrModule`` instances have a ``log`` property which is a logger instance that
|
||||
sends log messages into the Ceph logging layer where they will be recorded
|
||||
in the mgr daemon's log file.
|
||||
|
||||
@ -169,7 +169,7 @@ serve HTTP redirect responses from the standby managers so that
|
||||
the user can point his browser at any of the manager daemons without
|
||||
having to worry about which one is active.
|
||||
|
||||
Standby manager daemons look for a class called ``StandbyModule``
|
||||
Standby manager daemons look for a subclass of ``StandbyModule``
|
||||
in each module. If the class is not found then the module is not
|
||||
used at all on standby daemons. If the class is found, then
|
||||
its ``serve`` method is called. Implementations of ``StandbyModule``
|
||||
|
@ -254,43 +254,80 @@ int PyModule::load(PyThreadState *pMainThreadState)
|
||||
// Environment is all good, import the external module
|
||||
{
|
||||
Gil gil(pMyThreadState);
|
||||
|
||||
// Load the module
|
||||
PyObject *pName = PyString_FromString(module_name.c_str());
|
||||
auto pModule = PyImport_Import(pName);
|
||||
Py_DECREF(pName);
|
||||
if (pModule == nullptr) {
|
||||
derr << "Module not found: '" << module_name << "'" << dendl;
|
||||
derr << handle_pyerror() << dendl;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
// Find the class
|
||||
// TODO: let them call it what they want instead of just 'Module'
|
||||
pClass = PyObject_GetAttrString(pModule, (const char*)"Module");
|
||||
if (pClass == nullptr) {
|
||||
int r;
|
||||
r = load_subclass_of("MgrModule", &pClass);
|
||||
if (r) {
|
||||
derr << "Class not found in module '" << module_name << "'" << dendl;
|
||||
derr << handle_pyerror() << dendl;
|
||||
return -EINVAL;
|
||||
return r;
|
||||
}
|
||||
|
||||
pStandbyClass = PyObject_GetAttrString(pModule,
|
||||
(const char*)"StandbyModule");
|
||||
if (pStandbyClass) {
|
||||
r = load_subclass_of("MgrStandbyModule", &pStandbyClass);
|
||||
if (!r) {
|
||||
dout(4) << "Standby mode available in module '" << module_name
|
||||
<< "'" << dendl;
|
||||
} else {
|
||||
dout(4) << "Standby mode not provided by module '" << module_name
|
||||
<< "'" << dendl;
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
Py_DECREF(pModule);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PyModule::load_subclass_of(const char* base_class, PyObject** py_class)
|
||||
{
|
||||
// load the base class
|
||||
PyObject *mgr_module = PyImport_ImportModule("mgr_module");
|
||||
if (!mgr_module) {
|
||||
derr << "Module not found: 'mgr_module'" << dendl;
|
||||
derr << handle_pyerror() << dendl;
|
||||
return -EINVAL;
|
||||
}
|
||||
auto mgr_module_type = PyObject_GetAttrString(mgr_module, base_class);
|
||||
Py_DECREF(mgr_module);
|
||||
if (!mgr_module_type) {
|
||||
derr << "Unable to import MgrModule from mgr_module" << dendl;
|
||||
derr << handle_pyerror() << dendl;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// find the sub class
|
||||
PyObject *plugin_module = PyImport_ImportModule(module_name.c_str());
|
||||
if (!plugin_module) {
|
||||
derr << "Module not found: '" << module_name << "'" << dendl;
|
||||
derr << handle_pyerror() << dendl;
|
||||
return -ENOENT;
|
||||
}
|
||||
auto locals = PyModule_GetDict(plugin_module);
|
||||
Py_DECREF(plugin_module);
|
||||
PyObject *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
*py_class = nullptr;
|
||||
while (PyDict_Next(locals, &pos, &key, &value)) {
|
||||
if (!PyType_Check(value)) {
|
||||
continue;
|
||||
}
|
||||
if (!PyObject_IsSubclass(value, mgr_module_type)) {
|
||||
continue;
|
||||
}
|
||||
if (PyObject_RichCompareBool(value, mgr_module_type, Py_EQ)) {
|
||||
continue;
|
||||
}
|
||||
auto class_name = PyString_AsString(key);
|
||||
if (*py_class) {
|
||||
derr << __func__ << ": ignoring '"
|
||||
<< module_name << "." << class_name << "'"
|
||||
<< ": only one '" << base_class
|
||||
<< "' class is loaded from each plugin" << dendl;
|
||||
continue;
|
||||
}
|
||||
*py_class = value;
|
||||
dout(4) << __func__ << ": found class: '"
|
||||
<< module_name << "." << class_name << "'" << dendl;
|
||||
}
|
||||
Py_DECREF(mgr_module_type);
|
||||
|
||||
return *py_class ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
PyModule::~PyModule()
|
||||
{
|
||||
if (pMyThreadState.ts != nullptr) {
|
||||
|
@ -31,7 +31,7 @@ class PyModule
|
||||
private:
|
||||
const std::string module_name;
|
||||
std::string get_site_packages();
|
||||
|
||||
int load_subclass_of(const char* class_name, PyObject** py_class);
|
||||
public:
|
||||
SafeThreadState pMyThreadState;
|
||||
PyObject *pClass = nullptr;
|
||||
|
Loading…
Reference in New Issue
Block a user