dbaccess_parser.cc 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // Copyright (C) 2012-2016 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. #include <config.h>
  7. #include <dhcp/option.h>
  8. #include <dhcpsrv/cfg_db_access.h>
  9. #include <dhcpsrv/cfgmgr.h>
  10. #include <dhcpsrv/dhcpsrv_log.h>
  11. #include <dhcpsrv/lease_mgr_factory.h>
  12. #include <dhcpsrv/host_mgr.h>
  13. #include <dhcpsrv/parsers/dbaccess_parser.h>
  14. #include <boost/foreach.hpp>
  15. #include <boost/lexical_cast.hpp>
  16. #include <map>
  17. #include <string>
  18. #include <utility>
  19. using namespace std;
  20. using namespace isc::data;
  21. namespace isc {
  22. namespace dhcp {
  23. // Factory function to build the parser
  24. DbAccessParser::DbAccessParser(const std::string&, DBType db_type)
  25. : values_(), type_(db_type) {
  26. }
  27. // Parse the configuration and check that the various keywords are consistent.
  28. void
  29. DbAccessParser::build(isc::data::ConstElementPtr config_value) {
  30. // To cope with incremental updates, the strategy is:
  31. // 1. Take a copy of the stored keyword/value pairs.
  32. // 2. Update the copy with the passed keywords.
  33. // 3. Perform validation checks on the updated keyword/value pairs.
  34. // 4. If all is OK, update the stored keyword/value pairs.
  35. // 5. Save resulting database access string in the Configuration
  36. // Manager.
  37. // 1. Take a copy of the stored keyword/value pairs.
  38. std::map<string, string> values_copy = values_;
  39. int64_t lfc_interval = 0;
  40. int64_t timeout = 0;
  41. // 2. Update the copy with the passed keywords.
  42. BOOST_FOREACH(ConfigPair param, config_value->mapValue()) {
  43. try {
  44. if (param.first == "persist") {
  45. values_copy[param.first] = (param.second->boolValue() ?
  46. "true" : "false");
  47. } else if (param.first == "lfc-interval") {
  48. lfc_interval = param.second->intValue();
  49. values_copy[param.first] =
  50. boost::lexical_cast<std::string>(lfc_interval);
  51. } else if (param.first == "connect-timeout") {
  52. timeout = param.second->intValue();
  53. values_copy[param.first] =
  54. boost::lexical_cast<std::string>(timeout);
  55. } else {
  56. values_copy[param.first] = param.second->stringValue();
  57. }
  58. } catch (const isc::data::TypeError& ex) {
  59. // Append position of the element.
  60. isc_throw(isc::data::TypeError, ex.what() << " ("
  61. << param.second->getPosition() << ")");
  62. }
  63. }
  64. // 3. Perform validation checks on the updated set of keyword/values.
  65. //
  66. // a. Check if the "type" keyword exists and thrown an exception if not.
  67. StringPairMap::const_iterator type_ptr = values_copy.find("type");
  68. if (type_ptr == values_copy.end()) {
  69. isc_throw(TypeKeywordMissing, "lease database access parameters must "
  70. "include the keyword 'type' to determine type of database "
  71. "to be accessed (" << config_value->getPosition() << ")");
  72. }
  73. // b. Check if the 'type' keyword known and throw an exception if not.
  74. string dbtype = type_ptr->second;
  75. if ((dbtype != "memfile") && (dbtype != "mysql") && (dbtype != "postgresql")) {
  76. isc_throw(BadValue, "unknown backend database type: " << dbtype
  77. << " (" << config_value->getPosition() << ")");
  78. }
  79. // c. Check that the lfc-interval is a number and it is within a resonable
  80. // range.
  81. if ((lfc_interval < 0) || (lfc_interval > std::numeric_limits<uint32_t>::max())) {
  82. isc_throw(BadValue, "lfc-interval value: " << lfc_interval
  83. << " is out of range, expected value: 0.."
  84. << std::numeric_limits<uint32_t>::max());
  85. }
  86. // d. Check that the timeout is a number and it is within a resonable
  87. // range.
  88. if ((timeout < 0) || (timeout > std::numeric_limits<uint32_t>::max())) {
  89. isc_throw(BadValue, "timeout value: " << timeout
  90. << " is out of range, expected value: 0.."
  91. << std::numeric_limits<uint32_t>::max());
  92. }
  93. // 4. If all is OK, update the stored keyword/value pairs. We do this by
  94. // swapping contents - values_copy is destroyed immediately after the
  95. // operation (when the method exits), so we are not interested in its new
  96. // value.
  97. values_.swap(values_copy);
  98. // 5. Save the database access string in the Configuration Manager.
  99. CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
  100. if (type_ == LEASE_DB) {
  101. cfg_db->setLeaseDbAccessString(getDbAccessString());
  102. } else {
  103. cfg_db->setHostDbAccessString(getDbAccessString());
  104. }
  105. }
  106. // Create the database access string
  107. std::string
  108. DbAccessParser::getDbAccessString() const {
  109. // Construct the database access string from all keywords and values in the
  110. // parameter map where the value is not null.
  111. string dbaccess;
  112. BOOST_FOREACH(StringPair keyval, values_) {
  113. if (!keyval.second.empty()) {
  114. // Separate keyword/value pair from predecessor (if there is one).
  115. if (!dbaccess.empty()) {
  116. dbaccess += std::string(" ");
  117. }
  118. // Add the keyword/value pair to the access string.
  119. dbaccess += (keyval.first + std::string("=") + keyval.second);
  120. }
  121. }
  122. return (dbaccess);
  123. }
  124. // Commit the changes - reopen the database with the new parameters
  125. void
  126. DbAccessParser::commit() {
  127. }
  128. }; // namespace dhcp
  129. }; // namespace isc