#ifndef CEPH_CONFIG_H
#define CEPH_CONFIG_H
+#include <map>
+#include <boost/container/small_vector.hpp>
#include "common/ConfUtils.h"
-#include "common/entity_name.h"
#include "common/code_environment.h"
-#include "common/Mutex.h"
-#include "common/CondVar.h"
#include "log/SubsystemMap.h"
-#include "common/config_obs.h"
#include "common/options.h"
+#include "common/subsys_types.h"
+#include "common/config_tracker.h"
+#include "common/config_values.h"
+#include "include/common_fwd.h"
+
+enum {
+ CONF_DEFAULT,
+ CONF_MON,
+ CONF_FILE,
+ CONF_ENV,
+ CONF_CMDLINE,
+ CONF_OVERRIDE,
+ CONF_FINAL
+};
-#define OSD_REP_PRIMARY 0
-#define OSD_REP_SPLAY 1
-#define OSD_REP_CHAIN 2
-
-class CephContext;
-
-extern const char *CEPH_CONF_FILE_DEFAULT;
-
-#define LOG_TO_STDERR_NONE 0
-#define LOG_TO_STDERR_SOME 1
-#define LOG_TO_STDERR_ALL 2
+extern const char *ceph_conf_level_name(int level);
/** This class represents the current Ceph configuration.
*
* There are 3 ways to read the ceph context-- the old way and two new ways.
* In the old way, code would simply read the public variables of the
* configuration, without taking a lock. In the new way #1, code registers a
- * configuration obserever which receives callbacks when a value changes. These
+ * configuration observer which receives callbacks when a value changes. These
* callbacks take place under the md_config_t lock. Alternatively one can use
* get_val(const char *name) method to safely get a copy of the value.
*
* To prevent serious problems resulting from thread-safety issues, we disallow
* changing std::string configuration values after
- * md_config_t::internal_safe_to_start_threads becomes true. You can still
+ * md_config_t::safe_to_start_threads becomes true. You can still
* change integer or floating point values, and the option declared with
* SAFE_OPTION macro. Notice the latter options can not be read directly
* (conf->foo), one should use either observers or get_val() method
* while another thread is reading them, either.
*/
struct md_config_t {
-private:
- class CallGate {
- private:
- uint32_t call_count = 0;
- Mutex lock;
- Cond cond;
- public:
- CallGate()
- : lock("call::gate::lock", false, true) {
- }
-
- void enter() {
- Mutex::Locker locker(lock);
- ++call_count;
- }
- void leave() {
- Mutex::Locker locker(lock);
- ceph_assert(call_count > 0);
- if (--call_count == 0) {
- cond.Signal();
- }
- }
- void close() {
- Mutex::Locker locker(lock);
- while (call_count != 0) {
- cond.Wait(lock);
- }
- }
- };
-
- void call_gate_enter(md_config_obs_t *obs) {
- auto p = obs_call_gate.find(obs);
- ceph_assert(p != obs_call_gate.end());
- p->second->enter();
- }
- void call_gate_leave(md_config_obs_t *obs) {
- auto p = obs_call_gate.find(obs);
- ceph_assert(p != obs_call_gate.end());
- p->second->leave();
- }
- void call_gate_close(md_config_obs_t *obs) {
- auto p = obs_call_gate.find(obs);
- ceph_assert(p != obs_call_gate.end());
- p->second->close();
- }
-
- typedef std::unique_ptr<CallGate> CallGateRef;
- std::map<md_config_obs_t*, CallGateRef> obs_call_gate;
-
- typedef std::map<md_config_obs_t*, std::set<std::string>> rev_obs_map_t;
- typedef std::function<void(md_config_obs_t*, const std::string&)> config_gather_cb;
-
- void call_observers(rev_obs_map_t &rev_obs);
- void map_observer_changes(md_config_obs_t *obs, const std::string &key,
- rev_obs_map_t *rev_obs);
-
public:
- typedef boost::variant<int64_t md_config_t::*,
- uint64_t md_config_t::*,
- std::string md_config_t::*,
- double md_config_t::*,
- bool md_config_t::*,
- entity_addr_t md_config_t::*,
- uuid_d md_config_t::*> member_ptr_t;
-
- /* Maps configuration options to the observer listening for them. */
- typedef std::multimap <std::string, md_config_obs_t*> obs_map_t;
-
- /* Set of configuration options that have changed since the last
- * apply_changes */
- typedef std::set < std::string > changed_set_t;
+ typedef boost::variant<int64_t ConfigValues::*,
+ uint64_t ConfigValues::*,
+ std::string ConfigValues::*,
+ double ConfigValues::*,
+ bool ConfigValues::*,
+ entity_addr_t ConfigValues::*,
+ entity_addrvec_t ConfigValues::*,
+ uuid_d ConfigValues::*> member_ptr_t;
+
+ // For use when intercepting configuration updates
+ typedef std::function<bool(
+ const std::string &k, const std::string &v)> config_callback;
+
+ /// true if we are a daemon (as per CephContext::code_env)
+ const bool is_daemon;
/*
* Mapping from legacy config option names to class members
*/
- std::map<std::string, md_config_t::member_ptr_t> legacy_values;
+ std::map<std::string_view, member_ptr_t> legacy_values;
/**
* The configuration schema, in the form of Option objects describing
* possible settings.
*/
- std::map<std::string, const Option &> schema;
+ std::map<std::string_view, const Option&> schema;
- /**
- * The current values of all settings described by the schema
- */
- std::map<std::string, Option::value_t> values;
+ /// values from mon that we failed to set
+ std::map<std::string,std::string> ignored_mon_values;
+
+ /// original raw values saved that may need to re-expand at certain time
+ mutable std::vector<std::string> may_reexpand_meta;
+
+ /// encoded, cached copy of of values + ignored_mon_values
+ ceph::bufferlist values_bl;
+
+ /// version for values_bl; increments each time there is a change
+ uint64_t values_bl_version = 0;
- typedef enum {
- OPT_INT, OPT_LONGLONG, OPT_STR, OPT_DOUBLE, OPT_FLOAT, OPT_BOOL,
- OPT_ADDR, OPT_U32, OPT_U64, OPT_UUID
- } opt_type_t;
+ /// encoded copy of defaults (map<string,string>)
+ ceph::bufferlist defaults_bl;
// Create a new md_config_t structure.
- md_config_t(bool is_daemon=false);
+ explicit md_config_t(ConfigValues& values,
+ const ConfigTracker& tracker,
+ bool is_daemon=false);
~md_config_t();
- // Adds a new observer to this configuration. You can do this at any time,
- // but it will only receive notifications for the changes that happen after
- // you attach it, obviously.
- //
- // Most developers will probably attach their observers after global_init,
- // but before anyone can call injectargs.
- //
- // The caller is responsible for allocating observers.
- void add_observer(md_config_obs_t* observer_);
-
- // Remove an observer from this configuration.
- // This doesn't delete the observer! If you allocated it with new(),
- // you need to delete it yourself.
- // This function will assert if you try to delete an observer that isn't
- // there.
- void remove_observer(md_config_obs_t* observer_);
-
// Parse a config file
- int parse_config_files(const char *conf_files,
+ int parse_config_files(ConfigValues& values, const ConfigTracker& tracker,
+ const char *conf_files,
std::ostream *warnings, int flags);
-
+ int parse_buffer(ConfigValues& values, const ConfigTracker& tracker,
+ const char* buf, size_t len,
+ std::ostream *warnings);
+ void update_legacy_vals(ConfigValues& values);
// Absorb config settings from the environment
- void parse_env();
+ void parse_env(unsigned entity_type,
+ ConfigValues& values, const ConfigTracker& tracker,
+ const char *env_var = "CEPH_ARGS");
// Absorb config settings from argv
- int parse_argv(std::vector<const char*>& args);
+ int parse_argv(ConfigValues& values, const ConfigTracker& tracker,
+ std::vector<const char*>& args, int level=CONF_CMDLINE);
+
+ // do any commands we got from argv (--show-config, --show-config-val)
+ void do_argv_commands(const ConfigValues& values) const;
+
+ bool _internal_field(const std::string& k);
+
+ void set_safe_to_start_threads();
+ void _clear_safe_to_start_threads(); // this is only used by the unit test
+
+ /// Look up an option in the schema
+ const Option *find_option(const std::string_view name) const;
- // Expand all metavariables. Make any pending observer callbacks.
- void apply_changes(std::ostream *oss);
- void for_each_change(std::ostream *oss, config_gather_cb callback);
- bool _internal_field(const string& k);
- void call_all_observers();
+ /// Set a default value
+ void set_val_default(ConfigValues& values,
+ const ConfigTracker& tracker,
+ const std::string_view key, const std::string &val);
+
+ /// Set a values from mon
+ int set_mon_vals(CephContext *cct,
+ ConfigValues& values,
+ const ConfigTracker& tracker,
+ const std::map<std::string,std::string, std::less<>>& kv,
+ config_callback config_cb);
// Called by the Ceph daemons to make configuration changes at runtime
- int injectargs(const std::string &s, std::ostream *oss);
+ int injectargs(ConfigValues& values,
+ const ConfigTracker& tracker,
+ const std::string &s,
+ std::ostream *oss);
// Set a configuration value, or crash
// Metavariables will be expanded.
- void set_val_or_die(const std::string &key, const std::string &val,
- bool meta=true);
+ void set_val_or_die(ConfigValues& values, const ConfigTracker& tracker,
+ const std::string_view key, const std::string &val);
// Set a configuration value.
// Metavariables will be expanded.
- int set_val(const std::string &key, const char *val, bool meta=true,
+ int set_val(ConfigValues& values, const ConfigTracker& tracker,
+ const std::string_view key, const char *val,
std::stringstream *err_ss=nullptr);
- int set_val(const std::string &key, const string& s, bool meta=true,
+ int set_val(ConfigValues& values, const ConfigTracker& tracker,
+ const std::string_view key, const std::string& s,
std::stringstream *err_ss=nullptr) {
- return set_val(key, s.c_str(), meta, err_ss);
+ return set_val(values, tracker, key, s.c_str(), err_ss);
}
+ /// clear override value
+ int rm_val(ConfigValues& values, const std::string_view key);
+
+ /// get encoded map<string,map<int32_t,string>> of entire config
+ void get_config_bl(const ConfigValues& values,
+ uint64_t have_version,
+ ceph::buffer::list *bl,
+ uint64_t *got_version);
+
+ /// get encoded map<string,string> of compiled-in defaults
+ void get_defaults_bl(const ConfigValues& values, ceph::buffer::list *bl);
+
// Get a configuration value.
// No metavariables will be returned (they will have already been expanded)
- int get_val(const std::string &key, char **buf, int len) const;
- int _get_val(const std::string &key, char **buf, int len) const;
- Option::value_t get_val_generic(const std::string &key) const;
- template<typename T> T get_val(const std::string &key) const;
+ int get_val(const ConfigValues& values, const std::string_view key, char **buf, int len) const;
+ int get_val(const ConfigValues& values, const std::string_view key, std::string *val) const;
+ template<typename T> const T get_val(const ConfigValues& values, const std::string_view key) const;
+ template<typename T, typename Callback, typename...Args>
+ auto with_val(const ConfigValues& values, const std::string_view key,
+ Callback&& cb, Args&&... args) const ->
+ std::result_of_t<Callback(const T&, Args...)> {
+ return std::forward<Callback>(cb)(
+ boost::get<T>(this->get_val_generic(values, key)),
+ std::forward<Args>(args)...);
+ }
void get_all_keys(std::vector<std::string> *keys) const;
// Return a list of all the sections that the current entity is a member of.
- void get_my_sections(std::vector <std::string> §ions) const;
+ std::vector<std::string> get_my_sections(const ConfigValues& values) const;
// Return a list of all sections
int get_all_sections(std::vector <std::string> §ions) const;
// Get a value from the configuration file that we read earlier.
// Metavariables will be expanded if emeta is true.
- int get_val_from_conf_file(const std::vector <std::string> §ions,
- std::string const &key, std::string &out, bool emeta) const;
+ int get_val_from_conf_file(const ConfigValues& values,
+ const std::vector <std::string> §ions,
+ const std::string_view key, std::string &out, bool emeta) const;
/// dump all config values to a stream
- void show_config(std::ostream& out);
+ void show_config(const ConfigValues& values, std::ostream& out) const;
/// dump all config values to a formatter
- void show_config(Formatter *f);
-
- /// dump all config settings to a formatter
- void config_options(Formatter *f);
+ void show_config(const ConfigValues& values, ceph::Formatter *f) const;
- /// obtain a diff between our config values and another md_config_t values
- void diff(const md_config_t *other,
- map<string,pair<string,string> > *diff, set<string> *unknown);
+ /// dump all config settings to a formatter
+ void config_options(ceph::Formatter *f) const;
- /// obtain a diff between config values and another md_config_t
- /// values for a specific setting.
- void diff(const md_config_t *other,
- map<string,pair<string,string>> *diff, set<string> *unknown,
- const string& setting);
+ /// dump config diff from default, conf, mon, etc.
+ void diff(const ConfigValues& values,
+ ceph::Formatter *f,
+ std::string name = {}) const;
/// print/log warnings/errors from parsing the config
- void complain_about_parse_errors(CephContext *cct);
+ void complain_about_parse_error(CephContext *cct);
private:
+ // we use this to avoid variable expansion loops
+ typedef boost::container::small_vector<std::pair<const Option*,
+ const Option::value_t*>,
+ 4> expand_stack_t;
+
void validate_schema();
void validate_default_settings();
- int _get_val(const std::string &key, std::string *value) const;
- Option::value_t _get_val(const std::string &key) const;
- void _show_config(std::ostream *out, Formatter *f);
-
- void _get_my_sections(std::vector <std::string> §ions) const;
-
- int _get_val_from_conf_file(const std::vector <std::string> §ions,
- const std::string &key, std::string &out, bool emeta) const;
-
- int parse_option(std::vector<const char*>& args,
+ Option::value_t get_val_generic(const ConfigValues& values,
+ const std::string_view key) const;
+ int _get_val_cstr(const ConfigValues& values,
+ const std::string& key, char **buf, int len) const;
+ Option::value_t _get_val(const ConfigValues& values,
+ const std::string_view key,
+ expand_stack_t *stack=0,
+ std::ostream *err=0) const;
+ Option::value_t _get_val(const ConfigValues& values,
+ const Option& o,
+ expand_stack_t *stack=0,
+ std::ostream *err=0) const;
+ const Option::value_t& _get_val_default(const Option& o) const;
+ Option::value_t _get_val_nometa(const ConfigValues& values,
+ const Option& o) const;
+
+ int _rm_val(ConfigValues& values, const std::string_view key, int level);
+
+ void _refresh(ConfigValues& values, const Option& opt);
+
+ void _show_config(const ConfigValues& values,
+ std::ostream *out, ceph::Formatter *f) const;
+
+ int _get_val_from_conf_file(const std::vector<std::string> §ions,
+ const std::string_view key, std::string &out) const;
+
+ int parse_option(ConfigValues& values,
+ const ConfigTracker& tracker,
+ std::vector<const char*>& args,
std::vector<const char*>::iterator& i,
- std::ostream *oss);
- int parse_injectargs(std::vector<const char*>& args,
- std::ostream *oss);
- int parse_config_files_impl(const std::list<std::string> &conf_files,
- std::ostream *warnings);
-
- int set_val_impl(const std::string &val, const Option &opt,
- std::string *error_message);
+ std::ostream *oss,
+ int level);
+ int parse_injectargs(ConfigValues& values,
+ const ConfigTracker& tracker,
+ std::vector<const char*>& args,
+ std::ostream *oss);
+
+ // @returns negative number for an error, otherwise a
+ // @c ConfigValues::set_value_result_t is returned.
+ int _set_val(
+ ConfigValues& values,
+ const ConfigTracker& tracker,
+ const std::string &val,
+ const Option &opt,
+ int level, // CONF_*
+ std::string *error_message);
template <typename T>
void assign_member(member_ptr_t ptr, const Option::value_t &val);
- void update_legacy_val(const Option &opt,
- md_config_t::member_ptr_t member);
+ void update_legacy_val(ConfigValues& values,
+ const Option &opt,
+ member_ptr_t member);
- void init_subsys();
+ Option::value_t _expand_meta(
+ const ConfigValues& values,
+ const Option::value_t& in,
+ const Option *o,
+ expand_stack_t *stack,
+ std::ostream *err) const;
- bool expand_meta(std::string &val,
- std::ostream *oss) const;
+public: // for global_init
+ void early_expand_meta(const ConfigValues& values,
+ std::string &val,
+ std::ostream *oss) const;
- void diff_helper(const md_config_t* other,
- map<string, pair<string, string>>* diff,
- set<string>* unknown, const string& setting = string{});
+ // for those want to reexpand special meta, e.g, $pid
+ bool finalize_reexpand_meta(ConfigValues& values,
+ const ConfigTracker& tracker);
-public: // for global_init
- bool early_expand_meta(std::string &val,
- std::ostream *oss) const {
- Mutex::Locker l(lock);
- return expand_meta(val, oss);
+ std::list<std::string> get_conffile_paths(const ConfigValues& values,
+ const char *conf_files,
+ std::ostream *warnings,
+ int flags) const;
+
+ const std::string& get_conf_path() const {
+ return conf_path;
}
private:
- bool expand_meta(std::string &val,
- const Option *opt,
- std::list<const Option*> stack,
- std::ostream *oss) const;
-
- /// expand all metavariables in config structure.
- void expand_all_meta();
-
+ static std::string get_cluster_name(const char* conffile_path);
// The configuration file we read, or NULL if we haven't read one.
ConfFile cf;
+ std::string conf_path;
public:
- std::deque<std::string> parse_errors;
+ std::string parse_error;
private:
- obs_map_t observers;
- changed_set_t changed;
+ // This will be set to true when it is safe to start threads.
+ // Once it is true, it will never change.
+ bool safe_to_start_threads = false;
+
+ bool do_show_config = false;
+ std::string do_show_config_value;
+
+ std::vector<Option> subsys_options;
public:
- ceph::logging::SubsystemMap subsys;
-
- EntityName name;
- string data_dir_option; ///< data_dir config option, if any
-
- /// cluster name
- string cluster;
-
-// This macro block defines C members of the md_config_t struct
-// corresponding to the definitions in legacy_config_opts.h.
-// These C members are consumed by code that was written before
-// the new options.cc infrastructure: all newer code should
-// be consume options via explicit get() rather than C members.
-#define OPTION_OPT_INT(name) int64_t name;
-#define OPTION_OPT_LONGLONG(name) int64_t name;
-#define OPTION_OPT_STR(name) std::string name;
-#define OPTION_OPT_DOUBLE(name) double name;
-#define OPTION_OPT_FLOAT(name) double name;
-#define OPTION_OPT_BOOL(name) bool name;
-#define OPTION_OPT_ADDR(name) entity_addr_t name;
-#define OPTION_OPT_U32(name) uint64_t name;
-#define OPTION_OPT_U64(name) uint64_t name;
-#define OPTION_OPT_UUID(name) uuid_d name;
-#define OPTION(name, ty) \
- public: \
- OPTION_##ty(name)
-#define SAFE_OPTION(name, ty) \
- protected: \
- OPTION_##ty(name)
-#include "common/legacy_config_opts.h"
-#undef OPTION_OPT_INT
-#undef OPTION_OPT_LONGLONG
-#undef OPTION_OPT_STR
-#undef OPTION_OPT_DOUBLE
-#undef OPTION_OPT_FLOAT
-#undef OPTION_OPT_BOOL
-#undef OPTION_OPT_ADDR
-#undef OPTION_OPT_U32
-#undef OPTION_OPT_U64
-#undef OPTION_OPT_UUID
-#undef OPTION
-#undef SAFE_OPTION
+ std::string data_dir_option; ///< data_dir config option, if any
public:
- unsigned get_osd_pool_default_min_size() const {
- return osd_pool_default_min_size ?
- MIN(osd_pool_default_min_size, osd_pool_default_size) :
- osd_pool_default_size - osd_pool_default_size / 2;
+ unsigned get_osd_pool_default_min_size(const ConfigValues& values,
+ uint8_t size) const {
+ uint8_t min_size = get_val<uint64_t>(values, "osd_pool_default_min_size");
+ return min_size ? std::min(min_size, size) : (size - size / 2);
}
- /** A lock that protects the md_config_t internals. It is
- * recursive, for simplicity.
- * It is best if this lock comes first in the lock hierarchy. We will
- * hold this lock when calling configuration observers. */
- mutable Mutex lock;
-
friend class test_md_config_t;
};
template<typename T>
-struct get_typed_value_visitor : public boost::static_visitor<T> {
- template<typename U,
- typename boost::enable_if<boost::is_same<T, U>, int>::type = 0>
- T operator()(U & val) {
- return std::move(val);
- }
- template<typename U,
- typename boost::enable_if_c<!boost::is_same<T, U>::value, int>::type = 0>
- T operator()(U &val) {
- assert("wrong type or option does not exist" == nullptr);
- }
-};
-
-template<typename T> T md_config_t::get_val(const std::string &key) const {
- Option::value_t generic_val = this->get_val_generic(key);
- get_typed_value_visitor<T> gtv;
- return boost::apply_visitor(gtv, generic_val);
+const T md_config_t::get_val(const ConfigValues& values,
+ const std::string_view key) const {
+ return boost::get<T>(this->get_val_generic(values, key));
}
inline std::ostream& operator<<(std::ostream& o, const boost::blank& ) {
int ceph_resolve_file_search(const std::string& filename_list,
std::string& result);
-enum config_subsys_id {
- ceph_subsys_, // default
-#define SUBSYS(name, log, gather) \
- ceph_subsys_##name,
-#define DEFAULT_SUBSYS(log, gather)
-#include "common/subsys.h"
-#undef SUBSYS
-#undef DEFAULT_SUBSYS
- ceph_subsys_max
-};
-
#endif