From: John Spray Date: Mon, 14 Nov 2016 00:04:16 +0000 (+0000) Subject: mgr: pass through cluster log to plugins X-Git-Tag: v12.0.2~238^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=9ea37c223f92b8f228c57a4c17d4da02d99be756;p=ceph.git mgr: pass through cluster log to plugins Signed-off-by: John Spray --- diff --git a/src/mgr/Mgr.cc b/src/mgr/Mgr.cc index 090e0aa2f193..b8a731df2c21 100644 --- a/src/mgr/Mgr.cc +++ b/src/mgr/Mgr.cc @@ -28,6 +28,7 @@ #include "messages/MMgrDigest.h" #include "messages/MCommand.h" #include "messages/MCommandReply.h" +#include "messages/MLog.h" #include "Mgr.h" @@ -180,6 +181,7 @@ void Mgr::init() // Subscribe to OSDMap update to pass on to ClusterState objecter->maybe_request_map(); + monc->sub_want("log-info", 0, 0); monc->sub_want("mgrdigest", 0, 0); // Prepare to receive FSMap and request it @@ -197,6 +199,7 @@ void Mgr::init() waiting_for_fs_map = nullptr; dout(4) << "Got FSMap." << dendl; + // Wait for MgrDigest...? // TODO @@ -418,6 +421,13 @@ void Mgr::handle_osd_map() daemon_state.cull(CEPH_ENTITY_TYPE_OSD, names_exist); } +void Mgr::handle_log(MLog *m) +{ + for (const auto &e : m->entries) { + py_modules.notify_all(e); + } +} + bool Mgr::ms_dispatch(Message *m) { derr << *m << dendl; @@ -455,6 +465,10 @@ bool Mgr::ms_dispatch(Message *m) objecter->maybe_request_map(); m->put(); break; + case MSG_LOG: + handle_log(static_cast(m)); + m->put(); + break; default: return false; diff --git a/src/mgr/Mgr.h b/src/mgr/Mgr.h index ffe1d1460c90..178df38e77f7 100644 --- a/src/mgr/Mgr.h +++ b/src/mgr/Mgr.h @@ -38,6 +38,7 @@ class MCommand; class MMgrDigest; +class MLog; class Objecter; @@ -78,6 +79,7 @@ public: void handle_mgr_digest(MMgrDigest* m); void handle_fs_map(MFSMap* m); void handle_osd_map(); + void handle_log(MLog *m); bool ms_dispatch(Message *m); diff --git a/src/mgr/MgrPyModule.cc b/src/mgr/MgrPyModule.cc index 72ad59491e53..4e4c42483a51 100644 --- a/src/mgr/MgrPyModule.cc +++ b/src/mgr/MgrPyModule.cc @@ -140,6 +140,36 @@ void MgrPyModule::notify(const std::string ¬ify_type, const std::string ¬i PyGILState_Release(gstate); } +void MgrPyModule::notify_clog(const LogEntry &log_entry) +{ + assert(pClassInstance != nullptr); + + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); + + // Construct python-ized LogEntry + PyFormatter f; + log_entry.dump(&f); + auto py_log_entry = f.get(); + + // Execute + auto pValue = PyObject_CallMethod(pClassInstance, + const_cast("notify"), const_cast("(sN)"), + "clog", py_log_entry); + + if (pValue != NULL) { + Py_DECREF(pValue); + } else { + PyErr_Print(); + // FIXME: callers can't be expected to handle a python module + // that has spontaneously broken, but Mgr() should provide + // a hook to unload misbehaving modules when they have an + // error somewhere like this + } + + PyGILState_Release(gstate); +} + int MgrPyModule::load_commands() { PyGILState_STATE gstate; diff --git a/src/mgr/MgrPyModule.h b/src/mgr/MgrPyModule.h index dd490d7e7402..0588401a787f 100644 --- a/src/mgr/MgrPyModule.h +++ b/src/mgr/MgrPyModule.h @@ -20,6 +20,7 @@ #include "Python.h" #include "common/cmdparse.h" +#include "common/LogEntry.h" #include #include @@ -58,6 +59,7 @@ public: int serve(); void shutdown(); void notify(const std::string ¬ify_type, const std::string ¬ify_id); + void notify_clog(const LogEntry &le); const std::vector &get_commands() const { diff --git a/src/mgr/PyFormatter.h b/src/mgr/PyFormatter.h index a1dbf182d67d..4f273941ad8e 100644 --- a/src/mgr/PyFormatter.h +++ b/src/mgr/PyFormatter.h @@ -38,6 +38,9 @@ class PyFormatter : public ceph::Formatter public: PyFormatter(bool pretty = false, bool array = false) { + // It is forbidden to instantiate me outside of the GIL, + // because I construct python objects right away + // Initialise cursor to an empty dict if (!array) { root = cursor = PyDict_New(); diff --git a/src/mgr/PyModules.cc b/src/mgr/PyModules.cc index a4ddcda38c19..f7812eac5a26 100644 --- a/src/mgr/PyModules.cc +++ b/src/mgr/PyModules.cc @@ -476,6 +476,25 @@ void PyModules::notify_all(const std::string ¬ify_type, } } +void PyModules::notify_all(const LogEntry &log_entry) +{ + Mutex::Locker l(lock); + + dout(10) << __func__ << ": notify_all (clog)" << dendl; + for (auto i : modules) { + auto module = i.second; + // Send all python calls down a Finisher to avoid blocking + // C++ code, and avoid any potential lock cycles. + // + // Note intentional use of non-reference lambda binding on + // log_entry: we take a copy because caller's instance is + // probably ephemeral. + finisher.queue(new FunctionContext([module, log_entry](int r){ + module->notify_clog(log_entry); + })); + } +} + bool PyModules::get_config(const std::string &handle, const std::string &key, std::string *val) const { diff --git a/src/mgr/PyModules.h b/src/mgr/PyModules.h index 107d43b8560c..3c0f56c6ba5f 100644 --- a/src/mgr/PyModules.h +++ b/src/mgr/PyModules.h @@ -73,6 +73,7 @@ public: // send it to only the module that sent the command, not everyone void notify_all(const std::string ¬ify_type, const std::string ¬ify_id); + void notify_all(const LogEntry &log_entry); int init(); void start();