]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
ceph_mon: check for existing mon store before opening db 2197/head
authorJoao Eduardo Luis <joao.luis@inktank.com>
Mon, 4 Aug 2014 14:27:50 +0000 (14:27 +0000)
committerJoao Eduardo Luis <joao.luis@inktank.com>
Mon, 18 Aug 2014 16:22:42 +0000 (17:22 +0100)
This will make sure that the monitor data directory is populated before
proceeding to opening it up.  We have to do this in order to work around
leveldb, which will create 'store.db' (even though it won't populate it)
upon opening the database.  Unwillingly, running the monitor without
first issuing a mkfs would have us ending up with a 'store.db' in the
monitor's data directory, and later on we would get errors from the
monitor not finding magic values within the store -- which given mkfs
hadn't been run isn't surprising.

Signed-off-by: Joao Eduardo Luis <joao.luis@inktank.com>
src/ceph_mon.cc

index c0b1c2c43413ed4bef5a291aeb5074cc50de30ea..0ddf833f20a27a9c4d9aaa4ee13f660914f2ba2e 100644 (file)
@@ -100,24 +100,31 @@ int obtain_monmap(MonitorDBStore &store, bufferlist &bl)
   return -ENOENT;
 }
 
-int mon_data_exists(bool *r)
+int check_mon_data_exists()
 {
   string mon_data = g_conf->mon_data;
   struct stat buf;
   if (::stat(mon_data.c_str(), &buf)) {
-    if (errno == ENOENT) {
-      *r = false;
-    } else {
+    if (errno != ENOENT) {
       cerr << "stat(" << mon_data << ") " << cpp_strerror(errno) << std::endl;
-      return -errno;
     }
-  } else {
-    *r = true;
+    return -errno;
   }
   return 0;
 }
 
-int mon_data_empty(bool *r)
+/** Check whether **mon data** is empty.
+ *
+ * Being empty means mkfs has not been run and there's no monitor setup
+ * at **g_conf->mon_data**.
+ *
+ * If the directory g_conf->mon_data is not empty we will return -ENOTEMPTY.
+ * Otherwise we will return 0.  Any other negative returns will represent
+ * a failure to be handled by the caller.
+ *
+ * @return **0** on success, -ENOTEMPTY if not empty or **-errno** otherwise.
+ */
+int check_mon_data_empty()
 {
   string mon_data = g_conf->mon_data;
 
@@ -128,7 +135,6 @@ int mon_data_empty(bool *r)
   }
   char buf[offsetof(struct dirent, d_name) + PATH_MAX + 1];
 
-  *r = false;
   int code = 0;
   struct dirent *de;
   errno = 0;
@@ -142,7 +148,7 @@ int mon_data_empty(bool *r)
     }
     if (string(".") != de->d_name &&
        string("..") != de->d_name) {
-      *r = true;
+      code = -ENOTEMPTY;
       break;
     }
   }
@@ -152,14 +158,6 @@ int mon_data_empty(bool *r)
   return code;
 }
 
-int mon_exists(bool *r)
-{
-  int code = mon_data_exists(r);
-  if (code || *r == false)
-    return code;
-  return mon_data_empty(r);
-}
-
 void usage()
 {
   cerr << "usage: ceph-mon -i monid [flags]" << std::endl;
@@ -290,27 +288,32 @@ int main(int argc, const char **argv)
     usage();
   }
 
-  bool exists;
-  if (mon_exists(&exists))
-    exit(1);
-
-  if (mkfs && exists) {
-    cerr << g_conf->mon_data << " already exists" << std::endl;
-    exit(0);
-  }
-
   // -- mkfs --
   if (mkfs) {
 
-    if (mon_data_exists(&exists))
-      exit(1);
-
-    if (!exists) {
+    int err = check_mon_data_exists();
+    if (err == -ENOENT) {
       if (::mkdir(g_conf->mon_data.c_str(), 0755)) {
        cerr << "mkdir(" << g_conf->mon_data << ") : "
             << cpp_strerror(errno) << std::endl;
        exit(1);
       }
+    } else if (err < 0) {
+      cerr << "error opening '" << g_conf->mon_data << "': "
+           << cpp_strerror(-err) << std::endl;
+      exit(-err);
+    }
+
+    err = check_mon_data_empty();
+    if (err == -ENOTEMPTY) {
+      // Mon may exist.  Let the user know and exit gracefully.
+      cerr << "'" << g_conf->mon_data << "' already exists and is not empty"
+           << ": monitor may already exist" << std::endl;
+      exit(0);
+    } else if (err < 0) {
+      cerr << "error checking if '" << g_conf->mon_data << "' is empty: "
+           << cpp_strerror(-err) << std::endl;
+      exit(-err);
     }
 
     // resolve public_network -> public_addr
@@ -425,6 +428,29 @@ int main(int argc, const char **argv)
     return 0;
   }
 
+  err = check_mon_data_exists();
+  if (err < 0 && err == -ENOENT) {
+    cerr << "monitor data directory at '" << g_conf->mon_data << "'"
+         << " does not exist: have you run 'mkfs'?" << std::endl;
+    exit(1);
+  } else if (err < 0) {
+    cerr << "error accessing monitor data directory at '"
+         << g_conf->mon_data << "': " << cpp_strerror(-err) << std::endl;
+    exit(1);
+  }
+
+  err = check_mon_data_empty();
+  if (err == 0) {
+    derr << "monitor data directory at '" << g_conf->mon_data
+      << "' is empty: have you run 'mkfs'?" << dendl;
+    exit(1);
+  } else if (err < 0 && err != -ENOTEMPTY) {
+    // we don't want an empty data dir by now
+    cerr << "error accessing '" << g_conf->mon_data << "': "
+         << cpp_strerror(-err) << std::endl;
+    exit(1);
+  }
+
   // we fork early to prevent leveldb's environment static state from
   // screwing us over
   Preforker prefork;
@@ -445,19 +471,26 @@ int main(int argc, const char **argv)
 
   Monitor::StoreConverter converter(g_conf->mon_data, store);
   if (store->open(std::cerr) < 0) {
-    int ret = store->create_and_open(std::cerr);
-    if (ret < 0) {
-      derr << "failed to create new leveldb store" << dendl;
+    int needs_conversion = converter.needs_conversion();
+    if (needs_conversion < 0) {
+      if (needs_conversion == -ENOENT) {
+        derr << "monitor data directory at '" << g_conf->mon_data
+             << "' is not empty but has no valid store nor legacy monitor"
+             << " store." << dendl;
+      } else {
+        derr << "found errors while validating legacy unconverted"
+             << " monitor store: " << cpp_strerror(needs_conversion) << dendl;
+      }
       prefork.exit(1);
     }
 
-    ret = converter.needs_conversion();
+    int ret = store->create_and_open(std::cerr);
     if (ret < 0) {
-      derr << "found errors while validating legacy unconverted monitor store: "
-           << cpp_strerror(ret) << dendl;
+      derr << "failed to create new leveldb store" << dendl;
       prefork.exit(1);
     }
-    if (ret > 0) {
+
+    if (needs_conversion > 0) {
       dout(0) << "converting monitor store, please do not interrupt..." << dendl;
       int r = converter.convert();
       if (r) {