From: John Spray Date: Thu, 29 Jun 2017 10:13:44 +0000 (-0400) Subject: mon: load mgr commands dynamically X-Git-Tag: v12.1.2~196^2~8 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=54b693b06c635705066328083b5dd7f90daceda7;p=ceph.git mon: load mgr commands dynamically So that the list of commands includes python modules, thus allowing python-provided commands to be invoked by the CLI with out a `tell mgr` prefix. Signed-off-by: John Spray --- diff --git a/src/mon/MgrMonitor.cc b/src/mon/MgrMonitor.cc index b516083a0605..594cd4a8d4c7 100644 --- a/src/mon/MgrMonitor.cc +++ b/src/mon/MgrMonitor.cc @@ -35,6 +35,10 @@ static ostream& _prefix(std::ostream *_dout, Monitor *mon, } +// Prefix for mon store of active mgr's command descriptions +const static std::string command_descs_prefix = "mgr_command_descs"; + + void MgrMonitor::create_initial() { boost::tokenizer<> tok(g_conf->mgr_initial_modules); @@ -54,6 +58,9 @@ void MgrMonitor::update_from_paxos(bool *need_bootstrap) int err = get_version(version, bl); assert(err == 0); + bool old_available = map.get_available(); + uint64_t old_gid = map.get_active_gid(); + bufferlist::iterator p = bl.begin(); map.decode(p); @@ -71,6 +78,20 @@ void MgrMonitor::update_from_paxos(bool *need_bootstrap) } check_subs(); + + if (map.get_available() + && (!old_available || old_gid != map.get_active_gid())) + { + dout(4) << "daemon transitioned to available, loading commands" << dendl; + bufferlist loaded_commands; + int r = mon->store->get(command_descs_prefix, "", loaded_commands); + if (r < 0) { + derr << "Failed to load mgr commands: " << cpp_strerror(r) << dendl; + } else { + auto p = loaded_commands.begin(); + ::decode(command_descs, p); + } + } } // feed our pet MgrClient @@ -125,6 +146,15 @@ void MgrMonitor::encode_pending(MonitorDBStore::TransactionRef t) put_value(t, "ever_had_active_mgr", 1); } encode_health(next, t); + + if (pending_command_descs.size()) { + dout(4) << __func__ << " encoding " << pending_command_descs.size() + << " command_descs" << dendl; + bufferlist bl; + ::encode(pending_command_descs, bl); + t->put(command_descs_prefix, "", bl); + pending_command_descs.clear(); + } } bool MgrMonitor::check_caps(MonOpRequestRef op, const uuid_d& fsid) @@ -255,6 +285,21 @@ bool MgrMonitor::prepare_beacon(MonOpRequestRef op) dout(4) << "available " << m->get_gid() << dendl; mon->clog->info() << "Manager daemon " << pending_map.active_name << " is now available"; + + // This beacon should include command descriptions + pending_command_descs = m->get_command_descs(); + if (pending_command_descs.empty()) { + // This should not happen, but it also isn't fatal: we just + // won't successfully update our list of commands. + dout(4) << "First available beacon from " << pending_map.active_name + << "(" << m->get_gid() << ") does not include command descs" + << dendl; + } else { + dout(4) << "First available beacon from " << pending_map.active_name + << "(" << m->get_gid() << ") includes " + << pending_command_descs.size() << " command descs" << dendl; + } + pending_map.available = m->get_available(); updated = true; } diff --git a/src/mon/MgrMonitor.h b/src/mon/MgrMonitor.h index 0dc1af571dee..ed3e23e236b3 100644 --- a/src/mon/MgrMonitor.h +++ b/src/mon/MgrMonitor.h @@ -17,6 +17,7 @@ #include "include/Context.h" #include "MgrMap.h" #include "PaxosService.h" +#include "MonCommand.h" class MgrMonitor: public PaxosService { @@ -45,6 +46,10 @@ class MgrMonitor: public PaxosService health_status_t should_warn_about_mgr_down(); + // Command descriptions we've learned from the active mgr + std::vector command_descs; + std::vector pending_command_descs; + public: MgrMonitor(Monitor *mn, Paxos *p, const string& service_name) : PaxosService(mn, p, service_name) @@ -88,6 +93,10 @@ public: void print_summary(Formatter *f, std::ostream *ss) const; + const std::vector &get_command_descs() const { + return command_descs; + } + friend class C_Updated; }; diff --git a/src/mon/Monitor.cc b/src/mon/Monitor.cc index 9421b4cbf14f..29da4cd4c47d 100644 --- a/src/mon/Monitor.cc +++ b/src/mon/Monitor.cc @@ -112,17 +112,6 @@ MonCommand mon_commands[] = { #include #undef COMMAND #undef COMMAND_WITH_FLAG - - // FIXME: slurp up the Mgr commands too - -#define COMMAND(parsesig, helptext, modulename, req_perms, avail) \ - {parsesig, helptext, modulename, req_perms, avail, FLAG(MGR)}, -#define COMMAND_WITH_FLAG(parsesig, helptext, modulename, req_perms, avail, flags) \ - {parsesig, helptext, modulename, req_perms, avail, flags | FLAG(MGR)}, -#include -#undef COMMAND -#undef COMMAND_WITH_FLAG - }; @@ -2855,26 +2844,23 @@ bool Monitor::_allowed_command(MonSession *s, string &module, string &prefix, return capable; } -void Monitor::format_command_descriptions(const MonCommand *commands, - unsigned commands_size, +void Monitor::format_command_descriptions(const std::vector &commands, Formatter *f, bufferlist *rdata, bool hide_mgr_flag) { int cmdnum = 0; f->open_object_section("command_descriptions"); - for (const MonCommand *cp = commands; - cp < &commands[commands_size]; cp++) { - - unsigned flags = cp->flags; + for (const auto &cmd : commands) { + unsigned flags = cmd.flags; if (hide_mgr_flag) { flags &= ~MonCommand::FLAG_MGR; } ostringstream secname; secname << "cmd" << setfill('0') << std::setw(3) << cmdnum; dump_cmddesc_to_json(f, secname.str(), - cp->cmdstring, cp->helpstring, cp->module, - cp->req_perms, cp->availability, flags); + cmd.cmdstring, cmd.helpstring, cmd.module, + cmd.req_perms, cmd.availability, flags); cmdnum++; } f->close_section(); // command_descriptions @@ -2985,9 +2971,16 @@ void Monitor::handle_command(MonOpRequestRef op) // hide mgr commands until luminous upgrade is complete bool hide_mgr_flag = osdmon()->osdmap.require_osd_release < CEPH_RELEASE_LUMINOUS; - format_command_descriptions(leader_supported_mon_commands, - leader_supported_mon_commands_size, f, &rdata, - hide_mgr_flag); + + std::vector commands; + commands = static_cast( + paxos_service[PAXOS_MGR])->get_command_descs(); + + for (int i = 0 ; i < leader_supported_mon_commands_size; ++i) { + commands.push_back(leader_supported_mon_commands[i]); + } + + format_command_descriptions(commands, f, &rdata, hide_mgr_flag); delete f; reply_command(op, 0, "", rdata, 0); return; diff --git a/src/mon/Monitor.h b/src/mon/Monitor.h index fa7f9e9acdd3..7bed317ddf01 100644 --- a/src/mon/Monitor.h +++ b/src/mon/Monitor.h @@ -38,6 +38,7 @@ #include "Paxos.h" #include "Session.h" #include "PGStatService.h" +#include "MonCommand.h" #include "common/LogClient.h" #include "auth/cephx/CephxKeyServer.h" @@ -113,7 +114,6 @@ struct MRoute; struct MForward; struct MTimeCheck; struct MMonHealth; -struct MonCommand; #define COMPAT_SET_LOC "feature_set" @@ -960,8 +960,7 @@ private: Monitor& operator=(const Monitor &rhs); public: - static void format_command_descriptions(const MonCommand *commands, - unsigned commands_size, + static void format_command_descriptions(const std::vector &commands, Formatter *f, bufferlist *rdata, bool hide_mgr_flag=false); @@ -981,97 +980,6 @@ public: #define CEPH_MON_FEATURE_INCOMPAT_KRAKEN CompatSet::Feature(8, "support monmap features") // make sure you add your feature to Monitor::get_supported_features -struct MonCommand { - string cmdstring; - string helpstring; - string module; - string req_perms; - string availability; - uint64_t flags; - - // MonCommand flags - static const uint64_t FLAG_NONE = 0; - static const uint64_t FLAG_NOFORWARD = 1 << 0; - static const uint64_t FLAG_OBSOLETE = 1 << 1; - static const uint64_t FLAG_DEPRECATED = 1 << 2; - static const uint64_t FLAG_MGR = 1 << 3; - - bool has_flag(uint64_t flag) const { return (flags & flag) != 0; } - void set_flag(uint64_t flag) { flags |= flag; } - void unset_flag(uint64_t flag) { flags &= ~flag; } - - void encode(bufferlist &bl) const { - /* - * very naughty: deliberately unversioned because individual commands - * shouldn't be encoded standalone, only as a full set (which we do - * version, see encode_array() below). - */ - ::encode(cmdstring, bl); - ::encode(helpstring, bl); - ::encode(module, bl); - ::encode(req_perms, bl); - ::encode(availability, bl); - } - void decode(bufferlist::iterator &bl) { - ::decode(cmdstring, bl); - ::decode(helpstring, bl); - ::decode(module, bl); - ::decode(req_perms, bl); - ::decode(availability, bl); - } - bool is_compat(const MonCommand* o) const { - return cmdstring == o->cmdstring && - module == o->module && req_perms == o->req_perms && - availability == o->availability; - } - - bool is_noforward() const { - return has_flag(MonCommand::FLAG_NOFORWARD); - } - - bool is_obsolete() const { - return has_flag(MonCommand::FLAG_OBSOLETE); - } - - bool is_deprecated() const { - return has_flag(MonCommand::FLAG_DEPRECATED); - } - bool is_mgr() const { - return has_flag(MonCommand::FLAG_MGR); - } - - static void encode_array(const MonCommand *cmds, int size, bufferlist &bl) { - ENCODE_START(2, 1, bl); - uint16_t s = size; - ::encode(s, bl); - ::encode_array_nohead(cmds, size, bl); - for (int i = 0; i < size; i++) - ::encode(cmds[i].flags, bl); - ENCODE_FINISH(bl); - } - static void decode_array(MonCommand **cmds, int *size, - bufferlist::iterator &bl) { - DECODE_START(2, bl); - uint16_t s = 0; - ::decode(s, bl); - *size = s; - *cmds = new MonCommand[*size]; - ::decode_array_nohead(*cmds, *size, bl); - if (struct_v >= 2) { - for (int i = 0; i < *size; i++) - ::decode((*cmds)[i].flags, bl); - } else { - for (int i = 0; i < *size; i++) - (*cmds)[i].flags = 0; - } - DECODE_FINISH(bl); - } - - bool requires_perm(char p) const { - return (req_perms.find(p) != string::npos); - } -}; -WRITE_CLASS_ENCODER(MonCommand) #endif diff --git a/src/test/common/get_command_descriptions.cc b/src/test/common/get_command_descriptions.cc index 236122ae7986..93a8e842d3bf 100644 --- a/src/test/common/get_command_descriptions.cc +++ b/src/test/common/get_command_descriptions.cc @@ -41,11 +41,11 @@ static void usage(ostream &out) out << " get_command_descriptions --pull585\n"; } -static void json_print(const MonCommand *mon_commands, int size) +static void json_print(const std::vector &mon_commands) { bufferlist rdata; Formatter *f = Formatter::create("json"); - Monitor::format_command_descriptions(mon_commands, size, f, &rdata); + Monitor::format_command_descriptions(mon_commands, f, &rdata); delete f; string data(rdata.c_str(), rdata.length()); cout << data << std::endl; @@ -56,7 +56,7 @@ static void all() #undef FLAG #undef COMMAND #undef COMMAND_WITH_FLAG - MonCommand mon_commands[] = { + std::vector mon_commands = { #define FLAG(f) (MonCommand::FLAG_##f) #define COMMAND(parsesig, helptext, modulename, req_perms, avail) \ {parsesig, helptext, modulename, req_perms, avail, 0}, @@ -66,8 +66,6 @@ static void all() #undef COMMAND #undef COMMAND_WITH_FLAG - // FIXME: slurp up the Mgr commands too - #define COMMAND(parsesig, helptext, modulename, req_perms, avail) \ {parsesig, helptext, modulename, req_perms, avail, FLAG(MGR)}, #define COMMAND_WITH_FLAG(parsesig, helptext, modulename, req_perms, avail, flags) \ @@ -77,13 +75,13 @@ static void all() #undef COMMAND_WITH_FLAG }; - json_print(mon_commands, ARRAY_SIZE(mon_commands)); + json_print(mon_commands); } // syntax error https://github.com/ceph/ceph/pull/585 static void pull585() { - MonCommand mon_commands[] = { + std::vector mon_commands = { { "osd pool create " "name=pool,type=CephPoolname " "name=pg_num,type=CephInt,range=0 " @@ -92,7 +90,7 @@ static void pull585() "create pool", "osd", "rw", "cli,rest" } }; - json_print(mon_commands, ARRAY_SIZE(mon_commands)); + json_print(mon_commands); } int main(int argc, char **argv) {