Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mgr: In plugins 'module' classes need not to be called "Module" anymore #18171

Closed
wants to merge 1 commit into from

Conversation

bhavishyagopesh
Copy link
Contributor

Signed-off-by: bhavishyagopesh bhavishyagopesh@gmail.com

@@ -172,31 +172,43 @@ int MgrPyModule::load()

// Find the class
// TODO: let them call it what they want instead of just 'Module'
auto pClass = PyObject_GetAttrString(pModule, (const char*)"Module");
auto tempClass = PyObject_GetAttrString(pModule, (const char*)"MgrModule");
Copy link
Contributor

@tchaikov tchaikov Oct 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, checking the tp_subclasses might work. but because tp_subclasses is an internal member variable and only for CPython's internal usage, this is fragile. we should get using PyModule_GetDict() and check them using PyObject_IsSubclass(), the pseudo code looks like

auto locals = PyModule_GetDict(pModule);
PyObject *key, *value;
Py_ssize_t pos = 0;
while (PyDict_Next(locals, &pos, &key, &value)) {
  if (!PyType_Check(value)) {
    continue;
  }
  if (PyObject_IsSubclass(value, mgr_module_type)) {
    // ...
  }
}

where mgr_module_type is thePyObject of MgrModule .

@bhavishyagopesh
Copy link
Contributor Author

@tchaikov @jcsp I have made the appropriate changes, thanks.


if (!PyType_Check(value)) {
continue;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong indent

continue;
}

if (PyObject_IsSubclass(value, mgr_module_type)) {
Copy link
Contributor

@tchaikov tchaikov Oct 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (!PyObject_IsSubclass(value, mgr_module_type)) {
  continue;
}

to reduce the indent level.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bhavishyagopesh could you reconsider this suggestion?

PyObject *key, *value;
Py_ssize_t pos = 0;

if (mgr_module_type == nullptr) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this check to where mgr_module_type is initialized.

Py_DECREF(pyHandle);
Py_DECREF(pArgs);
if (pClassInstance == nullptr) {
derr << "Failed to construct class in '" << module_name << "'" << dendl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be helpful if we can print out the name (key) of the class.

derr << handle_pyerror() << dendl;
return -EINVAL;
} else {
dout(1) << "Constructed class from module: " << module_name << dendl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto.

dout(1) << "Constructed class from module: " << module_name << dendl;
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this empty line, please.

@bhavishyagopesh bhavishyagopesh force-pushed the feat/17454 branch 2 times, most recently from 4dab29a to f0a6b56 Compare October 10, 2017 06:19
@bhavishyagopesh
Copy link
Contributor Author

@tchaikov Any other suggestions?

Py_DECREF(pModule);
if (pClass == nullptr) {
auto mgr_module_type = PyObject_GetAttrString(pModule, (const char*)"MgrModule");

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this empty line.

return -EINVAL;
} else {
dout(1) << "Constructed class from module: " << module_name << dendl;
Py_DECREF(pModule);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we cannot deref pModule yet. we are actually referencing it right after this line.

Py_ssize_t pos = 0;

while (PyDict_Next(locals, &pos, &key, &value)) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this empty line.

if (!PyType_Check(value)) {
continue;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto.

}

if (PyObject_IsSubclass(value, mgr_module_type)) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto.

Py_DECREF(pyHandle);
Py_DECREF(pArgs);
if (pClassInstance == nullptr) {
derr << "Failed to construct class '" << PyObject_Str(pClass) << "'" << " in " << "'" << module_name << "'" << dendl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use key? also PyObject_Str() returns a new reference, we should deref after using it. and what's the point of printing a PyObjecter pointer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw, use PyString_AsString(key) to retrieve the c string from it.

@tchaikov
Copy link
Contributor

could you prefix the title of your commit message with the subcomponent your are changing ? see https://github.com/ceph/ceph/blob/master/SubmittingPatches.rst#3-describe-your-changes

if (pClass == nullptr) {
auto mgr_module_type = PyObject_GetAttrString(pModule, (const char*)"MgrModule");

if (mgr_module_type == nullptr) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think the plugin is not required to expose MgrModule. can we load this class from mgr_module instead?

@bhavishyagopesh
Copy link
Contributor Author

@tchaikov Any more improvements?

@ceph-jenkins
Copy link
Collaborator

OK - docs built

} else {
dout(1) << "Constructed class: " << PyString_AsString(key) << " from module: " << module_name << dendl;
}
Py_DECREF(pClass);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, could move this line next to Py_DECREF(pyHandle);.

auto pClass = PyObject_GetAttrString(pModule, (const char*)"Module");
Py_DECREF(pModule);
if (pClass == nullptr) {
auto mgr_module_type = PyImport_ImportModule("mgr_module.MgrModule");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the extra space after auto.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please Py_DECREF(mgr_module_type) after done with it.

Py_DECREF(pModule);
if (pClass == nullptr) {
auto mgr_module_type = PyImport_ImportModule("mgr_module.MgrModule");
if (mgr_module_type == nullptr) {
derr << "Class not found in module '" << module_name << "'" << dendl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change the error message to something like

Unable to import mgr_module from MgrModule

as we are not importing the Module from from $module_name here.

@tchaikov tchaikov changed the title Module classes are not forced to be called "Module". fixes #17454 mgr: In plugins 'module' classes need not to be called "Module" anymore Oct 11, 2017
auto locals = PyModule_GetDict(pModule);
PyObject *key, *value;
Py_ssize_t pos = 0;
Py_DECREF(pModule);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, move this line right after PyModule_GetDict(pModule).

@bhavishyagopesh
Copy link
Contributor Author

@tchaikov any more suggestions?

pClassInstance = PyObject_CallObject(pClass, pArgs);
Py_DECREF(pyHandle);
Py_DECREF(pArgs);
Py_DECREF(pClass);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please don't deref pClass here, as we are not holding a reference to it.

Py_DECREF(pArgs);
Py_DECREF(pClass);
if (pClassInstance == nullptr) {
derr << "Failed to construct class '" << PyString_AsString(key) << "'" << " in " << "'" << module_name << "'" << dendl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might want to have a variable holding the retval of PyString_AsString(key), like

auto class_name = PyString_AsString(key);

as you are referencing the class using pClass, while referencing its name using PyString_AsString(key).

@bhavishyagopesh
Copy link
Contributor Author

@tchaikov Probably due to some ci/infra issues build is not being reported...but if you still find any improvement you could mention it. Thanks.

@tchaikov
Copy link
Contributor

@bhavishyagopesh IIRC, this PR is addressing a ticket a tracker, could you reference it in the commit message? like

Fixes: http://tracker.ceph.com/issues/123456
Signed-off-by: bhavishyagopesh <bhavishyagopesh@gmail.com>

please replace "123456" with the actual ticket id.

@bhavishyagopesh
Copy link
Contributor Author

bhavishyagopesh commented Oct 16, 2017

@tchaikov is it okay now?

@jcsp
Copy link
Contributor

jcsp commented Oct 16, 2017

@bhavishyagopesh please could you test this yourself and let us know if it is working

@bhavishyagopesh
Copy link
Contributor Author

@jcsp Are there any available Dockerfiles that I can run on local system...only for testing purpose.

@bhavishyagopesh
Copy link
Contributor Author

@tchaikov @jcsp Is there some way of running the qa suite without openstack/bare-metal... I lack the hardware to run test-suite.

@tchaikov
Copy link
Contributor

tchaikov commented Oct 18, 2017

please run the minimal test, vstart would suffice. see http://docs.ceph.com/docs/master/dev/quick_guide/

@bhavishyagopesh
Copy link
Contributor Author

bhavishyagopesh commented Oct 18, 2017

@tchaikov two tests fail but they do not look related to plugins.

     The following tests FAILED:
	  7 - run-tox-ceph-disk (Failed)
	  8 - run-tox-ceph-detect-init (Failed)

@tchaikov
Copy link
Contributor

@bhavishyagopesh how did you test this change?

@bhavishyagopesh
Copy link
Contributor Author

@tchaikov I ran the run-make-check.sh script and vstart script inside an ubuntu docker(as the scripts do not work for my base installation)...but i guess for testing this specific plugin I should do ceph mgr module enable $plugin but due to above errors there is no ceph binary

@tchaikov
Copy link
Contributor

tchaikov commented Oct 19, 2017

restful, status, dashboard and balancer are enabled by default in vstart.sh. all you need to do is to make sure they are detected and loaded by ceph-mgr.

ceph cli is not a binary, it's a python script. and should be built by default.

@bhavishyagopesh
Copy link
Contributor Author

@tchaikov it does detect restful, status, dashboard and balancer...though restful should this error MGR Restful is not working, perhaps the package is not installed?
`

@tchaikov
Copy link
Contributor

it does detect restful, status, dashboard and balancer

again, how do you test this?

@bhavishyagopesh
Copy link
Contributor Author

@tchaikov I now ran the prometheus plugin on localhostport-forwarded from docker) and also I was able to access dashboard on an internal url ...so is that test sufficient..

@bhavishyagopesh
Copy link
Contributor Author

@jcsp @tchaikov is the above test insufficient to ensure that plugins are loaded properly("this change is okay")?

Py_DECREF(pModule);
if (pClass == nullptr) {
derr << "Class not found in module '" << module_name << "'" << dendl;
PyObject *mgr_module_name = PyString_FromString("mgr_module");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bhavishyagopesh why don't you just use PyImport_ImportModule() ?

see. #18171 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tchaikov I messed that up, I have changed it now.

@tchaikov
Copy link
Contributor

@bhavishyagopesh the test above would do.

Copy link
Contributor

@tchaikov tchaikov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am posting a fixed version at #18526

}
// Just using the module name as the handle, replace with a
// uuidish thing if needed
auto pClass = value;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is chance the last loaded class is MgrModule , which overwrites the one we want to load. so pClassInstance will be a MgrModule instance.

@tchaikov
Copy link
Contributor

closing in favor of #18526

@tchaikov
Copy link
Contributor

http://pulpito.ceph.com/kchai-2017-10-24_16:44:55-rados-wip-kefu-testing-2017-10-24-2303-distro-basic-mira/

failures are due to localpool and influx plugins' failure to load.

@jcsp
Copy link
Contributor

jcsp commented Oct 31, 2017

Seems like the failures are not exactly from failures to load but more from the way the tests are a bit racy (doesn't guarantee command descriptions have loaded before running).

The tests get more robust in #16651

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants