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