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