26 #include <boost/algorithm/string/split.hpp> 27 #include <boost/algorithm/string/classification.hpp> 28 #include <boost/array.hpp> 29 #include <boost/pointer_cast.hpp> 30 #include <boost/static_assert.hpp> 56 const uint8_t MAX_IDENTIFIER_TYPE =
static_cast<uint8_t
>(Host::LAST_IDENTIFIER_TYPE);
59 const size_t DHCP_IDENTIFIER_MAX_LEN = 128;
94 static const int HOST_ID_COL = 0;
95 static const int DHCP_IDENTIFIER_COL = 1;
96 static const int DHCP_IDENTIFIER_TYPE_COL = 2;
97 static const int DHCP4_SUBNET_ID_COL = 3;
98 static const int DHCP6_SUBNET_ID_COL = 4;
99 static const int IPV4_ADDRESS_COL = 5;
100 static const int HOSTNAME_COL = 6;
101 static const int DHCP4_CLIENT_CLASSES_COL = 7;
102 static const int DHCP6_CLIENT_CLASSES_COL = 8;
103 static const int USER_CONTEXT_COL = 9;
104 static const int DHCP4_NEXT_SERVER_COL = 10;
105 static const int DHCP4_SERVER_HOSTNAME_COL = 11;
106 static const int DHCP4_BOOT_FILE_NAME_COL = 12;
107 static const int AUTH_KEY_COL = 13;
109 static const size_t HOST_COLUMNS = 14;
119 PgSqlHostExchange(
const size_t additional_columns_num = 0)
125 columns_[HOST_ID_COL] =
"host_id";
126 columns_[DHCP_IDENTIFIER_COL] =
"dhcp_identifier";
127 columns_[DHCP_IDENTIFIER_TYPE_COL] =
"dhcp_identifier_type";
128 columns_[DHCP4_SUBNET_ID_COL] =
"dhcp4_subnet_id";
129 columns_[DHCP6_SUBNET_ID_COL] =
"dhcp6_subnet_id";
130 columns_[IPV4_ADDRESS_COL] =
"ipv4_address";
131 columns_[HOSTNAME_COL] =
"hostname";
132 columns_[DHCP4_CLIENT_CLASSES_COL] =
"dhcp4_client_classes";
133 columns_[DHCP6_CLIENT_CLASSES_COL] =
"dhcp6_client_classes";
134 columns_[USER_CONTEXT_COL] =
"user_context";
135 columns_[DHCP4_NEXT_SERVER_COL] =
"dhcp4_next_server";
136 columns_[DHCP4_SERVER_HOSTNAME_COL] =
"dhcp4_server_hostname";
137 columns_[DHCP4_BOOT_FILE_NAME_COL] =
"dhcp4_boot_file_name";
138 columns_[AUTH_KEY_COL] =
"auth_key";
140 BOOST_STATIC_ASSERT(12 < HOST_COLUMNS);
144 virtual ~PgSqlHostExchange() {
152 virtual void clear() {
170 size_t findAvailColumn()
const {
171 std::vector<std::string>::const_iterator empty_column =
172 std::find(columns_.begin(), columns_.end(), std::string());
173 return (std::distance(columns_.begin(), empty_column));
182 getColumnValue(r, row, HOST_ID_COL, host_id);
215 bind_array->add(host->getIdentifier());
218 bind_array->add(host->getIdentifierType());
221 if (host->getIPv4SubnetID() == SUBNET_ID_UNUSED) {
222 bind_array->addNull();
224 bind_array->add(host->getIPv4SubnetID());
228 if (host->getIPv6SubnetID() == SUBNET_ID_UNUSED) {
229 bind_array->addNull();
231 bind_array->add(host->getIPv6SubnetID());
235 bind_array->add((host->getIPv4Reservation()));
238 bind_array->add(host->getHostname());
242 bind_array->addTempString(host->getClientClasses4().toText(
","));
245 bind_array->addTempString(host->getClientClasses6().toText(
","));
250 std::string user_context_ = ctx->str();
251 bind_array->addTempString(user_context_);
253 bind_array->addNull();
257 bind_array->add((host->getNextServer()));
260 bind_array->add(host->getServerHostname());
263 bind_array->add(host->getBootFileName());
266 std::string key = host->getKey().toText();
268 bind_array->addNull();
270 bind_array->addTempString(key);
277 bind_array->add(host->getIPv4Reservation());
278 bind_array->add(host->getIPv4SubnetID());
281 }
catch (
const std::exception& ex) {
284 "Could not create bind array from Host: " 285 << host->getHostname() <<
", reason: " << ex.
what());
309 HostID row_host_id = getHostId(r, row);
314 if (hosts.empty() || row_host_id != hosts.back()->getHostId()) {
315 HostPtr host = retrieveHost(r, row, row_host_id);
316 hosts.push_back(host);
332 const HostID& peeked_host_id = 0) {
336 HostID host_id = (peeked_host_id ? peeked_host_id : getHostId(r,row));
339 uint8_t identifier_value[DHCP_IDENTIFIER_MAX_LEN];
340 size_t identifier_len;
341 convertFromBytea(r, row, DHCP_IDENTIFIER_COL, identifier_value,
342 sizeof(identifier_value), identifier_len);
346 getColumnValue(r, row, DHCP_IDENTIFIER_TYPE_COL, type);
347 if (type > MAX_IDENTIFIER_TYPE) {
349 << static_cast<int>(type));
356 uint32_t subnet_id(SUBNET_ID_UNUSED);
357 if (!isColumnNull(r, row, DHCP4_SUBNET_ID_COL)) {
358 getColumnValue(r, row, DHCP4_SUBNET_ID_COL, subnet_id);
363 subnet_id = SUBNET_ID_UNUSED;
364 if (!isColumnNull(r, row, DHCP6_SUBNET_ID_COL)) {
365 getColumnValue(r, row, DHCP6_SUBNET_ID_COL, subnet_id);
371 if (!isColumnNull(r, row, IPV4_ADDRESS_COL)) {
372 getColumnValue(r, row, IPV4_ADDRESS_COL, addr4);
377 std::string hostname;
378 if (!isColumnNull(r, row, HOSTNAME_COL)) {
379 getColumnValue(r, row, HOSTNAME_COL, hostname);
383 std::string dhcp4_client_classes;
384 if (!isColumnNull(r, row, DHCP4_CLIENT_CLASSES_COL)) {
385 getColumnValue(r, row, DHCP4_CLIENT_CLASSES_COL, dhcp4_client_classes);
389 std::string dhcp6_client_classes;
390 if (!isColumnNull(r, row, DHCP6_CLIENT_CLASSES_COL)) {
391 getColumnValue(r, row, DHCP6_CLIENT_CLASSES_COL, dhcp6_client_classes);
395 std::string user_context;
396 if (!isColumnNull(r, row, USER_CONTEXT_COL)) {
397 getColumnValue(r, row, USER_CONTEXT_COL, user_context);
401 uint32_t dhcp4_next_server_as_uint32(0);
402 if (!isColumnNull(r, row, DHCP4_NEXT_SERVER_COL)) {
403 getColumnValue(r, row, DHCP4_NEXT_SERVER_COL, dhcp4_next_server_as_uint32);
408 std::string dhcp4_server_hostname;
409 if (!isColumnNull(r, row, DHCP4_SERVER_HOSTNAME_COL)) {
410 getColumnValue(r, row, DHCP4_SERVER_HOSTNAME_COL, dhcp4_server_hostname);
414 std::string dhcp4_boot_file_name;
415 if (!isColumnNull(r, row, DHCP4_BOOT_FILE_NAME_COL)) {
416 getColumnValue(r, row, DHCP4_BOOT_FILE_NAME_COL, dhcp4_boot_file_name);
420 std::string auth_key;
421 if (!isColumnNull(r, row, AUTH_KEY_COL)) {
422 getColumnValue(r, row, AUTH_KEY_COL, auth_key);
428 host.reset(
new Host(identifier_value, identifier_len,
429 identifier_type, dhcp4_subnet_id,
430 dhcp6_subnet_id, ipv4_reservation, hostname,
431 dhcp4_client_classes, dhcp6_client_classes,
432 dhcp4_next_server, dhcp4_server_hostname,
433 dhcp4_boot_file_name,
AuthKey(auth_key)));
436 if (!user_context.empty()) {
439 if (!ctx || (ctx->getType() != Element::map)) {
441 <<
"' is not a JSON map");
443 host->setContext(ctx);
446 <<
"' is invalid JSON: " << ex.
what());
450 host->setHostId(host_id);
473 class PgSqlHostWithOptionsExchange :
public PgSqlHostExchange {
477 static const size_t OPTION_COLUMNS = 7;
493 class OptionProcessor {
503 const size_t start_column)
504 : universe_(universe), start_column_(start_column),
505 option_id_index_(start_column), code_index_(start_column_ + 1),
506 value_index_(start_column_ + 2),
507 formatted_value_index_(start_column_ + 3),
508 space_index_(start_column_ + 4),
509 persistent_index_(start_column_ + 5),
510 user_context_index_(start_column_ + 6),
511 most_recent_option_id_(0) {
519 most_recent_option_id_ = 0;
558 if (PgSqlExchange::isColumnNull(r, row, option_id_index_)) {
564 PgSqlExchange::getColumnValue(r, row, option_id_index_, option_id);
569 if (most_recent_option_id_ >= option_id) {
575 most_recent_option_id_ = option_id;
579 PgSqlExchange::getColumnValue(r, row, code_index_, code);
584 if (!isColumnNull(r, row, value_index_)) {
585 PgSqlExchange::convertFromBytea(r, row, value_index_, value,
586 sizeof(value), value_len);
590 std::string formatted_value;
591 if (!isColumnNull(r, row, formatted_value_index_)) {
592 PgSqlExchange::getColumnValue(r, row, formatted_value_index_,
598 if (!isColumnNull(r, row, space_index_)) {
599 PgSqlExchange::getColumnValue(r, row, space_index_, space);
604 space = (universe_ == Option::V4 ?
610 PgSqlExchange::getColumnValue(r, row, persistent_index_,
614 std::string user_context;
615 if (!isColumnNull(r, row, user_context_index_)) {
616 PgSqlExchange::getColumnValue(r, row, user_context_index_,
635 uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(space);
637 def = LibDHCP::getVendorOptionDef(universe_, vendor_id,
645 def = LibDHCP::getRuntimeOptionDef(space, code);
653 option.reset(
new Option(universe_, code, buf.begin(),
660 if (formatted_value.empty()) {
662 option = def->optionFactory(universe_, code, buf.begin(),
667 std::vector<std::string> split_vec;
668 boost::split(split_vec, formatted_value,
669 boost::is_any_of(
","));
670 option = def->optionFactory(universe_, code, split_vec);
677 if (!user_context.empty()) {
680 if (!ctx || (ctx->getType() != Element::map)) {
682 <<
"' is no a JSON map");
684 desc.setContext(ctx);
687 <<
"' is invalid JSON: " << ex.
what());
691 cfg->add(desc, space);
698 void setColumnNames(std::vector<std::string>& columns) {
699 columns[option_id_index_] =
"option_id";
700 columns[code_index_] =
"code";
701 columns[value_index_] =
"value";
702 columns[formatted_value_index_] =
"formatted_value";
703 columns[space_index_] =
"space";
704 columns[persistent_index_] =
"persistent";
705 columns[user_context_index_] =
"user_context";
713 size_t start_column_;
719 size_t option_id_index_;
729 size_t formatted_value_index_;
735 size_t persistent_index_;
739 size_t user_context_index_;
742 uint64_t most_recent_option_id_;
746 typedef boost::shared_ptr<OptionProcessor> OptionProcessorPtr;
756 enum FetchedOptions {
770 PgSqlHostWithOptionsExchange(
const FetchedOptions& fetched_options,
771 const size_t additional_columns_num = 0)
772 : PgSqlHostExchange(getRequiredColumnsNum(fetched_options)
773 + additional_columns_num),
774 opt_proc4_(), opt_proc6_() {
777 if ((fetched_options == DHCP4_ONLY) ||
778 (fetched_options == DHCP4_AND_DHCP6)) {
779 opt_proc4_.reset(
new OptionProcessor(Option::V4,
781 opt_proc4_->setColumnNames(columns_);
785 if ((fetched_options == DHCP6_ONLY) ||
786 (fetched_options == DHCP4_AND_DHCP6)) {
787 opt_proc6_.reset(
new OptionProcessor(Option::V6,
789 opt_proc6_->setColumnNames(columns_);
798 virtual void clear() {
799 PgSqlHostExchange::clear();
823 current_host = retrieveHost(r, row);
824 hosts.push_back(current_host);
829 HostID row_host_id = getHostId(r, row);
830 current_host = boost::const_pointer_cast<
Host>(hosts.back());
834 if (row_host_id > current_host->getHostId()) {
835 current_host = retrieveHost(r, row, row_host_id);
836 hosts.push_back(current_host);
843 opt_proc4_->retrieveOption(cfg, r, row);
849 opt_proc6_->retrieveOption(cfg, r, row);
866 static size_t getRequiredColumnsNum(
const FetchedOptions& fetched_options) {
867 return (fetched_options == DHCP4_AND_DHCP6 ? 2 * OPTION_COLUMNS :
874 OptionProcessorPtr opt_proc4_;
879 OptionProcessorPtr opt_proc6_;
894 class PgSqlHostIPv6Exchange :
public PgSqlHostWithOptionsExchange {
898 static const size_t RESERVATION_COLUMNS = 5;
906 PgSqlHostIPv6Exchange(
const FetchedOptions& fetched_options)
907 : PgSqlHostWithOptionsExchange(fetched_options, RESERVATION_COLUMNS),
908 reservation_id_index_(findAvailColumn()),
909 address_index_(reservation_id_index_ + 1),
910 prefix_len_index_(reservation_id_index_ + 2),
911 type_index_(reservation_id_index_ + 3),
912 iaid_index_(reservation_id_index_ + 4),
913 most_recent_reservation_id_(0) {
916 columns_[reservation_id_index_] =
"reservation_id";
917 columns_[address_index_] =
"address";
918 columns_[prefix_len_index_] =
"prefix_len";
919 columns_[type_index_] =
"type";
920 columns_[iaid_index_] =
"dhcp6_iaid";
922 BOOST_STATIC_ASSERT(4 < RESERVATION_COLUMNS);
931 PgSqlHostWithOptionsExchange::clear();
932 most_recent_reservation_id_ = 0;
938 uint64_t getReservationId(
const PgSqlResult& r,
int row)
const {
939 uint64_t resv_id = 0;
940 if (!isColumnNull(r, row, reservation_id_index_)) {
941 getColumnValue(r, row, reservation_id_index_, resv_id);
955 getColumnValue(r, row, type_index_, tmp);
961 resv_type = IPv6Resrv::TYPE_NA;
965 resv_type = IPv6Resrv::TYPE_PD;
970 "invalid IPv6 reservation type returned: " 971 << tmp <<
". Only 0 or 2 are allowed.");
979 getColumnValue(r, row, prefix_len_index_, prefix_len);
988 return (reservation);
1015 PgSqlHostWithOptionsExchange::processRowData(hosts, r, row);
1018 if (hosts.empty()) {
1020 " IPv6 reservation");
1025 uint64_t reservation_id = getReservationId(r, row);
1026 if (reservation_id && (reservation_id > most_recent_reservation_id_)) {
1027 HostPtr host = boost::const_pointer_cast<
Host>(hosts.back());
1029 most_recent_reservation_id_ = reservation_id;
1036 size_t reservation_id_index_;
1040 size_t address_index_;
1043 size_t prefix_len_index_;
1054 uint64_t most_recent_reservation_id_;
1071 static const size_t RESRV_COLUMNS = 6;
1078 PgSqlIPv6ReservationExchange()
1082 columns_[0] =
"host_id";
1083 columns_[1] =
"address";
1084 columns_[2] =
"prefix_len";
1085 columns_[3] =
"type";
1086 columns_[4] =
"dhcp6_iaid";
1087 BOOST_STATIC_ASSERT(5 < RESRV_COLUMNS);
1106 const bool unique_ip) {
1123 uint16_t type = resv.
getType() == IPv6Resrv::TYPE_NA ? 0 : 2;
1124 bind_array->add(type);
1128 bind_array->addNull();
1131 bind_array->add(host_id);
1140 }
catch (
const std::exception& ex) {
1142 "Could not create bind array from IPv6 Reservation: " 1143 << resv_.toText() <<
", reason: " << ex.
what());
1146 return (bind_array);
1160 static const int OPTION_ID_COL = 0;
1161 static const int CODE_COL = 1;
1162 static const int VALUE_COL = 2;
1163 static const int FORMATTED_VALUE_COL = 3;
1164 static const int SPACE_COL = 4;
1165 static const int PERSISTENT_COL = 5;
1166 static const int USER_CONTEXT_COL = 6;
1167 static const int DHCP_CLIENT_CLASS_COL = 7;
1168 static const int DHCP_SUBNET_ID_COL = 8;
1169 static const int HOST_ID_COL = 9;
1170 static const int SCOPE_ID_COL = 10;
1173 static const size_t OPTION_COLUMNS = 11;
1178 PgSqlOptionExchange()
1180 value_len_(0), option_() {
1181 columns_[OPTION_ID_COL] =
"option_id";
1182 columns_[CODE_COL] =
"code";
1183 columns_[VALUE_COL] =
"value";
1184 columns_[FORMATTED_VALUE_COL] =
"formatted_value";
1185 columns_[SPACE_COL] =
"space";
1186 columns_[PERSISTENT_COL] =
"persistent";
1187 columns_[USER_CONTEXT_COL] =
"user_context";
1188 columns_[DHCP_CLIENT_CLASS_COL] =
"dhcp_client_class";
1189 columns_[DHCP_SUBNET_ID_COL] =
"dhcp_subnet_id";
1190 columns_[HOST_ID_COL] =
"host_id";
1191 columns_[SCOPE_ID_COL] =
"scope_id";
1193 BOOST_STATIC_ASSERT(10 < OPTION_COLUMNS);
1205 const std::string& opt_space,
1218 bind_array->add(option_->getType());
1228 const char* buf_ptr =
static_cast<const char*
>(buf.getData());
1229 value_.assign(buf_ptr + opt_desc.
option_->getHeaderLen(),
1230 buf_ptr + buf.getLength());
1231 value_len_ = value_.size();
1232 bind_array->add(value_);
1236 bind_array->addNull(PsqlBindArray::BINARY_FMT);
1243 bind_array->addNull();
1247 if (!opt_space.empty()) {
1248 bind_array->addTempString(opt_space);
1250 bind_array->addNull();
1259 std::string user_context_ = ctx->str();
1260 bind_array->addTempString(user_context_);
1262 bind_array->addNull();
1269 bind_array->add(host_id);
1271 }
catch (
const std::exception& ex) {
1273 "Could not create bind array for inserting DHCP " 1274 "host option: " << option_->toText() <<
", reason: " 1278 return (bind_array);
1284 std::vector<uint8_t> value_;
1484 const bool return_last_id =
false);
1518 const std::string& opt_space,
1533 const uint64_t host_id);
1556 boost::shared_ptr<PgSqlHostExchange> exchange,
1580 const uint8_t* identifier_begin,
1581 const size_t identifier_len,
1583 boost::shared_ptr<PgSqlHostExchange> exchange)
const;
1604 std::pair<uint32_t, uint32_t> getVersion()
const;
1627 typedef boost::array<PgSqlTaggedStatement, PgSqlHostDataSourceImpl::NUM_STATEMENTS>
1628 TaggedStatementArray;
1632 TaggedStatementArray tagged_statements = { {
1641 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, " 1642 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, " 1643 " h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, " 1645 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1646 " h.dhcp4_boot_file_name, h.auth_key, " 1647 " o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, " 1648 " o4.persistent, o4.user_context, " 1649 " o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, " 1650 " o6.persistent, o6.user_context, " 1651 " r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid " 1653 "LEFT JOIN dhcp4_options AS o4 ON h.host_id = o4.host_id " 1654 "LEFT JOIN dhcp6_options AS o6 ON h.host_id = o6.host_id " 1655 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " 1656 "WHERE dhcp_identifier = $1 AND dhcp_identifier_type = $2 " 1657 "ORDER BY h.host_id, o4.option_id, o6.option_id, r.reservation_id" 1667 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, " 1668 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1669 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1670 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1671 " h.dhcp4_boot_file_name, h.auth_key, " 1672 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1673 " o.persistent, o.user_context " 1675 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id " 1676 "WHERE ipv4_address = $1 " 1677 "ORDER BY h.host_id, o.option_id" 1686 "get_host_subid4_dhcpid",
1687 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, " 1688 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1689 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1690 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1691 " h.dhcp4_boot_file_name, h.auth_key, " 1692 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1693 " o.persistent, o.user_context " 1695 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id " 1696 "WHERE h.dhcp4_subnet_id = $1 AND h.dhcp_identifier_type = $2 " 1697 " AND h.dhcp_identifier = $3 " 1698 "ORDER BY h.host_id, o.option_id" 1707 "get_host_subid6_dhcpid",
1708 "SELECT h.host_id, h.dhcp_identifier, " 1709 " h.dhcp_identifier_type, h.dhcp4_subnet_id, " 1710 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1711 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1712 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1713 " h.dhcp4_boot_file_name, h.auth_key, " 1714 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1715 " o.persistent, o.user_context, " 1716 " r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid " 1718 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id " 1719 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " 1720 "WHERE h.dhcp6_subnet_id = $1 AND h.dhcp_identifier_type = $2 " 1721 " AND h.dhcp_identifier = $3 " 1722 "ORDER BY h.host_id, o.option_id, r.reservation_id" 1732 "get_host_subid_addr",
1733 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, " 1734 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1735 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1736 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1737 " h.dhcp4_boot_file_name, h.auth_key, " 1738 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1739 " o.persistent, o.user_context " 1741 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id " 1742 "WHERE h.dhcp4_subnet_id = $1 AND h.ipv4_address = $2 " 1743 "ORDER BY h.host_id, o.option_id" 1756 "SELECT h.host_id, h.dhcp_identifier, " 1757 " h.dhcp_identifier_type, h.dhcp4_subnet_id, " 1758 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1759 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1760 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1761 " h.dhcp4_boot_file_name, h.auth_key, " 1762 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1763 " o.persistent, o.user_context, " 1764 " r.reservation_id, r.address, r.prefix_len, r.type, " 1767 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id " 1768 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " 1769 "WHERE h.host_id = " 1770 " (SELECT host_id FROM ipv6_reservations " 1771 " WHERE address = $1 AND prefix_len = $2) " 1772 "ORDER BY h.host_id, o.option_id, r.reservation_id" 1784 "get_host_subid6_addr",
1785 "SELECT h.host_id, h.dhcp_identifier, " 1786 " h.dhcp_identifier_type, h.dhcp4_subnet_id, " 1787 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1788 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1789 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1790 " h.dhcp4_boot_file_name, h.auth_key, " 1791 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1792 " o.persistent, o.user_context, " 1793 " r.reservation_id, r.address, r.prefix_len, r.type, " 1796 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id " 1797 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " 1798 "WHERE h.dhcp6_subnet_id = $1 AND r.address = $2 " 1799 "ORDER BY h.host_id, o.option_id, r.reservation_id" 1811 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, " 1812 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1813 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1814 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1815 " h.dhcp4_boot_file_name, h.auth_key, " 1816 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1817 " o.persistent, o.user_context " 1819 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id " 1820 "WHERE h.dhcp4_subnet_id = $1 " 1821 "ORDER BY h.host_id, o.option_id" 1837 "SELECT h.host_id, h.dhcp_identifier, " 1838 " h.dhcp_identifier_type, h.dhcp4_subnet_id, " 1839 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1840 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1841 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1842 " h.dhcp4_boot_file_name, h.auth_key, " 1843 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1844 " o.persistent, o.user_context, " 1845 " r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid " 1847 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id " 1848 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " 1849 "WHERE h.dhcp6_subnet_id = $1 " 1850 "ORDER BY h.host_id, o.option_id, r.reservation_id" 1861 "get_host_hostname",
1862 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, " 1863 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, " 1864 " h.hostname, h.dhcp4_client_classes, h.dhcp6_client_classes, " 1866 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1867 " h.dhcp4_boot_file_name, h.auth_key, " 1868 " o4.option_id, o4.code, o4.value, o4.formatted_value, o4.space, " 1869 " o4.persistent, o4.user_context, " 1870 " o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, " 1871 " o6.persistent, o6.user_context, " 1872 " r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid " 1874 "LEFT JOIN dhcp4_options AS o4 ON h.host_id = o4.host_id " 1875 "LEFT JOIN dhcp6_options AS o6 ON h.host_id = o6.host_id " 1876 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " 1877 "WHERE lower(h.hostname) = $1 " 1878 "ORDER BY h.host_id, o4.option_id, o6.option_id, r.reservation_id" 1888 "get_host_hostname_subid4",
1889 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, " 1890 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1891 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1892 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1893 " h.dhcp4_boot_file_name, h.auth_key, " 1894 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1895 " o.persistent, o.user_context " 1897 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id " 1898 "WHERE lower(h.hostname) = $1 AND h.dhcp4_subnet_id = $2 " 1899 "ORDER BY h.host_id, o.option_id" 1911 "get_host_hostname_subid6",
1912 "SELECT h.host_id, h.dhcp_identifier, " 1913 " h.dhcp_identifier_type, h.dhcp4_subnet_id, " 1914 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1915 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1916 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1917 " h.dhcp4_boot_file_name, h.auth_key, " 1918 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1919 " o.persistent, o.user_context, " 1920 " r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid " 1922 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id " 1923 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " 1924 "WHERE lower(h.hostname) = $1 AND h.dhcp6_subnet_id = $2 " 1925 "ORDER BY h.host_id, o.option_id, r.reservation_id" 1935 "get_host_subid4_page",
1936 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, " 1937 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1938 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1939 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1940 " h.dhcp4_boot_file_name, h.auth_key, " 1941 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1942 " o.persistent, o.user_context " 1943 "FROM ( SELECT * FROM hosts AS h " 1944 " WHERE h.dhcp4_subnet_id = $1 AND h.host_id > $2 " 1945 " ORDER BY h.host_id " 1947 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id " 1948 "ORDER BY h.host_id, o.option_id" 1960 "get_host_subid6_page",
1961 "SELECT h.host_id, h.dhcp_identifier, " 1962 " h.dhcp_identifier_type, h.dhcp4_subnet_id, " 1963 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1964 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1965 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1966 " h.dhcp4_boot_file_name, h.auth_key, " 1967 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1968 " o.persistent, o.user_context, " 1969 " r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid " 1970 "FROM ( SELECT * FROM hosts AS h " 1971 " WHERE h.dhcp6_subnet_id = $1 AND h.host_id > $2 " 1972 " ORDER BY h.host_id " 1974 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id " 1975 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " 1976 "ORDER BY h.host_id, o.option_id, r.reservation_id" 1987 "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, " 1988 " h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 1989 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 1990 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 1991 " h.dhcp4_boot_file_name, h.auth_key, " 1992 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 1993 " o.persistent, o.user_context " 1994 "FROM ( SELECT * FROM hosts AS h " 1995 " WHERE h.host_id > $1 " 1996 " ORDER BY h.host_id " 1998 "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id " 1999 "ORDER BY h.host_id, o.option_id" 2012 "SELECT h.host_id, h.dhcp_identifier, " 2013 " h.dhcp_identifier_type, h.dhcp4_subnet_id, " 2014 " h.dhcp6_subnet_id, h.ipv4_address, h.hostname, " 2015 " h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, " 2016 " h.dhcp4_next_server, h.dhcp4_server_hostname, " 2017 " h.dhcp4_boot_file_name, h.auth_key, " 2018 " o.option_id, o.code, o.value, o.formatted_value, o.space, " 2019 " o.persistent, o.user_context, " 2020 " r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid " 2021 "FROM ( SELECT * FROM hosts AS h " 2022 " WHERE h.host_id > $1 " 2023 " ORDER BY h.host_id " 2025 "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id " 2026 "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id " 2027 "ORDER BY h.host_id, o.option_id, r.reservation_id" 2038 "insert_host_non_unique_ip",
2039 "INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, " 2040 " dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, " 2041 " dhcp4_client_classes, dhcp6_client_classes, user_context, " 2042 " dhcp4_next_server, dhcp4_server_hostname, dhcp4_boot_file_name, auth_key)" 2043 "VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13 ) " 2064 "insert_host_unique_ip",
2065 "INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, " 2066 " dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, " 2067 " dhcp4_client_classes, dhcp6_client_classes, user_context, " 2068 " dhcp4_next_server, dhcp4_server_hostname, dhcp4_boot_file_name, auth_key)" 2069 " SELECT $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13" 2070 " WHERE NOT EXISTS (" 2071 " SELECT 1 FROM hosts WHERE ipv4_address = $14 AND dhcp4_subnet_id = $15" 2082 "insert_v6_resrv_non_unique",
2083 "INSERT INTO ipv6_reservations(address, prefix_len, type, " 2084 " dhcp6_iaid, host_id) " 2085 "VALUES ($1, $2, $3, $4, $5)" 2093 "insert_v6_resrv_unique",
2094 "INSERT INTO ipv6_reservations(address, prefix_len, type, " 2095 " dhcp6_iaid, host_id) " 2096 "SELECT $1, $2, $3, $4, $5 " 2097 " WHERE NOT EXISTS (" 2098 " SELECT 1 FROM ipv6_reservations" 2099 " WHERE address = $6 AND prefix_len = $7" 2110 "insert_v4_host_option",
2111 "INSERT INTO dhcp4_options(code, value, formatted_value, space, " 2112 " persistent, user_context, host_id, scope_id) " 2113 "VALUES ($1, $2, $3, $4, $5, $6, $7, 3)" 2122 "insert_v6_host_option",
2123 "INSERT INTO dhcp6_options(code, value, formatted_value, space, " 2124 " persistent, user_context, host_id, scope_id) " 2125 "VALUES ($1, $2, $3, $4, $5, $6, $7, 3)" 2133 "DELETE FROM hosts WHERE dhcp4_subnet_id = $1 AND ipv4_address = $2" 2141 "DELETE FROM hosts USING ipv6_reservations " 2142 " WHERE dhcp6_subnet_id = $1 AND ipv6_reservations.address = $2" 2149 "del_host_subid4_id",
2150 "DELETE FROM hosts WHERE dhcp4_subnet_id = $1 " 2151 "AND dhcp_identifier_type = $2 " 2152 "AND dhcp_identifier = $3" 2159 "del_host_subid6_id",
2160 "DELETE FROM hosts WHERE dhcp6_subnet_id = $1 " 2161 "AND dhcp_identifier_type = $2 " 2162 "AND dhcp_identifier = $3" 2174 : conn_(parameters, io_service_accessor, db_reconnect_callback),
2175 is_readonly_(true) {
2183 if (MultiThreadingMgr::instance().getMode()) {
2187 lock_guard<mutex> lock(mgr_.
pool_->mutex_);
2188 if (!mgr_.
pool_->pool_.empty()) {
2190 mgr_.
pool_->pool_.pop_back();
2198 if (mgr_.
pool_->pool_.empty()) {
2206 if (MultiThreadingMgr::instance().getMode()) {
2208 lock_guard<mutex> lock(mgr_.
pool_->mutex_);
2210 if (
ctx_->conn_.isUnusable()) {
2213 }
else if (
ctx_->conn_.isUnusable()) {
2219 : parameters_(parameters), ip_reservations_unique_(true), unusable_(false),
2224 timer_name_ += boost::lexical_cast<std::string>(
reinterpret_cast<uint64_t
>(
this));
2229 tls += parameters.count(
"trust-anchor");
2230 tls += parameters.count(
"cert-file");
2231 tls += parameters.count(
"key-file");
2232 tls += parameters.count(
"cipher-list");
2233 #ifdef HAVE_PGSQL_SSL 2245 <<
"backend (built with this feature disabled)");
2252 std::pair<uint32_t, uint32_t> db_version =
getVersion();
2253 if (code_version != db_version) {
2255 "PostgreSQL schema version mismatch: need version: " 2256 << code_version.first <<
"." << code_version.second
2257 <<
" found version: " << db_version.first <<
"." 2258 << db_version.second);
2275 ctx->conn_.openDatabase();
2278 ctx->conn_.prepareStatements(tagged_statements.begin(),
2283 ctx->is_readonly_ = ctx->conn_.configuredReadOnly();
2287 if (!ctx->is_readonly_) {
2289 tagged_statements.end());
2294 ctx->host_ipv4_exchange_.reset(
new PgSqlHostWithOptionsExchange(PgSqlHostWithOptionsExchange::DHCP4_ONLY));
2295 ctx->host_ipv6_exchange_.reset(
new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::DHCP6_ONLY));
2296 ctx->host_ipv46_exchange_.reset(
new PgSqlHostIPv6Exchange(PgSqlHostWithOptionsExchange::DHCP4_AND_DHCP6));
2297 ctx->host_ipv6_reservation_exchange_.reset(
new PgSqlIPv6ReservationExchange());
2298 ctx->host_option_exchange_.reset(
new PgSqlOptionExchange());
2318 bool reopened =
false;
2320 const std::string timer_name = db_reconnect_ctl->timerName();
2325 std::list<std::string> host_db_access_list = cfg_db->getHostDbAccessStringList();
2326 for (std::string& hds : host_db_access_list) {
2333 }
catch (
const std::exception& ex) {
2349 if (!db_reconnect_ctl->checkRetries()) {
2352 .arg(db_reconnect_ctl->maxRetries());
2365 .arg(db_reconnect_ctl->maxRetries() - db_reconnect_ctl->retriesLeft() + 1)
2366 .arg(db_reconnect_ctl->maxRetries())
2367 .arg(db_reconnect_ctl->retryInterval());
2373 db_reconnect_ctl->retryInterval(),
2386 const bool return_last_id) {
2387 uint64_t last_id = 0;
2388 PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2389 tagged_statements[stindex].nbparams,
2390 &bind_array->values_[0],
2391 &bind_array->lengths_[0],
2392 &bind_array->formats_[0], 0));
2394 int s = PQresultStatus(r);
2396 if (s != PGRES_COMMAND_OK) {
2404 ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2408 char* rows_affected = PQcmdTuples(r);
2409 if (!rows_affected) {
2411 "Could not retrieve the number of affected rows.");
2419 if (rows_affected[0] ==
'0') {
2423 if (return_last_id) {
2434 PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2435 tagged_statements[stindex].nbparams,
2436 &bind_array->values_[0],
2437 &bind_array->lengths_[0],
2438 &bind_array->formats_[0], 0));
2440 int s = PQresultStatus(r);
2442 if (s != PGRES_COMMAND_OK) {
2445 ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2450 char* rows_deleted = PQcmdTuples(r);
2451 if (!rows_deleted) {
2453 "Could not retrieve the number of deleted rows.");
2455 return (rows_deleted[0] !=
'0');
2474 const std::string& opt_space,
2477 PsqlBindArrayPtr bind_array = ctx->host_option_exchange_->createBindForSend(opt_desc, opt_space,
id);
2486 const uint64_t host_id) {
2489 std::list<std::string> option_spaces = options_cfg->getOptionSpaceNames();
2490 std::list<std::string> vendor_spaces = options_cfg->getVendorIdsSpaceNames();
2491 option_spaces.insert(option_spaces.end(), vendor_spaces.begin(),
2492 vendor_spaces.end());
2496 for (
auto space = option_spaces.begin(); space != option_spaces.end(); ++space) {
2498 if (options && !options->empty()) {
2499 for (
auto opt = options->begin(); opt != options->end(); ++opt) {
2510 boost::shared_ptr<PgSqlHostExchange> exchange,
2512 bool single)
const {
2515 PgSqlResult r(PQexecPrepared(ctx->conn_, tagged_statements[stindex].name,
2516 tagged_statements[stindex].nbparams,
2517 &bind_array->values_[0],
2518 &bind_array->lengths_[0],
2519 &bind_array->formats_[0], 0));
2521 ctx->conn_.checkStatementError(r, tagged_statements[stindex]);
2524 for (
int row = 0; row < rows; ++row) {
2525 exchange->processRowData(result, r, row);
2527 if (single && result.size() > 1) {
2529 "database where only one was expected for query " 2530 << tagged_statements[stindex].name);
2539 const uint8_t* identifier_begin,
2540 const size_t identifier_len,
2542 boost::shared_ptr<PgSqlHostExchange> exchange)
const {
2548 bind_array->add(subnet_id);
2551 bind_array->add(static_cast<uint8_t>(identifier_type));
2554 bind_array->add(identifier_begin, identifier_len);
2561 if (!collection.empty()) {
2562 result = *collection.begin();
2568 std::pair<uint32_t, uint32_t>
2577 if (ctx->is_readonly_) {
2579 " to operate in read only mode");
2594 return (impl_->parameters_);
2604 impl_->checkReadOnly(ctx);
2616 bool unique_ip = impl_->ip_reservations_unique_ && !host->getIPv4Reservation().isV4Zero()
2617 && host->getIPv4SubnetID() != SUBNET_ID_UNUSED;
2620 PsqlBindArrayPtr bind_array = ctx->host_ipv4_exchange_->createBindForSend(host, unique_ip);
2623 uint32_t host_id = impl_->addStatement(ctx,
2632 cfg_option4, host_id);
2639 cfg_option6, host_id);
2644 if (std::distance(v6resv.first, v6resv.second) > 0) {
2647 impl_->addResv(ctx, resv->second, host_id);
2663 impl_->checkReadOnly(ctx);
2666 bind_array->add(subnet_id);
2670 bind_array->add(addr);
2676 bind_array->addTempString(addr.
toText());
2685 const uint8_t* identifier_begin,
2686 const size_t identifier_len) {
2692 impl_->checkReadOnly(ctx);
2697 bind_array->add(subnet_id);
2700 bind_array->add(static_cast<uint8_t>(identifier_type));
2703 bind_array->add(identifier_begin, identifier_len);
2712 const uint8_t* identifier_begin,
2713 const size_t identifier_len) {
2719 impl_->checkReadOnly(ctx);
2724 bind_array->add(subnet_id);
2727 bind_array->add(static_cast<uint8_t>(identifier_type));
2730 bind_array->add(identifier_begin, identifier_len);
2738 const uint8_t* identifier_begin,
2739 const size_t identifier_len)
const {
2748 bind_array->add(identifier_begin, identifier_len);
2751 bind_array->add(static_cast<uint8_t>(identifier_type));
2755 bind_array, ctx->host_ipv46_exchange_, result,
false);
2770 bind_array->add(subnet_id);
2774 bind_array, ctx->host_ipv4_exchange_, result,
false);
2789 bind_array->add(subnet_id);
2793 bind_array, ctx->host_ipv6_exchange_, result,
false);
2808 bind_array->add(hostname);
2812 bind_array, ctx->host_ipv46_exchange_, result,
false);
2828 bind_array->add(hostname);
2831 bind_array->add(subnet_id);
2835 bind_array, ctx->host_ipv4_exchange_, result,
false);
2851 bind_array->add(hostname);
2854 bind_array->add(subnet_id);
2858 bind_array, ctx->host_ipv6_exchange_, result,
false);
2866 uint64_t lower_host_id,
2876 bind_array->add(subnet_id);
2879 bind_array->add(lower_host_id);
2882 string page_size_data =
2883 boost::lexical_cast<std::string>(page_size.
page_size_);
2884 bind_array->add(page_size_data);
2888 bind_array, ctx->host_ipv4_exchange_, result,
false);
2896 uint64_t lower_host_id,
2906 bind_array->add(subnet_id);
2909 bind_array->add(lower_host_id);
2912 string page_size_data =
2913 boost::lexical_cast<std::string>(page_size.
page_size_);
2914 bind_array->add(page_size_data);
2918 bind_array, ctx->host_ipv6_exchange_, result,
false);
2925 uint64_t lower_host_id,
2935 bind_array->add(lower_host_id);
2938 string page_size_data =
2939 boost::lexical_cast<std::string>(page_size.
page_size_);
2940 bind_array->add(page_size_data);
2944 bind_array, ctx->host_ipv4_exchange_, result,
false);
2951 uint64_t lower_host_id,
2961 bind_array->add(lower_host_id);
2964 string page_size_data =
2965 boost::lexical_cast<std::string>(page_size.
page_size_);
2966 bind_array->add(page_size_data);
2970 bind_array, ctx->host_ipv6_exchange_, result,
false);
2985 bind_array->add(address);
2989 bind_array, ctx->host_ipv4_exchange_, result,
false);
2997 const uint8_t* identifier_begin,
2998 const size_t identifier_len)
const {
3003 return (impl_->getHost(ctx, subnet_id, identifier_type, identifier_begin, identifier_len,
3005 ctx->host_ipv4_exchange_));
3015 if (!address.
isV4()) {
3017 " wrong address type, address supplied is an IPv6 address");
3024 bind_array->add(subnet_id);
3027 bind_array->add(address);
3031 bind_array, ctx->host_ipv4_exchange_, collection,
true);
3035 if (!collection.empty()) {
3036 result = *collection.begin();
3049 if (!address.
isV4()) {
3051 " wrong address type, address supplied is an IPv6 address");
3058 bind_array->add(subnet_id);
3061 bind_array->add(address);
3065 bind_array, ctx->host_ipv4_exchange_, collection,
false);
3066 return (collection);
3072 const uint8_t* identifier_begin,
3073 const size_t identifier_len)
const {
3078 return (impl_->getHost(ctx, subnet_id, identifier_type, identifier_begin, identifier_len,
3080 ctx->host_ipv6_exchange_));
3085 const uint8_t prefix_len)
const {
3086 if (!prefix.
isV6()) {
3088 "wrong address type, address supplied is an IPv4 address");
3099 bind_array->add(prefix);
3102 bind_array->add(prefix_len);
3106 bind_array, ctx->host_ipv6_exchange_, collection,
true);
3110 if (!collection.empty()) {
3111 result = *collection.begin();
3120 if (!address.
isV6()) {
3122 "wrong address type, address supplied is an IPv4 address");
3133 bind_array->add(subnet_id);
3136 bind_array->add(address);
3140 bind_array, ctx->host_ipv6_exchange_, collection,
true);
3144 if (!collection.empty()) {
3145 result = *collection.begin();
3154 if (!address.
isV6()) {
3156 "wrong address type, address supplied is an IPv4 address");
3167 bind_array->add(subnet_id);
3170 bind_array->add(address);
3174 bind_array, ctx->host_ipv6_exchange_, collection,
false);
3175 return (collection);
3182 std::string name =
"";
3188 name = ctx->conn_.getParameter(
"name");
3197 return (std::string(
"Host data source that stores host information" 3198 "in PostgreSQL database"));
3201 std::pair<uint32_t, uint32_t>
3203 return(impl_->getVersion());
3213 impl_->checkReadOnly(ctx);
3214 ctx->conn_.commit();
3224 impl_->checkReadOnly(ctx);
3225 ctx->conn_.rollback();
3230 impl_->ip_reservations_unique_ = unique;
3236 return (impl_->unusable_);
std::string timer_name_
Timer name used to register database reconnect timer.
RAII class creating a critical section.
std::function< bool(util::ReconnectCtlPtr db_reconnect_ctl)> DbCallback
Defines a callback prototype for propagating events upward.
RAII wrapper for PostgreSQL Result sets.
const isc::log::MessageID DHCPSRV_PGSQL_HOST_DB_RECONNECT_ATTEMPT_FAILED
Wraps value holding size of the page with host reservations.
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.
void addResv(PgSqlHostContextPtr &ctx, const IPv6Resrv &resv, const HostID &id)
Inserts IPv6 Reservation into ipv6_reservation table.
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< ReconnectCtl > ReconnectCtlPtr
Pointer to an instance of ReconnectCtl.
boost::shared_ptr< const CfgOption > ConstCfgOptionPtr
Const pointer.
const isc::log::MessageID DHCPSRV_PGSQL_NO_TLS_SUPPORT
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...
static CfgMgr & instance()
returns a single instance of Configuration Manager
~PgSqlHostContextAlloc()
Destructor.
const size_t page_size_
Holds page size.
static bool dbReconnect(ReconnectCtlPtr db_reconnect_ctl)
Attempts to reconnect the server to the host DB backend manager.
static isc::asiolink::IOServicePtr & getIOService()
Returns pointer to the IO service.
boost::shared_ptr< Option > OptionPtr
const isc::log::MessageID DHCPSRV_PGSQL_HOST_DB_RECONNECT_FAILED
static const char DUPLICATE_KEY[]
Define the PgSql error state for a duplicate key error.
PgSqlConnection conn_
PostgreSQL connection.
Universe
defines option universe DHCPv4 or DHCPv6
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
const isc::log::MessageID DHCPSRV_PGSQL_HOST_DB_GET_VERSION
SrvConfigPtr getCurrentCfg()
Returns a pointer to the current configuration.
virtual std::string getName() const
Returns the name of the open database.
virtual bool setIPReservationsUnique(const bool unique)
Controls whether IP reservations are unique or non-unique.
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)
Base class for marshalling data to and from PostgreSQL.
static ParameterMap parse(const std::string &dbaccess)
Parse database access string.
int getRows() const
Returns the number of rows in the result set.
IPv6 reservation for a host.
void checkReadOnly(PgSqlHostContextPtr &ctx) const
Throws exception if database is read only.
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.
virtual ConstHostCollection getAllbyHostname(const std::string &hostname) const
Return all hosts with a hostname.
std::pair< uint32_t, uint32_t > getVersion() const
Returns PostgreSQL schema version of the open database.
ConstHostPtr getHost(PgSqlHostContextPtr &ctx, 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.
Exception thrown on failure to open database.
PgSqlHostDataSourceImpl(const DatabaseConnection::ParameterMap ¶meters)
Constructor.
void addOption(PgSqlHostContextPtr &ctx, const PgSqlHostDataSourceImpl::StatementIndex &stindex, const OptionDescriptor &opt_desc, const std::string &opt_space, const Optional< SubnetID > &subnet_id, const HostID &host_id)
Inserts a single DHCP option into the database.
Multiple lease records found where one expected.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
void addOptions(PgSqlHostContextPtr &ctx, const StatementIndex &stindex, const ConstCfgOptionPtr &options_cfg, const uint64_t host_id)
Inserts multiple options into the database.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual ConstHostCollection getAll6(const SubnetID &subnet_id) const
Return all hosts in a DHCPv6 subnet.
std::string formatted_value_
Option value in textual (CSV) format.
~PgSqlHostDataSourceImpl()
Destructor.
std::pair< IPv6ResrvIterator, IPv6ResrvIterator > IPv6ResrvRange
boost::shared_ptr< PsqlBindArray > PsqlBindArrayPtr
Defines a smart pointer to PsqlBindArray.
static bool delBackend(const std::string &db_type)
Delete an alternate host backend (aka host data source).
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
uint64_t addStatement(PgSqlHostContextPtr &ctx, PgSqlHostDataSourceImpl::StatementIndex stindex, PsqlBindArrayPtr &bind, const bool return_last_id=false)
Executes statements which insert a row into one of the tables.
boost::shared_ptr< CfgDbAccess > CfgDbAccessPtr
A pointer to the CfgDbAccess.
std::vector< ConstHostPtr > ConstHostCollection
Collection of the const Host objects.
virtual ConstHostCollection getPage4(const SubnetID &subnet_id, size_t &source_index, uint64_t lower_host_id, const HostPageSize &page_size) const
Returns range of hosts in a DHCPv4 subnet.
static bool warned_about_tls
Emit the TLS support warning only once.
bool persistent_
Persistence flag.
virtual ConstHostCollection getAllbyHostname4(const std::string &hostname, const SubnetID &subnet_id) const
Return all hosts with a hostname in a DHCPv4 subnet.
A generic exception that is thrown when an unexpected error condition occurs.
PgSqlHostContextPtr ctx_
The context.
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)
static void getColumnValue(const PgSqlResult &r, const int row, const size_t col, std::string &value)
Fetches text column value as a string.
Common PgSql Connector Pool.
static bool invokeDbRecoveredCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's restored connectivity callback.
virtual ~PgSqlHostDataSource()
Virtual destructor.
bool ip_reservations_unique_
Holds the setting whether the IP reservations must be unique or may be non-unique.
Represents a device with IPv4 and/or IPv6 reservations.
Type
Type of the reservation.
bool isV6() const
Convenience function to check for an IPv6 address.
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 hosts by (subnet-id, address)
boost::shared_ptr< PgSqlHostContext > PgSqlHostContextPtr
Type of pointers to contexts.
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...
std::vector< PgSqlHostContextPtr > pool_
The vector of available contexts.
OptionPtr option_
Option instance.
bool delStatement(PgSqlHostContextPtr &ctx, PgSqlHostDataSourceImpl::StatementIndex stindex, PsqlBindArrayPtr &bind)
Executes statements that delete records.
const isc::log::MessageID DHCPSRV_PGSQL_HOST_DB_RECONNECT_ATTEMPT_SCHEDULE
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-lfc.
Type getType() const
Returns reservation type.
PgSqlHostContextPoolPtr pool_
The pool of contexts.
static bool invokeDbFailedCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's restore failed connectivity callback.
virtual ConstHostCollection getAllbyHostname6(const std::string &hostname, const SubnetID &subnet_id) const
Return all hosts with a hostname in a DHCPv6 subnet.
std::string toText() const
Convert the address to a string.
boost::shared_ptr< PgSqlHostContextPool > PgSqlHostContextPoolPtr
Type of pointers to context pools.
Implementation of the PgSqlHostDataSource.
bool is_readonly_
Indicates if the database is opened in read only mode.
PgSqlHostContextAlloc(PgSqlHostDataSourceImpl &mgr)
Constructor.
virtual bool isUnusable()
Flag which indicates if the host manager has at least one unusable connection.
void addReservation(const IPv6Resrv &reservation)
Adds new IPv6 reservation.
A wrapper interface for the ASIO library.
PgSqlHostContextPtr createContext() const
Create a new context.
#define DHCP6_OPTION_SPACE
virtual ConstHostCollection getPage6(const SubnetID &subnet_id, size_t &source_index, uint64_t lower_host_id, const HostPageSize &page_size) const
Returns range of hosts in a DHCPv6 subnet.
virtual ConstHostCollection getAll4(const SubnetID &subnet_id) const
Return all hosts in a DHCPv4 subnet.
virtual void rollback()
Rollback Transactions.
#define DHCP4_OPTION_SPACE
global std option spaces
static void addBackend(const std::string &access)
Add an alternate host backend (aka host data source).
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.
Attempt to modify data in read-only database.
DatabaseConnection::ParameterMap parameters_
The parameters.
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
virtual isc::db::DatabaseConnection::ParameterMap getParameters() const
Return backend parameters.
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.
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
const uint32_t PGSQL_SCHEMA_VERSION_MAJOR
Define the PostgreSQL backend version.
static std::pair< uint32_t, uint32_t > getVersion(const ParameterMap ¶meters)
Get the schema version.
virtual void commit()
Commit Transactions.
IdentifierType
Type of the host identifier.
std::function< isc::asiolink::IOServicePtr()> IOServiceAccessor
Function which returns the IOService that can be used to recover the connection.
virtual std::pair< uint32_t, uint32_t > getVersion() const
Returns backend version.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
static const TimerMgrPtr & instance()
Returns pointer to the sole instance of the TimerMgr.
The IOAddress class represents an IP addresses (version agnostic)
static bool invokeDbLostCallback(const util::ReconnectCtlPtr &db_reconnect_ctl)
Invokes the connection's lost connectivity callback.
boost::shared_ptr< PgSqlHostIPv6Exchange > host_ipv6_exchange_
Pointer to an object representing an exchange which can be used to retrieve hosts, DHCPv6 options and IPv6 reservations.
boost::shared_ptr< PgSqlHostIPv6Exchange > host_ipv46_exchange_
Pointer to an object representing an exchange which can be used to retrieve hosts, DHCPv4 and DHCPv6 options, and IPv6 reservations using a single query.
std::mutex mutex_
The mutex to protect pool access.
static const StatementIndex WRITE_STMTS_BEGIN
Index of first statement performing write to the database.
void getHostCollection(PgSqlHostContextPtr &ctx, 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 ...
const size_t OPTION_VALUE_MAX_LEN
Maximum length of option value.
static std::string redactedAccessString(const ParameterMap ¶meters)
Redact database access string.
uint64_t HostID
HostID (used only when storing in MySQL or PostgreSQL backends)
A template representing an optional value.
const isc::log::MessageID DHCPSRV_PGSQL_HOST_DB_READONLY
boost::shared_ptr< PgSqlIPv6ReservationExchange > host_ipv6_reservation_exchange_
Pointer to an object representing an exchange which can be used to insert new IPv6 reservation...
const asiolink::IOAddress & getPrefix() const
Returns prefix for the reservation.
const isc::log::MessageID DHCPSRV_PGSQL_TLS_SUPPORT
Exception thrown on failure to execute a database function.
boost::shared_ptr< IOServiceAccessor > IOServiceAccessorPtr
Pointer to an instance of IOServiceAccessor.
PostgreSQL Host Context Pool.
Database duplicate entry error.
const uint32_t PGSQL_SCHEMA_VERSION_MINOR
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
RAII object representing a PostgreSQL transaction.
boost::shared_ptr< PgSqlHostWithOptionsExchange > host_ipv4_exchange_
The exchange objects are used for transfer of data to/from the database.
bool unusable_
Indicates if there is at least one connection that can no longer be used for normal operations...