]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
tools/ceph-objectstore-tool: add "update-mon-db" command
authorKefu Chai <kchai@redhat.com>
Mon, 29 Aug 2016 11:52:19 +0000 (19:52 +0800)
committerKefu Chai <kchai@redhat.com>
Tue, 18 Oct 2016 02:49:42 +0000 (10:49 +0800)
Fixes: http://tracker.ceph.com/issues/17179
Signed-off-by: Kefu Chai <kchai@redhat.com>
Conflicts:
src/tools/CMakeLists.txt: this file was added in master, so
update src/CMakeLists.txt instead
src/tools/Makefile-server.am: jewel is still using autotools,
so update this file also.
        src/tools/rebuild_mondb.cc: move the code spilled into
                doc/rados/troubleshooting/troubleshooting-mon.rst
                by accident back to this commit.
(cherry picked from commit 24faea7ce446bbf09cbd4a9d3434dd5444a6c295)

src/CMakeLists.txt
src/tools/Makefile-server.am
src/tools/ceph_objectstore_tool.cc
src/tools/rebuild_mondb.cc [new file with mode: 0644]
src/tools/rebuild_mondb.h [new file with mode: 0644]

index 1bfc031c9d90c5675bae29b9fd2a7bc51b698015..d4a7d06b4d39cd5fad61a9d726429873ada103cf 100644 (file)
@@ -464,6 +464,7 @@ install(TARGETS ceph-monstore-tool DESTINATION bin)
 
 add_executable(ceph-objectstore-tool
   tools/ceph_objectstore_tool.cc
+  tools/rebuild_mondb.cc
   tools/RadosDump.cc
   $<TARGET_OBJECTS:common_util_obj>)
 target_link_libraries(ceph-objectstore-tool tcmalloc osd os global ${Boost_PROGRAM_OPTIONS_LIBRARY} fuse dl)
index cbdb7150d815e529cb0e875b4a55296681e534d3..da9513b45824ecafea0e9a7902818e51aa930cfd 100644 (file)
@@ -18,7 +18,11 @@ endif
 
 if WITH_OSD
 
-ceph_objectstore_tool_SOURCES = tools/ceph_objectstore_tool.cc tools/RadosDump.cc
+ceph_objectstore_tool_SOURCES = \
+       tools/ceph_objectstore_tool.cc \
+       tools/rebuild_mondb.cc \
+       tools/rebuild_mondb.h \
+       tools/RadosDump.cc
 ceph_objectstore_tool_LDADD = $(LIBOSD) $(LIBOS) $(CEPH_GLOBAL) $(BOOST_PROGRAM_OPTIONS_LIBS)
 if LINUX
 ceph_objectstore_tool_LDADD += -ldl
index 980be30f10aad35bbdb984e023710f1ddb6bd846..f3714a655499d118d6e91c2e010b2030d9e3c6f9 100644 (file)
@@ -38,6 +38,7 @@
 #include "json_spirit/json_spirit_value.h"
 #include "json_spirit/json_spirit_reader.h"
 
+#include "rebuild_mondb.h"
 #include "ceph_objectstore_tool.h"
 #include "include/compat.h"
 
@@ -2269,7 +2270,8 @@ int apply_layout_settings(ObjectStore *os, const OSDSuperblock &superblock,
 
 int main(int argc, char **argv)
 {
-  string dpath, jpath, pgidstr, op, file, mountpoint, object, objcmd, arg1, arg2, type, format, pool;
+  string dpath, jpath, pgidstr, op, file, mountpoint, mon_store_path, object;
+  string objcmd, arg1, arg2, type, format, pool;
   spg_t pgid;
   unsigned epoch = 0;
   ghobject_t ghobj;
@@ -2293,11 +2295,13 @@ int main(int argc, char **argv)
      "Pool name, mandatory for apply-layout-settings if --pgid is not specified")
     ("op", po::value<string>(&op),
      "Arg is one of [info, log, remove, mkfs, fsck, fuse, export, import, list, fix-lost, list-pgs, rm-past-intervals, dump-journal, dump-super, meta-list, "
-     "get-osdmap, set-osdmap, get-inc-osdmap, set-inc-osdmap, mark-complete, apply-layout-settings]")
+     "get-osdmap, set-osdmap, get-inc-osdmap, set-inc-osdmap, mark-complete, apply-layout-settings, update-mon-db]")
     ("epoch", po::value<unsigned>(&epoch),
      "epoch# for get-osdmap and get-inc-osdmap, the current epoch in use if not specified")
     ("file", po::value<string>(&file),
      "path of file to export, import, get-osdmap, set-osdmap, get-inc-osdmap or set-inc-osdmap")
+    ("mon-store-path", po::value<string>(&mon_store_path),
+     "path of monstore to update-mon-db")
     ("mountpoint", po::value<string>(&mountpoint),
      "fuse mountpoint")
     ("format", po::value<string>(&format)->default_value("json-pretty"),
@@ -2363,7 +2367,8 @@ int main(int argc, char **argv)
     flags |= SKIP_JOURNAL_REPLAY;
   if (vm.count("skip-mount-omap"))
     flags |= SKIP_MOUNT_OMAP;
-
+  if (op == "update-mon-db")
+    flags |= SKIP_JOURNAL_REPLAY;
   head = (vm.count("head") > 0);
 
   vector<const char *> ceph_options;
@@ -2804,6 +2809,13 @@ int main(int argc, char **argv)
       ret = set_inc_osdmap(fs, epoch, bl, force, *osr);
     }
     goto out;
+  } else if (op == "update-mon-db") {
+    if (!vm.count("mon-store-path")) {
+      cerr << "Please specify the path to monitor db to update" << std::endl;
+    } else {
+      ret = update_mon_db(*fs, superblock, dpath + "/keyring", mon_store_path);
+    }
+    goto out;
   }
 
   log_oid = OSD::make_pg_log_oid(pgid);
diff --git a/src/tools/rebuild_mondb.cc b/src/tools/rebuild_mondb.cc
new file mode 100644 (file)
index 0000000..a52577d
--- /dev/null
@@ -0,0 +1,434 @@
+#include "auth/cephx/CephxKeyServer.h"
+#include "common/errno.h"
+#include "mon/AuthMonitor.h"
+#include "mon/MonitorDBStore.h"
+#include "os/ObjectStore.h"
+#include "osd/OSD.h"
+
+static int update_auth(const string& keyring_path,
+                       const OSDSuperblock& sb,
+                       MonitorDBStore& ms);
+static int update_monitor(const OSDSuperblock& sb, MonitorDBStore& ms);
+static int update_osdmap(ObjectStore& fs,
+                         OSDSuperblock& sb,
+                         MonitorDBStore& ms);
+static int update_pgmap_pg(ObjectStore& fs, MonitorDBStore& ms);
+
+int update_mon_db(ObjectStore& fs, OSDSuperblock& sb,
+                  const string& keyring,
+                  const string& store_path)
+{
+  MonitorDBStore ms(store_path);
+  int r = ms.create_and_open(cerr);
+  if (r < 0) {
+    cerr << "unable to open mon store: " << store_path << std::endl;
+    return EINVAL;
+  }
+  if ((r = update_auth(keyring, sb, ms)) < 0) {
+    goto out;
+  }
+  if ((r = update_osdmap(fs, sb, ms)) < 0) {
+    goto out;
+  }
+  if ((r = update_pgmap_pg(fs, ms)) < 0) {
+    goto out;
+  }
+  if ((r = update_monitor(sb, ms)) < 0) {
+    goto out;
+  }
+ out:
+  ms.close();
+  return r;
+}
+
+static void add_auth(KeyServerData::Incremental& auth_inc,
+                     MonitorDBStore& ms)
+{
+  AuthMonitor::Incremental inc;
+  inc.inc_type = AuthMonitor::AUTH_DATA;
+  ::encode(auth_inc, inc.auth_data);
+  inc.auth_type = CEPH_AUTH_CEPHX;
+
+  bufferlist bl;
+  __u8 v = 1;
+  ::encode(v, bl);
+  inc.encode(bl, CEPH_FEATURES_ALL);
+
+  const string prefix("auth");
+  auto last_committed = ms.get(prefix, "last_committed") + 1;
+  auto t = make_shared<MonitorDBStore::Transaction>();
+  t->put(prefix, last_committed, bl);
+  t->put(prefix, "last_committed", last_committed);
+  auto first_committed = ms.get(prefix, "first_committed");
+  if (!first_committed) {
+    t->put(prefix, "first_committed", last_committed);
+  }
+  ms.apply_transaction(t);
+}
+
+static int get_auth_inc(const string& keyring_path,
+                        const OSDSuperblock& sb,
+                        KeyServerData::Incremental* auth_inc)
+{
+  auth_inc->op = KeyServerData::AUTH_INC_ADD;
+
+  // get the name
+  EntityName entity;
+  // assuming the entity name of OSD is "osd.<osd_id>"
+  entity.set(CEPH_ENTITY_TYPE_OSD, std::to_string(sb.whoami));
+  auth_inc->name = entity;
+
+  // read keyring from disk
+  KeyRing keyring;
+  {
+    bufferlist bl;
+    string error;
+    int r = bl.read_file(keyring_path.c_str(), &error);
+    if (r < 0) {
+      if (r == -ENOENT) {
+        cout << "ignoring keyring (" << keyring_path << ")"
+             << ": " << error << std::endl;
+        return 0;
+      } else {
+        cerr << "unable to read keyring (" << keyring_path << ")"
+             << ": " << error << std::endl;
+        return r;
+      }
+    } else if (bl.length() == 0) {
+      cout << "ignoring empty keyring: " << keyring_path << std::endl;
+      return 0;
+    }
+    auto bp = bl.begin();
+    try {
+      ::decode(keyring, bp);
+    } catch (const buffer::error& e) {
+      cerr << "error decoding keyring: " << keyring_path << std::endl;
+      return -EINVAL;
+    }
+  }
+
+  // get the key
+  EntityAuth new_inc;
+  if (!keyring.get_auth(auth_inc->name, new_inc)) {
+    cerr << "key for " << auth_inc->name << " not found in keyring: "
+         << keyring_path << std::endl;
+    return -EINVAL;
+  }
+  auth_inc->auth.key = new_inc.key;
+
+  // get the caps
+  map<string,bufferlist> caps;
+  if (new_inc.caps.empty()) {
+    // fallback to default caps for an OSD
+    //   osd 'allow *' mon 'allow rwx'
+    // as suggested by document.
+    ::encode(string("allow *"), caps["osd"]);
+    ::encode(string("allow rwx"), caps["mon"]);
+  } else {
+    caps = new_inc.caps;
+  }
+  auth_inc->auth.caps = caps;
+  return 0;
+}
+
+// rebuild
+//  - auth/${epoch}
+//  - auth/first_committed
+//  - auth/last_committed
+static int update_auth(const string& keyring_path,
+                       const OSDSuperblock& sb,
+                       MonitorDBStore& ms)
+{
+  // stolen from AuthMonitor::prepare_command(), where prefix is "auth add"
+  KeyServerData::Incremental auth_inc;
+  int r;
+  if ((r = get_auth_inc(keyring_path, sb, &auth_inc))) {
+    return r;
+  }
+  add_auth(auth_inc, ms);
+  return 0;
+}
+
+// stolen from Monitor::check_fsid()
+static int check_fsid(const uuid_d& fsid, MonitorDBStore& ms)
+{
+  bufferlist bl;
+  int r = ms.get("monitor", "cluster_uuid", bl);
+  if (r == -ENOENT)
+    return r;
+  string uuid(bl.c_str(), bl.length());
+  auto end = uuid.find_first_of('\n');
+  if (end != uuid.npos) {
+    uuid.resize(end);
+  }
+  uuid_d existing;
+  if (!existing.parse(uuid.c_str())) {
+    cerr << "error: unable to parse uuid" << std::endl;
+    return -EINVAL;
+  }
+  if (fsid != existing) {
+    cerr << "error: cluster_uuid " << existing << " != " << fsid << std::endl;
+    return -EEXIST;
+  }
+  return 0;
+}
+
+// rebuild
+//  - monitor/cluster_uuid
+int update_monitor(const OSDSuperblock& sb, MonitorDBStore& ms)
+{
+  switch (check_fsid(sb.cluster_fsid, ms)) {
+  case -ENOENT:
+    break;
+  case -EINVAL:
+    return -EINVAL;
+  case -EEXIST:
+    return -EEXIST;
+  case 0:
+    return 0;
+  default:
+    assert(0);
+  }
+  string uuid = stringify(sb.cluster_fsid) + "\n";
+  bufferlist bl;
+  bl.append(uuid);
+  auto t = make_shared<MonitorDBStore::Transaction>();
+  t->put("monitor", "cluster_uuid", bl);
+  ms.apply_transaction(t);
+  return 0;
+}
+
+// rebuild
+//  - osdmap/${epoch}
+//  - osdmap/full_${epoch}
+//  - osdmap/full_latest
+//  - osdmap/first_committed
+//  - osdmap/last_committed
+int update_osdmap(ObjectStore& fs, OSDSuperblock& sb, MonitorDBStore& ms)
+{
+  const string prefix("osdmap");
+  const string first_committed_name("first_committed");
+  const string last_committed_name("last_committed");
+  epoch_t first_committed = ms.get(prefix, first_committed_name);
+  epoch_t last_committed = ms.get(prefix, last_committed_name);
+  auto t = make_shared<MonitorDBStore::Transaction>();
+
+  // trim stale maps
+  unsigned ntrimmed = 0;
+  // osdmap starts at 1. if we have a "0" first_committed, then there is nothing
+  // to trim. and "1 osdmaps trimmed" in the output message is misleading. so
+  // let's make it an exception.
+  for (auto e = first_committed; first_committed && e < sb.oldest_map; e++) {
+    t->erase(prefix, e);
+    t->erase(prefix, ms.combine_strings("full", e));
+    ntrimmed++;
+  }
+  if (!t->empty()) {
+    t->put(prefix, first_committed_name, sb.oldest_map);
+    ms.apply_transaction(t);
+    t = make_shared<MonitorDBStore::Transaction>();
+  }
+
+  unsigned nadded = 0;
+
+  OSDMap osdmap;
+  for (auto e = max(last_committed+1, sb.oldest_map);
+       e <= sb.newest_map; e++) {
+    bool have_crc = false;
+    uint32_t crc;
+    uint64_t features = 0;
+    // add inc maps
+    {
+      const auto oid = OSD::get_inc_osdmap_pobject_name(e);
+      bufferlist bl;
+      int nread = fs.read(coll_t::meta(), oid, 0, 0, bl);
+      if (nread <= 0) {
+        cerr << "missing " << oid << std::endl;
+        return -EINVAL;
+      }
+      t->put(prefix, e, bl);
+
+      OSDMap::Incremental inc;
+      auto p = bl.begin();
+      inc.decode(p);
+      features = inc.encode_features | CEPH_FEATURE_RESERVED;
+      if (osdmap.get_epoch() && e > 1) {
+        if (osdmap.apply_incremental(inc)) {
+          cerr << "bad fsid: "
+               << osdmap.get_fsid() << " != " << inc.fsid << std::endl;
+          return -EINVAL;
+        }
+        have_crc = inc.have_crc;
+        if (inc.have_crc) {
+          crc = inc.full_crc;
+          bufferlist fbl;
+          osdmap.encode(fbl, features);
+          if (osdmap.get_crc() != inc.full_crc) {
+            cerr << "mismatched inc crc: "
+                 << osdmap.get_crc() << " != " << inc.full_crc << std::endl;
+            return -EINVAL;
+          }
+          // inc.decode() verifies `inc_crc`, so it's been taken care of.
+        }
+      }
+    }
+    // add full maps
+    {
+      const auto oid = OSD::get_osdmap_pobject_name(e);
+      bufferlist bl;
+      int nread = fs.read(coll_t::meta(), oid, 0, 0, bl);
+      if (nread <= 0) {
+        cerr << "missing " << oid << std::endl;
+        return -EINVAL;
+      }
+      t->put(prefix, ms.combine_strings("full", e), bl);
+
+      auto p = bl.begin();
+      osdmap.decode(p);
+      if (osdmap.have_crc()) {
+        if (have_crc && osdmap.get_crc() != crc) {
+          cerr << "mismatched full/inc crc: "
+               << osdmap.get_crc() << " != " << crc << std::endl;
+          return -EINVAL;
+        }
+        uint32_t saved_crc = osdmap.get_crc();
+        bufferlist fbl;
+        osdmap.encode(fbl, features);
+        if (osdmap.get_crc() != saved_crc) {
+          cerr << "mismatched full crc: "
+               << saved_crc << " != " << osdmap.get_crc() << std::endl;
+          return -EINVAL;
+        }
+      }
+    }
+    nadded++;
+
+    // last_committed
+    t->put(prefix, last_committed_name, e);
+    // full last
+    t->put(prefix, ms.combine_strings("full", "latest"), e);
+
+    // this number comes from the default value of osd_target_transaction_size,
+    // so we won't OOM or stuff too many maps in a single transaction if OSD is
+    // keeping a large series of osdmap
+    static constexpr unsigned TRANSACTION_SIZE = 30;
+    if (t->size() >= TRANSACTION_SIZE) {
+      ms.apply_transaction(t);
+      t = make_shared<MonitorDBStore::Transaction>();
+    }
+  }
+  if (!t->empty()) {
+    ms.apply_transaction(t);
+  }
+  t.reset();
+
+  string osd_name("osd.");
+  osd_name += std::to_string(sb.whoami);
+  cout << std::left << setw(8)
+       << osd_name << ": "
+       << ntrimmed << " osdmaps trimmed, "
+       << nadded << " osdmaps added." << std::endl;
+  return 0;
+}
+
+// rebuild
+//  - pgmap_meta/version
+//  - pgmap_meta/last_osdmap_epoch
+//  - pgmap_meta/last_pg_scan
+//  - pgmap_meta/full_ratio
+//  - pgmap_meta/nearfull_ratio
+//  - pgmap_meta/stamp
+int update_pgmap_meta(MonitorDBStore& st)
+{
+  const string prefix("pgmap_meta");
+  auto t = make_shared<MonitorDBStore::Transaction>();
+  // stolen from PGMonitor::create_pending()
+  // the first pgmap_meta
+  t->put(prefix, "version", 1);
+  {
+    auto stamp = ceph_clock_now(g_ceph_context);
+    bufferlist bl;
+    ::encode(stamp, bl);
+    t->put(prefix, "stamp", bl);
+  }
+  {
+    auto last_osdmap_epoch = st.get("osdmap", "last_committed");
+    t->put(prefix, "last_osdmap_epoch", last_osdmap_epoch);
+  }
+  // be conservative, so PGMonitor will scan the all pools for pg changes
+  t->put(prefix, "last_pg_scan", 1);
+  {
+    auto full_ratio = g_ceph_context->_conf->mon_osd_full_ratio;
+    if (full_ratio > 1.0)
+      full_ratio /= 100.0;
+    bufferlist bl;
+    ::encode(full_ratio, bl);
+    t->put(prefix, "full_ratio", bl);
+  }
+  {
+    auto nearfull_ratio = g_ceph_context->_conf->mon_osd_nearfull_ratio;
+    if (nearfull_ratio > 1.0)
+      nearfull_ratio /= 100.0;
+    bufferlist bl;
+    ::encode(nearfull_ratio, bl);
+    t->put(prefix, "nearfull_ratio", bl);
+  }
+  st.apply_transaction(t);
+  return 0;
+}
+
+// rebuild
+//  - pgmap_pg/${pgid}
+int update_pgmap_pg(ObjectStore& fs, MonitorDBStore& ms)
+{
+  // pgmap/${epoch} is the incremental of: stamp, pgmap_pg, pgmap_osd
+  // if PGMonitor fails to read it, it will fall back to the pgmap_pg, i.e.
+  // the fullmap.
+  vector<coll_t> collections;
+  int r = fs.list_collections(collections);
+  if (r < 0) {
+    cerr << "failed to list pgs: "  << cpp_strerror(r) << std::endl;
+    return r;
+  }
+  const string prefix("pgmap_pg");
+  // in general, there are less than 100 PGs per OSD, so no need to apply
+  // transaction in batch.
+  auto t = make_shared<MonitorDBStore::Transaction>();
+  unsigned npg = 0;
+  for (const auto& coll : collections) {
+    spg_t pgid;
+    if (!coll.is_pg(&pgid))
+      continue;
+    bufferlist bl;
+    pg_info_t info(pgid);
+    map<epoch_t, pg_interval_t> past_intervals;
+    __u8 struct_v;
+    r = PG::read_info(&fs, pgid, coll, bl, info, past_intervals, struct_v);
+    if (r < 0) {
+      cerr << "failed to read_info: " << cpp_strerror(r) << std::endl;
+      return r;
+    }
+    if (struct_v < PG::cur_struct_v) {
+      cerr << "incompatible pg_info: v" << struct_v << std::endl;
+      return r;
+    }
+    version_t latest_epoch = 0;
+    r = ms.get(prefix, stringify(pgid.pgid), bl);
+    if (r >= 0) {
+      pg_stat_t pg_stat;
+      auto bp = bl.begin();
+      ::decode(pg_stat, bp);
+      latest_epoch = pg_stat.reported_epoch;
+    }
+    if (info.stats.reported_epoch > latest_epoch) {
+      bufferlist bl;
+      ::encode(info.stats, bl);
+      t->put(prefix, stringify(pgid.pgid), bl);
+      npg++;
+    }
+  }
+  ms.apply_transaction(t);
+  cout << std::left << setw(10)
+       << " " << npg << " pgs added." << std::endl;
+  return 0;
+}
diff --git a/src/tools/rebuild_mondb.h b/src/tools/rebuild_mondb.h
new file mode 100644 (file)
index 0000000..8a2317d
--- /dev/null
@@ -0,0 +1,9 @@
+#pragma once
+#include <string>
+
+class ObjectStore;
+class OSDSuperblock;
+
+int update_mon_db(ObjectStore& fs, OSDSuperblock& sb,
+                  const std::string& keyring_path,
+                  const std::string& store_path);