]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/common/config.h
import ceph pacific 16.2.5
[ceph.git] / ceph / src / common / config.h
index 1145e12e3c58652e39058cdecc89bb01a842aff4..ef7d5b34fdc6b3f19dd82c913d766620a6cdc14b 100644 (file)
 #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.
  *
@@ -50,13 +52,13 @@ extern const char *CEPH_CONF_FILE_DEFAULT;
  * 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
@@ -66,336 +68,296 @@ extern const char *CEPH_CONF_FILE_DEFAULT;
  * 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> &sections) 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> &sections) 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> &sections,
-                  std::string const &key, std::string &out, bool emeta) const;
+  int get_val_from_conf_file(const ConfigValues& values,
+                  const std::vector <std::string> &sections,
+                  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> &sections) const;
-
-  int _get_val_from_conf_file(const std::vector <std::string> &sections,
-                             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> &sections,
+                             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& ) {
@@ -405,15 +367,4 @@ 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