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