// -*- 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) 2004-2006 Sage Weil * * 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 CEPH_CONFIG_H #define CEPH_CONFIG_H #include #include #include #include "common/ConfUtils.h" #include "common/code_environment.h" #include "log/SubsystemMap.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 }; extern const char *ceph_conf_level_name(int level); /** This class represents the current Ceph configuration. * * For Ceph daemons, this is the daemon configuration. Log levels, caching * settings, btrfs settings, and so forth can all be found here. For libcephfs * and librados users, this is the configuration associated with their context. * * For information about how this class is loaded from a configuration file, * see common/ConfUtils. * * ACCESS * * 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 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::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 * (conf->get_val("foo")). * * FIXME: really we shouldn't allow changing integer or floating point values * while another thread is reading them, either. */ struct md_config_t { public: typedef std::variant member_ptr_t; // For use when intercepting configuration updates typedef std::function 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 legacy_values; /** * The configuration schema, in the form of Option objects describing * possible settings. */ std::map schema; /// values from mon that we failed to set std::map ignored_mon_values; /// original raw values saved that may need to re-expand at certain time mutable std::vector 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; /// encoded copy of defaults (map) ceph::bufferlist defaults_bl; // Create a new md_config_t structure. explicit md_config_t(ConfigValues& values, const ConfigTracker& tracker, bool is_daemon=false); ~md_config_t(); // Parse a config file 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(unsigned entity_type, ConfigValues& values, const ConfigTracker& tracker, const char *env_var = "CEPH_ARGS"); // Absorb config settings from argv int parse_argv(ConfigValues& values, const ConfigTracker& tracker, std::vector& 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; /// 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>& kv, config_callback config_cb); // Called by the Ceph daemons to make configuration changes at runtime 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(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(ConfigValues& values, const ConfigTracker& tracker, const std::string_view key, const char *val, std::stringstream *err_ss=nullptr); 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(values, tracker, key, s.c_str(), err_ss); } /// clear override value int rm_val(ConfigValues& values, const std::string_view key); /// get encoded map> 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 of compiled-in defaults void get_defaults_bl(const ConfigValues& values, ceph::buffer::list *bl); /// Get the default value of a configuration option std::optional get_val_default(std::string_view key); // Get a configuration value. // No metavariables will be returned (they will have already been expanded) 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 const T get_val(const ConfigValues& values, const std::string_view key) const; template auto with_val(const ConfigValues& values, const std::string_view key, Callback&& cb, Args&&... args) const -> std::result_of_t { return std::forward(cb)( std::get(this->get_val_generic(values, key)), std::forward(args)...); } void get_all_keys(std::vector *keys) const; // Return a list of all the sections that the current entity is a member of. std::vector get_my_sections(const ConfigValues& values) const; // Return a list of all sections int get_all_sections(std::vector §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 ConfigValues& values, const std::vector §ions, const std::string_view key, std::string &out, bool emeta) const; /// dump all config values to a stream void show_config(const ConfigValues& values, std::ostream& out) const; /// dump all config values to a formatter void show_config(const ConfigValues& values, ceph::Formatter *f) const; /// dump all config settings to a formatter void config_options(ceph::Formatter *f) const; /// 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_error(CephContext *cct); private: // we use this to avoid variable expansion loops typedef boost::container::small_vector, 4> expand_stack_t; void validate_schema(); void validate_default_settings(); 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 §ions, const std::string_view key, std::string &out) const; int parse_option(ConfigValues& values, const ConfigTracker& tracker, std::vector& args, std::vector::iterator& i, std::ostream *oss, int level); int parse_injectargs(ConfigValues& values, const ConfigTracker& tracker, std::vector& 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 void assign_member(member_ptr_t ptr, const Option::value_t &val); void update_legacy_val(ConfigValues& values, const Option &opt, member_ptr_t member); Option::value_t _expand_meta( const ConfigValues& values, const Option::value_t& in, const Option *o, expand_stack_t *stack, std::ostream *err) const; public: // for global_init void early_expand_meta(const ConfigValues& values, std::string &val, std::ostream *oss) const; // for those want to reexpand special meta, e.g, $pid bool finalize_reexpand_meta(ConfigValues& values, const ConfigTracker& tracker); std::list 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: 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::string parse_error; private: // 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