From e6918187568dbd01842d8d1d2c808ce16a894239 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 21 Apr 2024 13:54:28 +0200 Subject: Adding upstream version 18.2.2. Signed-off-by: Daniel Baumann --- src/mon/ConfigMap.cc | 291 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 src/mon/ConfigMap.cc (limited to 'src/mon/ConfigMap.cc') diff --git a/src/mon/ConfigMap.cc b/src/mon/ConfigMap.cc new file mode 100644 index 000000000..763b8ce9b --- /dev/null +++ b/src/mon/ConfigMap.cc @@ -0,0 +1,291 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include + +#include "ConfigMap.h" +#include "crush/CrushWrapper.h" +#include "common/entity_name.h" + +using namespace std::literals; + +using std::cerr; +using std::cout; +using std::dec; +using std::hex; +using std::list; +using std::map; +using std::make_pair; +using std::ostream; +using std::ostringstream; +using std::pair; +using std::set; +using std::setfill; +using std::string; +using std::stringstream; +using std::to_string; +using std::vector; +using std::unique_ptr; + +using ceph::bufferlist; +using ceph::decode; +using ceph::encode; +using ceph::Formatter; +using ceph::JSONFormatter; +using ceph::mono_clock; +using ceph::mono_time; +using ceph::timespan_str; + +int MaskedOption::get_precision(const CrushWrapper *crush) +{ + // 0 = most precise + if (mask.location_type.size()) { + int r = crush->get_type_id(mask.location_type); + if (r >= 0) { + return r; + } + // bad type name, ignore it + } + int num_types = crush->get_num_type_names(); + if (mask.device_class.size()) { + return num_types; + } + return num_types + 1; +} + +void OptionMask::dump(Formatter *f) const +{ + if (location_type.size()) { + f->dump_string("location_type", location_type); + f->dump_string("location_value", location_value); + } + if (device_class.size()) { + f->dump_string("device_class", device_class); + } +} + +void MaskedOption::dump(Formatter *f) const +{ + f->dump_string("name", opt->name); + f->dump_string("value", raw_value); + f->dump_string("level", Option::level_to_str(opt->level)); + f->dump_bool("can_update_at_runtime", opt->can_update_at_runtime()); + f->dump_string("mask", mask.to_str()); + mask.dump(f); +} + +ostream& operator<<(ostream& out, const MaskedOption& o) +{ + out << o.opt->name; + if (o.mask.location_type.size()) { + out << "@" << o.mask.location_type << '=' << o.mask.location_value; + } + if (o.mask.device_class.size()) { + out << "@class=" << o.mask.device_class; + } + return out; +} + +// ---------- + +void Section::dump(Formatter *f) const +{ + for (auto& i : options) { + f->dump_object(i.first.c_str(), i.second); + } +} + +std::string Section::get_minimal_conf() const +{ + std::string r; + for (auto& i : options) { + if (i.second.opt->has_flag(Option::FLAG_NO_MON_UPDATE) || + i.second.opt->has_flag(Option::FLAG_MINIMAL_CONF)) { + if (i.second.mask.empty()) { + r += "\t"s + i.first + " = " + i.second.raw_value + "\n"; + } else { + r += "\t# masked option excluded: " + i.first + " = " + + i.second.raw_value + "\n"; + } + } + } + return r; +} + + +// ------------ + +void ConfigMap::dump(Formatter *f) const +{ + f->dump_object("global", global); + f->open_object_section("by_type"); + for (auto& i : by_type) { + f->dump_object(i.first.c_str(), i.second); + } + f->close_section(); + f->open_object_section("by_id"); + for (auto& i : by_id) { + f->dump_object(i.first.c_str(), i.second); + } + f->close_section(); +} + +std::map> +ConfigMap::generate_entity_map( + const EntityName& name, + const map& crush_location, + const CrushWrapper *crush, + const std::string& device_class, + std::map> *src) +{ + // global, then by type, then by name prefix component(s), then name. + // name prefix components are .-separated, + // e.g. client.a.b.c -> [global, client, client.a, client.a.b, client.a.b.c] + vector> sections = { make_pair("global", &global) }; + auto p = by_type.find(name.get_type_name()); + if (p != by_type.end()) { + sections.emplace_back(name.get_type_name(), &p->second); + } + vector name_bits; + boost::split(name_bits, name.to_str(), [](char c){ return c == '.'; }); + std::string tname; + for (unsigned p = 0; p < name_bits.size(); ++p) { + if (p) { + tname += '.'; + } + tname += name_bits[p]; + auto q = by_id.find(tname); + if (q != by_id.end()) { + sections.push_back(make_pair(tname, &q->second)); + } + } + std::map> out; + MaskedOption *prev = nullptr; + for (auto s : sections) { + for (auto& i : s.second->options) { + auto& o = i.second; + // match against crush location, class + if (o.mask.device_class.size() && + o.mask.device_class != device_class) { + continue; + } + if (o.mask.location_type.size()) { + auto p = crush_location.find(o.mask.location_type); + if (p == crush_location.end() || + p->second != o.mask.location_value) { + continue; + } + } + if (prev && prev->opt->name != i.first) { + prev = nullptr; + } + if (prev && + prev->get_precision(crush) < o.get_precision(crush)) { + continue; + } + out[i.first] = o.raw_value; + if (src) { + (*src)[i.first] = make_pair(s.first, &o); + } + prev = &o; + } + } + return out; +} + +bool ConfigMap::parse_mask( + const std::string& who, + std::string *section, + OptionMask *mask) +{ + vector split; + boost::split(split, who, [](char c){ return c == '/'; }); + for (unsigned j = 0; j < split.size(); ++j) { + auto& i = split[j]; + if (i == "global") { + *section = "global"; + continue; + } + size_t delim = i.find(':'); + if (delim != std::string::npos) { + string k = i.substr(0, delim); + if (k == "class") { + mask->device_class = i.substr(delim + 1); + } else { + mask->location_type = k; + mask->location_value = i.substr(delim + 1); + } + continue; + } + string type, id; + auto dotpos = i.find('.'); + if (dotpos != std::string::npos) { + type = i.substr(0, dotpos); + id = i.substr(dotpos + 1); + } else { + type = i; + } + if (EntityName::str_to_ceph_entity_type(type) == CEPH_ENTITY_TYPE_ANY) { + return false; + } + *section = i; + } + return true; +} + +void ConfigMap::parse_key( + const std::string& key, + std::string *name, + std::string *who) +{ + auto last_slash = key.rfind('/'); + if (last_slash == std::string::npos) { + *name = key; + } else if (auto mgrpos = key.find("/mgr/"); mgrpos != std::string::npos) { + *name = key.substr(mgrpos + 1); + *who = key.substr(0, mgrpos); + } else { + *name = key.substr(last_slash + 1); + *who = key.substr(0, last_slash); + } +} + + +// -------------- + +void ConfigChangeSet::dump(Formatter *f) const +{ + f->dump_int("version", version); + f->dump_stream("timestamp") << stamp; + f->dump_string("name", name); + f->open_array_section("changes"); + for (auto& i : diff) { + f->open_object_section("change"); + f->dump_string("name", i.first); + if (i.second.first) { + f->dump_string("previous_value", *i.second.first); + } + if (i.second.second) { + f->dump_string("new_value", *i.second.second); + } + f->close_section(); + } + f->close_section(); +} + +void ConfigChangeSet::print(ostream& out) const +{ + out << "--- " << version << " --- " << stamp; + if (name.size()) { + out << " --- " << name; + } + out << " ---\n"; + for (auto& i : diff) { + if (i.second.first) { + out << "- " << i.first << " = " << *i.second.first << "\n"; + } + if (i.second.second) { + out << "+ " << i.first << " = " << *i.second.second << "\n"; + } + } +} -- cgit v1.2.3