From 9c6a6f19d84831036152a207dc8d9a28743f7265 Mon Sep 17 00:00:00 2001 From: Joao Eduardo Luis Date: Mon, 13 Feb 2017 00:35:18 +0000 Subject: [PATCH] mon: better 'mon features' cli Allows listing supported and currently set monmap features, as well as setting and unsetting them. Signed-off-by: Joao Eduardo Luis --- src/mon/MonCommands.h | 9 +++ src/mon/MonmapMonitor.cc | 145 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 151 insertions(+), 3 deletions(-) diff --git a/src/mon/MonCommands.h b/src/mon/MonCommands.h index 0d7dde8907a..3f2ba92d0c8 100644 --- a/src/mon/MonCommands.h +++ b/src/mon/MonCommands.h @@ -441,6 +441,15 @@ COMMAND("mon remove " \ COMMAND("mon rm " \ "name=name,type=CephString", \ "remove monitor named ", "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 diff --git a/src/mon/MonmapMonitor.cc b/src/mon/MonmapMonitor.cc index 8d9ef32f37a..5e18dba7572 100644 --- a/src/mon/MonmapMonitor.cc +++ b/src/mon/MonmapMonitor.cc @@ -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 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 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; -- 2.39.5