]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/options.cc
bump version to 18.2.2-pve1
[ceph.git] / ceph / src / common / options.cc
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#include "acconfig.h"
5#include "options.h"
6#include "common/Formatter.h"
20effc67 7#include "common/options/build_options.h"
c07f9fc5
FG
8
9// Helpers for validators
10#include "include/stringify.h"
9f95a23c 11#include "include/common_fwd.h"
c07f9fc5
FG
12#include <boost/algorithm/string.hpp>
13#include <boost/lexical_cast.hpp>
11fdf7f2 14#include <regex>
c07f9fc5 15
3efd9988
FG
16// Definitions for enums
17#include "common/perf_counters.h"
18
20effc67 19// rbd feature and io operation validation
11fdf7f2 20#include "librbd/Features.h"
20effc67 21#include "librbd/io/IoOperations.h"
11fdf7f2 22
f67539c2
TL
23using std::ostream;
24using std::ostringstream;
25
26using ceph::Formatter;
27using ceph::parse_timespan;
28
11fdf7f2 29namespace {
20effc67 30class printer {
11fdf7f2
TL
31 ostream& out;
32public:
33 explicit printer(ostream& os)
34 : out(os) {}
35 template<typename T>
36 void operator()(const T& v) const {
37 out << v;
38 }
20effc67 39 void operator()(std::monostate) const {
11fdf7f2
TL
40 return;
41 }
42 void operator()(bool v) const {
43 out << (v ? "true" : "false");
44 }
45 void operator()(double v) const {
46 out << std::fixed << v << std::defaultfloat;
47 }
48 void operator()(const Option::size_t& v) const {
49 out << v.value;
50 }
51 void operator()(const std::chrono::seconds v) const {
52 out << v.count();
53 }
f67539c2
TL
54 void operator()(const std::chrono::milliseconds v) const {
55 out << v.count();
56 }
11fdf7f2
TL
57};
58}
59
60ostream& operator<<(ostream& os, const Option::value_t& v) {
61 printer p{os};
20effc67 62 std::visit(p, v);
11fdf7f2
TL
63 return os;
64}
c07f9fc5
FG
65
66void Option::dump_value(const char *field_name,
67 const Option::value_t &v, Formatter *f) const
68{
20effc67 69 if (v == value_t{}) {
c07f9fc5
FG
70 // This should be nil but Formatter doesn't allow it.
71 f->dump_string(field_name, "");
11fdf7f2
TL
72 return;
73 }
74 switch (type) {
75 case TYPE_INT:
20effc67 76 f->dump_int(field_name, std::get<int64_t>(v)); break;
11fdf7f2 77 case TYPE_UINT:
20effc67 78 f->dump_unsigned(field_name, std::get<uint64_t>(v)); break;
11fdf7f2 79 case TYPE_STR:
20effc67 80 f->dump_string(field_name, std::get<std::string>(v)); break;
11fdf7f2 81 case TYPE_FLOAT:
20effc67 82 f->dump_float(field_name, std::get<double>(v)); break;
11fdf7f2 83 case TYPE_BOOL:
20effc67 84 f->dump_bool(field_name, std::get<bool>(v)); break;
11fdf7f2
TL
85 default:
86 f->dump_stream(field_name) << v; break;
c07f9fc5
FG
87 }
88}
89
90int Option::pre_validate(std::string *new_value, std::string *err) const
91{
92 if (validator) {
93 return validator(new_value, err);
94 } else {
95 return 0;
96 }
97}
98
99int Option::validate(const Option::value_t &new_value, std::string *err) const
100{
101 // Generic validation: min
20effc67 102 if (min != value_t{}) {
c07f9fc5
FG
103 if (new_value < min) {
104 std::ostringstream oss;
105 oss << "Value '" << new_value << "' is below minimum " << min;
106 *err = oss.str();
107 return -EINVAL;
108 }
109 }
110
111 // Generic validation: max
20effc67 112 if (max != value_t{}) {
c07f9fc5
FG
113 if (new_value > max) {
114 std::ostringstream oss;
115 oss << "Value '" << new_value << "' exceeds maximum " << max;
116 *err = oss.str();
117 return -EINVAL;
118 }
119 }
120
121 // Generic validation: enum
122 if (!enum_allowed.empty() && type == Option::TYPE_STR) {
123 auto found = std::find(enum_allowed.begin(), enum_allowed.end(),
20effc67 124 std::get<std::string>(new_value));
c07f9fc5
FG
125 if (found == enum_allowed.end()) {
126 std::ostringstream oss;
127 oss << "'" << new_value << "' is not one of the permitted "
128 "values: " << joinify(enum_allowed.begin(),
129 enum_allowed.end(),
130 std::string(", "));
131 *err = oss.str();
132 return -EINVAL;
133 }
134 }
135
136 return 0;
137}
138
11fdf7f2
TL
139int Option::parse_value(
140 const std::string& raw_val,
141 value_t *out,
142 std::string *error_message,
143 std::string *normalized_value) const
144{
145 std::string val = raw_val;
146
147 int r = pre_validate(&val, error_message);
148 if (r != 0) {
149 return r;
150 }
151
152 if (type == Option::TYPE_INT) {
20effc67 153 int64_t f = strict_si_cast<int64_t>(val, error_message);
11fdf7f2
TL
154 if (!error_message->empty()) {
155 return -EINVAL;
156 }
157 *out = f;
158 } else if (type == Option::TYPE_UINT) {
20effc67 159 uint64_t f = strict_si_cast<uint64_t>(val, error_message);
11fdf7f2
TL
160 if (!error_message->empty()) {
161 return -EINVAL;
162 }
163 *out = f;
164 } else if (type == Option::TYPE_STR) {
165 *out = val;
166 } else if (type == Option::TYPE_FLOAT) {
167 double f = strict_strtod(val.c_str(), error_message);
168 if (!error_message->empty()) {
169 return -EINVAL;
170 } else {
171 *out = f;
172 }
173 } else if (type == Option::TYPE_BOOL) {
f67539c2
TL
174 bool b = strict_strtob(val.c_str(), error_message);
175 if (!error_message->empty()) {
176 return -EINVAL;
11fdf7f2 177 } else {
f67539c2 178 *out = b;
11fdf7f2
TL
179 }
180 } else if (type == Option::TYPE_ADDR) {
181 entity_addr_t addr;
20effc67 182 if (!addr.parse(val)){
11fdf7f2
TL
183 return -EINVAL;
184 }
185 *out = addr;
9f95a23c 186 } else if (type == Option::TYPE_ADDRVEC) {
11fdf7f2
TL
187 entity_addrvec_t addr;
188 if (!addr.parse(val.c_str())){
189 return -EINVAL;
190 }
191 *out = addr;
192 } else if (type == Option::TYPE_UUID) {
193 uuid_d uuid;
194 if (!uuid.parse(val.c_str())) {
195 return -EINVAL;
196 }
197 *out = uuid;
198 } else if (type == Option::TYPE_SIZE) {
20effc67 199 Option::size_t sz{strict_iecstrtoll(val, error_message)};
11fdf7f2
TL
200 if (!error_message->empty()) {
201 return -EINVAL;
202 }
203 *out = sz;
204 } else if (type == Option::TYPE_SECS) {
205 try {
206 *out = parse_timespan(val);
f67539c2
TL
207 } catch (const std::invalid_argument& e) {
208 *error_message = e.what();
209 return -EINVAL;
210 }
211 } else if (type == Option::TYPE_MILLISECS) {
212 try {
20effc67
TL
213 *out = std::chrono::milliseconds(std::stoull(val));
214 } catch (const std::logic_error& e) {
11fdf7f2
TL
215 *error_message = e.what();
216 return -EINVAL;
217 }
218 } else {
219 ceph_abort();
220 }
221
222 r = validate(*out, error_message);
223 if (r != 0) {
224 return r;
225 }
226
227 if (normalized_value) {
228 *normalized_value = to_str(*out);
229 }
230 return 0;
231}
232
c07f9fc5
FG
233void Option::dump(Formatter *f) const
234{
c07f9fc5
FG
235 f->dump_string("name", name);
236
237 f->dump_string("type", type_to_str(type));
c07f9fc5
FG
238
239 f->dump_string("level", level_to_str(level));
240
241 f->dump_string("desc", desc);
242 f->dump_string("long_desc", long_desc);
243
244 dump_value("default", value, f);
245 dump_value("daemon_default", daemon_value, f);
246
247 f->open_array_section("tags");
248 for (const auto t : tags) {
249 f->dump_string("tag", t);
250 }
251 f->close_section();
252
253 f->open_array_section("services");
254 for (const auto s : services) {
255 f->dump_string("service", s);
256 }
257 f->close_section();
258
259 f->open_array_section("see_also");
260 for (const auto sa : see_also) {
261 f->dump_string("see_also", sa);
262 }
263 f->close_section();
264
265 if (type == TYPE_STR) {
266 f->open_array_section("enum_values");
267 for (const auto &ea : enum_allowed) {
268 f->dump_string("enum_value", ea);
269 }
270 f->close_section();
271 }
272
273 dump_value("min", min, f);
274 dump_value("max", max, f);
275
11fdf7f2
TL
276 f->dump_bool("can_update_at_runtime", can_update_at_runtime());
277
278 f->open_array_section("flags");
279 if (has_flag(FLAG_RUNTIME)) {
280 f->dump_string("option", "runtime");
281 }
282 if (has_flag(FLAG_NO_MON_UPDATE)) {
283 f->dump_string("option", "no_mon_update");
284 }
285 if (has_flag(FLAG_STARTUP)) {
286 f->dump_string("option", "startup");
287 }
288 if (has_flag(FLAG_CLUSTER_CREATE)) {
289 f->dump_string("option", "cluster_create");
290 }
291 if (has_flag(FLAG_CREATE)) {
292 f->dump_string("option", "create");
293 }
c07f9fc5
FG
294 f->close_section();
295}
296
11fdf7f2
TL
297std::string Option::to_str(const Option::value_t& v)
298{
299 return stringify(v);
300}
301
302void Option::print(ostream *out) const
303{
304 *out << name << " - " << desc << "\n";
305 *out << " (" << type_to_str(type) << ", " << level_to_str(level) << ")\n";
20effc67 306 if (daemon_value != value_t{}) {
11fdf7f2
TL
307 *out << " Default (non-daemon): " << stringify(value) << "\n";
308 *out << " Default (daemon): " << stringify(daemon_value) << "\n";
309 } else {
310 *out << " Default: " << stringify(value) << "\n";
311 }
312 if (!enum_allowed.empty()) {
313 *out << " Possible values: ";
314 for (auto& i : enum_allowed) {
315 *out << " " << stringify(i);
316 }
317 *out << "\n";
318 }
20effc67 319 if (min != value_t{}) {
11fdf7f2
TL
320 *out << " Minimum: " << stringify(min) << "\n"
321 << " Maximum: " << stringify(max) << "\n";
322 }
323 *out << " Can update at runtime: "
324 << (can_update_at_runtime() ? "true" : "false") << "\n";
325 if (!services.empty()) {
326 *out << " Services: " << services << "\n";
327 }
328 if (!tags.empty()) {
329 *out << " Tags: " << tags << "\n";
330 }
331 if (!see_also.empty()) {
332 *out << " See also: " << see_also << "\n";
333 }
334
335 if (long_desc.size()) {
336 *out << "\n" << long_desc << "\n";
337 }
338}
339
c07f9fc5 340const std::vector<Option> ceph_options = build_options();