]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr: pass through cluster log to plugins 13690/head
authorJohn Spray <john.spray@redhat.com>
Mon, 14 Nov 2016 00:04:16 +0000 (00:04 +0000)
committerJohn Spray <john.spray@redhat.com>
Sat, 11 Mar 2017 21:13:31 +0000 (21:13 +0000)
Signed-off-by: John Spray <john.spray@redhat.com>
src/mgr/Mgr.cc
src/mgr/Mgr.h
src/mgr/MgrPyModule.cc
src/mgr/MgrPyModule.h
src/mgr/PyFormatter.h
src/mgr/PyModules.cc
src/mgr/PyModules.h

index 090e0aa2f1937a87affaddde5edc8093d9317756..b8a731df2c21cbb4b4e2dc12c43f877ce4762487 100644 (file)
@@ -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<MLog *>(m));
+      m->put();
+      break;
 
     default:
       return false;
index ffe1d1460c90d984a65b56a888b36c76d26a25f0..178df38e77f72c42e4423e9ef0adc72d7d892429 100644 (file)
@@ -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);
 
index 72ad59491e5351042b3ad447750492040d87c8b1..4e4c42483a51b41223ce2fbad0186da1f03d79ce 100644 (file)
@@ -140,6 +140,36 @@ void MgrPyModule::notify(const std::string &notify_type, const std::string &noti
   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<char*>("notify"), const_cast<char*>("(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;
index dd490d7e7402d38a3cb3505a0faab74a71e1f1f6..0588401a787f3689dd0b5973bb655d206c3df9f1 100644 (file)
@@ -20,6 +20,7 @@
 #include "Python.h"
 
 #include "common/cmdparse.h"
+#include "common/LogEntry.h"
 
 #include <vector>
 #include <string>
@@ -58,6 +59,7 @@ public:
   int serve();
   void shutdown();
   void notify(const std::string &notify_type, const std::string &notify_id);
+  void notify_clog(const LogEntry &le);
 
   const std::vector<ModuleCommand> &get_commands() const
   {
index a1dbf182d67db5c09ddfdc3996b41c755c3970db..4f273941ad8e70ae78f9483baa3d31c8cdf56128 100644 (file)
@@ -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();
index a4ddcda38c199e5b4a47eeed4c24f3e8f513d363..f7812eac5a26c8ce28950af42359fbb131e597a0 100644 (file)
@@ -476,6 +476,25 @@ void PyModules::notify_all(const std::string &notify_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
 {
index 107d43b8560cc6f62858125fca6dfa317cb76673..3c0f56c6ba5f9c98137b32bc163775ba26961f5e 100644 (file)
@@ -73,6 +73,7 @@ public:
   // send it to only the module that sent the command, not everyone
   void notify_all(const std::string &notify_type,
                   const std::string &notify_id);
+  void notify_all(const LogEntry &log_entry);
 
   int init();
   void start();