]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
7c673cae FG |
18 | #include "common/ConfUtils.h" |
19 | #include "common/entity_name.h" | |
20 | #include "common/Mutex.h" | |
21 | #include "log/SubsystemMap.h" | |
22 | #include "common/config_obs.h" | |
7c673cae FG |
23 | |
24 | #define OSD_REP_PRIMARY 0 | |
25 | #define OSD_REP_SPLAY 1 | |
26 | #define OSD_REP_CHAIN 2 | |
27 | ||
28 | class CephContext; | |
29 | ||
30 | extern const char *CEPH_CONF_FILE_DEFAULT; | |
31 | ||
32 | #define LOG_TO_STDERR_NONE 0 | |
33 | #define LOG_TO_STDERR_SOME 1 | |
34 | #define LOG_TO_STDERR_ALL 2 | |
35 | ||
36 | /** This class represents the current Ceph configuration. | |
37 | * | |
38 | * For Ceph daemons, this is the daemon configuration. Log levels, caching | |
39 | * settings, btrfs settings, and so forth can all be found here. For libcephfs | |
40 | * and librados users, this is the configuration associated with their context. | |
41 | * | |
42 | * For information about how this class is loaded from a configuration file, | |
43 | * see common/ConfUtils. | |
44 | * | |
45 | * ACCESS | |
46 | * | |
47 | * There are 3 ways to read the ceph context-- the old way and two new ways. | |
48 | * In the old way, code would simply read the public variables of the | |
49 | * configuration, without taking a lock. In the new way #1, code registers a | |
50 | * configuration obserever which receives callbacks when a value changes. These | |
51 | * callbacks take place under the md_config_t lock. Alternatively one can use | |
52 | * get_val(const char *name) method to safely get a copy of the value. | |
53 | * | |
54 | * To prevent serious problems resulting from thread-safety issues, we disallow | |
55 | * changing std::string configuration values after | |
56 | * md_config_t::internal_safe_to_start_threads becomes true. You can still | |
57 | * change integer or floating point values, and the option declared with | |
58 | * SAFE_OPTION macro. Notice the latter options can not be read directly | |
59 | * (conf->foo), one should use either observers or get_val() method | |
60 | * (conf->get_val("foo")). | |
61 | * | |
62 | * FIXME: really we shouldn't allow changing integer or floating point values | |
63 | * while another thread is reading them, either. | |
64 | */ | |
65 | struct md_config_t { | |
66 | public: | |
67 | /* Maps configuration options to the observer listening for them. */ | |
68 | typedef std::multimap <std::string, md_config_obs_t*> obs_map_t; | |
69 | ||
70 | /* Set of configuration options that have changed since the last | |
71 | * apply_changes */ | |
72 | typedef std::set < std::string > changed_set_t; | |
73 | ||
74 | struct invalid_config_value_t { }; | |
75 | typedef boost::variant<invalid_config_value_t, | |
76 | int, | |
77 | long long, | |
78 | std::string, | |
79 | double, | |
80 | float, | |
81 | bool, | |
82 | entity_addr_t, | |
83 | uint32_t, | |
84 | uint64_t, | |
85 | uuid_d> config_value_t; | |
86 | typedef boost::variant<const int md_config_t::*, | |
87 | const long long md_config_t::*, | |
88 | const std::string md_config_t::*, | |
89 | const double md_config_t::*, | |
90 | const float md_config_t::*, | |
91 | const bool md_config_t::*, | |
92 | const entity_addr_t md_config_t::*, | |
93 | const uint32_t md_config_t::*, | |
94 | const uint64_t md_config_t::*, | |
95 | const uuid_d md_config_t::*> member_ptr_t; | |
96 | ||
97 | typedef enum { | |
98 | OPT_INT, OPT_LONGLONG, OPT_STR, OPT_DOUBLE, OPT_FLOAT, OPT_BOOL, | |
99 | OPT_ADDR, OPT_U32, OPT_U64, OPT_UUID | |
100 | } opt_type_t; | |
101 | ||
102 | typedef std::function<int(std::string*, std::string*)> validator_t; | |
103 | ||
104 | class config_option { | |
105 | public: | |
106 | const char *name; | |
107 | opt_type_t type; | |
108 | md_config_t::member_ptr_t md_member_ptr; | |
109 | bool safe; // promise to access it only via md_config_t::get_val | |
110 | validator_t validator; | |
111 | private: | |
112 | template<typename T> struct get_typed_pointer_visitor : public boost::static_visitor<T const *> { | |
113 | md_config_t const *conf; | |
114 | explicit get_typed_pointer_visitor(md_config_t const *conf_) : conf(conf_) { } | |
115 | template<typename U, | |
116 | typename boost::enable_if<boost::is_same<T, U>, int>::type = 0> | |
117 | T const *operator()(const U md_config_t::* member_ptr) { | |
118 | return &(conf->*member_ptr); | |
119 | } | |
120 | template<typename U, | |
121 | typename boost::enable_if_c<!boost::is_same<T, U>::value, int>::type = 0> | |
122 | T const *operator()(const U md_config_t::* member_ptr) { | |
123 | return nullptr; | |
124 | } | |
125 | }; | |
126 | public: | |
127 | // is it OK to alter the value when threads are running? | |
128 | bool is_safe() const; | |
129 | // Given a configuration, return a pointer to this option inside | |
130 | // that configuration. | |
131 | template<typename T> void conf_ptr(T const *&ptr, md_config_t const *conf) const { | |
132 | get_typed_pointer_visitor<T> gtpv(conf); | |
133 | ptr = boost::apply_visitor(gtpv, md_member_ptr); | |
134 | } | |
135 | template<typename T> void conf_ptr(T *&ptr, md_config_t *conf) const { | |
136 | get_typed_pointer_visitor<T> gtpv(conf); | |
137 | ptr = const_cast<T *>(boost::apply_visitor(gtpv, md_member_ptr)); | |
138 | } | |
139 | template<typename T> T const *conf_ptr(md_config_t const *conf) const { | |
140 | get_typed_pointer_visitor<T> gtpv(conf); | |
141 | return boost::apply_visitor(gtpv, md_member_ptr); | |
142 | } | |
143 | template<typename T> T *conf_ptr(md_config_t *conf) const { | |
144 | get_typed_pointer_visitor<T> gtpv(conf); | |
145 | return const_cast<T *>(boost::apply_visitor(gtpv, md_member_ptr)); | |
146 | } | |
147 | }; | |
148 | ||
149 | // Create a new md_config_t structure. | |
150 | md_config_t(); | |
151 | ~md_config_t(); | |
152 | ||
153 | // Adds a new observer to this configuration. You can do this at any time, | |
154 | // but it will only receive notifications for the changes that happen after | |
155 | // you attach it, obviously. | |
156 | // | |
157 | // Most developers will probably attach their observers after global_init, | |
158 | // but before anyone can call injectargs. | |
159 | // | |
160 | // The caller is responsible for allocating observers. | |
161 | void add_observer(md_config_obs_t* observer_); | |
162 | ||
163 | // Remove an observer from this configuration. | |
164 | // This doesn't delete the observer! If you allocated it with new(), | |
165 | // you need to delete it yourself. | |
166 | // This function will assert if you try to delete an observer that isn't | |
167 | // there. | |
168 | void remove_observer(md_config_obs_t* observer_); | |
169 | ||
170 | // Parse a config file | |
171 | int parse_config_files(const char *conf_files, | |
172 | std::ostream *warnings, int flags); | |
173 | ||
174 | // Absorb config settings from the environment | |
175 | void parse_env(); | |
176 | ||
177 | // Absorb config settings from argv | |
178 | int parse_argv(std::vector<const char*>& args); | |
179 | ||
180 | // Expand all metavariables. Make any pending observer callbacks. | |
181 | void apply_changes(std::ostream *oss); | |
182 | void _apply_changes(std::ostream *oss); | |
183 | bool _internal_field(const string& k); | |
184 | void call_all_observers(); | |
185 | ||
186 | // Called by the Ceph daemons to make configuration changes at runtime | |
187 | int injectargs(const std::string &s, std::ostream *oss); | |
188 | ||
189 | // Set a configuration value, or crash | |
190 | // Metavariables will be expanded. | |
191 | void set_val_or_die(const char *key, const char *val); | |
192 | ||
193 | // Set a configuration value. | |
194 | // Metavariables will be expanded. | |
195 | int set_val(const char *key, const char *val, bool meta=true); | |
196 | int set_val(const char *key, const string& s, bool meta=true) { | |
197 | return set_val(key, s.c_str(), meta); | |
198 | } | |
199 | ||
200 | // Get a configuration value. | |
201 | // No metavariables will be returned (they will have already been expanded) | |
202 | int get_val(const char *key, char **buf, int len) const; | |
203 | int _get_val(const char *key, char **buf, int len) const; | |
204 | config_value_t get_val_generic(const char *key) const; | |
205 | template<typename T> T get_val(const char *key) const; | |
206 | ||
207 | void get_all_keys(std::vector<std::string> *keys) const; | |
208 | ||
209 | // Return a list of all the sections that the current entity is a member of. | |
210 | void get_my_sections(std::vector <std::string> §ions) const; | |
211 | ||
212 | // Return a list of all sections | |
213 | int get_all_sections(std::vector <std::string> §ions) 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 std::vector <std::string> §ions, | |
218 | const char *key, std::string &out, bool emeta) const; | |
219 | ||
220 | /// dump all config values to a stream | |
221 | void show_config(std::ostream& out); | |
222 | /// dump all config values to a formatter | |
223 | void show_config(Formatter *f); | |
224 | ||
225 | /// obtain a diff between our config values and another md_config_t values | |
226 | void diff(const md_config_t *other, | |
227 | map<string,pair<string,string> > *diff, set<string> *unknown); | |
228 | ||
31f18b77 FG |
229 | /// obtain a diff between config values and another md_config_t |
230 | /// values for a specific setting. | |
231 | void diff(const md_config_t *other, | |
232 | map<string,pair<string,string>> *diff, set<string> *unknown, | |
233 | const string& setting); | |
234 | ||
7c673cae FG |
235 | /// print/log warnings/errors from parsing the config |
236 | void complain_about_parse_errors(CephContext *cct); | |
237 | ||
238 | private: | |
239 | void validate_default_settings(); | |
240 | ||
241 | int _get_val(const char *key, std::string *value) const; | |
242 | config_value_t _get_val(const char *key) const; | |
243 | void _show_config(std::ostream *out, Formatter *f); | |
244 | ||
245 | void _get_my_sections(std::vector <std::string> §ions) const; | |
246 | ||
247 | int _get_val_from_conf_file(const std::vector <std::string> §ions, | |
248 | const char *key, std::string &out, bool emeta) const; | |
249 | ||
250 | int parse_option(std::vector<const char*>& args, | |
251 | std::vector<const char*>::iterator& i, | |
252 | std::ostream *oss); | |
253 | int parse_injectargs(std::vector<const char*>& args, | |
254 | std::ostream *oss); | |
255 | int parse_config_files_impl(const std::list<std::string> &conf_files, | |
256 | std::ostream *warnings); | |
257 | ||
258 | int set_val_impl(const std::string &val, config_option const *opt, | |
259 | std::string *error_message); | |
260 | int set_val_raw(const char *val, config_option const *opt); | |
261 | ||
262 | void init_subsys(); | |
263 | ||
264 | bool expand_meta(std::string &val, | |
265 | std::ostream *oss) const; | |
31f18b77 FG |
266 | |
267 | void diff_helper(const md_config_t* other, | |
268 | map<string, pair<string, string>>* diff, | |
269 | set<string>* unknown, const string& setting = string{}); | |
270 | ||
7c673cae FG |
271 | public: // for global_init |
272 | bool early_expand_meta(std::string &val, | |
273 | std::ostream *oss) const { | |
274 | Mutex::Locker l(lock); | |
275 | return expand_meta(val, oss); | |
276 | } | |
277 | private: | |
278 | bool expand_meta(std::string &val, | |
279 | config_option const *opt, | |
280 | std::list<config_option const *> stack, | |
281 | std::ostream *oss) const; | |
282 | ||
283 | /// expand all metavariables in config structure. | |
284 | void expand_all_meta(); | |
285 | ||
286 | // The configuration file we read, or NULL if we haven't read one. | |
287 | ConfFile cf; | |
288 | public: | |
289 | std::deque<std::string> parse_errors; | |
290 | private: | |
291 | ||
292 | obs_map_t observers; | |
293 | changed_set_t changed; | |
294 | ||
295 | public: | |
296 | ceph::logging::SubsystemMap subsys; | |
297 | ||
298 | EntityName name; | |
299 | string data_dir_option; ///< data_dir config option, if any | |
300 | ||
301 | /// cluster name | |
302 | string cluster; | |
303 | ||
304 | #define OPTION_OPT_INT(name) const int name; | |
305 | #define OPTION_OPT_LONGLONG(name) const long long name; | |
306 | #define OPTION_OPT_STR(name) const std::string name; | |
307 | #define OPTION_OPT_DOUBLE(name) const double name; | |
308 | #define OPTION_OPT_FLOAT(name) const float name; | |
309 | #define OPTION_OPT_BOOL(name) const bool name; | |
310 | #define OPTION_OPT_ADDR(name) const entity_addr_t name; | |
311 | #define OPTION_OPT_U32(name) const uint32_t name; | |
312 | #define OPTION_OPT_U64(name) const uint64_t name; | |
313 | #define OPTION_OPT_UUID(name) const uuid_d name; | |
314 | #define OPTION(name, ty, init) \ | |
315 | public: \ | |
316 | OPTION_##ty(name) \ | |
317 | struct option_##name##_t; | |
318 | #define OPTION_VALIDATOR(name) | |
319 | #define SAFE_OPTION(name, ty, init) \ | |
320 | protected: \ | |
321 | OPTION_##ty(name) \ | |
322 | public: \ | |
323 | struct option_##name##_t; | |
324 | #define SUBSYS(name, log, gather) | |
325 | #define DEFAULT_SUBSYS(log, gather) | |
326 | #include "common/config_opts.h" | |
327 | #undef OPTION_OPT_INT | |
328 | #undef OPTION_OPT_LONGLONG | |
329 | #undef OPTION_OPT_STR | |
330 | #undef OPTION_OPT_DOUBLE | |
331 | #undef OPTION_OPT_FLOAT | |
332 | #undef OPTION_OPT_BOOL | |
333 | #undef OPTION_OPT_ADDR | |
334 | #undef OPTION_OPT_U32 | |
335 | #undef OPTION_OPT_U64 | |
336 | #undef OPTION_OPT_UUID | |
337 | #undef OPTION | |
338 | #undef OPTION_VALIDATOR | |
339 | #undef SAFE_OPTION | |
340 | #undef SUBSYS | |
341 | #undef DEFAULT_SUBSYS | |
342 | ||
343 | unsigned get_osd_pool_default_min_size() const { | |
344 | return osd_pool_default_min_size ? | |
345 | MIN(osd_pool_default_min_size, osd_pool_default_size) : | |
346 | osd_pool_default_size - osd_pool_default_size / 2; | |
347 | } | |
348 | ||
349 | /** A lock that protects the md_config_t internals. It is | |
350 | * recursive, for simplicity. | |
351 | * It is best if this lock comes first in the lock hierarchy. We will | |
352 | * hold this lock when calling configuration observers. */ | |
353 | mutable Mutex lock; | |
354 | ||
355 | friend class test_md_config_t; | |
356 | protected: | |
357 | // Tests and possibly users expect options to appear in the output | |
358 | // of ceph-conf in the same order as declared in config_opts.h | |
359 | std::shared_ptr<const std::vector<config_option>> config_options; | |
360 | config_option const *find_config_option(const std::string& normalized_key) const; | |
361 | }; | |
362 | ||
363 | template<typename T> | |
364 | struct get_typed_value_visitor : public boost::static_visitor<T> { | |
365 | template<typename U, | |
366 | typename boost::enable_if<boost::is_same<T, U>, int>::type = 0> | |
367 | T operator()(U & val) { | |
368 | return std::move(val); | |
369 | } | |
370 | template<typename U, | |
371 | typename boost::enable_if_c<!boost::is_same<T, U>::value, int>::type = 0> | |
372 | T operator()(U &val) { | |
373 | assert("wrong type or option does not exist" == nullptr); | |
374 | } | |
375 | }; | |
376 | ||
377 | template<typename T> T md_config_t::get_val(const char *key) const { | |
378 | config_value_t generic_val = this->get_val_generic(key); | |
379 | get_typed_value_visitor<T> gtv; | |
380 | return boost::apply_visitor(gtv, generic_val); | |
381 | } | |
382 | ||
383 | inline std::ostream& operator<<(std::ostream& o, const md_config_t::invalid_config_value_t& ) { | |
384 | return o << "INVALID_CONFIG_VALUE"; | |
385 | } | |
386 | ||
387 | int ceph_resolve_file_search(const std::string& filename_list, | |
388 | std::string& result); | |
389 | ||
390 | typedef md_config_t::config_option config_option; | |
391 | ||
392 | ||
393 | enum config_subsys_id { | |
394 | ceph_subsys_, // default | |
395 | #define OPTION(a,b,c) | |
396 | #define OPTION_VALIDATOR(name) | |
397 | #define SAFE_OPTION(a,b,c) | |
398 | #define SUBSYS(name, log, gather) \ | |
399 | ceph_subsys_##name, | |
400 | #define DEFAULT_SUBSYS(log, gather) | |
401 | #include "common/config_opts.h" | |
402 | #undef SUBSYS | |
403 | #undef OPTION | |
404 | #undef OPTION_VALIDATOR | |
405 | #undef SAFE_OPTION | |
406 | #undef DEFAULT_SUBSYS | |
407 | ceph_subsys_max | |
408 | }; | |
409 | ||
410 | #endif |