]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/options.h
import 15.2.0 Octopus source
[ceph.git] / ceph / src / common / options.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #pragma once
5
6 #include <chrono>
7 #include <string>
8 #include <vector>
9 #include <boost/variant.hpp>
10 #include "include/str_list.h"
11 #include "msg/msg_types.h"
12 #include "include/uuid.h"
13
14 struct Option {
15 enum type_t {
16 TYPE_UINT = 0,
17 TYPE_INT = 1,
18 TYPE_STR = 2,
19 TYPE_FLOAT = 3,
20 TYPE_BOOL = 4,
21 TYPE_ADDR = 5,
22 TYPE_ADDRVEC = 6,
23 TYPE_UUID = 7,
24 TYPE_SIZE = 8,
25 TYPE_SECS = 9,
26 };
27
28 static const char *type_to_c_type_str(type_t t) {
29 switch (t) {
30 case TYPE_UINT: return "uint64_t";
31 case TYPE_INT: return "int64_t";
32 case TYPE_STR: return "std::string";
33 case TYPE_FLOAT: return "double";
34 case TYPE_BOOL: return "bool";
35 case TYPE_ADDR: return "entity_addr_t";
36 case TYPE_ADDRVEC: return "entity_addrvec_t";
37 case TYPE_UUID: return "uuid_d";
38 case TYPE_SIZE: return "size_t";
39 case TYPE_SECS: return "secs";
40 default: return "unknown";
41 }
42 }
43 static const char *type_to_str(type_t t) {
44 switch (t) {
45 case TYPE_UINT: return "uint";
46 case TYPE_INT: return "int";
47 case TYPE_STR: return "str";
48 case TYPE_FLOAT: return "float";
49 case TYPE_BOOL: return "bool";
50 case TYPE_ADDR: return "addr";
51 case TYPE_ADDRVEC: return "addrvec";
52 case TYPE_UUID: return "uuid";
53 case TYPE_SIZE: return "size";
54 case TYPE_SECS: return "secs";
55 default: return "unknown";
56 }
57 }
58 static int str_to_type(const std::string& s) {
59 if (s == "uint") {
60 return TYPE_UINT;
61 }
62 if (s == "int") {
63 return TYPE_INT;
64 }
65 if (s == "str") {
66 return TYPE_STR;
67 }
68 if (s == "float") {
69 return TYPE_FLOAT;
70 }
71 if (s == "bool") {
72 return TYPE_BOOL;
73 }
74 if (s == "addr") {
75 return TYPE_ADDR;
76 }
77 if (s == "addrvec") {
78 return TYPE_ADDRVEC;
79 }
80 if (s == "uuid") {
81 return TYPE_UUID;
82 }
83 if (s == "size") {
84 return TYPE_SIZE;
85 }
86 if (s == "secs") {
87 return TYPE_SECS;
88 }
89 return -1;
90 }
91
92 /**
93 * Basic: for users, configures some externally visible functional aspect
94 * Advanced: for users, configures some internal behaviour
95 * Development: not for users. May be dangerous, may not be documented.
96 */
97 enum level_t {
98 LEVEL_BASIC = 0,
99 LEVEL_ADVANCED = 1,
100 LEVEL_DEV = 2,
101 LEVEL_UNKNOWN = 3,
102 };
103
104 static const char *level_to_str(level_t l) {
105 switch (l) {
106 case LEVEL_BASIC: return "basic";
107 case LEVEL_ADVANCED: return "advanced";
108 case LEVEL_DEV: return "dev";
109 default: return "unknown";
110 }
111 }
112
113 enum flag_t {
114 FLAG_RUNTIME = 0x1, ///< option can change changed at runtime
115 FLAG_NO_MON_UPDATE = 0x2, ///< option cannot be changed via mon config
116 FLAG_STARTUP = 0x4, ///< option can only take effect at startup
117 FLAG_CLUSTER_CREATE = 0x8, ///< option only has effect at cluster creation
118 FLAG_CREATE = 0x10, ///< option only has effect at daemon creation
119 FLAG_MGR = 0x20, ///< option is a mgr module option
120 FLAG_MINIMAL_CONF = 0x40, ///< option should go in a minimal ceph.conf
121 };
122
123 struct size_t {
124 std::size_t value;
125 operator uint64_t() const {
126 return static_cast<uint64_t>(value);
127 }
128 bool operator==(const size_t& rhs) const {
129 return value == rhs.value;
130 }
131 };
132
133 using value_t = boost::variant<
134 boost::blank,
135 std::string,
136 uint64_t,
137 int64_t,
138 double,
139 bool,
140 entity_addr_t,
141 entity_addrvec_t,
142 std::chrono::seconds,
143 size_t,
144 uuid_d>;
145 const std::string name;
146 const type_t type;
147 const level_t level;
148
149 std::string desc;
150 std::string long_desc;
151
152 unsigned flags = 0;
153
154 int subsys = -1; // if >= 0, we are a subsys debug level
155
156 value_t value;
157 value_t daemon_value;
158
159 static std::string to_str(const value_t& v);
160
161 // Items like mon, osd, rgw, rbd, ceph-fuse. This is advisory metadata
162 // for presentation layers (like web dashboards, or generated docs), so that
163 // they know which options to display where.
164 // Additionally: "common" for settings that exist in any Ceph code. Do
165 // not use common for settings that are just shared some places: for those
166 // places, list them.
167 std::vector<const char*> services;
168
169 // Topics like:
170 // "service": a catchall for the boring stuff like log/asok paths.
171 // "network"
172 // "performance": a setting that may need adjustment depending on
173 // environment/workload to get best performance.
174 std::vector<const char*> tags;
175
176 std::vector<const char*> see_also;
177
178 value_t min, max;
179 std::vector<const char*> enum_allowed;
180
181 /**
182 * Return nonzero and set second argument to error string if the
183 * value is invalid.
184 *
185 * These callbacks are more than just validators, as they can also
186 * modify the value as it passes through.
187 */
188 typedef std::function<int(std::string *, std::string *)> validator_fn_t;
189 validator_fn_t validator;
190
191 Option(std::string const &name, type_t t, level_t l)
192 : name(name), type(t), level(l)
193 {
194 // While value_t is nullable (via boost::blank), we don't ever
195 // want it set that way in an Option instance: within an instance,
196 // the type of ::value should always match the declared type.
197 switch (type) {
198 case TYPE_INT:
199 value = int64_t(0); break;
200 case TYPE_UINT:
201 value = uint64_t(0); break;
202 case TYPE_STR:
203 value = std::string(""); break;
204 case TYPE_FLOAT:
205 value = 0.0; break;
206 case TYPE_BOOL:
207 value = false; break;
208 case TYPE_ADDR:
209 value = entity_addr_t(); break;
210 case TYPE_ADDRVEC:
211 value = entity_addrvec_t(); break;
212 case TYPE_UUID:
213 value = uuid_d(); break;
214 case TYPE_SIZE:
215 value = size_t{0}; break;
216 case TYPE_SECS:
217 value = std::chrono::seconds{0}; break;
218 default:
219 ceph_abort();
220 }
221 }
222
223 void dump_value(const char *field_name, const value_t &v, ceph::Formatter *f) const;
224
225 // Validate and potentially modify incoming string value
226 int pre_validate(std::string *new_value, std::string *err) const;
227
228 // Validate properly typed value against bounds
229 int validate(const Option::value_t &new_value, std::string *err) const;
230
231 // const char * must be explicit to avoid it being treated as an int
232 Option& set_value(value_t& v, const char *new_value) {
233 v = std::string(new_value);
234 return *this;
235 }
236
237 // bool is an integer, but we don't think so. teach it the hard way.
238 template<typename T>
239 using is_not_integer = std::enable_if<!std::is_integral<T>::value ||
240 std::is_same<T, bool>::value, int>;
241 template<typename T>
242 using is_integer = std::enable_if<std::is_integral<T>::value &&
243 !std::is_same<T, bool>::value, int>;
244 template<typename T, typename is_not_integer<T>::type = 0>
245 Option& set_value(value_t& v, const T& new_value) {
246 v = new_value;
247 return *this;
248 }
249
250 // For potentially ambiguous types, inspect Option::type and
251 // do some casting. This is necessary to make sure that setting
252 // a float option to "0" actually sets the double part of variant.
253 template<typename T, typename is_integer<T>::type = 0>
254 Option& set_value(value_t& v, T new_value) {
255 switch (type) {
256 case TYPE_INT:
257 v = int64_t(new_value); break;
258 case TYPE_UINT:
259 v = uint64_t(new_value); break;
260 case TYPE_FLOAT:
261 v = double(new_value); break;
262 case TYPE_BOOL:
263 v = bool(new_value); break;
264 case TYPE_SIZE:
265 v = size_t{static_cast<std::size_t>(new_value)}; break;
266 case TYPE_SECS:
267 v = std::chrono::seconds{new_value}; break;
268 default:
269 std::cerr << "Bad type in set_value: " << name << ": "
270 << typeid(T).name() << std::endl;
271 ceph_abort();
272 }
273 return *this;
274 }
275
276 /// parse and validate a string input
277 int parse_value(
278 const std::string& raw_val,
279 value_t *out,
280 std::string *error_message,
281 std::string *normalized_value=nullptr) const;
282
283 template<typename T>
284 Option& set_default(const T& v) {
285 return set_value(value, v);
286 }
287
288 template<typename T>
289 Option& set_daemon_default(const T& v) {
290 return set_value(daemon_value, v);
291 }
292 Option& add_tag(const char* tag) {
293 tags.push_back(tag);
294 return *this;
295 }
296 Option& add_tag(const std::initializer_list<const char*>& ts) {
297 tags.insert(tags.end(), ts);
298 return *this;
299 }
300 Option& add_service(const char* service) {
301 services.push_back(service);
302 return *this;
303 }
304 Option& add_service(const std::initializer_list<const char*>& ss) {
305 services.insert(services.end(), ss);
306 return *this;
307 }
308 Option& add_see_also(const char* t) {
309 see_also.push_back(t);
310 return *this;
311 }
312 Option& add_see_also(const std::initializer_list<const char*>& ts) {
313 see_also.insert(see_also.end(), ts);
314 return *this;
315 }
316 Option& set_description(const char* new_desc) {
317 desc = new_desc;
318 return *this;
319 }
320 Option& set_long_description(const char* new_desc) {
321 long_desc = new_desc;
322 return *this;
323 }
324
325 template<typename T>
326 Option& set_min(const T& mi) {
327 set_value(min, mi);
328 return *this;
329 }
330
331 template<typename T>
332 Option& set_min_max(const T& mi, const T& ma) {
333 set_value(min, mi);
334 set_value(max, ma);
335 return *this;
336 }
337
338 Option& set_enum_allowed(const std::vector<const char*>& allowed)
339 {
340 enum_allowed = allowed;
341 return *this;
342 }
343
344 Option &set_flag(flag_t f) {
345 flags |= f;
346 return *this;
347 }
348 Option &set_flags(flag_t f) {
349 flags |= f;
350 return *this;
351 }
352
353 Option &set_validator(const validator_fn_t &validator_)
354 {
355 validator = validator_;
356 return *this;
357 }
358
359 Option &set_subsys(int s) {
360 subsys = s;
361 return *this;
362 }
363
364 void dump(ceph::Formatter *f) const;
365 void print(std::ostream *out) const;
366
367 bool has_flag(flag_t f) const {
368 return flags & f;
369 }
370
371 /**
372 * A crude indicator of whether the value may be
373 * modified safely at runtime -- should be replaced
374 * with proper locking!
375 */
376 bool can_update_at_runtime() const
377 {
378 return
379 (has_flag(FLAG_RUNTIME)
380 || (!has_flag(FLAG_MGR)
381 && (type == TYPE_BOOL || type == TYPE_INT
382 || type == TYPE_UINT || type == TYPE_FLOAT
383 || type == TYPE_SIZE || type == TYPE_SECS)))
384 && !has_flag(FLAG_STARTUP)
385 && !has_flag(FLAG_CLUSTER_CREATE)
386 && !has_flag(FLAG_CREATE);
387 }
388 };
389
390 extern const std::vector<Option> ceph_options;
391