20 #include <boost/algorithm/string/split.hpp> 21 #include <boost/algorithm/string/classification.hpp> 22 #include <boost/array.hpp> 23 #include <boost/pointer_cast.hpp> 24 #include <boost/static_assert.hpp> 42 const size_t OPTION_VALUE_MAX_LEN = 4096;
48 const uint8_t MAX_IDENTIFIER_TYPE = static_cast<uint8_t>(Host::LAST_IDENTIFIER_TYPE);
51 const size_t DHCP_IDENTIFIER_MAX_LEN = 128;
86 static const int HOST_ID_COL = 0;
87 static const int DHCP_IDENTIFIER_COL = 1;
88 static const int DHCP_IDENTIFIER_TYPE_COL = 2;
89 static const int DHCP4_SUBNET_ID_COL = 3;
90 static const int DHCP6_SUBNET_ID_COL = 4;
91 static const int IPV4_ADDRESS_COL = 5;
92 static const int HOSTNAME_COL = 6;
93 static const int DHCP4_CLIENT_CLASSES_COL = 7;
94 static const int DHCP6_CLIENT_CLASSES_COL = 8;
95 static const int USER_CONTEXT_COL = 9;
96 static const int DHCP4_NEXT_SERVER_COL = 10;
97 static const int DHCP4_SERVER_HOSTNAME_COL = 11;
98 static const int DHCP4_BOOT_FILE_NAME_COL = 12;
99 static const int AUTH_KEY_COL = 13;
101 static const size_t HOST_COLUMNS = 14;
111 PgSqlHostExchange(
const size_t additional_columns_num = 0)
117 columns_[HOST_ID_COL] =
"host_id";
118 columns_[DHCP_IDENTIFIER_COL] =
"dhcp_identifier";
119 columns_[DHCP_IDENTIFIER_TYPE_COL] =
"dhcp_identifier_type";
120 columns_[DHCP4_SUBNET_ID_COL] =
"dhcp4_subnet_id";
121 columns_[DHCP6_SUBNET_ID_COL] =
"dhcp6_subnet_id";
122 columns_[IPV4_ADDRESS_COL] =
"ipv4_address";
123 columns_[HOSTNAME_COL] =
"hostname";
124 columns_[DHCP4_CLIENT_CLASSES_COL] =
"dhcp4_client_classes";
125 columns_[DHCP6_CLIENT_CLASSES_COL] =
"dhcp6_client_classes";
126 columns_[USER_CONTEXT_COL] =
"user_context";
127 columns_[DHCP4_NEXT_SERVER_COL] =
"dhcp4_next_server";
128 columns_[DHCP4_SERVER_HOSTNAME_COL] =
"dhcp4_server_hostname";
129 columns_[DHCP4_BOOT_FILE_NAME_COL] =
"dhcp4_boot_file_name";
130 columns_[AUTH_KEY_COL] =
"auth_key";
132 BOOST_STATIC_ASSERT(12 < HOST_COLUMNS);
136 virtual ~PgSqlHostExchange() {
144 virtual void clear() {
162 size_t findAvailColumn()
const {
163 std::vector<std::string>::const_iterator empty_column =
164 std::find(columns_.begin(), columns_.end(), std::string());
165 return (std::distance(columns_.begin(), empty_column));
174 getColumnValue(r, row, HOST_ID_COL, host_id);
192 createBindForSend(
const HostPtr& host) {
206 bind_array->add(host->getIdentifier());
209 bind_array->add(host->getIdentifierType());
212 if (host->getIPv4SubnetID() == SUBNET_ID_UNUSED) {
213 bind_array->addNull();
216 bind_array->add(host->getIPv4SubnetID());
220 if (host->getIPv6SubnetID() == SUBNET_ID_UNUSED) {
221 bind_array->addNull();
224 bind_array->add(host->getIPv6SubnetID());
228 bind_array->add((host->getIPv4Reservation()));
231 bind_array->add(host->getHostname());
235 bind_array->addTempString(host->getClientClasses4().toText(
","));
238 bind_array->addTempString(host->getClientClasses6().toText(
","));
243 std::string user_context_ = ctx->str();
244 bind_array->addTempString(user_context_);
246 bind_array->addNull();
250 bind_array->add((host->getNextServer()));
253 bind_array->add(host->getServerHostname());
256 bind_array->add(host->getBootFileName());
259 std::string key = host->getKey().ToText();
261 bind_array->addNull();
263 bind_array->add(key);
266 }
catch (
const std::exception& ex) {
269 "Could not create bind array from Host: " 270 << host->getHostname() <<
", reason: " << ex.
what());
294 HostID row_host_id = getHostId(r, row);
299 if (hosts.empty() || row_host_id != hosts.back()->getHostId()) {
300 HostPtr host = retrieveHost(r, row, row_host_id);
301 hosts.push_back(host);
316 const HostID& peeked_host_id = 0) {
320 HostID host_id = (peeked_host_id ? peeked_host_id : getHostId(r,row));
323 uint8_t identifier_value[DHCP_IDENTIFIER_MAX_LEN];
324 size_t identifier_len;
325 convertFromBytea(r, row, DHCP_IDENTIFIER_COL, identifier_value,
326 sizeof(identifier_value), identifier_len);
330 getColumnValue(r, row, DHCP_IDENTIFIER_TYPE_COL, type);
331 if (type > MAX_IDENTIFIER_TYPE) {
333 << static_cast<int>(type));
337 static_cast<Host::IdentifierType>(type);
340 uint32_t subnet_id(SUBNET_ID_UNUSED);
341 if (!isColumnNull(r, row, DHCP4_SUBNET_ID_COL)) {
342 getColumnValue(r, row, DHCP4_SUBNET_ID_COL, subnet_id);
344 SubnetID dhcp4_subnet_id = static_cast<SubnetID>(subnet_id);
347 subnet_id = SUBNET_ID_UNUSED;
348 if (!isColumnNull(r, row, DHCP6_SUBNET_ID_COL)) {
349 getColumnValue(r, row, DHCP6_SUBNET_ID_COL, subnet_id);
351 SubnetID dhcp6_subnet_id = static_cast<SubnetID>(subnet_id);
355 if (!isColumnNull(r, row, IPV4_ADDRESS_COL)) {
356 getColumnValue(r, row, IPV4_ADDRESS_COL, addr4);
361 std::string hostname;
362 if (!isColumnNull(r, row, HOSTNAME_COL)) {
363 getColumnValue(r, row, HOSTNAME_COL, hostname);
367 std::string dhcp4_client_classes;
368 if (!isColumnNull(r, row, DHCP4_CLIENT_CLASSES_COL)) {
369 getColumnValue(r, row, DHCP4_CLIENT_CLASSES_COL, dhcp4_client_classes);
373 std::string dhcp6_client_classes;
374 if (!isColumnNull(r, row, DHCP6_CLIENT_CLASSES_COL)) {
375 getColumnValue(r, row, DHCP6_CLIENT_CLASSES_COL, dhcp6_client_classes);
379 std::string user_context;
380 if (!isColumnNull(r, row, USER_CONTEXT_COL)) {
381 getColumnValue(r, row, USER_CONTEXT_COL, user_context);
385 uint32_t dhcp4_next_server_as_uint32(0);
386 if (!isColumnNull(r, row, DHCP4_NEXT_SERVER_COL)) {
387 getColumnValue(r, row, DHCP4_NEXT_SERVER_COL, dhcp4_next_server_as_uint32);
392 std::string dhcp4_server_hostname;
393 if (!isColumnNull(r, row, DHCP4_SERVER_HOSTNAME_COL)) {
394 getColumnValue(r, row, DHCP4_SERVER_HOSTNAME_COL, dhcp4_server_hostname);
398 std::string dhcp4_boot_file_name;
399 if (!isColumnNull(r, row, DHCP4_BOOT_FILE_NAME_COL)) {
400 getColumnValue(r, row, DHCP4_BOOT_FILE_NAME_COL, dhcp4_boot_file_name);
404 std::string auth_key;
405 if (!isColumnNull(r, row, AUTH_KEY_COL)) {
406 getColumnValue(r, row, AUTH_KEY_COL, auth_key);
412 host.reset(
new Host(identifier_value, identifier_len,
413 identifier_type, dhcp4_subnet_id,
414 dhcp6_subnet_id, ipv4_reservation, hostname,
415 dhcp4_client_classes, dhcp6_client_classes,
416 dhcp4_next_server, dhcp4_server_hostname,
417 dhcp4_boot_file_name,
AuthKey(auth_key)));
420 if (!user_context.empty()) {
423 if (!ctx || (ctx->getType() != Element::map)) {
425 <<
"' is not a JSON map");
427 host->setContext(ctx);
430 <<
"' is invalid JSON: " << ex.
what());
434 host->setHostId(host_id);
457 class PgSqlHostWithOptionsExchange :
public PgSqlHostExchange {
461 static const size_t OPTION_COLUMNS = 7;
477 class OptionProcessor {
487 const size_t start_column)
488 : universe_(universe), start_column_(start_column),
489 option_id_index_(start_column), code_index_(start_column_ + 1),
490 value_index_(start_column_ + 2),
491 formatted_value_index_(start_column_ + 3),
492 space_index_(start_column_ + 4),
493 persistent_index_(start_column_ + 5),
494 user_context_index_(start_column_ + 6),
495 most_recent_option_id_(0) {
503 most_recent_option_id_ = 0;
542 if (PgSqlExchange::isColumnNull(r, row, option_id_index_)) {
548 PgSqlExchange::getColumnValue(r, row, option_id_index_, option_id);
553 if (most_recent_option_id_ >= option_id) {
559 most_recent_option_id_ = option_id;
563 PgSqlExchange::getColumnValue(r, row, code_index_, code);
566 uint8_t value[OPTION_VALUE_MAX_LEN];
568 if (!isColumnNull(r, row, value_index_)) {
569 PgSqlExchange::convertFromBytea(r, row, value_index_, value,
570 sizeof(value), value_len);
574 std::string formatted_value;
575 if (!isColumnNull(r, row, formatted_value_index_)) {
576 PgSqlExchange::getColumnValue(r, row, formatted_value_index_,
582 if (!isColumnNull(r, row, space_index_)) {
583 PgSqlExchange::getColumnValue(r, row, space_index_, space);
588 space = (universe_ == Option::V4 ?
"dhcp4" :
"dhcp6");
593 PgSqlExchange::getColumnValue(r, row, persistent_index_,
597 std::string user_context;
598 if (!isColumnNull(r, row, user_context_index_)) {
599 PgSqlExchange::getColumnValue(r, row, user_context_index_,
618 uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(space);
620 def = LibDHCP::getVendorOptionDef(universe_, vendor_id,
628 def = LibDHCP::getRuntimeOptionDef(space, code);
636 option.reset(
new Option(universe_, code, buf.begin(),
643 if (formatted_value.empty()) {
645 option = def->optionFactory(universe_, code, buf.begin(),
650 std::vector<std::string> split_vec;
651 boost::split(split_vec, formatted_value,
652 boost::is_any_of(
","));
653 option = def->optionFactory(universe_, code, split_vec);
660 if (!user_context.empty()) {
663 if (!ctx || (ctx->getType() != Element::map)) {
665 <<
"' is no a JSON map");
667 desc.setContext(ctx);
670 <<
"' is invalid JSON: " << ex.
what());
674 cfg->add(desc, space);
681 void setColumnNames(std::vector<std::string>& columns) {
682 columns[option_id_index_] =
"option_id";
683 columns[code_index_] =
"code";
684 columns[value_index_] =
"value";
685 columns[formatted_value_index_] =
"formatted_value";
686 columns[space_index_] =
"space";
687 columns[persistent_index_] =
"persistent";
688 columns[user_context_index_] =
"user_context";
696 size_t start_column_;
702 size_t option_id_index_;
712 size_t formatted_value_index_;
718 size_t persistent_index_;
722 size_t user_context_index_;
725 uint64_t most_recent_option_id_;
729 typedef boost::shared_ptr<OptionProcessor> OptionProcessorPtr;
739 enum FetchedOptions {
753 PgSqlHostWithOptionsExchange(
const FetchedOptions& fetched_options,
754 const size_t additional_columns_num = 0)
755 : PgSqlHostExchange(getRequiredColumnsNum(fetched_options)
756 + additional_columns_num),
757 opt_proc4_(), opt_proc6_() {
760 if ((fetched_options == DHCP4_ONLY) ||
761 (fetched_options == DHCP4_AND_DHCP6)) {
762 opt_proc4_.reset(
new OptionProcessor(Option::V4,
764 opt_proc4_->setColumnNames(columns_);
768 if ((fetched_options == DHCP6_ONLY) ||
769 (fetched_options == DHCP4_AND_DHCP6)) {
770 opt_proc6_.reset(
new OptionProcessor(Option::V6,
772 opt_proc6_->setColumnNames(columns_);
781 virtual void clear() {
782 PgSqlHostExchange::clear();
806 current_host = retrieveHost(r, row);
807 hosts.push_back(current_host);
812 HostID row_host_id = getHostId(r, row);
813 current_host = boost::const_pointer_cast<Host>(hosts.back());
817 if (row_host_id > current_host->getHostId()) {
818 current_host = retrieveHost(r, row, row_host_id);
819 hosts.push_back(current_host);
826 opt_proc4_->retrieveOption(cfg, r, row);
832 opt_proc6_->retrieveOption(cfg, r, row);
849 static size_t getRequiredColumnsNum(
const FetchedOptions& fetched_options) {
850 return (fetched_options == DHCP4_AND_DHCP6 ? 2 * OPTION_COLUMNS :
857 OptionProcessorPtr opt_proc4_;
862 OptionProcessorPtr opt_proc6_;
877 class PgSqlHostIPv6Exchange :
public PgSqlHostWithOptionsExchange {
881 static const size_t RESERVATION_COLUMNS = 5;
889 PgSqlHostIPv6Exchange(
const FetchedOptions& fetched_options)
890 : PgSqlHostWithOptionsExchange(fetched_options, RESERVATION_COLUMNS),
891 reservation_id_index_(findAvailColumn()),
892 address_index_(reservation_id_index_ + 1),
893 prefix_len_index_(reservation_id_index_ + 2),
894 type_index_(reservation_id_index_ + 3),
895 iaid_index_(reservation_id_index_ + 4),
896 most_recent_reservation_id_(0) {
899 columns_[reservation_id_index_] =
"reservation_id";
900 columns_[address_index_] =
"address";
901 columns_[prefix_len_index_] =
"prefix_len";
902 columns_[type_index_] =
"type";
903 columns_[iaid_index_] =
"dhcp6_iaid";
905 BOOST_STATIC_ASSERT(4 < RESERVATION_COLUMNS);
914 PgSqlHostWithOptionsExchange::clear();
915 most_recent_reservation_id_ = 0;
921 uint64_t getReservationId(
const PgSqlResult& r,
int row)
const {
922 uint64_t resv_id = 0;
923 if (!isColumnNull(r, row, reservation_id_index_)) {
924 getColumnValue(r, row, reservation_id_index_, resv_id);
938 getColumnValue(r, row, type_index_, tmp);
944 resv_type = IPv6Resrv::TYPE_NA;
948 resv_type = IPv6Resrv::TYPE_PD;
953 "invalid IPv6 reservation type returned: " 954 << tmp <<
". Only 0 or 2 are allowed.");
962 getColumnValue(r, row, prefix_len_index_, prefix_len);
971 return (reservation);
998 PgSqlHostWithOptionsExchange::processRowData(hosts, r, row);
1001 if (hosts.empty()) {
1003 " IPv6 reservation");
1008 uint64_t reservation_id = getReservationId(r, row);
1009 if (reservation_id && (reservation_id > most_recent_reservation_id_)) {
1010 HostPtr host = boost::const_pointer_cast<Host>(hosts.back());
1011 host->addReservation(retrieveReservation(r, row));
1012 most_recent_reservation_id_ = reservation_id;
1019 size_t reservation_id_index_;
1023 size_t address_index_;
1026 size_t prefix_len_index_;
1037 uint64_t most_recent_reservation_id_;
1054 static const size_t RESRV_COLUMNS = 6;
1061 PgSqlIPv6ReservationExchange()
1065 columns_[0] =
"host_id";
1066 columns_[1] =
"address";
1067 columns_[2] =
"prefix_len";
1068 columns_[3] =
"type";
1069 columns_[4] =
"dhcp6_iaid";
1070 BOOST_STATIC_ASSERT(5 < RESRV_COLUMNS);
1103 uint16_t type = resv.
getType() == IPv6Resrv::TYPE_NA ? 0 : 2;
1104 bind_array->add(type);
1108 bind_array->addNull();
1111 bind_array->add(host_id);
1112 }
catch (
const std::exception& ex) {
1114 "Could not create bind array from IPv6 Reservation: " 1115 << resv_.toText() <<
", reason: " << ex.
what());
1118 return (bind_array);
1132 static const int OPTION_ID_COL = 0;
1133 static const int CODE_COL = 1;
1134 static const int VALUE_COL = 2;
1135 static const int FORMATTED_VALUE_COL = 3;
1136 static const int SPACE_COL = 4;
1137 static const int PERSISTENT_COL = 5;
1138 static const int USER_CONTEXT_COL = 6;
1139 static const int DHCP_CLIENT_CLASS_COL = 7;
1140 static const int DHCP_SUBNET_ID_COL = 8;
1141 static const int HOST_ID_COL = 9;
1142 static const int SCOPE_ID_COL = 10;
1145 static const size_t OPTION_COLUMNS = 11;
1150 PgSqlOptionExchange()
1152 value_len_(0), option_() {
1153 columns_[OPTION_ID_COL] =
"option_id";
1154 columns_[CODE_COL] =
"code";
1155 columns_[VALUE_COL] =
"value";
1156 columns_[FORMATTED_VALUE_COL] =
"formatted_value";
1157 columns_[SPACE_COL] =
"space";
1158 columns_[PERSISTENT_COL] =
"persistent";
1159 columns_[USER_CONTEXT_COL] =
"user_context";
1160 columns_[DHCP_CLIENT_CLASS_COL] =
"dhcp_client_class";
1161 columns_[DHCP_SUBNET_ID_COL] =
"dhcp_subnet_id";
1162 columns_[HOST_ID_COL] =
"host_id";
1163 columns_[SCOPE_ID_COL] =
"scope_id";
1165 BOOST_STATIC_ASSERT(10 < OPTION_COLUMNS);
1178 const std::string& opt_space,
1191 bind_array->add(option_->getType());
1201 const char* buf_ptr = static_cast<const char*>(buf.getData());
1202 value_.assign(buf_ptr + opt_desc.
option_->getHeaderLen(),
1203 buf_ptr + buf.getLength());
1204 value_len_ = value_.size();
1205 bind_array->add(value_);
1209 bind_array->addNull(PsqlBindArray::BINARY_FMT);
1216 bind_array->addNull();
1220 if (!opt_space.empty()) {
1221 bind_array->addTempString(opt_space);
1223 bind_array->addNull();
1232 std::string user_context_ = ctx->str();
1233 bind_array->addTempString(user_context_);
1235 bind_array->addNull();
1242 bind_array->add(host_id);
1244 }
catch (
const std::exception& ex) {
1246 "Could not create bind array for inserting DHCP " 1247 "host option: " << option_->toText() <<
", reason: " 1251 return (bind_array);
1257 std::vector<uint8_t> value_;
1332 const bool return_last_id =
false);
1358 const std::string& opt_space,
1371 const uint64_t host_id);
1391 boost::shared_ptr<PgSqlHostExchange> exchange,
1412 const uint8_t* identifier_begin,
1413 const size_t identifier_len,
1415 boost::shared_ptr<PgSqlHostExchange> exchange)
const;
1424 void checkReadOnly()
const;
1434 std::pair<uint32_t, uint32_t> getVersion()
const;
1468 typedef boost::array<PgSqlTaggedStatement, PgSqlHostDataSourceImpl::NUM_STATEMENTS>
1482 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, " 1483 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, " 1484 " h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, " 1486 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1487 " h.dhcp4_boot_file_name, h.auth_key, " 1488 " o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, " 1489 " o4.persistent, o4.user_context, " 1490 " o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, " 1491 " o6.persistent, o6.user_context, " 1492 " r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid " 1494 "LEFT JOIN dhcp4_options AS o4 ON h.host_id = o4.host_id " 1495 "LEFT JOIN dhcp6_options AS o6 ON h.host_id = o6.host_id " 1496 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " 1497 "WHERE dhcp_identifier = $1 AND dhcp_identifier_type = $2 " 1498 "ORDER BY h.host_id, o4.option_id, o6.option_id, r.reservation_id" 1507 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, " 1508 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1509 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1510 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1511 " h.dhcp4_boot_file_name, h.auth_key, " 1512 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1513 " o.persistent, o.user_context " 1515 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id " 1516 "WHERE ipv4_address = $1 " 1517 "ORDER BY h.host_id, o.option_id" 1526 "get_host_subid4_dhcpid",
1527 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, " 1528 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1529 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1530 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1531 " h.dhcp4_boot_file_name, h.auth_key, " 1532 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1533 " o.persistent, o.user_context " 1535 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id " 1536 "WHERE h.dhcp4_subnet_id = $1 AND h.dhcp_identifier_type = $2 " 1537 " AND h.dhcp_identifier = $3 " 1538 "ORDER BY h.host_id, o.option_id" 1547 "get_host_subid6_dhcpid",
1548 "SELECT h.host_id, h.dhcp_identifier, " 1549 " h.dhcp_identifier_type, h.dhcp4_subnet_id, " 1550 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1551 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1552 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1553 " h.dhcp4_boot_file_name, h.auth_key, " 1554 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1555 " o.persistent, o.user_context, " 1556 " r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid " 1558 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id " 1559 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " 1560 "WHERE h.dhcp6_subnet_id = $1 AND h.dhcp_identifier_type = $2 " 1561 " AND h.dhcp_identifier = $3 " 1562 "ORDER BY h.host_id, o.option_id, r.reservation_id" 1572 "get_host_subid_addr",
1573 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, " 1574 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1575 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1576 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1577 " h.dhcp4_boot_file_name, h.auth_key, " 1578 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1579 " o.persistent, o.user_context " 1581 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id " 1582 "WHERE h.dhcp4_subnet_id = $1 AND h.ipv4_address = $2 " 1583 "ORDER BY h.host_id, o.option_id" 1596 "SELECT h.host_id, h.dhcp_identifier, " 1597 " h.dhcp_identifier_type, h.dhcp4_subnet_id, " 1598 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1599 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1600 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1601 " h.dhcp4_boot_file_name, h.auth_key, " 1602 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1603 " o.persistent, o.user_context, " 1604 " r.reservation_id, r.address, r.prefix_len, r.type, " 1607 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id " 1608 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " 1609 "WHERE h.host_id = " 1610 " (SELECT host_id FROM ipv6_reservations " 1611 " WHERE address = $1 AND prefix_len = $2) " 1612 "ORDER BY h.host_id, o.option_id, r.reservation_id" 1624 "get_host_subid6_addr",
1625 "SELECT h.host_id, h.dhcp_identifier, " 1626 " h.dhcp_identifier_type, h.dhcp4_subnet_id, " 1627 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1628 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1629 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1630 " h.dhcp4_boot_file_name, h.auth_key, " 1631 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1632 " o.persistent, o.user_context, " 1633 " r.reservation_id, r.address, r.prefix_len, r.type, " 1636 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id " 1637 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " 1638 "WHERE h.dhcp6_subnet_id = $1 AND r.address = $2 " 1639 "ORDER BY h.host_id, o.option_id, r.reservation_id" 1649 "INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, " 1650 " dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, " 1651 " dhcp4_client_classes, dhcp6_client_classes, user_context, " 1652 " dhcp4_next_server, dhcp4_server_hostname, dhcp4_boot_file_name, auth_key) " 1653 "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) " 1662 "INSERT INTO ipv6_reservations(address, prefix_len, type, " 1663 " dhcp6_iaid, host_id) " 1664 "VALUES ($1, $2, $3, $4, $5)" 1673 "insert_v4_host_option",
1674 "INSERT INTO dhcp4_options(code, value, formatted_value, space, " 1675 " persistent, user_context, host_id, scope_id) " 1676 "VALUES ($1, $2, $3, $4, $5, $6, $7, 3)" 1685 "insert_v6_host_option",
1686 "INSERT INTO dhcp6_options(code, value, formatted_value, space, " 1687 " persistent, user_context, host_id, scope_id) " 1688 "VALUES ($1, $2, $3, $4, $5, $6, $7, 3)" 1696 "DELETE FROM hosts WHERE dhcp4_subnet_id = $1 AND ipv4_address = $2" 1703 "del_host_subid4_id",
1704 "DELETE FROM hosts WHERE dhcp4_subnet_id = $1 " 1705 "AND dhcp_identifier_type = $2 " 1706 "AND dhcp_identifier = $3" 1713 "del_host_subid6_id",
1714 "DELETE FROM hosts WHERE dhcp6_subnet_id = $1 " 1715 "AND dhcp_identifier_type = $2 " 1716 "AND dhcp_identifier = $3" 1723 PgSqlHostDataSourceImpl::
1724 PgSqlHostDataSourceImpl(
const PgSqlConnection::ParameterMap& parameters)
1725 : host_exchange_(new PgSqlHostWithOptionsExchange(PgSqlHostWithOptionsExchange::DHCP4_ONLY)),
1726 host_ipv6_exchange_(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::DHCP6_ONLY)),
1727 host_ipv46_exchange_(new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::
1729 host_ipv6_reservation_exchange_(new PgSqlIPv6ReservationExchange()),
1730 host_option_exchange_(new PgSqlOptionExchange()),
1732 is_readonly_(false) {
1740 std::pair<uint32_t, uint32_t> db_version =
getVersion();
1741 if (code_version != db_version) {
1743 "PostgreSQL schema version mismatch: need version: " 1744 << code_version.first <<
"." << code_version.second
1745 <<
" found version: " << db_version.first <<
"." 1746 << db_version.second);
1774 const bool return_last_id) {
1775 uint64_t last_id = 0;
1778 &bind_array->values_[0],
1779 &bind_array->lengths_[0],
1780 &bind_array->formats_[0], 0));
1782 int s = PQresultStatus(r);
1784 if (s != PGRES_COMMAND_OK) {
1795 if (return_last_id) {
1796 PgSqlExchange::getColumnValue(r, 0, 0, last_id);
1807 &bind_array->values_[0],
1808 &bind_array->lengths_[0],
1809 &bind_array->formats_[0], 0));
1811 int s = PQresultStatus(r);
1813 if (s != PGRES_COMMAND_OK) {
1821 char* rows_deleted = PQcmdTuples(r);
1822 if (!rows_deleted) {
1824 "Could not retrieve the number of deleted rows.");
1826 return (rows_deleted[0] !=
'0');
1840 const std::string& opt_space,
1852 const uint64_t host_id) {
1855 std::list<std::string> option_spaces = options_cfg->getOptionSpaceNames();
1856 std::list<std::string> vendor_spaces = options_cfg->getVendorIdsSpaceNames();
1857 option_spaces.insert(option_spaces.end(), vendor_spaces.begin(),
1858 vendor_spaces.end());
1862 for (std::list<std::string>::const_iterator space = option_spaces.begin();
1863 space != option_spaces.end(); ++space) {
1865 if (options && !options->empty()) {
1866 for (OptionContainer::const_iterator opt = options->begin();
1867 opt != options->end(); ++opt) {
1878 boost::shared_ptr<PgSqlHostExchange> exchange,
1884 &bind_array->values_[0],
1885 &bind_array->lengths_[0],
1886 &bind_array->formats_[0], 0));
1891 for(
int row = 0; row < rows; ++row) {
1892 exchange->processRowData(result, r, row);
1894 if (single && result.size() > 1) {
1896 "database where only one was expected for query " 1906 const uint8_t* identifier_begin,
1907 const size_t identifier_len,
1909 boost::shared_ptr<PgSqlHostExchange> exchange)
const {
1915 bind_array->add(subnet_id);
1918 bind_array->add(static_cast<uint8_t>(identifier_type));
1921 bind_array->add(identifier_begin, identifier_len);
1928 if (!collection.empty())
1929 result = *collection.begin();
1936 DHCPSRV_PGSQL_HOST_DB_GET_VERSION);
1937 const char* version_sql =
"SELECT version, minor FROM schema_version;";
1939 if(PQresultStatus(r) != PGRES_TUPLES_OK) {
1941 << version_sql <<
">, reason: " << PQerrorMessage(
conn_));
1945 PgSqlExchange::getColumnValue(r, 0, 0,
version);
1948 PgSqlExchange::getColumnValue(r, 0, 1, minor);
1950 return (std::make_pair(
version, minor));
1957 " to operate in read only mode");
1994 cfg_option4, host_id);
2001 cfg_option6, host_id);
2006 if (std::distance(v6resv.first, v6resv.second) > 0) {
2009 impl_->
addResv(resv->second, host_id);
2024 bind_array->add(subnet_id);
2025 bind_array->add(addr);
2035 return del6(subnet_id, host->getIdentifierType(), &host->getIdentifier()[0],
2036 host->getIdentifier().size());
2042 const uint8_t* identifier_begin,
2043 const size_t identifier_len) {
2048 bind_array->add(subnet_id);
2051 bind_array->add(static_cast<uint8_t>(identifier_type));
2054 bind_array->add(identifier_begin, identifier_len);
2063 const uint8_t* identifier_begin,
2064 const size_t identifier_len) {
2068 bind_array->add(subnet_id);
2071 bind_array->add(static_cast<uint8_t>(identifier_type));
2074 bind_array->add(identifier_begin, identifier_len);
2082 const uint8_t* identifier_begin,
2083 const size_t identifier_len)
const {
2088 bind_array->add(identifier_begin, identifier_len);
2091 bind_array->add(static_cast<uint8_t>(identifier_type));
2107 bind_array->add(address);
2119 const uint8_t* identifier_begin,
2120 const size_t identifier_len)
const {
2122 return (impl_->
getHost(subnet_id, identifier_type, identifier_begin,
2131 if (!address.
isV4()) {
2133 " wrong address type, address supplied is an IPv6 address");
2140 bind_array->add(subnet_id);
2143 bind_array->add(address);
2152 if (!collection.empty())
2153 result = *collection.begin();
2161 const uint8_t* identifier_begin,
2162 const size_t identifier_len)
const {
2164 return (impl_->
getHost(subnet_id, identifier_type, identifier_begin,
2171 const uint8_t prefix_len)
const {
2178 bind_array->add(prefix);
2181 bind_array->add(prefix_len);
2190 if (!collection.empty()) {
2191 result = *collection.begin();
2206 bind_array->add(subnet_id);
2209 bind_array->add(address);
2218 if (!collection.empty()) {
2219 result = *collection.begin();
2228 std::string name =
"";
2238 return (std::string(
"Host data source that stores host information" 2239 "in PostgreSQL database"));
RAII wrapper for PostgreSQL Result sets.
Simple class representing an optional value.
boost::shared_ptr< CfgOption > CfgOptionPtr
Non-const pointer.
void commit()
Commits transaction.
data::ConstElementPtr getContext() const
Returns const pointer to the user context.
virtual void add(const HostPtr &host)
Adds a new host to the collection.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
uint8_t getPrefixLen() const
Returns prefix length.
A standard Data module exception that is thrown if a parse error is encountered when constructing an ...
boost::shared_ptr< Host > HostPtr
Pointer to the Host object.
StatementIndex
Statement Tags.
boost::shared_ptr< const CfgOption > ConstCfgOptionPtr
Const pointer.
#define DHCP6_OPTION_SPACE
boost::shared_ptr< PgSqlHostIPv6Exchange > host_ipv6_exchange_
Pointer to an object representing an exchange which can be used to retrieve hosts,...
bool compareError(const PgSqlResult &r, const char *error_state)
Checks a result set's SQL state against an error state.
boost::shared_ptr< Option > OptionPtr
void addOption(const PgSqlHostDataSourceImpl::StatementIndex &stindex, const OptionDescriptor &opt_desc, const std::string &opt_space, const OptionalValue< SubnetID > &subnet_id, const HostID &host_id)
Inserts a single DHCP option into the database.
Universe
defines option universe DHCPv4 or DHCPv6
virtual std::string getName() const
Returns the name of the open database.
boost::shared_ptr< PgSqlHostWithOptionsExchange > host_exchange_
Pointer to the object representing an exchange which can be used to retrieve hosts and DHCPv4 options...
uint64_t addStatement(PgSqlHostDataSourceImpl::StatementIndex stindex, PsqlBindArrayPtr &bind, const bool return_last_id=false)
Executes statements which insert a row into one of the tables.
PgSqlHostDataSource(const db::DatabaseConnection::ParameterMap ¶meters)
Constructor.
virtual bool del6(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len)
Attempts to delete a host by (subnet6-id, identifier type, identifier)
boost::shared_ptr< PgSqlIPv6ReservationExchange > host_ipv6_reservation_exchange_
Pointer to an object representing an exchange which can be used to insert new IPv6 reservation.
Base class for marshalling data to and from PostgreSQL.
int getRows() const
Returns the number of rows in the result set.
IPv6 reservation for a host.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
std::pair< uint32_t, uint32_t > getVersion() const
Returns PostgreSQL schema version of the open database.
Exception thrown on failure to open database.
ConstHostPtr getHost(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len, StatementIndex stindex, boost::shared_ptr< PgSqlHostExchange > exchange) const
Retrieves a host by subnet and client's unique identifier.
void commit()
Commit Transactions.
TaggedStatementArray tagged_statements
Prepared MySQL statements used by the backend to insert and retrieve hosts from the database.
Multiple lease records found where one expected.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
std::string formatted_value_
Option value in textual (CSV) format.
~PgSqlHostDataSourceImpl()
Destructor.
void addResv(const IPv6Resrv &resv, const HostID &id)
Inserts IPv6 Reservation into ipv6_reservation table.
void prepareStatements(const PgSqlTaggedStatement *start_statement, const PgSqlTaggedStatement *end_statement)
Prepare statements.
virtual ConstHostCollection getAll4(const asiolink::IOAddress &address) const
Returns a collection of hosts using the specified IPv4 address.
std::pair< IPv6ResrvIterator, IPv6ResrvIterator > IPv6ResrvRange
const uint32_t PG_SCHEMA_VERSION_MINOR
boost::shared_ptr< PsqlBindArray > PsqlBindArrayPtr
Defines a smart pointer to PsqlBindArray.
void addOptions(const StatementIndex &stindex, const ConstCfgOptionPtr &options_cfg, const uint64_t host_id)
Inserts multiple options into the database.
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
std::vector< ConstHostPtr > ConstHostCollection
Collection of the const Host objects.
bool persistent_
Persistence flag.
A generic exception that is thrown when an unexpected error condition occurs.
void rollback()
Rollback Transactions.
boost::shared_ptr< const Element > ConstElementPtr
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
virtual bool del4(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len)
Attempts to delete a host by (subnet4-id, identifier type, identifier)
std::string getParameter(const std::string &name) const
Returns value of a connection parameter.
Common PgSql Connector Pool.
virtual ~PgSqlHostDataSource()
Virtual destructor.
Represents a device with IPv4 and/or IPv6 reservations.
bool configuredReadOnly() const
Convenience method checking if database should be opened with read only access.
Type
Type of the reservation.
virtual ConstHostPtr get4(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Returns a host connected to the IPv4 subnet.
virtual bool del(const SubnetID &subnet_id, const asiolink::IOAddress &addr)
Attempts to delete a host by (subnet-id, address)
#define DHCP4_OPTION_SPACE
bool isV4() const
Convenience function to check for an IPv4 address.
IPv6ResrvCollection::const_iterator IPv6ResrvIterator
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
virtual ConstHostCollection getAll(const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Return all hosts connected to any subnet for which reservations have been made using a specified iden...
OptionPtr option_
Option instance.
virtual std::string getDescription() const
Returns description of the backend.
This is a base class for exceptions thrown from the DNS library module.
Defines the logger used by the top-level component of kea-dhcp-ddns.
Type getType() const
Returns reservation type.
void checkStatementError(const PgSqlResult &r, PgSqlTaggedStatement &statement) const
Checks result of the r object.
Implementation of the PgSqlHostDataSource.
void checkReadOnly() const
Throws exception if database is read only.
boost::shared_ptr< PgSqlOptionExchange > host_option_exchange_
Pointer to an object representing an exchange which can be used to insert DHCPv4 or DHCPv6 option int...
boost::shared_ptr< PgSqlHostIPv6Exchange > host_ipv46_exchange_
Pointer to an object representing an exchange which can be used to retrieve hosts,...
A wrapper interface for the ASIO library.
PgSqlConnection conn_
PgSQL connection.
virtual void rollback()
Rollback Transactions.
boost::shared_ptr< OptionContainer > OptionContainerPtr
Pointer to the OptionContainer object.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
void getHostCollection(StatementIndex stindex, PsqlBindArrayPtr bind, boost::shared_ptr< PgSqlHostExchange > exchange, ConstHostCollection &result, bool single) const
Creates collection of Host objects with associated information such as IPv6 reservations and/or DHCP ...
Attempt to modify data in read-only database.
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
virtual ConstHostPtr get6(const SubnetID &subnet_id, const Host::IdentifierType &identifier_type, const uint8_t *identifier_begin, const size_t identifier_len) const
Returns a host connected to the IPv6 subnet.
void openDatabase()
Open Database.
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
virtual void commit()
Commit Transactions.
IdentifierType
Type of the host identifier.
virtual std::pair< uint32_t, uint32_t > getVersion() const
Returns backend version.
The IOAddress class represents an IP addresses (version agnostic)
int version()
returns Kea hooks version.
static const StatementIndex WRITE_STMTS_BEGIN
Index of first statement performing write to the database.
const uint32_t PG_SCHEMA_VERSION_MAJOR
Define PostgreSQL backend version: 5.0.
uint64_t HostID
HostID (used only when storing in MySQL, PostgreSQL or Cassandra)
bool delStatement(PgSqlHostDataSourceImpl::StatementIndex stindex, PsqlBindArrayPtr &bind)
Executes statements that delete records.
bool is_readonly_
Indicates if the database is opened in read only mode.
const asiolink::IOAddress & getPrefix() const
Returns prefix for the reservation.
Exception thrown on failure to execute a database function.
boost::array< TaggedStatement, MySqlHostDataSourceImpl::NUM_STATEMENTS > TaggedStatementArray
Array of tagged statements.
Database duplicate entry error.
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
RAII object representing a PostgreSQL transaction.