#include "messages/MMgrDigest.h"
#include "messages/MCommand.h"
#include "messages/MCommandReply.h"
+#include "messages/MLog.h"
#include "Mgr.h"
// 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
waiting_for_fs_map = nullptr;
dout(4) << "Got FSMap." << dendl;
+
// Wait for MgrDigest...?
// TODO
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;
objecter->maybe_request_map();
m->put();
break;
+ case MSG_LOG:
+ handle_log(static_cast<MLog *>(m));
+ m->put();
+ break;
default:
return false;
class MCommand;
class MMgrDigest;
+class MLog;
class Objecter;
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);
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;
#include "Python.h"
#include "common/cmdparse.h"
+#include "common/LogEntry.h"
#include <vector>
#include <string>
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<ModuleCommand> &get_commands() const
{
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();
}
}
+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
{
// 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();