dbaccess_parser.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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/host_mgr.h>
  19. #include <dhcpsrv/parsers/dbaccess_parser.h>
  20. #include <boost/foreach.hpp>
  21. #include <boost/lexical_cast.hpp>
  22. #include <map>
  23. #include <string>
  24. #include <utility>
  25. using namespace std;
  26. using namespace isc::data;
  27. namespace isc {
  28. namespace dhcp {
  29. // Factory function to build the parser
  30. DbAccessParser::DbAccessParser(const std::string&, DBType db_type,
  31. const ParserContext& ctx)
  32. : values_(), type_(db_type), ctx_(ctx)
  33. {
  34. }
  35. // Parse the configuration and check that the various keywords are consistent.
  36. void
  37. DbAccessParser::build(isc::data::ConstElementPtr config_value) {
  38. // To cope with incremental updates, the strategy is:
  39. // 1. Take a copy of the stored keyword/value pairs.
  40. // 2. Inject the universe parameter.
  41. // 3. Update the copy with the passed keywords.
  42. // 4. Perform validation checks on the updated keyword/value pairs.
  43. // 5. If all is OK, update the stored keyword/value pairs.
  44. // 1. Take a copy of the stored keyword/value pairs.
  45. std::map<string, string> values_copy = values_;
  46. // 2. Inject the parameter which defines whether we are configuring
  47. // DHCPv4 or DHCPv6. Some database backends (e.g. Memfile make
  48. // use of it).
  49. values_copy["universe"] = ctx_.universe_ == Option::V4 ? "4" : "6";
  50. int64_t lfc_interval = 0;
  51. // 3. Update the copy with the passed keywords.
  52. BOOST_FOREACH(ConfigPair param, config_value->mapValue()) {
  53. try {
  54. if (param.first == "persist") {
  55. values_copy[param.first] = (param.second->boolValue() ?
  56. "true" : "false");
  57. } else if (param.first == "lfc-interval") {
  58. lfc_interval = param.second->intValue();
  59. values_copy[param.first] =
  60. boost::lexical_cast<std::string>(lfc_interval);
  61. } else {
  62. values_copy[param.first] = param.second->stringValue();
  63. }
  64. } catch (const isc::data::TypeError& ex) {
  65. // Append position of the element.
  66. isc_throw(isc::data::TypeError, ex.what() << " ("
  67. << param.second->getPosition() << ")");
  68. }
  69. }
  70. // 4. Perform validation checks on the updated set of keyword/values.
  71. //
  72. // a. Check if the "type" keyword exists and thrown an exception if not.
  73. StringPairMap::const_iterator type_ptr = values_copy.find("type");
  74. if (type_ptr == values_copy.end()) {
  75. isc_throw(TypeKeywordMissing, "lease database access parameters must "
  76. "include the keyword 'type' to determine type of database "
  77. "to be accessed (" << config_value->getPosition() << ")");
  78. }
  79. // b. Check if the 'type' keyword known and throw an exception if not.
  80. string dbtype = type_ptr->second;
  81. if ((dbtype != "memfile") && (dbtype != "mysql") && (dbtype != "postgresql")) {
  82. isc_throw(BadValue, "unknown backend database type: " << dbtype
  83. << " (" << config_value->getPosition() << ")");
  84. }
  85. // c. Check that the lfc-interval is a number and it is within a resonable
  86. // range.
  87. if ((lfc_interval < 0) || (lfc_interval > std::numeric_limits<uint32_t>::max())) {
  88. isc_throw(BadValue, "lfc-interval value: " << lfc_interval
  89. << " is out of range, expected value: 0.."
  90. << std::numeric_limits<uint32_t>::max());
  91. }
  92. // 5. If all is OK, update the stored keyword/value pairs. We do this by
  93. // swapping contents - values_copy is destroyed immediately after the
  94. // operation (when the method exits), so we are not interested in its new
  95. // value.
  96. values_.swap(values_copy);
  97. }
  98. // Create the database access string
  99. std::string
  100. DbAccessParser::getDbAccessString() const {
  101. // Construct the database access string from all keywords and values in the
  102. // parameter map where the value is not null.
  103. string dbaccess;
  104. BOOST_FOREACH(StringPair keyval, values_) {
  105. if (!keyval.second.empty()) {
  106. // Separate keyword/value pair from predecessor (if there is one).
  107. if (!dbaccess.empty()) {
  108. dbaccess += std::string(" ");
  109. }
  110. // Add the keyword/value pair to the access string.
  111. dbaccess += (keyval.first + std::string("=") + keyval.second);
  112. }
  113. }
  114. return (dbaccess);
  115. }
  116. // Commit the changes - reopen the database with the new parameters
  117. void
  118. DbAccessParser::commit() {
  119. switch (type_) {
  120. case LEASE_DB:
  121. {
  122. // Close current lease manager database.
  123. LeaseMgrFactory::destroy();
  124. // ... and open the new database using the access string.
  125. LeaseMgrFactory::create(getDbAccessString());
  126. break;
  127. }
  128. case HOSTS_DB:
  129. {
  130. // Let's instantiate HostMgr with new parameters. Note that HostMgr's
  131. // create method will call HostDataSourceFactory::create() with
  132. // appropriate parameters. It will also destroy a pre-existing
  133. // instance, if it existed.
  134. HostMgr::create(getDbAccessString());
  135. break;
  136. }
  137. default:
  138. isc_throw(BadValue, "Incorrect type specified in DbAccessParser: "
  139. << type_);
  140. };
  141. }
  142. }; // namespace dhcp
  143. }; // namespace isc