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