]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mon: better 'mon features' cli
authorJoao Eduardo Luis <joao@suse.de>
Mon, 13 Feb 2017 00:35:18 +0000 (00:35 +0000)
committerJoao Eduardo Luis <joao@suse.de>
Thu, 2 Mar 2017 17:32:34 +0000 (17:32 +0000)
Allows listing supported and currently set monmap features, as well as
setting and unsetting them.

Signed-off-by: Joao Eduardo Luis <joao@suse.de>
src/mon/MonCommands.h
src/mon/MonmapMonitor.cc

index 0d7dde8907a4d0778858feb4a9a737e491059016..3f2ba92d0c84098b4fa0350ec73e07cbe0166c89 100644 (file)
@@ -441,6 +441,15 @@ COMMAND("mon remove " \
 COMMAND("mon rm " \
        "name=name,type=CephString", \
        "remove monitor named <name>", "mon", "rw", "cli,rest")
+COMMAND("mon feature list " \
+        "name=with_value,type=CephChoices,strings=--with-value,req=false", \
+        "list available mon map features to be set/unset", \
+        "mon", "r", "cli,rest")
+COMMAND("mon feature set " \
+        "name=feature_name,type=CephString " \
+        "name=sure,type=CephChoices,strings=--yes-i-really-mean-it,req=false", \
+        "set provided feature on mon map", \
+        "mon", "rw", "cli,rest")
 
 /*
  * OSD commands
index 8d9ef32f37a55c863073c84a281d80c82ecba768..5e18dba75727534e3ebc5e617e3374851357e47e 100644 (file)
@@ -224,6 +224,10 @@ bool MonmapMonitor::preprocess_command(MonOpRequestRef op)
     return true;
   }
 
+  string format;
+  cmd_getval(g_ceph_context, cmdmap, "format", format, string("plain"));
+  boost::scoped_ptr<Formatter> f(Formatter::create(format));
+
   if (prefix == "mon stat") {
     mon->monmap->print_summary(ss);
     ss << ", election epoch " << mon->get_epoch() << ", quorum " << mon->get_quorum()
@@ -261,10 +265,7 @@ bool MonmapMonitor::preprocess_command(MonOpRequestRef op)
       r = 0;
       ss << "got monmap epoch " << p->get_epoch();
     } else if (prefix == "mon dump") {
-      string format;
-      cmd_getval(g_ceph_context, cmdmap, "format", format, string("plain"));
       stringstream ds;
-      boost::scoped_ptr<Formatter> f(Formatter::create(format));
       if (f) {
         f->open_object_section("monmap");
         p->dump(f.get());
@@ -286,6 +287,78 @@ bool MonmapMonitor::preprocess_command(MonOpRequestRef op)
     }
     if (p != mon->monmap)
        delete p;
+
+  } else if (prefix == "mon feature list") {
+   
+    bool list_with_value = false;
+    string with_value;
+    if (cmd_getval(g_ceph_context, cmdmap, "with_value", with_value) &&
+        with_value == "--with-value") {
+      list_with_value = true;
+    }
+
+    MonMap *p = mon->monmap;
+
+    // list features
+    mon_feature_t supported = ceph::features::mon::get_supported();
+    mon_feature_t persistent = ceph::features::mon::get_persistent();
+    mon_feature_t required = p->get_required_features();
+
+    stringstream ds;
+    auto print_feature = [&](mon_feature_t& m_features, const char* m_str) {
+      if (f) {
+        if (list_with_value)
+          m_features.dump_with_value(f.get(), m_str);
+        else
+          m_features.dump(f.get(), m_str);
+      } else {
+        if (list_with_value)
+          m_features.print_with_value(ds);
+        else
+          m_features.print(ds);
+      }
+    };
+
+    if (f) {
+      f->open_object_section("features");
+
+      f->open_object_section("all");
+      print_feature(supported, "supported");
+      print_feature(persistent, "persistent");
+      f->close_section(); // all
+
+      f->open_object_section("monmap");
+      print_feature(p->persistent_features, "persistent");
+      print_feature(p->optional_features, "optional");
+      print_feature(required, "required");
+      f->close_section(); // monmap 
+
+      f->close_section(); // features
+      f->flush(ds);
+
+    } else {
+      ds << "all features" << std::endl
+        << "\tsupported: ";
+      print_feature(supported, nullptr);
+      ds << std::endl
+        << "\tpersistent: ";
+      print_feature(persistent, nullptr);
+      ds << std::endl
+        << std::endl;
+
+      ds << "on current monmap (epoch "
+         << p->get_epoch() << ")" << std::endl
+         << "\tpersistent: ";
+      print_feature(p->persistent_features, nullptr);
+      ds << std::endl
+        // omit optional features in plain-text
+        // makes it easier to read, and they're, currently, empty.
+        << "\trequired: ";
+      print_feature(required, nullptr);
+      ds << std::endl;
+    }
+    rdata.append(ds);
+    r = 0;
   }
 
 reply:
@@ -513,6 +586,72 @@ bool MonmapMonitor::prepare_command(MonOpRequestRef op)
     propose = true;
     err = 0;
 
+  } else if (prefix == "mon feature set") {
+
+    /* PLEASE NOTE:
+     *
+     * We currently only support setting/unsetting persistent features.
+     * This is by design, given at the moment we still don't have optional
+     * features, and, as such, there is no point introducing an interface
+     * to manipulate them. This allows us to provide a cleaner, more
+     * intuitive interface to the user, modifying solely persistent
+     * features.
+     *
+     * In the future we should consider adding another interface to handle
+     * optional features/flags; e.g., 'mon feature flag set/unset', or
+     * 'mon flag set/unset'.
+     */
+    string feature_name;
+    if (!cmd_getval(g_ceph_context, cmdmap, "feature_name", feature_name)) {
+      ss << "missing required feature name";
+      err = -EINVAL;
+      goto reply;
+    }
+
+    mon_feature_t feature;
+    feature = ceph::features::mon::get_feature_by_name(feature_name);
+    if (feature == ceph::features::mon::FEATURE_NONE) {
+      ss << "unknown feature '" << feature_name << "'";
+      err = -ENOENT;
+      goto reply;
+    }
+
+    string sure;
+    if (!cmd_getval(g_ceph_context, cmdmap, "sure", sure) ||
+        sure != "--yes-i-really-mean-it") {
+      ss << "please specify '--yes-i-really-mean-it' if you "
+         << "really, **really** want to set feature '"
+         << feature << "' in the monmap.";
+      err = -EPERM;
+      goto reply;
+    }
+
+    if (!mon->get_quorum_mon_features().contains_all(feature)) {
+      ss << "current quorum does not support feature '" << feature
+         << "'; supported features: "
+         << mon->get_quorum_mon_features();
+      err = -EINVAL;
+      goto reply;
+    }
+
+    ss << "setting feature '" << feature << "'";
+
+    err = 0;
+    if (monmap.persistent_features.contains_all(feature)) {
+      dout(10) << __func__ << " feature '" << feature
+               << "' already set on monmap; no-op." << dendl;
+      goto reply;
+    }
+
+    pending_map.persistent_features.set_feature(feature);
+    pending_map.last_changed = ceph_clock_now();
+    propose = true;
+
+    dout(1) << __func__ << ss.str() << "; new features will be: "
+            << "persistent = " << pending_map.persistent_features
+            // output optional nevertheless, for auditing purposes.
+            << ", optional = " << pending_map.optional_features << dendl;
+    
   } else {
     ss << "unknown command " << prefix;
     err = -EINVAL;