#define dout_prefix *_dout << "mgr " << __func__ << " "
ActivePyModules::ActivePyModules(PyModuleConfig &module_config_,
+ std::map<std::string, std::string> store_data,
DaemonStateIndex &ds, ClusterState &cs,
MonClient &mc, LogChannelRef clog_, Objecter &objecter_,
Client &client_, Finisher &f)
monc(mc), clog(clog_), objecter(objecter_), client(client_), finisher(f),
lock("ActivePyModules")
{
+ store_cache = std::move(store_data);
}
ActivePyModules::~ActivePyModules() = default;
Mutex::Locker l(lock);
PyEval_RestoreThread(tstate);
- const std::string global_key = PyModuleRegistry::config_prefix
+ const std::string global_key = PyModule::config_prefix
+ module_name + "/" + key;
dout(4) << __func__ << "key: " << global_key << dendl;
Mutex::Locker l(lock);
PyEval_RestoreThread(tstate);
- const std::string global_key = PyModuleRegistry::config_prefix
+ const std::string global_key = PyModule::config_prefix
+ module_name + "/" + key;
dout(4) << __func__ << " key: " << global_key << dendl;
Mutex::Locker l(lock);
PyEval_RestoreThread(tstate);
- const std::string base_prefix = PyModuleRegistry::config_prefix
+ const std::string base_prefix = PyModule::config_prefix
+ module_name + "/";
const std::string global_prefix = base_prefix + prefix;
dout(4) << __func__ << " prefix: " << global_prefix << dendl;
void ActivePyModules::set_store(const std::string &module_name,
const std::string &key, const boost::optional<std::string>& val)
{
- const std::string global_key = PyModuleRegistry::config_prefix
+ const std::string global_key = PyModule::config_prefix
+ module_name + "/" + key;
Command set_cmd;
void ActivePyModules::set_config(const std::string &module_name,
const std::string &key, const boost::optional<std::string>& val)
{
- const std::string global_key = PyModuleRegistry::config_prefix
- + module_name + "/" + key;
-
- Command set_cmd;
- {
- PyThreadState *tstate = PyEval_SaveThread();
- Mutex::Locker l(lock);
- PyEval_RestoreThread(tstate);
-
- Mutex::Locker lock(module_config.lock);
-
- if (val) {
- module_config.config[global_key] = *val;
- } else {
- module_config.config.erase(global_key);
- }
-
- std::ostringstream cmd_json;
- JSONFormatter jf;
- jf.open_object_section("cmd");
- if (val) {
- jf.dump_string("prefix", "config set mgr");
- jf.dump_string("key", global_key);
- jf.dump_string("val", *val);
- } else {
- jf.dump_string("prefix", "config rm");
- jf.dump_string("key", global_key);
- }
- jf.close_section();
- jf.flush(cmd_json);
- set_cmd.run(&monc, cmd_json.str());
- }
- set_cmd.wait();
-
- if (set_cmd.r != 0) {
- dout(0) << "`config set mgr" << global_key << " " << val << "` failed: "
- << cpp_strerror(set_cmd.r) << dendl;
- dout(0) << "mon returned " << set_cmd.r << ": " << set_cmd.outs << dendl;
- }
+ module_config.set_config(&monc, module_name, key, val);
}
std::map<std::string, std::string> ActivePyModules::get_services() const
public:
ActivePyModules(PyModuleConfig &module_config,
+ std::map<std::string, std::string> store_data,
DaemonStateIndex &ds, ClusterState &cs, MonClient &mc,
LogChannelRef clog_, Objecter &objecter_, Client &client_,
Finisher &f);
Py_RETURN_NONE;
}
+
+static PyObject*
+ceph_store_get(BaseMgrModule *self, PyObject *args)
+{
+ char *what = nullptr;
+ if (!PyArg_ParseTuple(args, "s:ceph_store_get", &what)) {
+ derr << "Invalid args!" << dendl;
+ return nullptr;
+ }
+
+ std::string value;
+ bool found = self->py_modules->get_store(self->this_module->get_name(),
+ what, &value);
+ if (found) {
+ dout(10) << "ceph_store_get " << what << " found: " << value.c_str() << dendl;
+ return PyString_FromString(value.c_str());
+ } else {
+ dout(4) << "ceph_store_get " << what << " not found " << dendl;
+ Py_RETURN_NONE;
+ }
+}
+
+
+
+static PyObject*
+ceph_store_set(BaseMgrModule *self, PyObject *args)
+{
+ char *key = nullptr;
+ char *value = nullptr;
+ if (!PyArg_ParseTuple(args, "sz:ceph_store_set", &key, &value)) {
+ return nullptr;
+ }
+ boost::optional<string> val;
+ if (value) {
+ val = value;
+ }
+ self->py_modules->set_store(self->this_module->get_name(), key, val);
+
+ Py_RETURN_NONE;
+}
+
static PyObject*
get_metadata(BaseMgrModule *self, PyObject *args)
{
{"_ceph_set_config", (PyCFunction)ceph_config_set, METH_VARARGS,
"Set a configuration value"},
+ {"_ceph_get_store", (PyCFunction)ceph_store_get, METH_VARARGS,
+ "Get a stored field"},
+
+ {"_ceph_set_store", (PyCFunction)ceph_store_set, METH_VARARGS,
+ "Set a stored field"},
+
{"_ceph_get_counter", (PyCFunction)get_counter, METH_VARARGS,
"Get a performance counter"},
}));
}
+std::map<std::string, std::string> Mgr::load_store()
+{
+ assert(lock.is_locked_by_me());
+
+ dout(10) << "listing keys" << dendl;
+ JSONCommand cmd;
+ cmd.run(monc, "{\"prefix\": \"config-key ls\"}");
+ lock.Unlock();
+ cmd.wait();
+ lock.Lock();
+ assert(cmd.r == 0);
+
+ std::map<std::string, std::string> loaded;
+
+ for (auto &key_str : cmd.json_result.get_array()) {
+ std::string const key = key_str.get_str();
+
+ dout(20) << "saw key '" << key << "'" << dendl;
+
+ const std::string config_prefix = PyModule::config_prefix;
+
+ if (key.substr(0, config_prefix.size()) == config_prefix) {
+ dout(20) << "fetching '" << key << "'" << dendl;
+ Command get_cmd;
+ std::ostringstream cmd_json;
+ cmd_json << "{\"prefix\": \"config-key get\", \"key\": \"" << key << "\"}";
+ get_cmd.run(monc, cmd_json.str());
+ lock.Unlock();
+ get_cmd.wait();
+ lock.Lock();
+ assert(get_cmd.r == 0);
+ loaded[key] = get_cmd.outbl.to_str();
+ }
+ }
+
+ return loaded;
+}
+
void Mgr::init()
{
Mutex::Locker l(lock);
dout(4) << "waiting for config-keys..." << dendl;
- // Preload config keys (`get` for plugins is to be a fast local
- // operation, we we don't have to synchronize these later because
- // all sets will come via mgr)
- auto loaded_config = load_config();
-
// Wait for MgrDigest...
dout(4) << "waiting for MgrDigest..." << dendl;
while (!digest_received) {
digest_cond.Wait(lock);
}
+ // Load module KV store
+ auto kv_store = load_store();
+
+ // Migrate config from KV store on luminous->mimic
+ // drop lock because we do blocking config sets to mon
+ lock.Unlock();
+ py_module_registry->upgrade_config(monc, kv_store);
+ lock.Lock();
+
// assume finisher already initialized in background_init
dout(4) << "starting python modules..." << dendl;
- py_module_registry->active_start(loaded_config, daemon_state, cluster_state,
- *monc, clog, *objecter, *client, finisher);
+ py_module_registry->active_start(daemon_state, cluster_state,
+ kv_store, *monc, clog, *objecter, *client, finisher);
dout(4) << "Complete." << dendl;
initializing = false;
}
}
-PyModuleConfig Mgr::load_config()
-{
- assert(lock.is_locked_by_me());
-
- dout(10) << "listing keys" << dendl;
- JSONCommand cmd;
- cmd.run(monc, "{\"prefix\": \"config-key ls\"}");
- lock.Unlock();
- cmd.wait();
- lock.Lock();
- assert(cmd.r == 0);
-
- PyModuleConfig loaded;
-
- for (auto &key_str : cmd.json_result.get_array()) {
- std::string const key = key_str.get_str();
-
- dout(20) << "saw key '" << key << "'" << dendl;
-
- const std::string config_prefix = PyModuleRegistry::config_prefix;
-
- if (key.substr(0, config_prefix.size()) == config_prefix) {
- dout(20) << "fetching '" << key << "'" << dendl;
- Command get_cmd;
- std::ostringstream cmd_json;
- cmd_json << "{\"prefix\": \"config-key get\", \"key\": \"" << key << "\"}";
- get_cmd.run(monc, cmd_json.str());
- lock.Unlock();
- get_cmd.wait();
- lock.Lock();
- assert(get_cmd.r == 0);
- loaded.config[key] = get_cmd.outbl.to_str();
- }
- }
-
- return loaded;
-}
void Mgr::shutdown()
{
LogChannelRef clog;
LogChannelRef audit_clog;
- PyModuleConfig load_config();
void load_all_metadata();
+ std::map<std::string, std::string> load_store();
void init();
bool initialized;
monc.register_config_callback([this](const std::string &k, const std::string &v){
dout(10) << "config_callback: " << k << " : " << v << dendl;
if (k.substr(0, 4) == "mgr/") {
- const std::string global_key = PyModuleRegistry::config_prefix + k.substr(4);
+ const std::string global_key = PyModule::config_prefix + k.substr(4);
py_module_registry.handle_config(global_key, v);
return true;
// I am the standby and someone else is active, start modules
// in standby mode to do redirects if needed
if (!py_module_registry.is_standby_running()) {
- py_module_registry.standby_start(&monc);
+ py_module_registry.standby_start();
}
}
}
#include "BaseMgrModule.h"
#include "BaseMgrStandbyModule.h"
#include "PyOSDMap.h"
+#include "MgrContext.h"
#include "PyModule.h"
#undef dout_prefix
#define dout_prefix *_dout << "mgr[py] "
+// definition for non-const static member
+std::string PyModule::config_prefix = "mgr/";
+
// Courtesy of http://stackoverflow.com/questions/1418015/how-to-get-python-exception-text
#include <boost/python.hpp>
#include <boost/algorithm/string/predicate.hpp>
PyModuleConfig::~PyModuleConfig() = default;
+
+void PyModuleConfig::set_config(
+ MonClient *monc,
+ const std::string &module_name,
+ const std::string &key, const boost::optional<std::string>& val)
+{
+ const std::string global_key = PyModule::config_prefix
+ + module_name + "/" + key;
+ {
+ Mutex::Locker l(lock);
+
+ if (val) {
+ config[global_key] = *val;
+ } else {
+ config.erase(global_key);
+ }
+ }
+
+ Command set_cmd;
+ {
+ std::ostringstream cmd_json;
+ JSONFormatter jf;
+ jf.open_object_section("cmd");
+ if (val) {
+ jf.dump_string("prefix", "config set mgr");
+ jf.dump_string("key", global_key);
+ jf.dump_string("val", *val);
+ } else {
+ jf.dump_string("prefix", "config rm");
+ jf.dump_string("key", global_key);
+ }
+ jf.close_section();
+ jf.flush(cmd_json);
+ set_cmd.run(monc, cmd_json.str());
+ }
+ set_cmd.wait();
+
+ if (set_cmd.r != 0) {
+ dout(0) << "`config set mgr" << global_key << " " << val << "` failed: "
+ << cpp_strerror(set_cmd.r) << dendl;
+ dout(0) << "mon returned " << set_cmd.r << ": " << set_cmd.outs << dendl;
+ }
+}
+
std::string PyModule::get_site_packages()
{
std::stringstream site_packages;
#include <string>
#include "common/Mutex.h"
#include <memory>
+#include <boost/optional.hpp>
+
+class MonClient;
std::string handle_pyerror();
std::vector<ModuleCommand> commands;
public:
+ static std::string config_prefix;
+
SafeThreadState pMyThreadState;
PyObject *pClass = nullptr;
PyObject *pStandbyClass = nullptr;
PyModuleConfig(PyModuleConfig &mconfig);
~PyModuleConfig();
+
+ void set_config(
+ MonClient *monc,
+ const std::string &module_name,
+ const std::string &key, const boost::optional<std::string>& val);
+
};
#include "PyOSDMap.h"
#include "BaseMgrStandbyModule.h"
#include "Gil.h"
+#include "MgrContext.h"
#include "ActivePyModules.h"
#include "PyModuleRegistry.h"
-// definition for non-const static member
-std::string PyModuleRegistry::config_prefix;
-
-
-
#define dout_context g_ceph_context
#define dout_subsys ceph_subsys_mgr
{
Mutex::Locker locker(lock);
- // namespace in config-key prefixed by "mgr/"
- config_prefix = std::string(g_conf->name.get_type_str()) + "/";
-
// Set up global python interpreter
#if PY_MAJOR_VERSION >= 3
#define WCHAR(s) L ## #s
}
}
-void PyModuleRegistry::standby_start(MonClient *monc)
+
+
+void PyModuleRegistry::standby_start()
{
Mutex::Locker l(lock);
assert(active_modules == nullptr);
dout(4) << "Starting modules in standby mode" << dendl;
standby_modules.reset(new StandbyPyModules(
- monc, mgr_map, module_config, clog));
+ mgr_map, module_config, clog));
std::set<std::string> failed_modules;
for (const auto &i : modules) {
}
void PyModuleRegistry::active_start(
- PyModuleConfig &module_config,
- DaemonStateIndex &ds, ClusterState &cs, MonClient &mc,
- LogChannelRef clog_, Objecter &objecter_, Client &client_,
- Finisher &f)
+ DaemonStateIndex &ds, ClusterState &cs,
+ const std::map<std::string, std::string> &kv_store,
+ MonClient &mc, LogChannelRef clog_, Objecter &objecter_,
+ Client &client_, Finisher &f)
{
Mutex::Locker locker(lock);
}
active_modules.reset(new ActivePyModules(
- module_config, ds, cs, mc, clog_, objecter_, client_, f));
+ module_config, kv_store, ds, cs, mc,
+ clog_, objecter_, client_, f));
for (const auto &i : modules) {
// Anything we're skipping because of !can_run will be flagged
}
}
+void PyModuleRegistry::upgrade_config(
+ MonClient *monc,
+ const std::map<std::string, std::string> &old_config)
+{
+ // Only bother doing anything if we didn't already have
+ // some new-style config.
+ if (module_config.config.empty()) {
+ // Upgrade luminous->mimic: migrate config-key configuration
+ // into main configuration store
+ for(auto &i : old_config) {
+ auto last_slash = i.first.rfind('/');
+ const std::string module_name = i.first.substr(4, i.first.substr(4).find('/'));
+ const std::string key = i.first.substr(last_slash + 1);
+ module_config.set_config(monc, module_name, key, i.second);
+ }
+ } else {
+ dout(10) << "Module configuration contains "
+ << module_config.config.size() << " keys" << dendl;
+ }
+}
+
PyModuleConfig module_config;
public:
- static std::string config_prefix;
-
void handle_config(const std::string &k, const std::string &v);
/**
void init();
+ void upgrade_config(
+ MonClient *monc,
+ const std::map<std::string, std::string> &old_config);
+
void active_start(
- PyModuleConfig &module_config,
- DaemonStateIndex &ds, ClusterState &cs, MonClient &mc,
- LogChannelRef clog_, Objecter &objecter_, Client &client_,
- Finisher &f);
- void standby_start(
- MonClient *monc);
+ DaemonStateIndex &ds, ClusterState &cs,
+ const std::map<std::string, std::string> &kv_store,
+ MonClient &mc, LogChannelRef clog_, Objecter &objecter_,
+ Client &client_, Finisher &f);
+ void standby_start();
bool is_standby_running() const
{
StandbyPyModules::StandbyPyModules(
- MonClient *monc_, const MgrMap &mgr_map_,
+ const MgrMap &mgr_map_,
PyModuleConfig &module_config, LogChannelRef clog_)
- : monc(monc_),
- state(module_config),
+ : state(module_config),
clog(clog_)
{
state.set_mgr_map(mgr_map_);
PyThreadState *tstate = PyEval_SaveThread();
PyEval_RestoreThread(tstate);
- const std::string global_key = PyModuleRegistry::config_prefix
+ const std::string global_key = PyModule::config_prefix
+ get_name() + "/" + key;
dout(4) << __func__ << " key: " << global_key << dendl;
mutable Mutex lock{"StandbyPyModules::lock"};
std::map<std::string, std::unique_ptr<StandbyPyModule>> modules;
- MonClient *monc;
-
StandbyPyModuleState state;
LogChannelRef clog;
public:
StandbyPyModules(
- MonClient *monc_,
const MgrMap &mgr_map_,
PyModuleConfig &module_config,
LogChannelRef clog_);