dbaccess_parser.cc 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <dhcp/option.h>
  16. #include <dhcpsrv/dhcpsrv_log.h>
  17. #include <dhcpsrv/lease_mgr_factory.h>
  18. #include <dhcpsrv/parsers/dbaccess_parser.h>
  19. #include <boost/foreach.hpp>
  20. #include <boost/lexical_cast.hpp>
  21. #include <map>
  22. #include <string>
  23. #include <utility>
  24. using namespace std;
  25. using namespace isc::data;
  26. namespace isc {
  27. namespace dhcp {
  28. // Factory function to build the parser
  29. DbAccessParser::DbAccessParser(const std::string&, const ParserContext& ctx)
  30. : values_(), ctx_(ctx)
  31. {
  32. }
  33. // Parse the configuration and check that the various keywords are consistent.
  34. void
  35. DbAccessParser::build(isc::data::ConstElementPtr config_value) {
  36. // To cope with incremental updates, the strategy is:
  37. // 1. Take a copy of the stored keyword/value pairs.
  38. // 2. Inject the universe parameter.
  39. // 3. Update the copy with the passed keywords.
  40. // 4. Perform validation checks on the updated keyword/value pairs.
  41. // 5. If all is OK, update the stored keyword/value pairs.
  42. // 1. Take a copy of the stored keyword/value pairs.
  43. std::map<string, string> values_copy = values_;
  44. // 2. Inject the parameter which defines whether we are configuring
  45. // DHCPv4 or DHCPv6. Some database backends (e.g. Memfile make
  46. // use of it).
  47. values_copy["universe"] = ctx_.universe_ == Option::V4 ? "4" : "6";
  48. int64_t lfc_interval = 0;
  49. // 3. Update the copy with the passed keywords.
  50. BOOST_FOREACH(ConfigPair param, config_value->mapValue()) {
  51. try {
  52. if (param.first == "persist") {
  53. values_copy[param.first] = (param.second->boolValue() ?
  54. "true" : "false");
  55. } else if (param.first == "lfc-interval") {
  56. lfc_interval = param.second->intValue();
  57. values_copy[param.first] =
  58. boost::lexical_cast<std::string>(lfc_interval);
  59. } else {
  60. values_copy[param.first] = param.second->stringValue();
  61. }
  62. } catch (const isc::data::TypeError& ex) {
  63. // Append position of the element.
  64. isc_throw(isc::data::TypeError, ex.what() << " ("
  65. << param.second->getPosition() << ")");
  66. }
  67. }
  68. // 4. Perform validation checks on the updated set of keyword/values.
  69. //
  70. // a. Check if the "type" keyword exists and thrown an exception if not.
  71. StringPairMap::const_iterator type_ptr = values_copy.find("type");
  72. if (type_ptr == values_copy.end()) {
  73. isc_throw(TypeKeywordMissing, "lease database access parameters must "
  74. "include the keyword 'type' to determine type of database "
  75. "to be accessed (" << config_value->getPosition() << ")");
  76. }
  77. // b. Check if the 'type' keyword known and throw an exception if not.
  78. string dbtype = type_ptr->second;
  79. if ((dbtype != "memfile") && (dbtype != "mysql") && (dbtype != "postgresql")) {
  80. isc_throw(BadValue, "unknown backend database type: " << dbtype
  81. << " (" << config_value->getPosition() << ")");
  82. }
  83. // c. Check that the lfc-interval is a number and it is within a resonable
  84. // range.
  85. if ((lfc_interval < 0) || (lfc_interval > std::numeric_limits<uint32_t>::max())) {
  86. isc_throw(BadValue, "lfc-interval value: " << lfc_interval
  87. << " is out of range, expected value: 0.."
  88. << std::numeric_limits<uint32_t>::max());
  89. }
  90. // 5. If all is OK, update the stored keyword/value pairs. We do this by
  91. // swapping contents - values_copy is destroyed immediately after the
  92. // operation (when the method exits), so we are not interested in its new
  93. // value.
  94. values_.swap(values_copy);
  95. }
  96. // Create the database access string
  97. std::string
  98. DbAccessParser::getDbAccessString() const {
  99. // Construct the database access string from all keywords and values in the
  100. // parameter map where the value is not null.
  101. string dbaccess;
  102. BOOST_FOREACH(StringPair keyval, values_) {
  103. if (!keyval.second.empty()) {
  104. // Separate keyword/value pair from predecessor (if there is one).
  105. if (!dbaccess.empty()) {
  106. dbaccess += std::string(" ");
  107. }
  108. // Add the keyword/value pair to the access string.
  109. dbaccess += (keyval.first + std::string("=") + keyval.second);
  110. }
  111. }
  112. return (dbaccess);
  113. }
  114. // Commit the changes - reopen the database with the new parameters
  115. void
  116. DbAccessParser::commit() {
  117. // Close current lease manager database.
  118. LeaseMgrFactory::destroy();
  119. // ... and open the new database using the access string.
  120. LeaseMgrFactory::create(getDbAccessString());
  121. }
  122. }; // namespace dhcp
  123. }; // namespace isc