mirror of
https://github.com/ceph/ceph
synced 2025-04-11 04:02:04 +00:00
Merge pull request #16028 from jcsp/wip-mgr-commands
mon: load mgr commands at runtime Reviewed-by: Sage Weil <sage@redhat.com> Reviewed-by: Kefu Chai <kchai@redhat.com>
This commit is contained in:
commit
0193e38b3f
@ -55,17 +55,20 @@ daemon as failed using ``ceph mgr fail <mgr name>``.
|
|||||||
Calling module commands
|
Calling module commands
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
Where a module implements command line hooks, using the Ceph CLI's
|
Where a module implements command line hooks, the commands will
|
||||||
``tell`` command to call them like this::
|
be accessible as ordinary Ceph commands::
|
||||||
|
|
||||||
ceph tell mgr <command | help>
|
ceph <command | help>
|
||||||
|
|
||||||
|
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,
|
Note that it is not necessary to address a particular mgr instance,
|
||||||
simply ``mgr`` will pick the current active daemon.
|
simply ``mgr`` will pick the current active daemon.
|
||||||
|
|
||||||
Use the ``help`` command to get a list of available commands from all
|
|
||||||
modules.
|
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
@ -8,8 +8,8 @@ tasks:
|
|||||||
- (MGR_DOWN)
|
- (MGR_DOWN)
|
||||||
- exec:
|
- exec:
|
||||||
mon.a:
|
mon.a:
|
||||||
- ceph tell mgr.x restful create-key admin
|
- ceph restful create-key admin
|
||||||
- ceph tell mgr.x restful create-self-signed-cert
|
- ceph restful create-self-signed-cert
|
||||||
- ceph.restart: [mgr.x]
|
- ceph.restart: [mgr.x]
|
||||||
- workunit:
|
- workunit:
|
||||||
clients:
|
clients:
|
||||||
|
@ -691,7 +691,8 @@ if (WITH_MGR)
|
|||||||
mgr/PyState.cc
|
mgr/PyState.cc
|
||||||
mgr/MgrPyModule.cc
|
mgr/MgrPyModule.cc
|
||||||
mgr/MgrStandby.cc
|
mgr/MgrStandby.cc
|
||||||
mgr/Mgr.cc)
|
mgr/Mgr.cc
|
||||||
|
mgr/mgr_commands.cc)
|
||||||
add_executable(ceph-mgr ${mgr_srcs}
|
add_executable(ceph-mgr ${mgr_srcs}
|
||||||
$<TARGET_OBJECTS:heap_profiler_objs>)
|
$<TARGET_OBJECTS:heap_profiler_objs>)
|
||||||
target_include_directories(ceph-mgr PRIVATE "${PYTHON_INCLUDE_DIRS}")
|
target_include_directories(ceph-mgr PRIVATE "${PYTHON_INCLUDE_DIRS}")
|
||||||
|
@ -197,22 +197,6 @@ inline void encode(const char *s, bufferlist& bl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// array
|
|
||||||
template<class A>
|
|
||||||
inline void encode_array_nohead(const A a[], int n, bufferlist &bl)
|
|
||||||
{
|
|
||||||
for (int i=0; i<n; i++)
|
|
||||||
encode(a[i], bl);
|
|
||||||
}
|
|
||||||
template<class A>
|
|
||||||
inline void decode_array_nohead(A a[], int n, bufferlist::iterator &p)
|
|
||||||
{
|
|
||||||
for (int i=0; i<n; i++)
|
|
||||||
decode(a[i], p);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// buffers
|
// buffers
|
||||||
|
|
||||||
|
@ -2635,7 +2635,7 @@ namespace {
|
|||||||
};
|
};
|
||||||
bufferlist inbl, outbl;
|
bufferlist inbl, outbl;
|
||||||
string outstring;
|
string outstring;
|
||||||
int ret = client.mon_command(cmd, inbl, &outbl, &outstring);
|
int ret = client.mgr_command(cmd, inbl, &outbl, &outstring);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -16,13 +16,14 @@
|
|||||||
#define CEPH_MMGRBEACON_H
|
#define CEPH_MMGRBEACON_H
|
||||||
|
|
||||||
#include "messages/PaxosServiceMessage.h"
|
#include "messages/PaxosServiceMessage.h"
|
||||||
|
#include "mon/MonCommand.h"
|
||||||
|
|
||||||
#include "include/types.h"
|
#include "include/types.h"
|
||||||
|
|
||||||
|
|
||||||
class MMgrBeacon : public PaxosServiceMessage {
|
class MMgrBeacon : public PaxosServiceMessage {
|
||||||
|
|
||||||
static const int HEAD_VERSION = 3;
|
static const int HEAD_VERSION = 4;
|
||||||
static const int COMPAT_VERSION = 1;
|
static const int COMPAT_VERSION = 1;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -33,6 +34,9 @@ protected:
|
|||||||
uuid_d fsid;
|
uuid_d fsid;
|
||||||
std::set<std::string> available_modules;
|
std::set<std::string> available_modules;
|
||||||
|
|
||||||
|
// Only populated during activation
|
||||||
|
std::vector<MonCommand> command_descs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MMgrBeacon()
|
MMgrBeacon()
|
||||||
: PaxosServiceMessage(MSG_MGR_BEACON, 0, HEAD_VERSION, COMPAT_VERSION),
|
: PaxosServiceMessage(MSG_MGR_BEACON, 0, HEAD_VERSION, COMPAT_VERSION),
|
||||||
@ -56,6 +60,16 @@ public:
|
|||||||
const uuid_d& get_fsid() const { return fsid; }
|
const uuid_d& get_fsid() const { return fsid; }
|
||||||
std::set<std::string>& get_available_modules() { return available_modules; }
|
std::set<std::string>& get_available_modules() { return available_modules; }
|
||||||
|
|
||||||
|
void set_command_descs(const std::vector<MonCommand> &cmds)
|
||||||
|
{
|
||||||
|
command_descs = cmds;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<MonCommand> &get_command_descs()
|
||||||
|
{
|
||||||
|
return command_descs;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~MMgrBeacon() override {}
|
~MMgrBeacon() override {}
|
||||||
|
|
||||||
@ -77,6 +91,7 @@ public:
|
|||||||
::encode(name, payload);
|
::encode(name, payload);
|
||||||
::encode(fsid, payload);
|
::encode(fsid, payload);
|
||||||
::encode(available_modules, payload);
|
::encode(available_modules, payload);
|
||||||
|
::encode(command_descs, payload);
|
||||||
}
|
}
|
||||||
void decode_payload() override {
|
void decode_payload() override {
|
||||||
bufferlist::iterator p = payload.begin();
|
bufferlist::iterator p = payload.begin();
|
||||||
@ -91,6 +106,9 @@ public:
|
|||||||
if (header.version >= 3) {
|
if (header.version >= 3) {
|
||||||
::decode(available_modules, p);
|
::decode(available_modules, p);
|
||||||
}
|
}
|
||||||
|
if (header.version >= 4) {
|
||||||
|
::decode(command_descs, p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
#include "auth/RotatingKeyRing.h"
|
#include "auth/RotatingKeyRing.h"
|
||||||
#include "json_spirit/json_spirit_writer.h"
|
#include "json_spirit/json_spirit_writer.h"
|
||||||
|
|
||||||
|
#include "mgr/mgr_commands.h"
|
||||||
|
#include "mon/MonCommand.h"
|
||||||
|
|
||||||
#include "messages/MMgrOpen.h"
|
#include "messages/MMgrOpen.h"
|
||||||
#include "messages/MMgrConfigure.h"
|
#include "messages/MMgrConfigure.h"
|
||||||
#include "messages/MMonMgrReport.h"
|
#include "messages/MMonMgrReport.h"
|
||||||
@ -31,6 +34,8 @@
|
|||||||
#undef dout_prefix
|
#undef dout_prefix
|
||||||
#define dout_prefix *_dout << "mgr.server " << __func__ << " "
|
#define dout_prefix *_dout << "mgr.server " << __func__ << " "
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DaemonServer::DaemonServer(MonClient *monc_,
|
DaemonServer::DaemonServer(MonClient *monc_,
|
||||||
Finisher &finisher_,
|
Finisher &finisher_,
|
||||||
DaemonStateIndex &daemon_state_,
|
DaemonStateIndex &daemon_state_,
|
||||||
@ -402,24 +407,6 @@ bool DaemonServer::handle_report(MMgrReport *m)
|
|||||||
return true;
|
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[] = {
|
|
||||||
|
|
||||||
#define COMMAND(parsesig, helptext, module, perm, availability) \
|
|
||||||
{parsesig, helptext, module, perm, availability},
|
|
||||||
#include "MgrCommands.h"
|
|
||||||
#undef COMMAND
|
|
||||||
};
|
|
||||||
|
|
||||||
void DaemonServer::_generate_command_map(
|
void DaemonServer::_generate_command_map(
|
||||||
map<string,cmd_vartype>& cmdmap,
|
map<string,cmd_vartype>& cmdmap,
|
||||||
@ -444,16 +431,14 @@ void DaemonServer::_generate_command_map(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MgrCommand *DaemonServer::_get_mgrcommand(
|
const MonCommand *DaemonServer::_get_mgrcommand(
|
||||||
const string &cmd_prefix,
|
const string &cmd_prefix,
|
||||||
MgrCommand *cmds,
|
const std::vector<MonCommand> &cmds)
|
||||||
int cmds_size)
|
|
||||||
{
|
{
|
||||||
MgrCommand *this_cmd = NULL;
|
const MonCommand *this_cmd = nullptr;
|
||||||
for (MgrCommand *cp = cmds;
|
for (const auto &cmd : cmds) {
|
||||||
cp < &cmds[cmds_size]; cp++) {
|
if (cmd.cmdstring.compare(0, cmd_prefix.size(), cmd_prefix) == 0) {
|
||||||
if (cp->cmdstring.compare(0, cmd_prefix.size(), cmd_prefix) == 0) {
|
this_cmd = &cmd;
|
||||||
this_cmd = cp;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -466,7 +451,7 @@ bool DaemonServer::_allowed_command(
|
|||||||
const string &prefix,
|
const string &prefix,
|
||||||
const map<string,cmd_vartype>& cmdmap,
|
const map<string,cmd_vartype>& cmdmap,
|
||||||
const map<string,string>& param_str_map,
|
const map<string,string>& param_str_map,
|
||||||
const MgrCommand *this_cmd) {
|
const MonCommand *this_cmd) {
|
||||||
|
|
||||||
if (s->entity_name.is_mon()) {
|
if (s->entity_name.is_mon()) {
|
||||||
// mon is all-powerful. even when it is forwarding commands on behalf of
|
// mon is all-powerful. even when it is forwarding commands on behalf of
|
||||||
@ -593,30 +578,29 @@ bool DaemonServer::handle_command(MCommand *m)
|
|||||||
dout(4) << "prefix=" << prefix << dendl;
|
dout(4) << "prefix=" << prefix << dendl;
|
||||||
|
|
||||||
if (prefix == "get_command_descriptions") {
|
if (prefix == "get_command_descriptions") {
|
||||||
int cmdnum = 0;
|
|
||||||
|
|
||||||
dout(10) << "reading commands from python modules" << dendl;
|
dout(10) << "reading commands from python modules" << dendl;
|
||||||
auto py_commands = py_modules.get_commands();
|
const auto py_commands = py_modules.get_commands();
|
||||||
|
|
||||||
|
int cmdnum = 0;
|
||||||
JSONFormatter f;
|
JSONFormatter f;
|
||||||
f.open_object_section("command_descriptions");
|
f.open_object_section("command_descriptions");
|
||||||
for (const auto &pyc : py_commands) {
|
|
||||||
|
auto dump_cmd = [&cmdnum, &f](const MonCommand &mc){
|
||||||
ostringstream secname;
|
ostringstream secname;
|
||||||
secname << "cmd" << setfill('0') << std::setw(3) << cmdnum;
|
secname << "cmd" << setfill('0') << std::setw(3) << cmdnum;
|
||||||
dout(20) << "Dumping " << pyc.cmdstring << " (" << pyc.helpstring
|
dump_cmddesc_to_json(&f, secname.str(), mc.cmdstring, mc.helpstring,
|
||||||
<< ")" << dendl;
|
mc.module, mc.req_perms, mc.availability, 0);
|
||||||
dump_cmddesc_to_json(&f, secname.str(), pyc.cmdstring, pyc.helpstring,
|
|
||||||
"mgr", pyc.perm, "cli", 0);
|
|
||||||
cmdnum++;
|
cmdnum++;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto &pyc : py_commands) {
|
||||||
|
dump_cmd(pyc);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &cp : mgr_commands) {
|
for (const auto &mgr_cmd : mgr_commands) {
|
||||||
ostringstream secname;
|
dump_cmd(mgr_cmd);
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
f.close_section(); // command_descriptions
|
f.close_section(); // command_descriptions
|
||||||
f.flush(cmdctx->odata);
|
f.flush(cmdctx->odata);
|
||||||
cmdctx->reply(0, ss);
|
cmdctx->reply(0, ss);
|
||||||
@ -624,11 +608,10 @@ bool DaemonServer::handle_command(MCommand *m)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// lookup command
|
// lookup command
|
||||||
const MgrCommand *mgr_cmd = _get_mgrcommand(prefix, mgr_commands,
|
const MonCommand *mgr_cmd = _get_mgrcommand(prefix, mgr_commands);
|
||||||
ARRAY_SIZE(mgr_commands));
|
|
||||||
_generate_command_map(cmdctx->cmdmap, param_str_map);
|
_generate_command_map(cmdctx->cmdmap, param_str_map);
|
||||||
if (!mgr_cmd) {
|
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,
|
if (!_allowed_command(session.get(), py_command.module, prefix, cmdctx->cmdmap,
|
||||||
param_str_map, &py_command)) {
|
param_str_map, &py_command)) {
|
||||||
dout(1) << " access denied" << dendl;
|
dout(1) << " access denied" << dendl;
|
||||||
@ -937,7 +920,7 @@ bool DaemonServer::handle_command(MCommand *m)
|
|||||||
|
|
||||||
// None of the special native commands,
|
// None of the special native commands,
|
||||||
MgrPyModule *handler = nullptr;
|
MgrPyModule *handler = nullptr;
|
||||||
auto py_commands = py_modules.get_commands();
|
auto py_commands = py_modules.get_py_commands();
|
||||||
for (const auto &pyc : py_commands) {
|
for (const auto &pyc : py_commands) {
|
||||||
auto pyc_prefix = cmddesc_get_prefix(pyc.cmdstring);
|
auto pyc_prefix = cmddesc_get_prefix(pyc.cmdstring);
|
||||||
dout(1) << "pyc_prefix: '" << pyc_prefix << "'" << dendl;
|
dout(1) << "pyc_prefix: '" << pyc_prefix << "'" << dendl;
|
||||||
|
@ -35,7 +35,7 @@ class MMgrReport;
|
|||||||
class MMgrOpen;
|
class MMgrOpen;
|
||||||
class MMonMgrReport;
|
class MMonMgrReport;
|
||||||
class MCommand;
|
class MCommand;
|
||||||
struct MgrCommand;
|
struct MonCommand;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,13 +74,13 @@ protected:
|
|||||||
|
|
||||||
static void _generate_command_map(map<string,cmd_vartype>& cmdmap,
|
static void _generate_command_map(map<string,cmd_vartype>& cmdmap,
|
||||||
map<string,string> ¶m_str_map);
|
map<string,string> ¶m_str_map);
|
||||||
static const MgrCommand *_get_mgrcommand(const string &cmd_prefix,
|
static const MonCommand *_get_mgrcommand(const string &cmd_prefix,
|
||||||
MgrCommand *cmds, int cmds_size);
|
const std::vector<MonCommand> &commands);
|
||||||
bool _allowed_command(
|
bool _allowed_command(
|
||||||
MgrSession *s, const string &module, const string &prefix,
|
MgrSession *s, const string &module, const string &prefix,
|
||||||
const map<string,cmd_vartype>& cmdmap,
|
const map<string,cmd_vartype>& cmdmap,
|
||||||
const map<string,string>& param_str_map,
|
const map<string,string>& param_str_map,
|
||||||
const MgrCommand *this_cmd);
|
const MonCommand *this_cmd);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class ReplyOnFinish;
|
friend class ReplyOnFinish;
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "global/signal_handler.h"
|
#include "global/signal_handler.h"
|
||||||
|
|
||||||
#include "mgr/MgrContext.h"
|
#include "mgr/MgrContext.h"
|
||||||
|
#include "mgr/mgr_commands.h"
|
||||||
|
|
||||||
#include "MgrPyModule.h"
|
#include "MgrPyModule.h"
|
||||||
#include "DaemonServer.h"
|
#include "DaemonServer.h"
|
||||||
@ -632,3 +633,14 @@ void Mgr::tick()
|
|||||||
dout(10) << dendl;
|
dout(10) << dendl;
|
||||||
server.send_report();
|
server.send_report();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<MonCommand> Mgr::get_command_set() const
|
||||||
|
{
|
||||||
|
Mutex::Locker l(lock);
|
||||||
|
|
||||||
|
std::vector<MonCommand> commands = mgr_commands;
|
||||||
|
std::vector<MonCommand> py_commands = py_modules.get_commands();
|
||||||
|
commands.insert(commands.end(), py_commands.begin(), py_commands.end());
|
||||||
|
return commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ protected:
|
|||||||
Client *client;
|
Client *client;
|
||||||
Messenger *client_messenger;
|
Messenger *client_messenger;
|
||||||
|
|
||||||
Mutex lock;
|
mutable Mutex lock;
|
||||||
SafeTimer timer;
|
SafeTimer timer;
|
||||||
Finisher finisher;
|
Finisher finisher;
|
||||||
|
|
||||||
@ -98,6 +98,8 @@ public:
|
|||||||
|
|
||||||
void background_init(Context *completion);
|
void background_init(Context *completion);
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
|
std::vector<MonCommand> get_command_set() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -48,7 +48,8 @@ MgrStandby::MgrStandby(int argc, const char **argv) :
|
|||||||
timer(g_ceph_context, lock),
|
timer(g_ceph_context, lock),
|
||||||
active_mgr(nullptr),
|
active_mgr(nullptr),
|
||||||
orig_argc(argc),
|
orig_argc(argc),
|
||||||
orig_argv(argv)
|
orig_argv(argv),
|
||||||
|
available_in_map(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +152,11 @@ void MgrStandby::send_beacon()
|
|||||||
|
|
||||||
set<string> modules;
|
set<string> modules;
|
||||||
PyModules::list_modules(&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();
|
bool available = active_mgr != nullptr && active_mgr->is_initialized();
|
||||||
|
|
||||||
auto addr = available ? active_mgr->get_server_addr() : entity_addr_t();
|
auto addr = available ? active_mgr->get_server_addr() : entity_addr_t();
|
||||||
dout(10) << "sending beacon as gid " << monc.get_global_id()
|
dout(10) << "sending beacon as gid " << monc.get_global_id()
|
||||||
<< " modules " << modules << dendl;
|
<< " modules " << modules << dendl;
|
||||||
@ -162,6 +167,16 @@ void MgrStandby::send_beacon()
|
|||||||
addr,
|
addr,
|
||||||
available,
|
available,
|
||||||
modules);
|
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);
|
monc.send_mon_message(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,7 +293,7 @@ void MgrStandby::_update_log_config()
|
|||||||
|
|
||||||
void MgrStandby::handle_mgr_map(MMgrMap* mmap)
|
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;
|
dout(4) << "received map epoch " << map.get_epoch() << dendl;
|
||||||
const bool active_in_map = map.active_gid == monc.get_global_id();
|
const bool active_in_map = map.active_gid == monc.get_global_id();
|
||||||
dout(4) << "active in map: " << active_in_map
|
dout(4) << "active in map: " << active_in_map
|
||||||
@ -303,6 +318,11 @@ void MgrStandby::handle_mgr_map(MMgrMap* mmap)
|
|||||||
respawn();
|
respawn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!available_in_map && map.get_available()) {
|
||||||
|
dout(4) << "Map now says I am available" << dendl;
|
||||||
|
available_in_map = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (active_mgr != nullptr) {
|
if (active_mgr != nullptr) {
|
||||||
derr << "I was active but no longer am" << dendl;
|
derr << "I was active but no longer am" << dendl;
|
||||||
|
@ -59,6 +59,8 @@ protected:
|
|||||||
void _update_log_config();
|
void _update_log_config();
|
||||||
void send_beacon();
|
void send_beacon();
|
||||||
|
|
||||||
|
bool available_in_map;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MgrStandby(int argc, const char **argv);
|
MgrStandby(int argc, const char **argv);
|
||||||
~MgrStandby() override;
|
~MgrStandby() override;
|
||||||
|
@ -608,12 +608,12 @@ void PyModules::set_config(const std::string &handle,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ModuleCommand> PyModules::get_commands()
|
std::vector<ModuleCommand> PyModules::get_py_commands() const
|
||||||
{
|
{
|
||||||
Mutex::Locker l(lock);
|
Mutex::Locker l(lock);
|
||||||
|
|
||||||
std::vector<ModuleCommand> result;
|
std::vector<ModuleCommand> result;
|
||||||
for (auto& i : modules) {
|
for (const auto& i : modules) {
|
||||||
auto module = i.second.get();
|
auto module = i.second.get();
|
||||||
auto mod_commands = module->get_commands();
|
auto mod_commands = module->get_commands();
|
||||||
for (auto j : mod_commands) {
|
for (auto j : mod_commands) {
|
||||||
@ -624,6 +624,17 @@ std::vector<ModuleCommand> PyModules::get_commands()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<MonCommand> PyModules::get_commands() const
|
||||||
|
{
|
||||||
|
std::vector<ModuleCommand> commands = get_py_commands();
|
||||||
|
std::vector<MonCommand> 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<std::string,
|
void PyModules::insert_config(const std::map<std::string,
|
||||||
std::string> &new_config)
|
std::string> &new_config)
|
||||||
{
|
{
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "client/Client.h"
|
#include "client/Client.h"
|
||||||
#include "common/LogClient.h"
|
#include "common/LogClient.h"
|
||||||
#include "mon/MgrMap.h"
|
#include "mon/MgrMap.h"
|
||||||
|
#include "mon/MonCommand.h"
|
||||||
|
|
||||||
#include "DaemonState.h"
|
#include "DaemonState.h"
|
||||||
#include "ClusterState.h"
|
#include "ClusterState.h"
|
||||||
@ -80,7 +81,11 @@ public:
|
|||||||
|
|
||||||
std::map<std::string, std::string> config_cache;
|
std::map<std::string, std::string> config_cache;
|
||||||
|
|
||||||
std::vector<ModuleCommand> get_commands();
|
// Python command definitions, including callback
|
||||||
|
std::vector<ModuleCommand> get_py_commands() const;
|
||||||
|
|
||||||
|
// Monitor command definitions, suitable for CLI
|
||||||
|
std::vector<MonCommand> get_commands() const;
|
||||||
|
|
||||||
void insert_config(const std::map<std::string, std::string> &new_config);
|
void insert_config(const std::map<std::string, std::string> &new_config);
|
||||||
|
|
||||||
|
14
src/mgr/mgr_commands.cc
Normal file
14
src/mgr/mgr_commands.cc
Normal file
@ -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<MonCommand> mgr_commands = {
|
||||||
|
#define COMMAND(parsesig, helptext, module, perm, availability) \
|
||||||
|
{parsesig, helptext, module, perm, availability, 0},
|
||||||
|
#include "MgrCommands.h"
|
||||||
|
#undef COMMAND
|
||||||
|
};
|
9
src/mgr/mgr_commands.h
Normal file
9
src/mgr/mgr_commands.h
Normal file
@ -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 <vector>
|
||||||
|
|
||||||
|
extern const std::vector<MonCommand> mgr_commands;
|
@ -20,7 +20,8 @@ set(lib_mon_srcs
|
|||||||
DataHealthService.cc
|
DataHealthService.cc
|
||||||
PGMonitor.cc
|
PGMonitor.cc
|
||||||
PGMap.cc
|
PGMap.cc
|
||||||
ConfigKeyService.cc)
|
ConfigKeyService.cc
|
||||||
|
../mgr/mgr_commands.cc)
|
||||||
add_library(mon STATIC
|
add_library(mon STATIC
|
||||||
${lib_mon_srcs}
|
${lib_mon_srcs}
|
||||||
$<TARGET_OBJECTS:kv_objs>
|
$<TARGET_OBJECTS:kv_objs>
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "PGStatService.h"
|
#include "PGStatService.h"
|
||||||
#include "include/stringify.h"
|
#include "include/stringify.h"
|
||||||
#include "mgr/MgrContext.h"
|
#include "mgr/MgrContext.h"
|
||||||
|
#include "mgr/mgr_commands.h"
|
||||||
#include "OSDMonitor.h"
|
#include "OSDMonitor.h"
|
||||||
|
|
||||||
#include "MgrMonitor.h"
|
#include "MgrMonitor.h"
|
||||||
@ -35,13 +36,20 @@ 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()
|
void MgrMonitor::create_initial()
|
||||||
{
|
{
|
||||||
boost::tokenizer<> tok(g_conf->mgr_initial_modules);
|
boost::tokenizer<> tok(g_conf->mgr_initial_modules);
|
||||||
for (auto& m : tok) {
|
for (auto& m : tok) {
|
||||||
pending_map.modules.insert(m);
|
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)
|
void MgrMonitor::update_from_paxos(bool *need_bootstrap)
|
||||||
@ -54,6 +62,9 @@ void MgrMonitor::update_from_paxos(bool *need_bootstrap)
|
|||||||
int err = get_version(version, bl);
|
int err = get_version(version, bl);
|
||||||
assert(err == 0);
|
assert(err == 0);
|
||||||
|
|
||||||
|
bool old_available = map.get_available();
|
||||||
|
uint64_t old_gid = map.get_active_gid();
|
||||||
|
|
||||||
bufferlist::iterator p = bl.begin();
|
bufferlist::iterator p = bl.begin();
|
||||||
map.decode(p);
|
map.decode(p);
|
||||||
|
|
||||||
@ -71,6 +82,21 @@ void MgrMonitor::update_from_paxos(bool *need_bootstrap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
check_subs();
|
check_subs();
|
||||||
|
|
||||||
|
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) {
|
||||||
|
derr << "Failed to load mgr commands: " << cpp_strerror(r) << dendl;
|
||||||
|
} else {
|
||||||
|
auto p = loaded_commands.begin();
|
||||||
|
::decode(command_descs, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// feed our pet MgrClient
|
// feed our pet MgrClient
|
||||||
@ -125,6 +151,18 @@ void MgrMonitor::encode_pending(MonitorDBStore::TransactionRef t)
|
|||||||
put_value(t, "ever_had_active_mgr", 1);
|
put_value(t, "ever_had_active_mgr", 1);
|
||||||
}
|
}
|
||||||
encode_health(next, t);
|
encode_health(next, 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);
|
||||||
|
pending_command_descs.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MgrMonitor::check_caps(MonOpRequestRef op, const uuid_d& fsid)
|
bool MgrMonitor::check_caps(MonOpRequestRef op, const uuid_d& fsid)
|
||||||
@ -255,6 +293,21 @@ bool MgrMonitor::prepare_beacon(MonOpRequestRef op)
|
|||||||
dout(4) << "available " << m->get_gid() << dendl;
|
dout(4) << "available " << m->get_gid() << dendl;
|
||||||
mon->clog->info() << "Manager daemon " << pending_map.active_name
|
mon->clog->info() << "Manager daemon " << pending_map.active_name
|
||||||
<< " is now available";
|
<< " 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();
|
pending_map.available = m->get_available();
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "include/Context.h"
|
#include "include/Context.h"
|
||||||
#include "MgrMap.h"
|
#include "MgrMap.h"
|
||||||
#include "PaxosService.h"
|
#include "PaxosService.h"
|
||||||
|
#include "MonCommand.h"
|
||||||
|
|
||||||
class MgrMonitor: public PaxosService
|
class MgrMonitor: public PaxosService
|
||||||
{
|
{
|
||||||
@ -45,6 +46,10 @@ class MgrMonitor: public PaxosService
|
|||||||
|
|
||||||
health_status_t should_warn_about_mgr_down();
|
health_status_t should_warn_about_mgr_down();
|
||||||
|
|
||||||
|
// Command descriptions we've learned from the active mgr
|
||||||
|
std::vector<MonCommand> command_descs;
|
||||||
|
std::vector<MonCommand> pending_command_descs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MgrMonitor(Monitor *mn, Paxos *p, const string& service_name)
|
MgrMonitor(Monitor *mn, Paxos *p, const string& service_name)
|
||||||
: PaxosService(mn, p, service_name)
|
: PaxosService(mn, p, service_name)
|
||||||
@ -88,6 +93,10 @@ public:
|
|||||||
|
|
||||||
void print_summary(Formatter *f, std::ostream *ss) const;
|
void print_summary(Formatter *f, std::ostream *ss) const;
|
||||||
|
|
||||||
|
const std::vector<MonCommand> &get_command_descs() const {
|
||||||
|
return command_descs;
|
||||||
|
}
|
||||||
|
|
||||||
friend class C_Updated;
|
friend class C_Updated;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
127
src/mon/MonCommand.h
Normal file
127
src/mon/MonCommand.h
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
// -*- 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 <john.spray@redhat.com>
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "include/encoding.h"
|
||||||
|
|
||||||
|
struct MonCommand {
|
||||||
|
std::string cmdstring;
|
||||||
|
std::string helpstring;
|
||||||
|
std::string module;
|
||||||
|
std::string req_perms;
|
||||||
|
std::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) != std::string::npos);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
WRITE_CLASS_ENCODER(MonCommand)
|
@ -112,17 +112,6 @@ MonCommand mon_commands[] = {
|
|||||||
#include <mon/MonCommands.h>
|
#include <mon/MonCommands.h>
|
||||||
#undef COMMAND
|
#undef COMMAND
|
||||||
#undef COMMAND_WITH_FLAG
|
#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 <mgr/MgrCommands.h>
|
|
||||||
#undef COMMAND
|
|
||||||
#undef COMMAND_WITH_FLAG
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -2821,11 +2810,13 @@ void Monitor::_generate_command_map(map<string,cmd_vartype>& cmdmap,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MonCommand *Monitor::_get_moncommand(const string &cmd_prefix,
|
const MonCommand *Monitor::_get_moncommand(
|
||||||
MonCommand *cmds, int cmds_size)
|
const string &cmd_prefix,
|
||||||
|
const MonCommand *cmds,
|
||||||
|
int cmds_size)
|
||||||
{
|
{
|
||||||
MonCommand *this_cmd = NULL;
|
const MonCommand *this_cmd = NULL;
|
||||||
for (MonCommand *cp = cmds;
|
for (const MonCommand *cp = cmds;
|
||||||
cp < &cmds[cmds_size]; cp++) {
|
cp < &cmds[cmds_size]; cp++) {
|
||||||
if (cp->cmdstring.compare(0, cmd_prefix.size(), cmd_prefix) == 0) {
|
if (cp->cmdstring.compare(0, cmd_prefix.size(), cmd_prefix) == 0) {
|
||||||
this_cmd = cp;
|
this_cmd = cp;
|
||||||
@ -2855,26 +2846,23 @@ bool Monitor::_allowed_command(MonSession *s, string &module, string &prefix,
|
|||||||
return capable;
|
return capable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Monitor::format_command_descriptions(const MonCommand *commands,
|
void Monitor::format_command_descriptions(const std::vector<MonCommand> &commands,
|
||||||
unsigned commands_size,
|
|
||||||
Formatter *f,
|
Formatter *f,
|
||||||
bufferlist *rdata,
|
bufferlist *rdata,
|
||||||
bool hide_mgr_flag)
|
bool hide_mgr_flag)
|
||||||
{
|
{
|
||||||
int cmdnum = 0;
|
int cmdnum = 0;
|
||||||
f->open_object_section("command_descriptions");
|
f->open_object_section("command_descriptions");
|
||||||
for (const MonCommand *cp = commands;
|
for (const auto &cmd : commands) {
|
||||||
cp < &commands[commands_size]; cp++) {
|
unsigned flags = cmd.flags;
|
||||||
|
|
||||||
unsigned flags = cp->flags;
|
|
||||||
if (hide_mgr_flag) {
|
if (hide_mgr_flag) {
|
||||||
flags &= ~MonCommand::FLAG_MGR;
|
flags &= ~MonCommand::FLAG_MGR;
|
||||||
}
|
}
|
||||||
ostringstream secname;
|
ostringstream secname;
|
||||||
secname << "cmd" << setfill('0') << std::setw(3) << cmdnum;
|
secname << "cmd" << setfill('0') << std::setw(3) << cmdnum;
|
||||||
dump_cmddesc_to_json(f, secname.str(),
|
dump_cmddesc_to_json(f, secname.str(),
|
||||||
cp->cmdstring, cp->helpstring, cp->module,
|
cmd.cmdstring, cmd.helpstring, cmd.module,
|
||||||
cp->req_perms, cp->availability, flags);
|
cmd.req_perms, cmd.availability, flags);
|
||||||
cmdnum++;
|
cmdnum++;
|
||||||
}
|
}
|
||||||
f->close_section(); // command_descriptions
|
f->close_section(); // command_descriptions
|
||||||
@ -2985,9 +2973,16 @@ void Monitor::handle_command(MonOpRequestRef op)
|
|||||||
// hide mgr commands until luminous upgrade is complete
|
// hide mgr commands until luminous upgrade is complete
|
||||||
bool hide_mgr_flag =
|
bool hide_mgr_flag =
|
||||||
osdmon()->osdmap.require_osd_release < CEPH_RELEASE_LUMINOUS;
|
osdmon()->osdmap.require_osd_release < CEPH_RELEASE_LUMINOUS;
|
||||||
format_command_descriptions(leader_supported_mon_commands,
|
|
||||||
leader_supported_mon_commands_size, f, &rdata,
|
std::vector<MonCommand> commands;
|
||||||
hide_mgr_flag);
|
commands = static_cast<MgrMonitor*>(
|
||||||
|
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;
|
delete f;
|
||||||
reply_command(op, 0, "", rdata, 0);
|
reply_command(op, 0, "", rdata, 0);
|
||||||
return;
|
return;
|
||||||
@ -3017,17 +3012,26 @@ void Monitor::handle_command(MonOpRequestRef op)
|
|||||||
// validate command is in leader map
|
// validate command is in leader map
|
||||||
|
|
||||||
const MonCommand *leader_cmd;
|
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,
|
leader_cmd = _get_moncommand(prefix,
|
||||||
// the boost underlying this isn't const for some reason
|
// the boost underlying this isn't const for some reason
|
||||||
const_cast<MonCommand*>(leader_supported_mon_commands),
|
const_cast<MonCommand*>(leader_supported_mon_commands),
|
||||||
leader_supported_mon_commands_size);
|
leader_supported_mon_commands_size);
|
||||||
if (!leader_cmd) {
|
if (!leader_cmd) {
|
||||||
reply_command(op, -EINVAL, "command not known", 0);
|
leader_cmd = mgr_cmd;
|
||||||
return;
|
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
|
// validate command is in our map & matches, or forward if it is allowed
|
||||||
const MonCommand *mon_cmd = _get_moncommand(prefix, mon_commands,
|
const MonCommand *mon_cmd = _get_moncommand(prefix, mon_commands,
|
||||||
ARRAY_SIZE(mon_commands));
|
ARRAY_SIZE(mon_commands));
|
||||||
|
if (!mon_cmd) {
|
||||||
|
mon_cmd = mgr_cmd;
|
||||||
|
}
|
||||||
if (!is_leader()) {
|
if (!is_leader()) {
|
||||||
if (!mon_cmd) {
|
if (!mon_cmd) {
|
||||||
if (leader_cmd->is_noforward()) {
|
if (leader_cmd->is_noforward()) {
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include "Paxos.h"
|
#include "Paxos.h"
|
||||||
#include "Session.h"
|
#include "Session.h"
|
||||||
#include "PGStatService.h"
|
#include "PGStatService.h"
|
||||||
|
#include "MonCommand.h"
|
||||||
|
|
||||||
#include "common/LogClient.h"
|
#include "common/LogClient.h"
|
||||||
#include "auth/cephx/CephxKeyServer.h"
|
#include "auth/cephx/CephxKeyServer.h"
|
||||||
@ -113,7 +114,6 @@ struct MRoute;
|
|||||||
struct MForward;
|
struct MForward;
|
||||||
struct MTimeCheck;
|
struct MTimeCheck;
|
||||||
struct MMonHealth;
|
struct MMonHealth;
|
||||||
struct MonCommand;
|
|
||||||
|
|
||||||
#define COMPAT_SET_LOC "feature_set"
|
#define COMPAT_SET_LOC "feature_set"
|
||||||
|
|
||||||
@ -685,8 +685,10 @@ public:
|
|||||||
|
|
||||||
static void _generate_command_map(map<string,cmd_vartype>& cmdmap,
|
static void _generate_command_map(map<string,cmd_vartype>& cmdmap,
|
||||||
map<string,string> ¶m_str_map);
|
map<string,string> ¶m_str_map);
|
||||||
static const MonCommand *_get_moncommand(const string &cmd_prefix,
|
static const MonCommand *_get_moncommand(
|
||||||
MonCommand *cmds, int cmds_size);
|
const string &cmd_prefix,
|
||||||
|
const MonCommand *cmds,
|
||||||
|
int cmds_size);
|
||||||
bool _allowed_command(MonSession *s, string &module, string &prefix,
|
bool _allowed_command(MonSession *s, string &module, string &prefix,
|
||||||
const map<string,cmd_vartype>& cmdmap,
|
const map<string,cmd_vartype>& cmdmap,
|
||||||
const map<string,string>& param_str_map,
|
const map<string,string>& param_str_map,
|
||||||
@ -960,8 +962,7 @@ private:
|
|||||||
Monitor& operator=(const Monitor &rhs);
|
Monitor& operator=(const Monitor &rhs);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void format_command_descriptions(const MonCommand *commands,
|
static void format_command_descriptions(const std::vector<MonCommand> &commands,
|
||||||
unsigned commands_size,
|
|
||||||
Formatter *f,
|
Formatter *f,
|
||||||
bufferlist *rdata,
|
bufferlist *rdata,
|
||||||
bool hide_mgr_flag=false);
|
bool hide_mgr_flag=false);
|
||||||
@ -981,97 +982,6 @@ public:
|
|||||||
#define CEPH_MON_FEATURE_INCOMPAT_KRAKEN CompatSet::Feature(8, "support monmap features")
|
#define CEPH_MON_FEATURE_INCOMPAT_KRAKEN CompatSet::Feature(8, "support monmap features")
|
||||||
// make sure you add your feature to Monitor::get_supported_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
|
#endif
|
||||||
|
@ -58,7 +58,7 @@ struct Page {
|
|||||||
::encode(offset, bl);
|
::encode(offset, bl);
|
||||||
}
|
}
|
||||||
void decode(bufferlist::iterator &p, size_t page_size) {
|
void decode(bufferlist::iterator &p, size_t page_size) {
|
||||||
::decode_array_nohead(data, page_size, p);
|
p.copy(page_size, data);
|
||||||
::decode(offset, p);
|
::decode(offset, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ class Root(RestController):
|
|||||||
return {
|
return {
|
||||||
'api_version': 1,
|
'api_version': 1,
|
||||||
'auth':
|
'auth':
|
||||||
'Use "ceph tell mgr restful create_key <key>" to create a key pair, '
|
'Use "ceph restful create_key <key>" to create a key pair, '
|
||||||
'pass it as HTTP Basic auth to authenticate',
|
'pass it as HTTP Basic auth to authenticate',
|
||||||
'doc': 'See /doc endpoint',
|
'doc': 'See /doc endpoint',
|
||||||
'info': "Ceph Manager RESTful API server",
|
'info': "Ceph Manager RESTful API server",
|
||||||
|
@ -41,11 +41,11 @@ static void usage(ostream &out)
|
|||||||
out << " get_command_descriptions --pull585\n";
|
out << " get_command_descriptions --pull585\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void json_print(const MonCommand *mon_commands, int size)
|
static void json_print(const std::vector<MonCommand> &mon_commands)
|
||||||
{
|
{
|
||||||
bufferlist rdata;
|
bufferlist rdata;
|
||||||
Formatter *f = Formatter::create("json");
|
Formatter *f = Formatter::create("json");
|
||||||
Monitor::format_command_descriptions(mon_commands, size, f, &rdata);
|
Monitor::format_command_descriptions(mon_commands, f, &rdata);
|
||||||
delete f;
|
delete f;
|
||||||
string data(rdata.c_str(), rdata.length());
|
string data(rdata.c_str(), rdata.length());
|
||||||
cout << data << std::endl;
|
cout << data << std::endl;
|
||||||
@ -56,7 +56,7 @@ static void all()
|
|||||||
#undef FLAG
|
#undef FLAG
|
||||||
#undef COMMAND
|
#undef COMMAND
|
||||||
#undef COMMAND_WITH_FLAG
|
#undef COMMAND_WITH_FLAG
|
||||||
MonCommand mon_commands[] = {
|
std::vector<MonCommand> mon_commands = {
|
||||||
#define FLAG(f) (MonCommand::FLAG_##f)
|
#define FLAG(f) (MonCommand::FLAG_##f)
|
||||||
#define COMMAND(parsesig, helptext, modulename, req_perms, avail) \
|
#define COMMAND(parsesig, helptext, modulename, req_perms, avail) \
|
||||||
{parsesig, helptext, modulename, req_perms, avail, 0},
|
{parsesig, helptext, modulename, req_perms, avail, 0},
|
||||||
@ -66,8 +66,6 @@ static void all()
|
|||||||
#undef COMMAND
|
#undef COMMAND
|
||||||
#undef COMMAND_WITH_FLAG
|
#undef COMMAND_WITH_FLAG
|
||||||
|
|
||||||
// FIXME: slurp up the Mgr commands too
|
|
||||||
|
|
||||||
#define COMMAND(parsesig, helptext, modulename, req_perms, avail) \
|
#define COMMAND(parsesig, helptext, modulename, req_perms, avail) \
|
||||||
{parsesig, helptext, modulename, req_perms, avail, FLAG(MGR)},
|
{parsesig, helptext, modulename, req_perms, avail, FLAG(MGR)},
|
||||||
#define COMMAND_WITH_FLAG(parsesig, helptext, modulename, req_perms, avail, flags) \
|
#define COMMAND_WITH_FLAG(parsesig, helptext, modulename, req_perms, avail, flags) \
|
||||||
@ -77,13 +75,13 @@ static void all()
|
|||||||
#undef COMMAND_WITH_FLAG
|
#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
|
// syntax error https://github.com/ceph/ceph/pull/585
|
||||||
static void pull585()
|
static void pull585()
|
||||||
{
|
{
|
||||||
MonCommand mon_commands[] = {
|
std::vector<MonCommand> mon_commands = {
|
||||||
{ "osd pool create "
|
{ "osd pool create "
|
||||||
"name=pool,type=CephPoolname "
|
"name=pool,type=CephPoolname "
|
||||||
"name=pg_num,type=CephInt,range=0 "
|
"name=pg_num,type=CephInt,range=0 "
|
||||||
@ -92,7 +90,7 @@ static void pull585()
|
|||||||
"create pool", "osd", "rw", "cli,rest" }
|
"create pool", "osd", "rw", "cli,rest" }
|
||||||
};
|
};
|
||||||
|
|
||||||
json_print(mon_commands, ARRAY_SIZE(mon_commands));
|
json_print(mon_commands);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
@ -661,9 +661,9 @@ EOF
|
|||||||
run 'mgr' $CEPH_BIN/ceph-mgr -i $name $ARGS
|
run 'mgr' $CEPH_BIN/ceph-mgr -i $name $ARGS
|
||||||
done
|
done
|
||||||
|
|
||||||
if ceph_adm tell mgr restful create-self-signed-cert; then
|
if ceph_adm restful create-self-signed-cert; then
|
||||||
SF=`mktemp`
|
SF=`mktemp`
|
||||||
ceph_adm tell mgr restful create-key admin -o $SF
|
ceph_adm restful create-key admin -o $SF
|
||||||
RESTFUL_SECRET=`cat $SF`
|
RESTFUL_SECRET=`cat $SF`
|
||||||
rm $SF
|
rm $SF
|
||||||
else
|
else
|
||||||
|
Loading…
Reference in New Issue
Block a user