Require --force to enable a module that isn't reported as available.
Signed-off-by: Sage Weil <sage@redhat.com>
ceph mgr dump
ceph mgr module ls
- ceph mgr module enable foo
- ceph mgr module disable foo
+ ceph mgr module enable restful
+ expect_false ceph mgr module enable foodne
+ ceph mgr module enable foodne --force
+ ceph mgr module disable foodne
+ ceph mgr module disable foodnebizbangbash
ceph mon metadata a
ceph mon metadata
class MMgrBeacon : public PaxosServiceMessage {
- static const int HEAD_VERSION = 2;
+ static const int HEAD_VERSION = 3;
static const int COMPAT_VERSION = 1;
protected:
bool available;
std::string name;
uuid_d fsid;
+ std::set<std::string> available_modules;
public:
MMgrBeacon()
}
MMgrBeacon(const uuid_d& fsid_, uint64_t gid_, const std::string &name_,
- entity_addr_t server_addr_, bool available_)
+ entity_addr_t server_addr_, bool available_,
+ const std::set<std::string>& module_list)
: PaxosServiceMessage(MSG_MGR_BEACON, 0, HEAD_VERSION, COMPAT_VERSION),
gid(gid_), server_addr(server_addr_), available(available_), name(name_),
- fsid(fsid_)
+ fsid(fsid_), available_modules(module_list)
{
}
bool get_available() const { return available; }
const std::string& get_name() const { return name; }
const uuid_d& get_fsid() const { return fsid; }
+ std::set<std::string>& get_available_modules() { return available_modules; }
private:
~MMgrBeacon() override {}
void print(ostream& out) const override {
out << get_type_name() << " mgr." << name << "(" << fsid << ","
- << gid << ", " << server_addr << ", " << available << ")";
+ << gid << ", " << server_addr << ", " << available
+ << ")";
}
void encode_payload(uint64_t features) override {
::encode(available, payload);
::encode(name, payload);
::encode(fsid, payload);
+ ::encode(available_modules, payload);
}
void decode_payload() override {
bufferlist::iterator p = payload.begin();
if (header.version >= 2) {
::decode(fsid, p);
}
+ if (header.version >= 3) {
+ ::decode(available_modules, p);
+ }
}
};
{
assert(lock.is_locked_by_me());
dout(1) << state_str() << dendl;
- dout(10) << "sending beacon as gid " << monc.get_global_id() << dendl;
+ set<string> modules;
+ PyModules::list_modules(&modules);
bool available = active_mgr != nullptr && active_mgr->is_initialized();
auto addr = available ? active_mgr->get_server_addr() : entity_addr_t();
+ dout(10) << "sending beacon as gid " << monc.get_global_id()
+ << " modules " << modules << dendl;
+
MMgrBeacon *m = new MMgrBeacon(monc.get_fsid(),
monc.get_global_id(),
g_conf->name.get_id(),
addr,
- available);
-
+ available,
+ modules);
monc.send_mon_message(m);
}
return capsule;
}
+static void _list_modules(
+ const std::string path,
+ std::set<std::string> *modules)
+{
+ DIR *dir = opendir(path.c_str());
+ if (!dir) {
+ return;
+ }
+ struct dirent *entry = NULL;
+ while ((entry = readdir(dir)) != NULL) {
+ string n(entry->d_name);
+ string fn = path + "/" + n;
+ struct stat st;
+ int r = ::stat(fn.c_str(), &st);
+ if (r == 0 && S_ISDIR(st.st_mode)) {
+ string initfn = fn + "/module.py";
+ r = ::stat(initfn.c_str(), &st);
+ if (r == 0) {
+ modules->insert(n);
+ }
+ }
+ }
+ closedir(dir);
+}
+
+void PyModules::list_modules(std::set<std::string> *modules)
+{
+ _list_modules(g_conf->mgr_module_path, modules);
+}
void log(const std::string &handle,
int level, const std::string &record);
+
+ static void list_modules(std::set<std::string> *modules);
};
#endif
public:
uint64_t gid;
std::string name;
+ std::set<std::string> available_modules;
- StandbyInfo(uint64_t gid_, const std::string &name_)
- : gid(gid_), name(name_)
+ StandbyInfo(uint64_t gid_, const std::string &name_,
+ std::set<std::string>& am)
+ : gid(gid_), name(name_), available_modules(am)
{}
StandbyInfo()
void encode(bufferlist& bl) const
{
- ENCODE_START(1, 1, bl);
+ ENCODE_START(2, 1, bl);
::encode(gid, bl);
::encode(name, bl);
+ ::encode(available_modules, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::iterator& p)
{
- DECODE_START(1, p);
+ DECODE_START(2, p);
::decode(gid, p);
::decode(name, p);
+ if (struct_v >= 2) {
+ ::decode(available_modules, p);
+ }
DECODE_FINISH(p);
}
};
std::map<uint64_t, StandbyInfo> standbys;
std::set<std::string> modules;
+ std::set<std::string> available_modules;
epoch_t get_epoch() const { return epoch; }
entity_addr_t get_active_addr() const { return active_addr; }
bool get_available() const { return available; }
const std::string &get_active_name() const { return active_name; }
+ bool all_support_module(const std::string& module) {
+ if (!available_modules.count(module)) {
+ return false;
+ }
+ for (auto& p : standbys) {
+ if (!p.second.available_modules.count(module)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
void encode(bufferlist& bl, uint64_t features) const
{
ENCODE_START(2, 1, bl);
::encode(active_name, bl);
::encode(standbys, bl);
::encode(modules, bl);
+ ::encode(available_modules, bl);
ENCODE_FINISH(bl);
}
::decode(standbys, p);
if (struct_v >= 2) {
::decode(modules, p);
+ ::decode(available_modules, p);
}
DECODE_FINISH(p);
}
f->open_object_section("standby");
f->dump_int("gid", i.second.gid);
f->dump_string("name", i.second.name);
+ f->open_array_section("available_modules");
+ for (auto& j : i.second.available_modules) {
+ f->dump_string("module", j);
+ }
+ f->close_section();
f->close_section();
}
f->close_section();
f->dump_string("module", i);
}
f->close_section();
+ f->open_array_section("available_modules");
+ for (auto& j : available_modules) {
+ f->dump_string("module", j);
+ }
+ f->close_section();
}
static void generate_test_instances(list<MgrMap*> &l) {
pending_map.available = m->get_available();
updated = true;
}
+ if (pending_map.available_modules != m->get_available_modules()) {
+ dout(4) << "available_modules " << m->get_available_modules()
+ << " (was " << pending_map.available_modules << ")" << dendl;
+ pending_map.available_modules = m->get_available_modules();
+ updated = true;
+ }
} else if (pending_map.active_gid == 0) {
// There is no currently active daemon, select this one.
if (pending_map.standbys.count(m->get_gid())) {
<< pending_map.active_name << ")" << dendl;
pending_map.active_gid = m->get_gid();
pending_map.active_name = m->get_name();
+ pending_map.available_modules = m->get_available_modules();
updated = true;
} else {
if (pending_map.standbys.count(m->get_gid()) > 0) {
dout(10) << "from existing standby " << m->get_gid() << dendl;
+ if (pending_map.standbys[m->get_gid()].available_modules !=
+ m->get_available_modules()) {
+ dout(10) << "existing standby " << m->get_gid() << " available_modules "
+ << m->get_available_modules() << " (was "
+ << pending_map.standbys[m->get_gid()].available_modules << ")"
+ << dendl;
+ pending_map.standbys[m->get_gid()].available_modules =
+ m->get_available_modules();
+ updated = true;
+ }
} else {
dout(10) << "new standby " << m->get_gid() << dendl;
- pending_map.standbys[m->get_gid()] = {m->get_gid(), m->get_name()};
+ pending_map.standbys[m->get_gid()] = {m->get_gid(), m->get_name(),
+ m->get_available_modules()};
updated = true;
}
}
r = -EINVAL;
goto out;
}
+ string force;
+ cmd_getval(g_ceph_context, cmdmap, "force", force);
+ if (!pending_map.all_support_module(module) &&
+ force != "--force") {
+ ss << "all mgr daemons do not support module '" << module << "', pass "
+ << "--force to force enablement";
+ r = -ENOENT;
+ goto out;
+ }
pending_map.modules.insert(module);
} else if (prefix == "mgr module disable") {
string module;
"treat the named manager daemon as failed", "mgr", "rw", "cli,rest")
COMMAND("mgr module ls",
"list active mgr modules", "mgr", "r", "cli,rest")
-COMMAND("mgr module enable " \
- "name=module,type=CephString",
+COMMAND("mgr module enable " \
+ "name=module,type=CephString " \
+ "name=force,type=CephChoices,strings=--force,req=false",
"enable mgr module", "mgr", "rw", "cli,rest")
-COMMAND("mgr module disable " \
+COMMAND("mgr module disable " \
"name=module,type=CephString",
- "enable mgr module", "mgr", "rw", "cli,rest")
+ "disable mgr module", "mgr", "rw", "cli,rest")