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:
bhavishyagopesh 2017-10-09 11:10:41 +05:30 committed by Kefu Chai
parent 540b4cf575
commit 345c14438e
3 changed files with 66 additions and 29 deletions

View File

@ -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``

View File

@ -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) {

View File

@ -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;