From 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 20:24:20 +0200 Subject: Adding upstream version 14.2.21. Signed-off-by: Daniel Baumann --- src/common/options.cc | 8633 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 8633 insertions(+) create mode 100644 src/common/options.cc (limited to 'src/common/options.cc') diff --git a/src/common/options.cc b/src/common/options.cc new file mode 100644 index 00000000..768d6505 --- /dev/null +++ b/src/common/options.cc @@ -0,0 +1,8633 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "acconfig.h" +#include "options.h" +#include "common/Formatter.h" + +// Helpers for validators +#include "include/stringify.h" +#include +#include +#include + +// Definitions for enums +#include "common/perf_counters.h" + +// rbd feature validation +#include "librbd/Features.h" + +namespace { +class printer : public boost::static_visitor<> { + ostream& out; +public: + explicit printer(ostream& os) + : out(os) {} + template + void operator()(const T& v) const { + out << v; + } + void operator()(boost::blank blank) const { + return; + } + void operator()(bool v) const { + out << (v ? "true" : "false"); + } + void operator()(double v) const { + out << std::fixed << v << std::defaultfloat; + } + void operator()(const Option::size_t& v) const { + out << v.value; + } + void operator()(const std::chrono::seconds v) const { + out << v.count(); + } +}; +} + +ostream& operator<<(ostream& os, const Option::value_t& v) { + printer p{os}; + v.apply_visitor(p); + return os; +} + +void Option::dump_value(const char *field_name, + const Option::value_t &v, Formatter *f) const +{ + if (boost::get(&v)) { + // This should be nil but Formatter doesn't allow it. + f->dump_string(field_name, ""); + return; + } + switch (type) { + case TYPE_INT: + f->dump_int(field_name, boost::get(v)); break; + case TYPE_UINT: + f->dump_unsigned(field_name, boost::get(v)); break; + case TYPE_STR: + f->dump_string(field_name, boost::get(v)); break; + case TYPE_FLOAT: + f->dump_float(field_name, boost::get(v)); break; + case TYPE_BOOL: + f->dump_bool(field_name, boost::get(v)); break; + default: + f->dump_stream(field_name) << v; break; + } +} + +int Option::pre_validate(std::string *new_value, std::string *err) const +{ + if (validator) { + return validator(new_value, err); + } else { + return 0; + } +} + +int Option::validate(const Option::value_t &new_value, std::string *err) const +{ + // Generic validation: min + if (!boost::get(&(min))) { + if (new_value < min) { + std::ostringstream oss; + oss << "Value '" << new_value << "' is below minimum " << min; + *err = oss.str(); + return -EINVAL; + } + } + + // Generic validation: max + if (!boost::get(&(max))) { + if (new_value > max) { + std::ostringstream oss; + oss << "Value '" << new_value << "' exceeds maximum " << max; + *err = oss.str(); + return -EINVAL; + } + } + + // Generic validation: enum + if (!enum_allowed.empty() && type == Option::TYPE_STR) { + auto found = std::find(enum_allowed.begin(), enum_allowed.end(), + boost::get(new_value)); + if (found == enum_allowed.end()) { + std::ostringstream oss; + oss << "'" << new_value << "' is not one of the permitted " + "values: " << joinify(enum_allowed.begin(), + enum_allowed.end(), + std::string(", ")); + *err = oss.str(); + return -EINVAL; + } + } + + return 0; +} + +int Option::parse_value( + const std::string& raw_val, + value_t *out, + std::string *error_message, + std::string *normalized_value) const +{ + std::string val = raw_val; + + int r = pre_validate(&val, error_message); + if (r != 0) { + return r; + } + + if (type == Option::TYPE_INT) { + int64_t f = strict_si_cast(val.c_str(), error_message); + if (!error_message->empty()) { + return -EINVAL; + } + *out = f; + } else if (type == Option::TYPE_UINT) { + uint64_t f = strict_si_cast(val.c_str(), error_message); + if (!error_message->empty()) { + return -EINVAL; + } + *out = f; + } else if (type == Option::TYPE_STR) { + *out = val; + } else if (type == Option::TYPE_FLOAT) { + double f = strict_strtod(val.c_str(), error_message); + if (!error_message->empty()) { + return -EINVAL; + } else { + *out = f; + } + } else if (type == Option::TYPE_BOOL) { + if (strcasecmp(val.c_str(), "false") == 0) { + *out = false; + } else if (strcasecmp(val.c_str(), "true") == 0) { + *out = true; + } else { + int b = strict_strtol(val.c_str(), 10, error_message); + if (!error_message->empty()) { + return -EINVAL; + } + *out = (bool)!!b; + } + } else if (type == Option::TYPE_ADDR) { + entity_addr_t addr; + if (!addr.parse(val.c_str())){ + return -EINVAL; + } + *out = addr; + } else if (type == Option::TYPE_ADDR) { + entity_addrvec_t addr; + if (!addr.parse(val.c_str())){ + return -EINVAL; + } + *out = addr; + } else if (type == Option::TYPE_UUID) { + uuid_d uuid; + if (!uuid.parse(val.c_str())) { + return -EINVAL; + } + *out = uuid; + } else if (type == Option::TYPE_SIZE) { + Option::size_t sz{strict_iecstrtoll(val.c_str(), error_message)}; + if (!error_message->empty()) { + return -EINVAL; + } + *out = sz; + } else if (type == Option::TYPE_SECS) { + try { + *out = parse_timespan(val); + } catch (const invalid_argument& e) { + *error_message = e.what(); + return -EINVAL; + } + } else { + ceph_abort(); + } + + r = validate(*out, error_message); + if (r != 0) { + return r; + } + + if (normalized_value) { + *normalized_value = to_str(*out); + } + return 0; +} + +void Option::dump(Formatter *f) const +{ + f->dump_string("name", name); + + f->dump_string("type", type_to_str(type)); + + f->dump_string("level", level_to_str(level)); + + f->dump_string("desc", desc); + f->dump_string("long_desc", long_desc); + + dump_value("default", value, f); + dump_value("daemon_default", daemon_value, f); + + f->open_array_section("tags"); + for (const auto t : tags) { + f->dump_string("tag", t); + } + f->close_section(); + + f->open_array_section("services"); + for (const auto s : services) { + f->dump_string("service", s); + } + f->close_section(); + + f->open_array_section("see_also"); + for (const auto sa : see_also) { + f->dump_string("see_also", sa); + } + f->close_section(); + + if (type == TYPE_STR) { + f->open_array_section("enum_values"); + for (const auto &ea : enum_allowed) { + f->dump_string("enum_value", ea); + } + f->close_section(); + } + + dump_value("min", min, f); + dump_value("max", max, f); + + f->dump_bool("can_update_at_runtime", can_update_at_runtime()); + + f->open_array_section("flags"); + if (has_flag(FLAG_RUNTIME)) { + f->dump_string("option", "runtime"); + } + if (has_flag(FLAG_NO_MON_UPDATE)) { + f->dump_string("option", "no_mon_update"); + } + if (has_flag(FLAG_STARTUP)) { + f->dump_string("option", "startup"); + } + if (has_flag(FLAG_CLUSTER_CREATE)) { + f->dump_string("option", "cluster_create"); + } + if (has_flag(FLAG_CREATE)) { + f->dump_string("option", "create"); + } + f->close_section(); +} + +std::string Option::to_str(const Option::value_t& v) +{ + return stringify(v); +} + +void Option::print(ostream *out) const +{ + *out << name << " - " << desc << "\n"; + *out << " (" << type_to_str(type) << ", " << level_to_str(level) << ")\n"; + if (!boost::get(&daemon_value)) { + *out << " Default (non-daemon): " << stringify(value) << "\n"; + *out << " Default (daemon): " << stringify(daemon_value) << "\n"; + } else { + *out << " Default: " << stringify(value) << "\n"; + } + if (!enum_allowed.empty()) { + *out << " Possible values: "; + for (auto& i : enum_allowed) { + *out << " " << stringify(i); + } + *out << "\n"; + } + if (!boost::get(&min)) { + *out << " Minimum: " << stringify(min) << "\n" + << " Maximum: " << stringify(max) << "\n"; + } + *out << " Can update at runtime: " + << (can_update_at_runtime() ? "true" : "false") << "\n"; + if (!services.empty()) { + *out << " Services: " << services << "\n"; + } + if (!tags.empty()) { + *out << " Tags: " << tags << "\n"; + } + if (!see_also.empty()) { + *out << " See also: " << see_also << "\n"; + } + + if (long_desc.size()) { + *out << "\n" << long_desc << "\n"; + } +} + +constexpr unsigned long long operator"" _min (unsigned long long min) { + return min * 60; +} +constexpr unsigned long long operator"" _hr (unsigned long long hr) { + return hr * 60 * 60; +} +constexpr unsigned long long operator"" _day (unsigned long long day) { + return day * 60 * 60 * 24; +} +constexpr unsigned long long operator"" _K (unsigned long long n) { + return n << 10; +} +constexpr unsigned long long operator"" _M (unsigned long long n) { + return n << 20; +} +constexpr unsigned long long operator"" _G (unsigned long long n) { + return n << 30; +} + +std::vector