From bcf28db383aab52a9cded9a32067df21daf9339a Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 10 Dec 2018 08:19:27 -0600 Subject: [PATCH] mon: CephBool -> CephChoices in command map for pre-nautilus mons If pre-nautilus mons are in quorum, send out a pre-nautilus compatible set of commands. Although nautilus mons can do this same translation on the fly for pre-nautilus clients, pre-nautilus mons can't, so do it for all mons. This means the new CephBool behavior will only start working once you upgrade all mons to nautilus. Fixes: http://tracker.ceph.com/issues/37583 Signed-off-by: Sage Weil --- src/common/cmdparse.cc | 49 ++++++++++++++++++++++++++++++++++++++++++ src/common/cmdparse.h | 1 + src/mon/Monitor.cc | 11 ++++++++++ src/mon/Monitor.h | 15 +++++++++++-- 4 files changed, 74 insertions(+), 2 deletions(-) diff --git a/src/common/cmdparse.cc b/src/common/cmdparse.cc index 3380178934d6c..5945c0baf766d 100644 --- a/src/common/cmdparse.cc +++ b/src/common/cmdparse.cc @@ -65,6 +65,55 @@ arg_desc_t cmddesc_get_args(const String& cmddesc) return arg_desc; } +std::string cmddesc_get_prenautilus_compat(const std::string &cmddesc) +{ + std::vector out; + stringstream ss(cmddesc); + std::string word; + bool changed = false; + while (std::getline(ss, word, ' ')) { + // if no , or =, must be a plain word to put out + if (word.find_first_of(",=") == string::npos) { + out.push_back(word); + continue; + } + auto desckv = cmddesc_get_args(word); + auto j = desckv.find("type"); + if (j != desckv.end() && j->second == "CephBool") { + // Instruct legacy clients or mons to send --foo-bar string in place + // of a 'true'/'false' value + std::ostringstream oss; + oss << std::string("--") << desckv["name"]; + std::string val = oss.str(); + std::replace(val.begin(), val.end(), '_', '-'); + desckv["type"] = "CephChoices"; + desckv["strings"] = val; + std::ostringstream fss; + for (auto k = desckv.begin(); k != desckv.end(); ++k) { + if (k != desckv.begin()) { + fss << ","; + } + fss << k->first << "=" << k->second; + } + out.push_back(fss.str()); + changed = true; + } else { + out.push_back(word); + } + } + if (!changed) { + return cmddesc; + } + std::string o; + for (auto i = out.begin(); i != out.end(); ++i) { + if (i != out.begin()) { + o += " "; + } + o += *i; + } + return o; +} + /** * Read a command description list out of cmd, and dump it to f. * A signature description is a set of space-separated words; diff --git a/src/common/cmdparse.h b/src/common/cmdparse.h index 550851b216a8d..2c59567d588d9 100644 --- a/src/common/cmdparse.h +++ b/src/common/cmdparse.h @@ -23,6 +23,7 @@ typedef boost::variant> cmdmap_t; std::string cmddesc_get_prefix(const std::string &cmddesc); +std::string cmddesc_get_prenautilus_compat(const std::string &cmddesc); void dump_cmd_to_json(ceph::Formatter *f, uint64_t features, const std::string& cmd); void dump_cmd_and_help_to_json(ceph::Formatter *f, diff --git a/src/mon/Monitor.cc b/src/mon/Monitor.cc index 01c1cc877a08d..38875e8a2bdc7 100644 --- a/src/mon/Monitor.cc +++ b/src/mon/Monitor.cc @@ -29,6 +29,7 @@ #include "Monitor.h" #include "common/version.h" #include "common/blkdev.h" +#include "common/cmdparse.h" #include "osd/OSDMap.h" @@ -221,6 +222,16 @@ Monitor::Monitor(CephContext* cct_, string nm, MonitorDBStore *s, } MonCommand::encode_vector(local_mon_commands, local_mon_commands_bl); + prenautilus_local_mon_commands = local_mon_commands; + for (auto& i : prenautilus_local_mon_commands) { + std::string n = cmddesc_get_prenautilus_compat(i.cmdstring); + if (n != i.cmdstring) { + dout(20) << " pre-nautilus cmd " << i.cmdstring << " -> " << n << dendl; + i.cmdstring = n; + } + } + MonCommand::encode_vector(prenautilus_local_mon_commands, prenautilus_local_mon_commands_bl); + // assume our commands until we have an election. this only means // we won't reply with EINVAL before the election; any command that // actually matters will wait until we have quorum etc and then diff --git a/src/mon/Monitor.h b/src/mon/Monitor.h index 3c2685ae45f47..d30afddad1c80 100644 --- a/src/mon/Monitor.h +++ b/src/mon/Monitor.h @@ -165,6 +165,9 @@ public: vector local_mon_commands; // commands i support bufferlist local_mon_commands_bl; // encoded version of above + vector prenautilus_local_mon_commands; + bufferlist prenautilus_local_mon_commands_bl; + Messenger *mgr_messenger; MgrClient mgr_client; uint64_t mgr_proxy_bytes = 0; // in-flight proxied mgr command message bytes @@ -967,10 +970,18 @@ public: bufferlist *rdata); const std::vector &get_local_commands(mon_feature_t f) { - return local_mon_commands; + if (f.contains_all(ceph::features::mon::FEATURE_NAUTILUS)) { + return local_mon_commands; + } else { + return prenautilus_local_mon_commands; + } } const bufferlist& get_local_commands_bl(mon_feature_t f) { - return local_mon_commands_bl; + if (f.contains_all(ceph::features::mon::FEATURE_NAUTILUS)) { + return local_mon_commands_bl; + } else { + return prenautilus_local_mon_commands_bl; + } } void set_leader_commands(const std::vector& cmds) { leader_mon_commands = cmds; -- 2.39.5