summaryrefslogtreecommitdiffstats
path: root/src/common/config.h
blob: 989f5029e1270493ddf680d372d35219cac53185 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
// -*- 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 <sage@newdream.net>
 *
 * 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 <map>
#include <boost/container/small_vector.hpp>
#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 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_view, member_ptr_t> legacy_values;

  /**
   * The configuration schema, in the form of Option objects describing
   * possible settings.
   */
  std::map<std::string_view, const Option&> schema;

  /// 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;

  /// encoded copy of defaults (map<string,string>)
  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<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;

  /// 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(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<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 the default value of a configuration option
  std::optional<std::string> 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<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.
  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 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(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<std::pair<const Option*,
						   const Option::value_t*>,
					 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<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 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(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<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:
  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<Option> subsys_options;

public:
  std::string data_dir_option;  ///< data_dir config option, if any

public:
  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);
  }

  friend class test_md_config_t;
};

template<typename T>
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& ) {
      return o << "INVALID_CONFIG_VALUE";
}

int ceph_resolve_file_search(const std::string& filename_list,
			     std::string& result);

#endif