Kea 2.0.2
dbaccess_parser.cc
Go to the documentation of this file.
1// Copyright (C) 2012-2021 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
12
13#include <boost/lexical_cast.hpp>
14
15#include <map>
16#include <string>
17#include <utility>
18
19using namespace std;
20using namespace isc::data;
21
22namespace isc {
23namespace db {
24
25
26// Factory function to build the parser
28 : values_() {
29}
30
31// Parse the configuration and check that the various keywords are consistent.
32void
33DbAccessParser::parse(std::string& access_string,
34 ConstElementPtr database_config) {
35
36 // To cope with incremental updates, the strategy is:
37 // 1. Take a copy of the stored keyword/value pairs.
38 // 2. Update the copy with the passed keywords.
39 // 3. Perform validation checks on the updated keyword/value pairs.
40 // 4. If all is OK, update the stored keyword/value pairs.
41 // 5. Save resulting database access string in the Configuration
42 // Manager.
43
44 // Note only range checks can fail with a database_config from
45 // a flex/bison parser.
46
47 // 1. Take a copy of the stored keyword/value pairs.
48 DatabaseConnection::ParameterMap values_copy = values_;
49
50 int64_t lfc_interval = 0;
51 int64_t timeout = 0;
52 int64_t port = 0;
53 int64_t max_reconnect_tries = 0;
54 int64_t reconnect_wait_time = 0;
55 int64_t request_timeout = 0;
56 int64_t tcp_keepalive = 0;
57 int64_t max_row_errors = 0;
58
59 // 2. Update the copy with the passed keywords.
60 for (std::pair<std::string, ConstElementPtr> param : database_config->mapValue()) {
61 try {
62 if ((param.first == "persist") ||
63 (param.first == "tcp-nodelay") ||
64 (param.first == "readonly")) {
65 values_copy[param.first] = (param.second->boolValue() ?
66 "true" : "false");
67
68 } else if (param.first == "lfc-interval") {
69 lfc_interval = param.second->intValue();
70 values_copy[param.first] =
71 boost::lexical_cast<std::string>(lfc_interval);
72
73 } else if (param.first == "connect-timeout") {
74 timeout = param.second->intValue();
75 values_copy[param.first] =
76 boost::lexical_cast<std::string>(timeout);
77
78 } else if (param.first == "max-reconnect-tries") {
79 max_reconnect_tries = param.second->intValue();
80 values_copy[param.first] =
81 boost::lexical_cast<std::string>(max_reconnect_tries);
82
83 } else if (param.first == "reconnect-wait-time") {
84 reconnect_wait_time = param.second->intValue();
85 values_copy[param.first] =
86 boost::lexical_cast<std::string>(reconnect_wait_time);
87
88 } else if (param.first == "request-timeout") {
89 request_timeout = param.second->intValue();
90 values_copy[param.first] =
91 boost::lexical_cast<std::string>(request_timeout);
92
93 } else if (param.first == "tcp-keepalive") {
94 tcp_keepalive = param.second->intValue();
95 values_copy[param.first] =
96 boost::lexical_cast<std::string>(tcp_keepalive);
97
98 } else if (param.first == "port") {
99 port = param.second->intValue();
100 values_copy[param.first] =
101 boost::lexical_cast<std::string>(port);
102
103 } else if (param.first == "max-row-errors") {
104 max_row_errors = param.second->intValue();
105 values_copy[param.first] =
106 boost::lexical_cast<std::string>(max_row_errors);
107 } else {
108
109 // all remaining string parameters
110 // type
111 // user
112 // password
113 // host
114 // name
115 // contact-points
116 // keyspace
117 // consistency
118 // serial-consistency
119 // on-fail
120 values_copy[param.first] = param.second->stringValue();
121 }
122 } catch (const isc::data::TypeError& ex) {
123 // Append position of the element.
124 isc_throw(DbConfigError, "invalid value type specified for "
125 "parameter '" << param.first << "' ("
126 << param.second->getPosition() << ")");
127 }
128 }
129
130 // 3. Perform validation checks on the updated set of keyword/values.
131 //
132 // a. Check if the "type" keyword exists and thrown an exception if not.
133 auto type_ptr = values_copy.find("type");
134 if (type_ptr == values_copy.end()) {
136 "database access parameters must "
137 "include the keyword 'type' to determine type of database "
138 "to be accessed (" << database_config->getPosition() << ")");
139 }
140
141 // b. Check if the 'type' keyword known and throw an exception if not.
142 //
143 // Please note when you add a new database backend you have to add
144 // the new type here and in server grammars.
145 string dbtype = type_ptr->second;
146 if ((dbtype != "memfile") &&
147 (dbtype != "mysql") &&
148 (dbtype != "postgresql") &&
149 (dbtype != "cql")) {
150 ConstElementPtr value = database_config->get("type");
151 isc_throw(DbConfigError, "unknown backend database type: " << dbtype
152 << " (" << value->getPosition() << ")");
153 }
154
155 // c. Check that the lfc-interval is within a reasonable range.
156 if ((lfc_interval < 0) ||
157 (lfc_interval > std::numeric_limits<uint32_t>::max())) {
158 ConstElementPtr value = database_config->get("lfc-interval");
159 isc_throw(DbConfigError, "lfc-interval value: " << lfc_interval
160 << " is out of range, expected value: 0.."
161 << std::numeric_limits<uint32_t>::max()
162 << " (" << value->getPosition() << ")");
163 }
164
165 // d. Check that the timeout is within a reasonable range.
166 if ((timeout < 0) ||
167 (timeout > std::numeric_limits<uint32_t>::max())) {
168 ConstElementPtr value = database_config->get("connect-timeout");
169 isc_throw(DbConfigError, "connect-timeout value: " << timeout
170 << " is out of range, expected value: 0.."
171 << std::numeric_limits<uint32_t>::max()
172 << " (" << value->getPosition() << ")");
173 }
174
175 // e. Check that the port is within a reasonable range.
176 if ((port < 0) ||
177 (port > std::numeric_limits<uint16_t>::max())) {
178 ConstElementPtr value = database_config->get("port");
179 isc_throw(DbConfigError, "port value: " << port
180 << " is out of range, expected value: 0.."
181 << std::numeric_limits<uint16_t>::max()
182 << " (" << value->getPosition() << ")");
183 }
184
185 // f. Check that the max-row-errors is within a reasonable range.
186 if ((max_row_errors < 0) ||
187 (max_row_errors > std::numeric_limits<uint32_t>::max())) {
188 ConstElementPtr value = database_config->get("max-row-errors");
189 isc_throw(DbConfigError, "max-row-errors value: " << max_row_errors
190 << " is out of range, expected value: 0.."
191 << std::numeric_limits<uint32_t>::max()
192 << " (" << value->getPosition() << ")");
193 }
194
195 // Check that the max-reconnect-tries is reasonable.
196 if (max_reconnect_tries < 0) {
197 ConstElementPtr value = database_config->get("max-reconnect-tries");
199 "max-reconnect-tries cannot be less than zero: ("
200 << value->getPosition() << ")");
201 }
202
203 // Check that the reconnect-wait-time is reasonable.
204 if ((reconnect_wait_time < 0) ||
205 (reconnect_wait_time > std::numeric_limits<uint32_t>::max())) {
206 ConstElementPtr value = database_config->get("reconnect-wait-time");
207 isc_throw(DbConfigError, "reconnect-wait-time " << reconnect_wait_time
208 << " must be in range 0...MAX_UINT32 (4294967295) "
209 << "(" << value->getPosition() << ")");
210 }
211
212 // Check that request_timeout value makes sense.
213 if ((request_timeout < 0) ||
214 (request_timeout > std::numeric_limits<uint32_t>::max())) {
215 ConstElementPtr value = database_config->get("request-timeout");
216 isc_throw(DbConfigError, "request-timeout " << request_timeout
217 << " must be in range 0...MAX_UINT32 (4294967295) "
218 << "(" << value->getPosition() << ")");
219 }
220
221 // Check that tcp_keepalive value makes sense.
222 if ((tcp_keepalive < 0) ||
223 (tcp_keepalive > std::numeric_limits<uint32_t>::max())) {
224 ConstElementPtr value = database_config->get("tcp-keepalive");
225 isc_throw(DbConfigError, "tcp-keepalive " << tcp_keepalive
226 << " must be in range 0...MAX_UINT32 (4294967295) "
227 << "(" << value->getPosition() << ")");
228 }
229
230 // 4. If all is OK, update the stored keyword/value pairs. We do this by
231 // swapping contents - values_copy is destroyed immediately after the
232 // operation (when the method exits), so we are not interested in its new
233 // value.
234 values_.swap(values_copy);
235
236 // 5. Save the database access string in the Configuration Manager.
237 access_string = getDbAccessString();
238}
239
240// Create the database access string
241std::string
243
244 // Construct the database access string from all keywords and values in the
245 // parameter map where the value is not null.
246 string dbaccess;
247 for (auto keyval : values_) {
248 if (!keyval.second.empty()) {
249
250 // Separate keyword/value pair from predecessor (if there is one).
251 if (!dbaccess.empty()) {
252 dbaccess += std::string(" ");
253 }
254
255 // Add the keyword/value pair to the access string.
256 auto val = keyval.second;
257 if (val.find_first_of("\t ") != string::npos){
258 val = "'" + val + "'";
259 }
260 dbaccess += (keyval.first + std::string("=") + val);
261 }
262 }
263
264 return (dbaccess);
265}
266
267} // namespace db
268} // namespace isc
A standard Data module exception that is thrown if a function is called for an Element that has a wro...
Definition: data.h:34
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
void parse(std::string &access_string, isc::data::ConstElementPtr database_config)
Parse configuration value.
DbAccessParser()
Constructor.
std::string getDbAccessString() const
Construct database access string.
Error detected in the database configuration.
Definition: db_exceptions.h:78
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
Defines the logger used by the top-level component of kea-lfc.