]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mon: load mgr commands dynamically
authorJohn Spray <john.spray@redhat.com>
Thu, 29 Jun 2017 10:13:44 +0000 (06:13 -0400)
committerJohn Spray <john.spray@redhat.com>
Wed, 19 Jul 2017 12:58:40 +0000 (08:58 -0400)
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 <john.spray@redhat.com>
src/mon/MgrMonitor.cc
src/mon/MgrMonitor.h
src/mon/Monitor.cc
src/mon/Monitor.h
src/test/common/get_command_descriptions.cc

index b516083a06054442df43e91ca6aa3e94e42595e1..594cd4a8d4c79f3a8612033736047b84a16ea02a 100644 (file)
@@ -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;
     }
index 0dc1af571deeaaf9dcdf50789a5e9d14d823a307..ed3e23e236b3d5f7065d371c284072c9cb74ce6d 100644 (file)
@@ -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<MonCommand> command_descs;
+  std::vector<MonCommand> 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<MonCommand> &get_command_descs() const {
+    return command_descs;
+  }
+
   friend class C_Updated;
 };
 
index 9421b4cbf14fc55619a9568a7de757979ab532bd..29da4cd4c47deba01e9016a27a7821bd512a9514 100644 (file)
@@ -112,17 +112,6 @@ MonCommand mon_commands[] = {
 #include <mon/MonCommands.h>
 #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 <mgr/MgrCommands.h>
-#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<MonCommand> &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<MonCommand> commands;
+    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;
     reply_command(op, 0, "", rdata, 0);
     return;
index fa7f9e9acdd32f8cd99f25f32ae942253eb5db3b..7bed317ddf0191f7d80b4e429e4b54be3d3248d5 100644 (file)
@@ -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<MonCommand> &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
index 236122ae7986d70b7aced783b255a4acf02b795f..93a8e842d3bf42c079369a371edcb23672a76e1c 100644 (file)
@@ -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<MonCommand> &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<MonCommand> 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<MonCommand> 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) {