1    	// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2    	// vim: ts=8 sw=2 smarttab
3    	/*
4    	 * Ceph - scalable distributed file system
5    	 *
6    	 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7    	 *
8    	 * This is free software; you can redistribute it and/or
9    	 * modify it under the terms of the GNU Lesser General Public
10   	 * License version 2.1, as published by the Free Software
11   	 * Foundation.  See file COPYING.
12   	 *
13   	 */
14   	
15   	#ifndef CEPH_CONFIG_H
16   	#define CEPH_CONFIG_H
17   	
18   	#include <map>
19   	#include <boost/container/small_vector.hpp>
20   	#include "common/ConfUtils.h"
21   	#include "common/code_environment.h"
22   	#include "log/SubsystemMap.h"
23   	#include "common/options.h"
24   	#include "common/subsys_types.h"
25   	#include "common/config_tracker.h"
26   	#include "common/config_values.h"
27   	
28   	class CephContext;
29   	
30   	enum {
31   	  CONF_DEFAULT,
32   	  CONF_MON,
33   	  CONF_FILE,
34   	  CONF_ENV,
35   	  CONF_CMDLINE,
36   	  CONF_OVERRIDE,
37   	  CONF_FINAL
38   	};
39   	
40   	extern const char *ceph_conf_level_name(int level);
41   	
42   	/** This class represents the current Ceph configuration.
43   	 *
44   	 * For Ceph daemons, this is the daemon configuration.  Log levels, caching
45   	 * settings, btrfs settings, and so forth can all be found here.  For libcephfs
46   	 * and librados users, this is the configuration associated with their context.
47   	 *
48   	 * For information about how this class is loaded from a configuration file,
49   	 * see common/ConfUtils.
50   	 *
51   	 * ACCESS
52   	 *
53   	 * There are 3 ways to read the ceph context-- the old way and two new ways.
54   	 * In the old way, code would simply read the public variables of the
55   	 * configuration, without taking a lock. In the new way #1, code registers a
56   	 * configuration observer which receives callbacks when a value changes. These
57   	 * callbacks take place under the md_config_t lock. Alternatively one can use
58   	 * get_val(const char *name) method to safely get a copy of the value.
59   	 *
60   	 * To prevent serious problems resulting from thread-safety issues, we disallow
61   	 * changing std::string configuration values after
62   	 * md_config_t::safe_to_start_threads becomes true. You can still
63   	 * change integer or floating point values, and the option declared with
64   	 * SAFE_OPTION macro. Notice the latter options can not be read directly
65   	 * (conf->foo), one should use either observers or get_val() method
66   	 * (conf->get_val("foo")).
67   	 *
68   	 * FIXME: really we shouldn't allow changing integer or floating point values
69   	 * while another thread is reading them, either.
70   	 */
71   	struct md_config_t {
72   	public:
73   	  typedef boost::variant<int64_t ConfigValues::*,
74   	                         uint64_t ConfigValues::*,
75   	                         std::string ConfigValues::*,
76   	                         double ConfigValues::*,
77   	                         bool ConfigValues::*,
78   	                         entity_addr_t ConfigValues::*,
79   				 entity_addrvec_t ConfigValues::*,
80   	                         uuid_d ConfigValues::*> member_ptr_t;
81   	
82   	  // For use when intercepting configuration updates
83   	  typedef std::function<bool(
84   	      const std::string &k, const std::string &v)> config_callback;
85   	
86   	  /// true if we are a daemon (as per CephContext::code_env)
87   	  const bool is_daemon;
88   	
89   	  /*
90   	   * Mapping from legacy config option names to class members
91   	   */
92   	  std::map<std::string_view, member_ptr_t> legacy_values;
93   	
94   	  /**
95   	   * The configuration schema, in the form of Option objects describing
96   	   * possible settings.
97   	   */
98   	  std::map<std::string_view, const Option&> schema;
99   	
100  	  /// values from mon that we failed to set
101  	  std::map<std::string,std::string> ignored_mon_values;
102  	
103  	  /// original raw values saved that may need to re-expand at certain time
104  	  mutable std::map<std::string, std::string> may_reexpand_meta;
105  	
106  	  /// encoded, cached copy of of values + ignored_mon_values
107  	  ceph::bufferlist values_bl;
108  	
109  	  /// version for values_bl; increments each time there is a change
110  	  uint64_t values_bl_version = 0;
111  	
112  	  /// encoded copy of defaults (map<string,string>)
113  	  ceph::bufferlist defaults_bl;
114  	
115  	  // Create a new md_config_t structure.
116  	  explicit md_config_t(ConfigValues& values,
117  			       const ConfigTracker& tracker,
118  			       bool is_daemon=false);
119  	  ~md_config_t();
120  	
121  	  // Parse a config file
122  	  int parse_config_files(ConfigValues& values, const ConfigTracker& tracker,
123  				 const char *conf_files,
124  				 std::ostream *warnings, int flags);
125  	
126  	  // Absorb config settings from the environment
127  	  void parse_env(unsigned entity_type,
128  			 ConfigValues& values, const ConfigTracker& tracker,
129  			 const char *env_var = "CEPH_ARGS");
130  	
131  	  // Absorb config settings from argv
132  	  int parse_argv(ConfigValues& values, const ConfigTracker& tracker,
133  			 std::vector<const char*>& args, int level=CONF_CMDLINE);
134  	
135  	  // do any commands we got from argv (--show-config, --show-config-val)
136  	  void do_argv_commands(const ConfigValues& values) const;
137  	
138  	  bool _internal_field(const std::string& k);
139  	
140  	  void set_safe_to_start_threads();
141  	  void _clear_safe_to_start_threads();  // this is only used by the unit test
142  	
143  	  /// Look up an option in the schema
144  	  const Option *find_option(const std::string_view name) const;
145  	
146  	  /// Set a default value
147  	  void set_val_default(ConfigValues& values,
148  			       const ConfigTracker& tracker,
149  			       const std::string_view key, const std::string &val);
150  	
151  	  /// Set a values from mon
152  	  int set_mon_vals(CephContext *cct,
153  			   ConfigValues& values,
154  			   const ConfigTracker& tracker,
155  			   const std::map<std::string,std::string, std::less<>>& kv,
156  			   config_callback config_cb);
157  	
158  	  // Called by the Ceph daemons to make configuration changes at runtime
159  	  int injectargs(ConfigValues& values,
160  			 const ConfigTracker& tracker,
161  			 const std::string &s,
162  			 std::ostream *oss);
163  	
164  	  // Set a configuration value, or crash
165  	  // Metavariables will be expanded.
166  	  void set_val_or_die(ConfigValues& values, const ConfigTracker& tracker,
167  			      const std::string_view key, const std::string &val);
168  	
169  	  // Set a configuration value.
170  	  // Metavariables will be expanded.
171  	  int set_val(ConfigValues& values, const ConfigTracker& tracker,
172  		      const std::string_view key, const char *val,
173  	              std::stringstream *err_ss=nullptr);
174  	  int set_val(ConfigValues& values, const ConfigTracker& tracker,
175  		      const std::string_view key, const std::string& s,
176  	              std::stringstream *err_ss=nullptr) {
(1) Event fun_call_w_exception: Called function throws an exception of type "boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::bad_get> >". [details]
177  	    return set_val(values, tracker, key, s.c_str(), err_ss);
178  	  }
179  	
180  	  /// clear override value
181  	  int rm_val(ConfigValues& values, const std::string_view key);
182  	
183  	  /// get encoded map<string,map<int32_t,string>> of entire config
184  	  void get_config_bl(const ConfigValues& values,
185  			     uint64_t have_version,
186  			     ceph::buffer::list *bl,
187  			     uint64_t *got_version);
188  	
189  	  /// get encoded map<string,string> of compiled-in defaults
190  	  void get_defaults_bl(const ConfigValues& values, ceph::buffer::list *bl);
191  	
192  	  // Get a configuration value.
193  	  // No metavariables will be returned (they will have already been expanded)
194  	  int get_val(const ConfigValues& values, const std::string_view key, char **buf, int len) const;
195  	  int get_val(const ConfigValues& values, const std::string_view key, std::string *val) const;
196  	  template<typename T> const T get_val(const ConfigValues& values, const std::string_view key) const;
197  	  template<typename T, typename Callback, typename...Args>
198  	  auto with_val(const ConfigValues& values, const std::string_view key,
199  			Callback&& cb, Args&&... args) const ->
200  	    std::result_of_t<Callback(const T&, Args...)> {
201  	    return std::forward<Callback>(cb)(
202  	      boost::get<T>(this->get_val_generic(values, key)),
203  	      std::forward<Args>(args)...);
204  	  }
205  	
206  	  void get_all_keys(std::vector<std::string> *keys) const;
207  	
208  	  // Return a list of all the sections that the current entity is a member of.
209  	  void get_my_sections(const ConfigValues& values,
210  			       std::vector <std::string> &sections) const;
211  	
212  	  // Return a list of all sections
213  	  int get_all_sections(std::vector <std::string> &sections) const;
214  	
215  	  // Get a value from the configuration file that we read earlier.
216  	  // Metavariables will be expanded if emeta is true.
217  	  int get_val_from_conf_file(const ConfigValues& values,
218  			   const std::vector <std::string> &sections,
219  			   const std::string_view key, std::string &out, bool emeta) const;
220  	
221  	  /// dump all config values to a stream
222  	  void show_config(const ConfigValues& values, std::ostream& out) const;
223  	  /// dump all config values to a formatter
224  	  void show_config(const ConfigValues& values, ceph::Formatter *f) const;
225  	
226  	  /// dump all config settings to a formatter
227  	  void config_options(ceph::Formatter *f) const;
228  	
229  	  /// dump config diff from default, conf, mon, etc.
230  	  void diff(const ConfigValues& values,
231  		    ceph::Formatter *f,
232  		    std::string name = {}) const;
233  	
234  	  /// print/log warnings/errors from parsing the config
235  	  void complain_about_parse_error(CephContext *cct);
236  	
237  	private:
238  	  // we use this to avoid variable expansion loops
239  	  typedef boost::container::small_vector<std::pair<const Option*,
240  							   const Option::value_t*>,
241  						 4> expand_stack_t;
242  	
243  	  void validate_schema();
244  	  void validate_default_settings();
245  	
246  	  Option::value_t get_val_generic(const ConfigValues& values,
247  					  const std::string_view key) const;
248  	  int _get_val_cstr(const ConfigValues& values,
249  			    const std::string& key, char **buf, int len) const;
250  	  Option::value_t _get_val(const ConfigValues& values,
251  				   const std::string_view key,
252  				   expand_stack_t *stack=0,
253  				   std::ostream *err=0) const;
254  	  Option::value_t _get_val(const ConfigValues& values,
255  				   const Option& o,
256  				   expand_stack_t *stack=0,
257  				   std::ostream *err=0) const;
258  	  const Option::value_t& _get_val_default(const Option& o) const;
259  	  Option::value_t _get_val_nometa(const ConfigValues& values,
260  					  const Option& o) const;
261  	
262  	  int _rm_val(ConfigValues& values, const std::string_view key, int level);
263  	
264  	  void _refresh(ConfigValues& values, const Option& opt);
265  	
266  	  void _show_config(const ConfigValues& values,
267  			    std::ostream *out, ceph::Formatter *f) const;
268  	
269  	  void _get_my_sections(const ConfigValues& values,
270  				std::vector<std::string> &sections) const;
271  	
272  	  int _get_val_from_conf_file(const std::vector<std::string> &sections,
273  				      const std::string_view key, std::string &out) const;
274  	
275  	  int parse_option(ConfigValues& values,
276  			   const ConfigTracker& tracker,
277  			   std::vector<const char*>& args,
278  			   std::vector<const char*>::iterator& i,
279  			   std::ostream *oss,
280  			   int level);
281  	  int parse_injectargs(ConfigValues& values,
282  			       const ConfigTracker& tracker,
283  			       std::vector<const char*>& args,
284  			       std::ostream *oss);
285  	
286  	  // @returns negative number for an error, otherwise a
287  	  //          @c ConfigValues::set_value_result_t is returned.
288  	  int _set_val(
289  	    ConfigValues& values,
290  	    const ConfigTracker& tracker,
291  	    const std::string &val,
292  	    const Option &opt,
293  	    int level,  // CONF_*
294  	    std::string *error_message);
295  	
296  	  template <typename T>
297  	  void assign_member(member_ptr_t ptr, const Option::value_t &val);
298  	
299  	
300  	  void update_legacy_vals(ConfigValues& values);
301  	  void update_legacy_val(ConfigValues& values,
302  				 const Option &opt,
303  				 member_ptr_t member);
304  	
305  	  Option::value_t _expand_meta(
306  	    const ConfigValues& values,
307  	    const Option::value_t& in,
308  	    const Option *o,
309  	    expand_stack_t *stack,
310  	    std::ostream *err) const;
311  	
312  	public:  // for global_init
313  	  void early_expand_meta(const ConfigValues& values,
314  				 std::string &val,
315  				 std::ostream *oss) const;
316  	
317  	  // for those want to reexpand special meta, e.g, $pid
318  	  bool finalize_reexpand_meta(ConfigValues& values,
319  				      const ConfigTracker& tracker);
320  	private:
321  	
322  	  /// expand all metavariables in config structure.
323  	  void expand_all_meta();
324  	
325  	  // The configuration file we read, or NULL if we haven't read one.
326  	  ConfFile cf;
327  	public:
328  	  std::string parse_error;
329  	private:
330  	
331  	  // This will be set to true when it is safe to start threads.
332  	  // Once it is true, it will never change.
333  	  bool safe_to_start_threads = false;
334  	
335  	  bool do_show_config = false;
336  	  std::string do_show_config_value;
337  	
338  	  std::vector<Option> subsys_options;
339  	
340  	public:
341  	  std::string data_dir_option;  ///< data_dir config option, if any
342  	
343  	public:
344  	  unsigned get_osd_pool_default_min_size(const ConfigValues& values,
345  	                                         uint8_t size) const {
346  	    uint8_t min_size = get_val<uint64_t>(values, "osd_pool_default_min_size");
347  	    return min_size ? std::min(min_size, size) : (size - size / 2);
348  	  }
349  	
350  	  friend class test_md_config_t;
351  	};
352  	
353  	template<typename T>
354  	const T md_config_t::get_val(const ConfigValues& values,
355  				     const std::string_view key) const {
356  	  return boost::get<T>(this->get_val_generic(values, key));
357  	}
358  	
359  	inline std::ostream& operator<<(std::ostream& o, const boost::blank& ) {
360  	      return o << "INVALID_CONFIG_VALUE";
361  	}
362  	
363  	int ceph_resolve_file_search(const std::string& filename_list,
364  				     std::string& result);
365  	
366  	#endif
367