"only be rejected later, when they are used.")
.set_flag(Option::FLAG_RUNTIME),
+ Option("mon_warn_on_older_version", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
+ .set_default(true)
+ .add_service("mon")
+ .set_description("issue DAEMON_OLD_VERSION health warning if daemons are not all running the same version"),
+
// PAXOS
Option("paxos_stash_full_interval", Option::TYPE_INT, Option::LEVEL_ADVANCED)
#include <limits.h>
#include <sstream>
#include <regex>
+#include <time.h>
+#include <iterator>
#include "include/ceph_assert.h"
#include "include/common_fwd.h"
health_check_map_t next;
+ // DAEMON_OLD_VERSION
+ if (g_conf().get_val<bool>("mon_warn_on_older_version")) {
+ std::map<string, std::list<string> > all_versions;
+ mon->get_all_versions(all_versions);
+ if (all_versions.size() > 1) {
+ dout(20) << __func__ << " all_versions=" << all_versions << dendl;
+ // The last entry has the largest version
+ dout(20) << __func__ << " highest version daemon count "
+ << all_versions.rbegin()->second.size() << dendl;
+ // Erase last element (the highest version running)
+ all_versions.erase(all_versions.rbegin()->first);
+ ceph_assert(all_versions.size() > 0);
+ ostringstream ss;
+ unsigned daemon_count = 0;
+ for (auto& g:all_versions) {
+ daemon_count += g.second.size();
+ }
+ int ver_count = all_versions.size();
+ ceph_assert(!(daemon_count == 1 && ver_count != 1));
+ ss << "There " << (daemon_count == 1 ? "is a daemon" : "are daemons")
+ << " running " << (ver_count > 1 ? "multiple old versions" : "an older version") << " of ceph";
+ health_status_t status;
+ if (ver_count > 1)
+ status = HEALTH_ERR;
+ else
+ status = HEALTH_WARN;
+ auto& d = next.add("DAEMON_OLD_VERSION", status, ss.str(), all_versions.size());
+ for (auto& g:all_versions) {
+ ostringstream ds;
+ for (auto& i : g.second) { // Daemon list
+ ds << i << " ";
+ }
+ ds << (g.second.size() == 1 ? "is" : "are")
+ << " running an older version of ceph: " << g.first;
+ d.detail.push_back(ds.str());
+ }
+ }
+ }
+
// MON_DOWN
{
int max = mon->monmap->size();
f->close_section();
}
+void Monitor::get_all_versions(std::map<string, list<string> > &versions)
+{
+ // mon
+ get_versions(versions);
+ dout(20) << __func__ << " all versions=" << versions << dendl;
+}
+
+void Monitor::get_versions(std::map<string, list<string> > &versions)
+{
+ int i = 0;
+ for (auto& [rank, metadata] : mon_metadata) {
+ auto q = metadata.find("ceph_version_short");
+ versions[q->second].push_back(string("mon.") + monmap->get_name(rank));
+ i = i + 1;
+ }
+}
+
int Monitor::print_nodes(Formatter *f, ostream& err)
{
map<string, list<string> > mons; // hostname => mon
int load_metadata();
void count_metadata(const std::string& field, ceph::Formatter *f);
void count_metadata(const std::string& field, std::map<std::string,int> *out);
+ // get_all_versions() gathers version information from daemons for health check
+ void get_all_versions(std::map<string, list<string> > &versions);
+ void get_versions(std::map<string, list<string> > &versions);
// features
static CompatSet get_initial_supported_features();