From 2350d2aded7101cf8ba60af0de7cbf0df8ef964b Mon Sep 17 00:00:00 2001 From: John Spray Date: Wed, 28 Jun 2017 09:27:07 -0400 Subject: [PATCH 01/12] encoding: remove encode_array_nohead This was just a for loop. No longer needed for MonCommands, and the usage in memstore/PageSet was just iterating over char* and should never have been there to begin with. Signed-off-by: John Spray --- src/include/encoding.h | 16 ---------------- src/os/memstore/PageSet.h | 2 +- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/src/include/encoding.h b/src/include/encoding.h index 0013728efed..f7ee5d11828 100644 --- a/src/include/encoding.h +++ b/src/include/encoding.h @@ -197,22 +197,6 @@ inline void encode(const char *s, bufferlist& bl) } -// array -template -inline void encode_array_nohead(const A a[], int n, bufferlist &bl) -{ - for (int i=0; i -inline void decode_array_nohead(A a[], int n, bufferlist::iterator &p) -{ - for (int i=0; i Date: Wed, 28 Jun 2017 09:47:37 -0400 Subject: [PATCH 02/12] mgr: use MonCommand for command descriptions ...and update the MonCommand encoding so that we can readily send vectors of them around. Signed-off-by: John Spray --- src/mgr/DaemonServer.cc | 92 +++++++++++++++-------------- src/mgr/DaemonServer.h | 8 +-- src/mon/MonCommand.h | 124 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 51 deletions(-) create mode 100644 src/mon/MonCommand.h diff --git a/src/mgr/DaemonServer.cc b/src/mgr/DaemonServer.cc index 6454c8da306..3b25ef49010 100644 --- a/src/mgr/DaemonServer.cc +++ b/src/mgr/DaemonServer.cc @@ -17,6 +17,8 @@ #include "auth/RotatingKeyRing.h" #include "json_spirit/json_spirit_writer.h" +#include "mon/MonCommand.h" + #include "messages/MMgrOpen.h" #include "messages/MMgrConfigure.h" #include "messages/MMonMgrReport.h" @@ -402,21 +404,9 @@ bool DaemonServer::handle_report(MMgrReport *m) return true; } -struct MgrCommand { - string cmdstring; - string helpstring; - string module; - string perm; - string availability; - - bool requires_perm(char p) const { - return (perm.find(p) != string::npos); - } - -} mgr_commands[] = { - +std::vector mgr_commands = { #define COMMAND(parsesig, helptext, module, perm, availability) \ - {parsesig, helptext, module, perm, availability}, + {parsesig, helptext, module, perm, availability, 0}, #include "MgrCommands.h" #undef COMMAND }; @@ -444,16 +434,14 @@ void DaemonServer::_generate_command_map( } } -const MgrCommand *DaemonServer::_get_mgrcommand( +const MonCommand *DaemonServer::_get_mgrcommand( const string &cmd_prefix, - MgrCommand *cmds, - int cmds_size) + const std::vector &cmds) { - MgrCommand *this_cmd = NULL; - for (MgrCommand *cp = cmds; - cp < &cmds[cmds_size]; cp++) { - if (cp->cmdstring.compare(0, cmd_prefix.size(), cmd_prefix) == 0) { - this_cmd = cp; + const MonCommand *this_cmd = nullptr; + for (const auto &cmd : cmds) { + if (cmd.cmdstring.compare(0, cmd_prefix.size(), cmd_prefix) == 0) { + this_cmd = &cmd; break; } } @@ -466,7 +454,7 @@ bool DaemonServer::_allowed_command( const string &prefix, const map& cmdmap, const map& param_str_map, - const MgrCommand *this_cmd) { + const MonCommand *this_cmd) { if (s->entity_name.is_mon()) { // mon is all-powerful. even when it is forwarding commands on behalf of @@ -593,42 +581,52 @@ bool DaemonServer::handle_command(MCommand *m) dout(4) << "prefix=" << prefix << dendl; if (prefix == "get_command_descriptions") { - int cmdnum = 0; - dout(10) << "reading commands from python modules" << dendl; auto py_commands = py_modules.get_commands(); - JSONFormatter f; - f.open_object_section("command_descriptions"); - for (const auto &pyc : py_commands) { - ostringstream secname; - secname << "cmd" << setfill('0') << std::setw(3) << cmdnum; - dout(20) << "Dumping " << pyc.cmdstring << " (" << pyc.helpstring - << ")" << dendl; - dump_cmddesc_to_json(&f, secname.str(), pyc.cmdstring, pyc.helpstring, - "mgr", pyc.perm, "cli", 0); - cmdnum++; - } + bool binary = false; + cmd_getval(g_ceph_context, cmdctx->cmdmap, "binary", binary); + if (binary) { + std::vector commands = mgr_commands; + for (const auto &pyc : py_commands) { + commands.push_back({pyc.cmdstring, pyc.helpstring, "mgr", + pyc.perm, "cli", MonCommand::FLAG_MGR}); + } + ::encode(commands, cmdctx->odata); + } else { + int cmdnum = 0; - for (const auto &cp : mgr_commands) { - ostringstream secname; - secname << "cmd" << setfill('0') << std::setw(3) << cmdnum; - dump_cmddesc_to_json(&f, secname.str(), cp.cmdstring, cp.helpstring, - cp.module, cp.perm, cp.availability, 0); - cmdnum++; + JSONFormatter f; + f.open_object_section("command_descriptions"); + for (const auto &pyc : py_commands) { + ostringstream secname; + secname << "cmd" << setfill('0') << std::setw(3) << cmdnum; + dout(20) << "Dumping " << pyc.cmdstring << " (" << pyc.helpstring + << ")" << dendl; + dump_cmddesc_to_json(&f, secname.str(), pyc.cmdstring, pyc.helpstring, + "mgr", pyc.perm, "cli", 0); + cmdnum++; + } + + for (const auto &cp : mgr_commands) { + 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, 0); + cmdnum++; + } + f.close_section(); // command_descriptions + f.flush(cmdctx->odata); } - f.close_section(); // command_descriptions - f.flush(cmdctx->odata); cmdctx->reply(0, ss); return true; } // lookup command - const MgrCommand *mgr_cmd = _get_mgrcommand(prefix, mgr_commands, - ARRAY_SIZE(mgr_commands)); + const MonCommand *mgr_cmd = _get_mgrcommand(prefix, mgr_commands); _generate_command_map(cmdctx->cmdmap, param_str_map); if (!mgr_cmd) { - MgrCommand py_command = {"", "", "py", "rw", "cli"}; + MonCommand py_command = {"", "", "py", "rw", "cli"}; if (!_allowed_command(session.get(), py_command.module, prefix, cmdctx->cmdmap, param_str_map, &py_command)) { dout(1) << " access denied" << dendl; diff --git a/src/mgr/DaemonServer.h b/src/mgr/DaemonServer.h index 4877cfe85ae..6e448320215 100644 --- a/src/mgr/DaemonServer.h +++ b/src/mgr/DaemonServer.h @@ -35,7 +35,7 @@ class MMgrReport; class MMgrOpen; class MMonMgrReport; class MCommand; -struct MgrCommand; +struct MonCommand; /** @@ -74,13 +74,13 @@ protected: static void _generate_command_map(map& cmdmap, map ¶m_str_map); - static const MgrCommand *_get_mgrcommand(const string &cmd_prefix, - MgrCommand *cmds, int cmds_size); + static const MonCommand *_get_mgrcommand(const string &cmd_prefix, + const std::vector &commands); bool _allowed_command( MgrSession *s, const string &module, const string &prefix, const map& cmdmap, const map& param_str_map, - const MgrCommand *this_cmd); + const MonCommand *this_cmd); private: friend class ReplyOnFinish; diff --git a/src/mon/MonCommand.h b/src/mon/MonCommand.h new file mode 100644 index 00000000000..94716d6c9e9 --- /dev/null +++ b/src/mon/MonCommand.h @@ -0,0 +1,124 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2017 John Spray + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + */ + +#pragma once + +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 { + ENCODE_START(1, 1, bl); + encode_bare(bl); + ::encode(flags, bl); + ENCODE_FINISH(bl); + } + + void decode(bufferlist::iterator &bl) { + DECODE_START(1, bl); + decode_bare(bl); + ::decode(flags, bl); + DECODE_FINISH(bl); + } + + /** + * Unversioned encoding for use within encode_array. + */ + void encode_bare(bufferlist &bl) const { + ::encode(cmdstring, bl); + ::encode(helpstring, bl); + ::encode(module, bl); + ::encode(req_perms, bl); + ::encode(availability, bl); + } + void decode_bare(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); + for (int i = 0; i < size; ++i) { + cmds[i].encode_bare(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]; + for (int i = 0; i < *size; ++i) { + (*cmds)[i].decode_bare(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) From 5c3846306b6bf7864327265bbac9607295f46cfc Mon Sep 17 00:00:00 2001 From: John Spray Date: Thu, 29 Jun 2017 15:11:12 -0400 Subject: [PATCH 03/12] mgr: transmit command descriptions to mgr in activating beacon The mgr already sends a beacon to the mon immediately after loading python modules in Mgr::init, to indicate that it is now available. Use that beacon to transmit the command descriptions. The monitor should handle this beacon by persisting the command descriptions before persisting the updated mgrmap that indicates that the mgr is now active. Signed-off-by: John Spray --- src/messages/MMgrBeacon.h | 20 ++++++++++- src/mgr/DaemonServer.cc | 72 ++++++++++++++++++--------------------- src/mgr/DaemonServer.h | 2 ++ src/mgr/Mgr.cc | 11 ++++++ src/mgr/Mgr.h | 4 ++- src/mgr/MgrStandby.cc | 24 +++++++++++-- src/mgr/MgrStandby.h | 2 ++ src/mgr/PyModules.cc | 15 ++++++-- src/mgr/PyModules.h | 7 +++- 9 files changed, 111 insertions(+), 46 deletions(-) diff --git a/src/messages/MMgrBeacon.h b/src/messages/MMgrBeacon.h index ab55a9642a2..c2ccee1fc4d 100644 --- a/src/messages/MMgrBeacon.h +++ b/src/messages/MMgrBeacon.h @@ -16,13 +16,14 @@ #define CEPH_MMGRBEACON_H #include "messages/PaxosServiceMessage.h" +#include "mon/MonCommand.h" #include "include/types.h" class MMgrBeacon : public PaxosServiceMessage { - static const int HEAD_VERSION = 3; + static const int HEAD_VERSION = 4; static const int COMPAT_VERSION = 1; protected: @@ -33,6 +34,9 @@ protected: uuid_d fsid; std::set available_modules; + // Only populated during activation + std::vector command_descs; + public: MMgrBeacon() : PaxosServiceMessage(MSG_MGR_BEACON, 0, HEAD_VERSION, COMPAT_VERSION), @@ -56,6 +60,16 @@ public: const uuid_d& get_fsid() const { return fsid; } std::set& get_available_modules() { return available_modules; } + void set_command_descs(const std::vector &cmds) + { + command_descs = cmds; + } + + const std::vector &get_command_descs() + { + return command_descs; + } + private: ~MMgrBeacon() override {} @@ -77,6 +91,7 @@ public: ::encode(name, payload); ::encode(fsid, payload); ::encode(available_modules, payload); + ::encode(command_descs, payload); } void decode_payload() override { bufferlist::iterator p = payload.begin(); @@ -91,6 +106,9 @@ public: if (header.version >= 3) { ::decode(available_modules, p); } + if (header.version >= 4) { + ::decode(command_descs, p); + } } }; diff --git a/src/mgr/DaemonServer.cc b/src/mgr/DaemonServer.cc index 3b25ef49010..e54fd5a6255 100644 --- a/src/mgr/DaemonServer.cc +++ b/src/mgr/DaemonServer.cc @@ -33,6 +33,18 @@ #undef dout_prefix #define dout_prefix *_dout << "mgr.server " << __func__ << " " + +/* The set of statically defined (C++-handled) commands. This + * does not include the Python-defined commands, which are loaded + * in PyModules */ +const std::vector DaemonServer::mgr_commands = { +#define COMMAND(parsesig, helptext, module, perm, availability) \ + {parsesig, helptext, module, perm, availability, 0}, +#include "MgrCommands.h" +#undef COMMAND +}; + + DaemonServer::DaemonServer(MonClient *monc_, Finisher &finisher_, DaemonStateIndex &daemon_state_, @@ -404,12 +416,6 @@ bool DaemonServer::handle_report(MMgrReport *m) return true; } -std::vector mgr_commands = { -#define COMMAND(parsesig, helptext, module, perm, availability) \ - {parsesig, helptext, module, perm, availability, 0}, -#include "MgrCommands.h" -#undef COMMAND -}; void DaemonServer::_generate_command_map( map& cmdmap, @@ -582,42 +588,30 @@ bool DaemonServer::handle_command(MCommand *m) if (prefix == "get_command_descriptions") { dout(10) << "reading commands from python modules" << dendl; - auto py_commands = py_modules.get_commands(); + const auto py_commands = py_modules.get_commands(); - bool binary = false; - cmd_getval(g_ceph_context, cmdctx->cmdmap, "binary", binary); - if (binary) { - std::vector commands = mgr_commands; - for (const auto &pyc : py_commands) { - commands.push_back({pyc.cmdstring, pyc.helpstring, "mgr", - pyc.perm, "cli", MonCommand::FLAG_MGR}); - } - ::encode(commands, cmdctx->odata); - } else { - int cmdnum = 0; + int cmdnum = 0; + JSONFormatter f; + f.open_object_section("command_descriptions"); - JSONFormatter f; - f.open_object_section("command_descriptions"); - for (const auto &pyc : py_commands) { - ostringstream secname; - secname << "cmd" << setfill('0') << std::setw(3) << cmdnum; - dout(20) << "Dumping " << pyc.cmdstring << " (" << pyc.helpstring - << ")" << dendl; - dump_cmddesc_to_json(&f, secname.str(), pyc.cmdstring, pyc.helpstring, - "mgr", pyc.perm, "cli", 0); - cmdnum++; - } + auto dump_cmd = [&cmdnum, &f](const MonCommand &mc){ + ostringstream secname; + secname << "cmd" << setfill('0') << std::setw(3) << cmdnum; + dump_cmddesc_to_json(&f, secname.str(), mc.cmdstring, mc.helpstring, + mc.module, mc.req_perms, mc.availability, 0); + cmdnum++; + }; - for (const auto &cp : mgr_commands) { - 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, 0); - cmdnum++; - } - f.close_section(); // command_descriptions - f.flush(cmdctx->odata); + for (const auto &pyc : py_commands) { + dump_cmd(pyc); } + + for (const auto &mgr_cmd : mgr_commands) { + dump_cmd(mgr_cmd); + } + + f.close_section(); // command_descriptions + f.flush(cmdctx->odata); cmdctx->reply(0, ss); return true; } @@ -935,7 +929,7 @@ bool DaemonServer::handle_command(MCommand *m) // None of the special native commands, MgrPyModule *handler = nullptr; - auto py_commands = py_modules.get_commands(); + auto py_commands = py_modules.get_py_commands(); for (const auto &pyc : py_commands) { auto pyc_prefix = cmddesc_get_prefix(pyc.cmdstring); dout(1) << "pyc_prefix: '" << pyc_prefix << "'" << dendl; diff --git a/src/mgr/DaemonServer.h b/src/mgr/DaemonServer.h index 6e448320215..1c5825502a2 100644 --- a/src/mgr/DaemonServer.h +++ b/src/mgr/DaemonServer.h @@ -95,6 +95,8 @@ private: void maybe_ready(int32_t osd_id); public: + static const std::vector mgr_commands; + int init(uint64_t gid, entity_addr_t client_addr); void shutdown(); diff --git a/src/mgr/Mgr.cc b/src/mgr/Mgr.cc index 68126e9430e..e46b2cabd63 100644 --- a/src/mgr/Mgr.cc +++ b/src/mgr/Mgr.cc @@ -632,3 +632,14 @@ void Mgr::tick() dout(10) << dendl; server.send_report(); } + +std::vector Mgr::get_command_set() const +{ + Mutex::Locker l(lock); + + std::vector commands = DaemonServer::mgr_commands; + std::vector py_commands = py_modules.get_commands(); + commands.insert(commands.end(), py_commands.begin(), py_commands.end()); + return commands; +} + diff --git a/src/mgr/Mgr.h b/src/mgr/Mgr.h index ccf22da9e7c..68f2b40b461 100644 --- a/src/mgr/Mgr.h +++ b/src/mgr/Mgr.h @@ -53,7 +53,7 @@ protected: Client *client; Messenger *client_messenger; - Mutex lock; + mutable Mutex lock; SafeTimer timer; Finisher finisher; @@ -98,6 +98,8 @@ public: void background_init(Context *completion); void shutdown(); + + std::vector get_command_set() const; }; #endif diff --git a/src/mgr/MgrStandby.cc b/src/mgr/MgrStandby.cc index 5e82de97f4c..6f83fc13f32 100644 --- a/src/mgr/MgrStandby.cc +++ b/src/mgr/MgrStandby.cc @@ -48,7 +48,8 @@ MgrStandby::MgrStandby(int argc, const char **argv) : timer(g_ceph_context, lock), active_mgr(nullptr), orig_argc(argc), - orig_argv(argv) + orig_argv(argv), + available_in_map(false) { } @@ -151,7 +152,11 @@ void MgrStandby::send_beacon() set modules; PyModules::list_modules(&modules); + + // Whether I think I am available (request MgrMonitor to set me + // as available in the map) 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; @@ -162,6 +167,16 @@ void MgrStandby::send_beacon() addr, available, modules); + + if (available && !available_in_map) { + // We are informing the mon that we are done initializing: inform + // it of our command set. This has to happen after init() because + // it needs the python modules to have loaded. + m->set_command_descs(active_mgr->get_command_set()); + dout(4) << "going active, including " << m->get_command_descs().size() + << " commands in beacon" << dendl; + } + monc.send_mon_message(m); } @@ -278,7 +293,7 @@ void MgrStandby::_update_log_config() void MgrStandby::handle_mgr_map(MMgrMap* mmap) { - auto map = mmap->get_map(); + auto &map = mmap->get_map(); dout(4) << "received map epoch " << map.get_epoch() << dendl; const bool active_in_map = map.active_gid == monc.get_global_id(); dout(4) << "active in map: " << active_in_map @@ -303,6 +318,11 @@ void MgrStandby::handle_mgr_map(MMgrMap* mmap) respawn(); } } + + if (!available_in_map && map.get_available()) { + dout(4) << "Map now says I am available" << dendl; + available_in_map = true; + } } else { if (active_mgr != nullptr) { derr << "I was active but no longer am" << dendl; diff --git a/src/mgr/MgrStandby.h b/src/mgr/MgrStandby.h index 2e2bc6b5f0a..e24f175cada 100644 --- a/src/mgr/MgrStandby.h +++ b/src/mgr/MgrStandby.h @@ -59,6 +59,8 @@ protected: void _update_log_config(); void send_beacon(); + bool available_in_map; + public: MgrStandby(int argc, const char **argv); ~MgrStandby() override; diff --git a/src/mgr/PyModules.cc b/src/mgr/PyModules.cc index 8412e6cbf5f..7860a88903f 100644 --- a/src/mgr/PyModules.cc +++ b/src/mgr/PyModules.cc @@ -608,12 +608,12 @@ void PyModules::set_config(const std::string &handle, } } -std::vector PyModules::get_commands() +std::vector PyModules::get_py_commands() const { Mutex::Locker l(lock); std::vector result; - for (auto& i : modules) { + for (const auto& i : modules) { auto module = i.second.get(); auto mod_commands = module->get_commands(); for (auto j : mod_commands) { @@ -624,6 +624,17 @@ std::vector PyModules::get_commands() return result; } +std::vector PyModules::get_commands() const +{ + std::vector commands = get_py_commands(); + std::vector result; + for (auto &pyc: commands) { + result.push_back({pyc.cmdstring, pyc.helpstring, "mgr", + pyc.perm, "cli", MonCommand::FLAG_MGR}); + } + return result; +} + void PyModules::insert_config(const std::map &new_config) { diff --git a/src/mgr/PyModules.h b/src/mgr/PyModules.h index 467555b51a1..9d9b8e1ec6c 100644 --- a/src/mgr/PyModules.h +++ b/src/mgr/PyModules.h @@ -24,6 +24,7 @@ #include "client/Client.h" #include "common/LogClient.h" #include "mon/MgrMap.h" +#include "mon/MonCommand.h" #include "DaemonState.h" #include "ClusterState.h" @@ -80,7 +81,11 @@ public: std::map config_cache; - std::vector get_commands(); + // Python command definitions, including callback + std::vector get_py_commands() const; + + // Monitor command definitions, suitable for CLI + std::vector get_commands() const; void insert_config(const std::map &new_config); From 54b693b06c635705066328083b5dd7f90daceda7 Mon Sep 17 00:00:00 2001 From: John Spray Date: Thu, 29 Jun 2017 06:13:44 -0400 Subject: [PATCH 04/12] 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 --- src/mon/MgrMonitor.cc | 45 ++++++++++ src/mon/MgrMonitor.h | 9 ++ src/mon/Monitor.cc | 37 ++++---- src/mon/Monitor.h | 96 +-------------------- src/test/common/get_command_descriptions.cc | 14 ++- 5 files changed, 77 insertions(+), 124 deletions(-) diff --git a/src/mon/MgrMonitor.cc b/src/mon/MgrMonitor.cc index b516083a060..594cd4a8d4c 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 0dc1af571de..ed3e23e236b 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 9421b4cbf14..29da4cd4c47 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 fa7f9e9acdd..7bed317ddf0 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 236122ae798..93a8e842d3b 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) { From b28c300258248d169167911866ba39239eb26b63 Mon Sep 17 00:00:00 2001 From: John Spray Date: Thu, 29 Jun 2017 18:06:34 -0400 Subject: [PATCH 05/12] qa/doc: update for "mgr tell" no longer needed Signed-off-by: John Spray --- doc/mgr/administrator.rst | 15 +++++++++------ qa/suites/rados/rest/mgr-restful.yaml | 4 ++-- src/pybind/mgr/restful/api/__init__.py | 2 +- src/vstart.sh | 4 ++-- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/doc/mgr/administrator.rst b/doc/mgr/administrator.rst index d78a30a4d55..453cd3fbe6d 100644 --- a/doc/mgr/administrator.rst +++ b/doc/mgr/administrator.rst @@ -55,17 +55,20 @@ daemon as failed using ``ceph mgr fail ``. Calling module commands ----------------------- -Where a module implements command line hooks, using the Ceph CLI's -``tell`` command to call them like this:: +Where a module implements command line hooks, the commands will +be accessible as ordinary Ceph commands:: - ceph tell mgr + ceph + +If you would like to see the list of commands handled by the +manager (where normal ``ceph help`` would show all mon and mgr commands), +you can send a command directly to the manager daemon:: + + ceph tell mgr help Note that it is not necessary to address a particular mgr instance, simply ``mgr`` will pick the current active daemon. -Use the ``help`` command to get a list of available commands from all -modules. - Configuration ------------- diff --git a/qa/suites/rados/rest/mgr-restful.yaml b/qa/suites/rados/rest/mgr-restful.yaml index f202976e8cf..e62dd068f11 100644 --- a/qa/suites/rados/rest/mgr-restful.yaml +++ b/qa/suites/rados/rest/mgr-restful.yaml @@ -8,8 +8,8 @@ tasks: - (MGR_DOWN) - exec: mon.a: - - ceph tell mgr.x restful create-key admin - - ceph tell mgr.x restful create-self-signed-cert + - ceph restful create-key admin + - ceph restful create-self-signed-cert - ceph.restart: [mgr.x] - workunit: clients: diff --git a/src/pybind/mgr/restful/api/__init__.py b/src/pybind/mgr/restful/api/__init__.py index d4345eebc64..93c7fdde207 100644 --- a/src/pybind/mgr/restful/api/__init__.py +++ b/src/pybind/mgr/restful/api/__init__.py @@ -30,7 +30,7 @@ class Root(RestController): return { 'api_version': 1, 'auth': - 'Use "ceph tell mgr restful create_key " to create a key pair, ' + 'Use "ceph restful create_key " to create a key pair, ' 'pass it as HTTP Basic auth to authenticate', 'doc': 'See /doc endpoint', 'info': "Ceph Manager RESTful API server", diff --git a/src/vstart.sh b/src/vstart.sh index c59180277a3..68ffff35add 100755 --- a/src/vstart.sh +++ b/src/vstart.sh @@ -661,9 +661,9 @@ EOF run 'mgr' $CEPH_BIN/ceph-mgr -i $name $ARGS done - if ceph_adm tell mgr restful create-self-signed-cert; then + if ceph_adm restful create-self-signed-cert; then SF=`mktemp` - ceph_adm tell mgr restful create-key admin -o $SF + ceph_adm restful create-key admin -o $SF RESTFUL_SECRET=`cat $SF` rm $SF else From 388c8e4abde03219021609d46e04411a5d9b7d03 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 18 Jul 2017 16:05:59 -0400 Subject: [PATCH 06/12] mon/MgrMonitor: mark mgr commands with FLAG_MGR Signed-off-by: Sage Weil --- src/mon/MgrMonitor.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mon/MgrMonitor.cc b/src/mon/MgrMonitor.cc index 594cd4a8d4c..bf70f7aee72 100644 --- a/src/mon/MgrMonitor.cc +++ b/src/mon/MgrMonitor.cc @@ -150,6 +150,9 @@ void MgrMonitor::encode_pending(MonitorDBStore::TransactionRef t) if (pending_command_descs.size()) { dout(4) << __func__ << " encoding " << pending_command_descs.size() << " command_descs" << dendl; + for (auto& p : pending_command_descs) { + p.set_flag(MonCommand::FLAG_MGR); + } bufferlist bl; ::encode(pending_command_descs, bl); t->put(command_descs_prefix, "", bl); From 8badb73b9a49fce5c1e5f77a85545f26644e2079 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 18 Jul 2017 15:44:59 -0400 Subject: [PATCH 07/12] mon/MonCommands: std:: Signed-off-by: Sage Weil --- src/mon/MonCommand.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/mon/MonCommand.h b/src/mon/MonCommand.h index 94716d6c9e9..e32cc5df2be 100644 --- a/src/mon/MonCommand.h +++ b/src/mon/MonCommand.h @@ -13,12 +13,15 @@ #pragma once +#include +#include "include/encoding.h" + struct MonCommand { - string cmdstring; - string helpstring; - string module; - string req_perms; - string availability; + std::string cmdstring; + std::string helpstring; + std::string module; + std::string req_perms; + std::string availability; uint64_t flags; // MonCommand flags @@ -118,7 +121,7 @@ struct MonCommand { } bool requires_perm(char p) const { - return (req_perms.find(p) != string::npos); + return (req_perms.find(p) != std::string::npos); } }; WRITE_CLASS_ENCODER(MonCommand) From c86c8b717e1850410c59f7c6c708b20619c60a6c Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 18 Jul 2017 16:00:28 -0400 Subject: [PATCH 08/12] mgr: move mgr_commands to separate compilation unit Signed-off-by: Sage Weil --- src/CMakeLists.txt | 3 ++- src/mgr/DaemonServer.cc | 11 +---------- src/mgr/DaemonServer.h | 2 -- src/mgr/Mgr.cc | 3 ++- src/mgr/mgr_commands.cc | 14 ++++++++++++++ src/mgr/mgr_commands.h | 9 +++++++++ 6 files changed, 28 insertions(+), 14 deletions(-) create mode 100644 src/mgr/mgr_commands.cc create mode 100644 src/mgr/mgr_commands.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a764c490e46..862dd2b19ab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -691,7 +691,8 @@ if (WITH_MGR) mgr/PyState.cc mgr/MgrPyModule.cc mgr/MgrStandby.cc - mgr/Mgr.cc) + mgr/Mgr.cc + mgr/mgr_commands.cc) add_executable(ceph-mgr ${mgr_srcs} $) target_include_directories(ceph-mgr PRIVATE "${PYTHON_INCLUDE_DIRS}") diff --git a/src/mgr/DaemonServer.cc b/src/mgr/DaemonServer.cc index e54fd5a6255..3259df58702 100644 --- a/src/mgr/DaemonServer.cc +++ b/src/mgr/DaemonServer.cc @@ -17,6 +17,7 @@ #include "auth/RotatingKeyRing.h" #include "json_spirit/json_spirit_writer.h" +#include "mgr/mgr_commands.h" #include "mon/MonCommand.h" #include "messages/MMgrOpen.h" @@ -34,16 +35,6 @@ #define dout_prefix *_dout << "mgr.server " << __func__ << " " -/* The set of statically defined (C++-handled) commands. This - * does not include the Python-defined commands, which are loaded - * in PyModules */ -const std::vector DaemonServer::mgr_commands = { -#define COMMAND(parsesig, helptext, module, perm, availability) \ - {parsesig, helptext, module, perm, availability, 0}, -#include "MgrCommands.h" -#undef COMMAND -}; - DaemonServer::DaemonServer(MonClient *monc_, Finisher &finisher_, diff --git a/src/mgr/DaemonServer.h b/src/mgr/DaemonServer.h index 1c5825502a2..6e448320215 100644 --- a/src/mgr/DaemonServer.h +++ b/src/mgr/DaemonServer.h @@ -95,8 +95,6 @@ private: void maybe_ready(int32_t osd_id); public: - static const std::vector mgr_commands; - int init(uint64_t gid, entity_addr_t client_addr); void shutdown(); diff --git a/src/mgr/Mgr.cc b/src/mgr/Mgr.cc index e46b2cabd63..dcadb254e98 100644 --- a/src/mgr/Mgr.cc +++ b/src/mgr/Mgr.cc @@ -22,6 +22,7 @@ #include "global/signal_handler.h" #include "mgr/MgrContext.h" +#include "mgr/mgr_commands.h" #include "MgrPyModule.h" #include "DaemonServer.h" @@ -637,7 +638,7 @@ std::vector Mgr::get_command_set() const { Mutex::Locker l(lock); - std::vector commands = DaemonServer::mgr_commands; + std::vector commands = mgr_commands; std::vector py_commands = py_modules.get_commands(); commands.insert(commands.end(), py_commands.begin(), py_commands.end()); return commands; diff --git a/src/mgr/mgr_commands.cc b/src/mgr/mgr_commands.cc new file mode 100644 index 00000000000..aafee99140c --- /dev/null +++ b/src/mgr/mgr_commands.cc @@ -0,0 +1,14 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "mgr_commands.h" + +/* The set of statically defined (C++-handled) commands. This + * does not include the Python-defined commands, which are loaded + * in PyModules */ +const std::vector mgr_commands = { +#define COMMAND(parsesig, helptext, module, perm, availability) \ + {parsesig, helptext, module, perm, availability, 0}, +#include "MgrCommands.h" +#undef COMMAND +}; diff --git a/src/mgr/mgr_commands.h b/src/mgr/mgr_commands.h new file mode 100644 index 00000000000..c6ed6c68d72 --- /dev/null +++ b/src/mgr/mgr_commands.h @@ -0,0 +1,9 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#pragma once + +#include "mon/MonCommand.h" +#include + +extern const std::vector mgr_commands; From f4d50c8f1461ddd0104e41c53e447ff5adbf722f Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 18 Jul 2017 15:49:31 -0400 Subject: [PATCH 09/12] mon: define static mgr_commands at mkfs time This closes a window between mkfs and when the first mgr goes active where *no* mgr commands are defined, and things like 'pg dump' fail. We do not get the default set of commands defined by modules, but we get everything else. Signed-off-by: Sage Weil --- src/mon/CMakeLists.txt | 3 ++- src/mon/MgrMonitor.cc | 15 ++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/mon/CMakeLists.txt b/src/mon/CMakeLists.txt index 556157132f8..04044543c21 100644 --- a/src/mon/CMakeLists.txt +++ b/src/mon/CMakeLists.txt @@ -20,7 +20,8 @@ set(lib_mon_srcs DataHealthService.cc PGMonitor.cc PGMap.cc - ConfigKeyService.cc) + ConfigKeyService.cc + ../mgr/mgr_commands.cc) add_library(mon STATIC ${lib_mon_srcs} $ diff --git a/src/mon/MgrMonitor.cc b/src/mon/MgrMonitor.cc index bf70f7aee72..b858c5c0459 100644 --- a/src/mon/MgrMonitor.cc +++ b/src/mon/MgrMonitor.cc @@ -20,6 +20,7 @@ #include "PGStatService.h" #include "include/stringify.h" #include "mgr/MgrContext.h" +#include "mgr/mgr_commands.h" #include "OSDMonitor.h" #include "MgrMonitor.h" @@ -45,7 +46,10 @@ void MgrMonitor::create_initial() for (auto& m : tok) { pending_map.modules.insert(m); } - dout(10) << __func__ << " initial modules " << pending_map.modules << dendl; + pending_command_descs = mgr_commands; + dout(10) << __func__ << " initial modules " << pending_map.modules + << ", " << pending_command_descs.size() << " commands" + << dendl; } void MgrMonitor::update_from_paxos(bool *need_bootstrap) @@ -79,10 +83,11 @@ 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; + if (version == 1 + || (map.get_available() + && (!old_available || old_gid != map.get_active_gid()))) { + dout(4) << "mkfs or daemon transitioned to available, loading commands" + << dendl; bufferlist loaded_commands; int r = mon->store->get(command_descs_prefix, "", loaded_commands); if (r < 0) { From 3e89e324551d4930855e75ebae75a8f9730f5706 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 19 Jul 2017 16:57:16 -0400 Subject: [PATCH 10/12] mon: constify _get_moncommand Signed-off-by: Sage Weil --- src/mon/Monitor.cc | 10 ++++++---- src/mon/Monitor.h | 6 ++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/mon/Monitor.cc b/src/mon/Monitor.cc index 29da4cd4c47..86cfa91e6b3 100644 --- a/src/mon/Monitor.cc +++ b/src/mon/Monitor.cc @@ -2810,11 +2810,13 @@ void Monitor::_generate_command_map(map& cmdmap, } } -const MonCommand *Monitor::_get_moncommand(const string &cmd_prefix, - MonCommand *cmds, int cmds_size) +const MonCommand *Monitor::_get_moncommand( + const string &cmd_prefix, + const MonCommand *cmds, + int cmds_size) { - MonCommand *this_cmd = NULL; - for (MonCommand *cp = cmds; + const MonCommand *this_cmd = NULL; + for (const MonCommand *cp = cmds; cp < &cmds[cmds_size]; cp++) { if (cp->cmdstring.compare(0, cmd_prefix.size(), cmd_prefix) == 0) { this_cmd = cp; diff --git a/src/mon/Monitor.h b/src/mon/Monitor.h index 7bed317ddf0..fafadada998 100644 --- a/src/mon/Monitor.h +++ b/src/mon/Monitor.h @@ -685,8 +685,10 @@ public: static void _generate_command_map(map& cmdmap, map ¶m_str_map); - static const MonCommand *_get_moncommand(const string &cmd_prefix, - MonCommand *cmds, int cmds_size); + static const MonCommand *_get_moncommand( + const string &cmd_prefix, + const MonCommand *cmds, + int cmds_size); bool _allowed_command(MonSession *s, string &module, string &prefix, const map& cmdmap, const map& param_str_map, From e07a84a01fb4b335d569b5e8e7e0287201a1a58e Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 19 Jul 2017 16:58:14 -0400 Subject: [PATCH 11/12] mon: restore mgr command lookup so that we can still proxy to mgr Since mgr commands aren't in the main mon_commands array now, we need to explicitly look up commands there too. This restores the behavior implemented below in which we forward misdirected mgr commands to the mon. Signed-off-by: Sage Weil --- src/mon/Monitor.cc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/mon/Monitor.cc b/src/mon/Monitor.cc index 86cfa91e6b3..7969df17f57 100644 --- a/src/mon/Monitor.cc +++ b/src/mon/Monitor.cc @@ -3012,17 +3012,26 @@ void Monitor::handle_command(MonOpRequestRef op) // validate command is in leader map const MonCommand *leader_cmd; + const auto& mgr_cmds = mgrmon()->get_command_descs(); + const MonCommand *mgr_cmd = _get_moncommand(prefix, &mgr_cmds.at(0), + mgr_cmds.size()); leader_cmd = _get_moncommand(prefix, // the boost underlying this isn't const for some reason const_cast(leader_supported_mon_commands), leader_supported_mon_commands_size); if (!leader_cmd) { - reply_command(op, -EINVAL, "command not known", 0); - return; + leader_cmd = mgr_cmd; + if (!leader_cmd) { + reply_command(op, -EINVAL, "command not known", 0); + return; + } } // validate command is in our map & matches, or forward if it is allowed const MonCommand *mon_cmd = _get_moncommand(prefix, mon_commands, ARRAY_SIZE(mon_commands)); + if (!mon_cmd) { + mon_cmd = mgr_cmd; + } if (!is_leader()) { if (!mon_cmd) { if (leader_cmd->is_noforward()) { From a09ac4003aad8ee6c4c31f38b3b4c9fc207bbf33 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 19 Jul 2017 17:00:00 -0400 Subject: [PATCH 12/12] librados: 'pg ls' is not a mgr command Note that this breaks the command *during* the mon upgrade from jewel -> luminous, which is slightly annoying, but means we avoid proxying via the mon after upgrade is complete, which is good and IMO more important. In the future we may want librados to cache the command descriptions so that commands can be directed automatically. Signed-off-by: Sage Weil --- src/librados/librados.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librados/librados.cc b/src/librados/librados.cc index b1002194a4f..5a7af8e14b0 100644 --- a/src/librados/librados.cc +++ b/src/librados/librados.cc @@ -2635,7 +2635,7 @@ namespace { }; bufferlist inbl, outbl; string outstring; - int ret = client.mon_command(cmd, inbl, &outbl, &outstring); + int ret = client.mgr_command(cmd, inbl, &outbl, &outstring); if (ret) { return ret; }