diff options
Diffstat (limited to 'src/mon/MgrMap.h')
-rw-r--r-- | src/mon/MgrMap.h | 639 |
1 files changed, 639 insertions, 0 deletions
diff --git a/src/mon/MgrMap.h b/src/mon/MgrMap.h new file mode 100644 index 000000000..f37ed97fd --- /dev/null +++ b/src/mon/MgrMap.h @@ -0,0 +1,639 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2016 John Spray <john.spray@redhat.com> + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + */ + +#ifndef MGR_MAP_H_ +#define MGR_MAP_H_ + +#include <sstream> +#include <set> + +#include "msg/msg_types.h" +#include "include/encoding.h" +#include "include/utime.h" +#include "common/Formatter.h" +#include "common/ceph_releases.h" +#include "common/version.h" +#include "common/options.h" +#include "common/Clock.h" + + +class MgrMap +{ +public: + struct ModuleOption { + std::string name; + uint8_t type = Option::TYPE_STR; // Option::type_t TYPE_* + uint8_t level = Option::LEVEL_ADVANCED; // Option::level_t LEVEL_* + uint32_t flags = 0; // Option::flag_t FLAG_* + std::string default_value; + std::string min, max; + std::set<std::string> enum_allowed; + std::string desc, long_desc; + std::set<std::string> tags; + std::set<std::string> see_also; + + void encode(ceph::buffer::list& bl) const { + ENCODE_START(1, 1, bl); + encode(name, bl); + encode(type, bl); + encode(level, bl); + encode(flags, bl); + encode(default_value, bl); + encode(min, bl); + encode(max, bl); + encode(enum_allowed, bl); + encode(desc, bl); + encode(long_desc, bl); + encode(tags, bl); + encode(see_also, bl); + ENCODE_FINISH(bl); + } + void decode(ceph::buffer::list::const_iterator& p) { + DECODE_START(1, p); + decode(name, p); + decode(type, p); + decode(level, p); + decode(flags, p); + decode(default_value, p); + decode(min, p); + decode(max, p); + decode(enum_allowed, p); + decode(desc, p); + decode(long_desc, p); + decode(tags, p); + decode(see_also, p); + DECODE_FINISH(p); + } + void dump(ceph::Formatter *f) const { + f->dump_string("name", name); + f->dump_string("type", Option::type_to_str( + static_cast<Option::type_t>(type))); + f->dump_string("level", Option::level_to_str( + static_cast<Option::level_t>(level))); + f->dump_unsigned("flags", flags); + f->dump_string("default_value", default_value); + f->dump_string("min", min); + f->dump_string("max", max); + f->open_array_section("enum_allowed"); + for (auto& i : enum_allowed) { + f->dump_string("value", i); + } + f->close_section(); + f->dump_string("desc", desc); + f->dump_string("long_desc", long_desc); + f->open_array_section("tags"); + for (auto& i : tags) { + f->dump_string("tag", i); + } + f->close_section(); + f->open_array_section("see_also"); + for (auto& i : see_also) { + f->dump_string("option", i); + } + f->close_section(); + } + }; + + class ModuleInfo + { + public: + std::string name; + bool can_run = true; + std::string error_string; + std::map<std::string,ModuleOption> module_options; + + // We do not include the module's `failed` field in the beacon, + // because it is exposed via health checks. + void encode(ceph::buffer::list &bl) const { + ENCODE_START(2, 1, bl); + encode(name, bl); + encode(can_run, bl); + encode(error_string, bl); + encode(module_options, bl); + ENCODE_FINISH(bl); + } + + void decode(ceph::buffer::list::const_iterator &bl) { + DECODE_START(1, bl); + decode(name, bl); + decode(can_run, bl); + decode(error_string, bl); + if (struct_v >= 2) { + decode(module_options, bl); + } + DECODE_FINISH(bl); + } + + bool operator==(const ModuleInfo &rhs) const + { + return (name == rhs.name) && (can_run == rhs.can_run); + } + + void dump(ceph::Formatter *f) const { + f->open_object_section("module"); + f->dump_string("name", name); + f->dump_bool("can_run", can_run); + f->dump_string("error_string", error_string); + f->open_object_section("module_options"); + for (auto& i : module_options) { + f->dump_object(i.first.c_str(), i.second); + } + f->close_section(); + f->close_section(); + } + }; + + class StandbyInfo + { + public: + uint64_t gid = 0; + std::string name; + std::vector<ModuleInfo> available_modules; + uint64_t mgr_features = 0; + + StandbyInfo(uint64_t gid_, const std::string &name_, + const std::vector<ModuleInfo>& am, + uint64_t feat) + : gid(gid_), name(name_), available_modules(am), + mgr_features(feat) + {} + + StandbyInfo() {} + + void encode(ceph::buffer::list& bl) const + { + ENCODE_START(4, 1, bl); + encode(gid, bl); + encode(name, bl); + std::set<std::string> old_available_modules; + for (const auto &i : available_modules) { + old_available_modules.insert(i.name); + } + encode(old_available_modules, bl); // version 2 + encode(available_modules, bl); // version 3 + encode(mgr_features, bl); // v4 + ENCODE_FINISH(bl); + } + + void decode(ceph::buffer::list::const_iterator& p) + { + DECODE_START(4, p); + decode(gid, p); + decode(name, p); + if (struct_v >= 2) { + std::set<std::string> old_available_modules; + decode(old_available_modules, p); + if (struct_v < 3) { + for (const auto &name : old_available_modules) { + MgrMap::ModuleInfo info; + info.name = name; + available_modules.push_back(std::move(info)); + } + } + } + if (struct_v >= 3) { + decode(available_modules, p); + } + if (struct_v >= 4) { + decode(mgr_features, p); + } + DECODE_FINISH(p); + } + + bool have_module(const std::string &module_name) const + { + auto it = std::find_if(available_modules.begin(), + available_modules.end(), + [module_name](const ModuleInfo &m) -> bool { + return m.name == module_name; + }); + + return it != available_modules.end(); + } + }; + + epoch_t epoch = 0; + epoch_t last_failure_osd_epoch = 0; + + /// global_id of the ceph-mgr instance selected as a leader + uint64_t active_gid = 0; + /// server address reported by the leader once it is active + entity_addrvec_t active_addrs; + /// whether the nominated leader is active (i.e. has initialized its server) + bool available = false; + /// the name (foo in mgr.<foo>) of the active daemon + std::string active_name; + /// when the active mgr became active, or we lost the active mgr + utime_t active_change; + /// features + uint64_t active_mgr_features = 0; + + std::multimap<std::string, entity_addrvec_t> clients; // for blocklist + + std::map<uint64_t, StandbyInfo> standbys; + + // Modules which are enabled + std::set<std::string> modules; + + // Modules which should always be enabled. A manager daemon will enable + // modules from the union of this set and the `modules` set above, latest + // active version. + std::map<uint32_t, std::set<std::string>> always_on_modules; + + // Modules which are reported to exist + std::vector<ModuleInfo> available_modules; + + // Map of module name to URI, indicating services exposed by + // running modules on the active mgr daemon. + std::map<std::string, std::string> services; + + static MgrMap create_null_mgrmap() { + MgrMap null_map; + /* Use the largest epoch so it's always bigger than whatever the mgr has. */ + null_map.epoch = std::numeric_limits<decltype(epoch)>::max(); + return null_map; + } + + epoch_t get_epoch() const { return epoch; } + epoch_t get_last_failure_osd_epoch() const { return last_failure_osd_epoch; } + const entity_addrvec_t& get_active_addrs() const { return active_addrs; } + uint64_t get_active_gid() const { return active_gid; } + bool get_available() const { return available; } + const std::string &get_active_name() const { return active_name; } + const utime_t& get_active_change() const { return active_change; } + int get_num_standby() const { return standbys.size(); } + + bool all_support_module(const std::string& module) { + if (!have_module(module)) { + return false; + } + for (auto& p : standbys) { + if (!p.second.have_module(module)) { + return false; + } + } + return true; + } + + bool have_module(const std::string &module_name) const + { + for (const auto &i : available_modules) { + if (i.name == module_name) { + return true; + } + } + + return false; + } + + const ModuleInfo *get_module_info(const std::string &module_name) const { + for (const auto &i : available_modules) { + if (i.name == module_name) { + return &i; + } + } + return nullptr; + } + + bool can_run_module(const std::string &module_name, std::string *error) const + { + for (const auto &i : available_modules) { + if (i.name == module_name) { + *error = i.error_string; + return i.can_run; + } + } + + std::ostringstream oss; + oss << "Module '" << module_name << "' does not exist"; + throw std::logic_error(oss.str()); + } + + bool module_enabled(const std::string& module_name) const + { + return modules.find(module_name) != modules.end(); + } + + bool any_supports_module(const std::string& module) const { + if (have_module(module)) { + return true; + } + for (auto& p : standbys) { + if (p.second.have_module(module)) { + return true; + } + } + return false; + } + + bool have_name(const std::string& name) const { + if (active_name == name) { + return true; + } + for (auto& p : standbys) { + if (p.second.name == name) { + return true; + } + } + return false; + } + + std::set<std::string> get_all_names() const { + std::set<std::string> ls; + if (active_name.size()) { + ls.insert(active_name); + } + for (auto& p : standbys) { + ls.insert(p.second.name); + } + return ls; + } + + std::set<std::string> get_always_on_modules() const { + unsigned rnum = to_integer<uint32_t>(ceph_release()); + auto it = always_on_modules.find(rnum); + if (it == always_on_modules.end()) { + // ok, try the most recent release + if (always_on_modules.empty()) { + return {}; // ugh + } + --it; + if (it->first < rnum) { + return it->second; + } + return {}; // wth + } + return it->second; + } + + void encode(ceph::buffer::list& bl, uint64_t features) const + { + if (!HAVE_FEATURE(features, SERVER_NAUTILUS)) { + ENCODE_START(5, 1, bl); + encode(epoch, bl); + encode(active_addrs.legacy_addr(), bl, features); + encode(active_gid, bl); + encode(available, bl); + encode(active_name, bl); + encode(standbys, bl); + encode(modules, bl); + + // Pre-version 4 std::string std::list of available modules + // (replaced by direct encode of ModuleInfo below) + std::set<std::string> old_available_modules; + for (const auto &i : available_modules) { + old_available_modules.insert(i.name); + } + encode(old_available_modules, bl); + + encode(services, bl); + encode(available_modules, bl); + ENCODE_FINISH(bl); + return; + } + ENCODE_START(12, 6, bl); + encode(epoch, bl); + encode(active_addrs, bl, features); + encode(active_gid, bl); + encode(available, bl); + encode(active_name, bl); + encode(standbys, bl); + encode(modules, bl); + encode(services, bl); + encode(available_modules, bl); + encode(active_change, bl); + encode(always_on_modules, bl); + encode(active_mgr_features, bl); + encode(last_failure_osd_epoch, bl); + std::vector<std::string> clients_names; + std::vector<entity_addrvec_t> clients_addrs; + for (const auto& i : clients) { + clients_names.push_back(i.first); + clients_addrs.push_back(i.second); + } + // The address vector needs to be encoded first to produce a + // backwards compatible messsage for older monitors. + encode(clients_addrs, bl, features); + encode(clients_names, bl, features); + ENCODE_FINISH(bl); + return; + } + + void decode(ceph::buffer::list::const_iterator& p) + { + DECODE_START(12, p); + decode(epoch, p); + decode(active_addrs, p); + decode(active_gid, p); + decode(available, p); + decode(active_name, p); + decode(standbys, p); + if (struct_v >= 2) { + decode(modules, p); + + if (struct_v < 6) { + // Reconstitute ModuleInfos from names + std::set<std::string> module_name_list; + decode(module_name_list, p); + // Only need to unpack this field if we won't have the full + // MgrMap::ModuleInfo structures added in v4 + if (struct_v < 4) { + for (const auto &i : module_name_list) { + MgrMap::ModuleInfo info; + info.name = i; + available_modules.push_back(std::move(info)); + } + } + } + } + if (struct_v >= 3) { + decode(services, p); + } + if (struct_v >= 4) { + decode(available_modules, p); + } + if (struct_v >= 7) { + decode(active_change, p); + } else { + active_change = {}; + } + if (struct_v >= 8) { + decode(always_on_modules, p); + } + if (struct_v >= 9) { + decode(active_mgr_features, p); + } + if (struct_v >= 10) { + decode(last_failure_osd_epoch, p); + } + if (struct_v >= 11) { + std::vector<entity_addrvec_t> clients_addrs; + decode(clients_addrs, p); + clients.clear(); + if (struct_v >= 12) { + std::vector<std::string> clients_names; + decode(clients_names, p); + if (clients_names.size() != clients_addrs.size()) { + throw ceph::buffer::malformed_input( + "clients_names.size() != clients_addrs.size()"); + } + auto cn = clients_names.begin(); + auto ca = clients_addrs.begin(); + for(; cn != clients_names.end(); ++cn, ++ca) { + clients.emplace(*cn, *ca); + } + } else { + for (const auto& i : clients_addrs) { + clients.emplace("", i); + } + } + } + DECODE_FINISH(p); + } + + void dump(ceph::Formatter *f) const { + f->dump_int("epoch", epoch); + f->dump_int("active_gid", get_active_gid()); + f->dump_string("active_name", get_active_name()); + f->dump_object("active_addrs", active_addrs); + f->dump_stream("active_addr") << active_addrs.get_legacy_str(); + f->dump_stream("active_change") << active_change; + f->dump_unsigned("active_mgr_features", active_mgr_features); + f->dump_bool("available", available); + f->open_array_section("standbys"); + for (const auto &i : standbys) { + f->open_object_section("standby"); + f->dump_int("gid", i.second.gid); + f->dump_string("name", i.second.name); + f->dump_unsigned("mgr_features", i.second.mgr_features); + f->open_array_section("available_modules"); + for (const auto& j : i.second.available_modules) { + j.dump(f); + } + f->close_section(); + f->close_section(); + } + f->close_section(); + f->open_array_section("modules"); + for (auto& i : modules) { + f->dump_string("module", i); + } + f->close_section(); + f->open_array_section("available_modules"); + for (const auto& j : available_modules) { + j.dump(f); + } + f->close_section(); + + f->open_object_section("services"); + for (const auto &i : services) { + f->dump_string(i.first.c_str(), i.second); + } + f->close_section(); + + f->open_object_section("always_on_modules"); + for (auto& v : always_on_modules) { + f->open_array_section(ceph_release_name(v.first)); + for (auto& m : v.second) { + f->dump_string("module", m); + } + f->close_section(); + } + f->close_section(); // always_on_modules + f->dump_int("last_failure_osd_epoch", last_failure_osd_epoch); + f->open_array_section("active_clients"); + for (const auto& i : clients) { + f->open_object_section("client"); + f->dump_string("name", i.first); + i.second.dump(f); + f->close_section(); + } + f->close_section(); // active_clients + } + + static void generate_test_instances(std::list<MgrMap*> &l) { + l.push_back(new MgrMap); + } + + void print_summary(ceph::Formatter *f, std::ostream *ss) const + { + // One or the other, not both + ceph_assert((ss != nullptr) != (f != nullptr)); + if (f) { + f->dump_bool("available", available); + f->dump_int("num_standbys", standbys.size()); + f->open_array_section("modules"); + for (auto& i : modules) { + f->dump_string("module", i); + } + f->close_section(); + f->open_object_section("services"); + for (const auto &i : services) { + f->dump_string(i.first.c_str(), i.second); + } + f->close_section(); + } else { + utime_t now = ceph_clock_now(); + if (get_active_gid() != 0) { + *ss << get_active_name(); + if (!available) { + // If the daemon hasn't gone active yet, indicate that. + *ss << "(active, starting"; + } else { + *ss << "(active"; + } + if (active_change) { + *ss << ", since " << utimespan_str(now - active_change); + } + *ss << ")"; + } else { + *ss << "no daemons active"; + if (active_change) { + *ss << " (since " << utimespan_str(now - active_change) << ")"; + } + } + if (standbys.size()) { + *ss << ", standbys: "; + bool first = true; + for (const auto &i : standbys) { + if (!first) { + *ss << ", "; + } + *ss << i.second.name; + first = false; + } + } + } + } + + friend std::ostream& operator<<(std::ostream& out, const MgrMap& m) { + std::ostringstream ss; + m.print_summary(nullptr, &ss); + return out << ss.str(); + } + + friend std::ostream& operator<<(std::ostream& out, const std::vector<ModuleInfo>& mi) { + for (const auto &i : mi) { + out << i.name << " "; + } + return out; + } +}; + +WRITE_CLASS_ENCODER_FEATURES(MgrMap) +WRITE_CLASS_ENCODER(MgrMap::StandbyInfo) +WRITE_CLASS_ENCODER(MgrMap::ModuleInfo); +WRITE_CLASS_ENCODER(MgrMap::ModuleOption); + +#endif + |