]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/mon/MgrMonitor.cc
update sources to v12.1.2
[ceph.git] / ceph / src / mon / MgrMonitor.cc
index f06c256b2c6a1706fc86b45d85f571fb7106084b..fb760260f3ec695cb5e799c62cb8ad13c75c2714 100644 (file)
 #include "PGStatService.h"
 #include "include/stringify.h"
 #include "mgr/MgrContext.h"
+#include "mgr/mgr_commands.h"
 #include "OSDMonitor.h"
 
 #include "MgrMonitor.h"
 
+#define MGR_METADATA_PREFIX "mgr_metadata"
+
 #define dout_subsys ceph_subsys_mon
 #undef dout_prefix
 #define dout_prefix _prefix(_dout, mon, map)
@@ -34,6 +37,9 @@ static ostream& _prefix(std::ostream *_dout, Monitor *mon,
                << ").mgr e" << mgrmap.get_epoch() << " ";
 }
 
+// Prefix for mon store of active mgr's command descriptions
+const static std::string command_descs_prefix = "mgr_command_descs";
+
 
 void MgrMonitor::create_initial()
 {
@@ -41,7 +47,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)
@@ -54,6 +63,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 +83,21 @@ void MgrMonitor::update_from_paxos(bool *need_bootstrap)
     }
 
     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
@@ -112,6 +139,17 @@ void MgrMonitor::encode_pending(MonitorDBStore::TransactionRef t)
   put_version(t, pending_map.epoch, bl);
   put_last_committed(t, pending_map.epoch);
 
+  for (auto& p : pending_metadata) {
+    dout(10) << __func__ << " set metadata for " << p.first << dendl;
+    t->put(MGR_METADATA_PREFIX, p.first, p.second);
+  }
+  for (auto& name : pending_metadata_rm) {
+    dout(10) << __func__ << " rm metadata for " << name << dendl;
+    t->erase(MGR_METADATA_PREFIX, name);
+  }
+  pending_metadata.clear();
+  pending_metadata_rm.clear();
+
   health_check_map_t next;
   if (pending_map.active_gid == 0) {
     auto level = should_warn_about_mgr_down();
@@ -125,6 +163,18 @@ 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;
+    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)
@@ -255,6 +305,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;
     }
@@ -276,6 +341,8 @@ bool MgrMonitor::prepare_beacon(MonOpRequestRef op)
     pending_map.active_gid = m->get_gid();
     pending_map.active_name = m->get_name();
     pending_map.available_modules = m->get_available_modules();
+    ::encode(m->get_metadata(), pending_metadata[m->get_name()]);
+    pending_metadata_rm.erase(m->get_name());
 
     mon->clog->info() << "Activating manager daemon "
                       << pending_map.active_name;
@@ -298,6 +365,10 @@ bool MgrMonitor::prepare_beacon(MonOpRequestRef op)
       dout(10) << "new standby " << m->get_gid() << dendl;
       mon->clog->debug() << "Standby manager daemon " << m->get_name()
                          << " started";
+      pending_map.standbys[m->get_gid()] = {m->get_gid(), m->get_name(),
+                                           m->get_available_modules()};
+      ::encode(m->get_metadata(), pending_metadata[m->get_name()]);
+      pending_metadata_rm.erase(m->get_name());
       updated = true;
     }
   }
@@ -337,6 +408,10 @@ void MgrMonitor::check_sub(Subscription *sub)
     }
   } else {
     assert(sub->type == "mgrdigest");
+    if (sub->next == 0) {
+      // new registration; cancel previous timer
+      cancel_timer();
+    }
     if (digest_event == nullptr) {
       send_digests();
     }
@@ -494,6 +569,7 @@ void MgrMonitor::tick()
   }
 
   if (!pending_map.available &&
+      !ever_had_active_mgr &&
       should_warn_about_mgr_down() != HEALTH_OK) {
     dout(10) << " exceeded mon_mgr_mkfs_grace " << g_conf->mon_mgr_mkfs_grace
             << " seconds" << dendl;
@@ -536,6 +612,8 @@ void MgrMonitor::drop_active()
     last_beacon.erase(pending_map.active_gid);
   }
 
+  pending_metadata_rm.insert(pending_map.active_name);
+  pending_metadata.erase(pending_map.active_name);
   pending_map.active_name = "";
   pending_map.active_gid = 0;
   pending_map.available = false;
@@ -548,11 +626,12 @@ void MgrMonitor::drop_active()
 
 void MgrMonitor::drop_standby(uint64_t gid)
 {
+  pending_metadata_rm.insert(pending_map.standbys[gid].name);
+  pending_metadata.erase(pending_map.standbys[gid].name);
   pending_map.standbys.erase(gid);
   if (last_beacon.count(gid) > 0) {
     last_beacon.erase(gid);
   }
-
 }
 
 bool MgrMonitor::preprocess_command(MonOpRequestRef op)
@@ -609,6 +688,58 @@ bool MgrMonitor::preprocess_command(MonOpRequestRef op)
     }
     f->close_section();
     f->flush(rdata);
+  } else if (prefix == "mgr metadata") {
+    string name;
+    cmd_getval(g_ceph_context, cmdmap, "id", name);
+    if (name.size() > 0 && !map.have_name(name)) {
+      ss << "mgr." << name << " does not exist";
+      r = -ENOENT;
+      goto reply;
+    }
+    string format;
+    cmd_getval(g_ceph_context, cmdmap, "format", format);
+    boost::scoped_ptr<Formatter> f(Formatter::create(format, "json-pretty", "json-pretty"));
+    if (name.size()) {
+      f->open_object_section("mgr_metadata");
+      f->dump_string("id", name);
+      r = dump_metadata(name, f.get(), &ss);
+      if (r < 0)
+        goto reply;
+      f->close_section();
+    } else {
+      r = 0;
+      f->open_array_section("mgr_metadata");
+      for (auto& i : map.get_all_names()) {
+       f->open_object_section("mgr");
+       f->dump_string("id", i);
+       r = dump_metadata(i, f.get(), NULL);
+       if (r == -EINVAL || r == -ENOENT) {
+         // Drop error, continue to get other daemons' metadata
+         dout(4) << "No metadata for mgr." << i << dendl;
+         r = 0;
+       } else if (r < 0) {
+         // Unexpected error
+         goto reply;
+       }
+       f->close_section();
+      }
+      f->close_section();
+    }
+    f->flush(rdata);
+  } else if (prefix == "mgr versions") {
+    if (!f)
+      f.reset(Formatter::create("json-pretty"));
+    count_metadata("ceph_version", f.get());
+    f->flush(rdata);
+    r = 0;
+  } else if (prefix == "mgr count-metadata") {
+    if (!f)
+      f.reset(Formatter::create("json-pretty"));
+    string field;
+    cmd_getval(g_ceph_context, cmdmap, "property", field);
+    count_metadata(field, f.get());
+    f->flush(rdata);
+    r = 0;
   } else {
     return false;
   }
@@ -751,4 +882,59 @@ void MgrMonitor::on_shutdown()
   cancel_timer();
 }
 
+int MgrMonitor::load_metadata(const string& name, std::map<string, string>& m,
+                             ostream *err)
+{
+  bufferlist bl;
+  int r = mon->store->get(MGR_METADATA_PREFIX, name, bl);
+  if (r < 0)
+    return r;
+  try {
+    bufferlist::iterator p = bl.begin();
+    ::decode(m, p);
+  }
+  catch (buffer::error& e) {
+    if (err)
+      *err << "mgr." << name << " metadata is corrupt";
+    return -EIO;
+  }
+  return 0;
+}
+
+void MgrMonitor::count_metadata(const string& field, std::map<string,int> *out)
+{
+  std::set<string> ls = map.get_all_names();
+  for (auto& name : ls) {
+    std::map<string,string> meta;
+    load_metadata(name, meta, nullptr);
+    auto p = meta.find(field);
+    if (p == meta.end()) {
+      (*out)["unknown"]++;
+    } else {
+      (*out)[p->second]++;
+    }
+  }
+}
+
+void MgrMonitor::count_metadata(const string& field, Formatter *f)
+{
+  std::map<string,int> by_val;
+  count_metadata(field, &by_val);
+  f->open_object_section(field.c_str());
+  for (auto& p : by_val) {
+    f->dump_int(p.first.c_str(), p.second);
+  }
+  f->close_section();
+}
+
+int MgrMonitor::dump_metadata(const string& name, Formatter *f, ostream *err)
+{
+  std::map<string,string> m;
+  if (int r = load_metadata(name, m, err))
+    return r;
+  for (auto& p : m) {
+    f->dump_string(p.first.c_str(), p.second);
+  }
+  return 0;
+}