2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-29 04:57:52 +00:00

[313-return-a-list-of-all-reservations-by-subnet-id] Finished the getAll[46] implementation

This commit is contained in:
Francis Dupont 2019-01-13 11:40:20 +01:00
parent 2a5750c931
commit 55e2828cf2
18 changed files with 625 additions and 36 deletions

View File

@ -106,7 +106,8 @@ EXTRA_DIST += api/network6-add.json api/network6-del.json
EXTRA_DIST += api/network6-get.json api/network6-list.json
EXTRA_DIST += api/network6-subnet-add.json api/network6-subnet-del.json
EXTRA_DIST += api/reservation-add.json api/reservation-del.json
EXTRA_DIST += api/reservation-get.json api/shutdown.json
EXTRA_DIST += api/reservation-get.json api/reservation-get-all.json
EXTRA_DIST += api/shutdown.json
EXTRA_DIST += api/statistic-get-all.json api/statistic-get.json
EXTRA_DIST += api/statistic-remove-all.json api/statistic-remove.json
EXTRA_DIST += api/statistic-reset-all.json api/statistic-reset.json

View File

@ -0,0 +1,14 @@
{
"name": "reservation-get-all",
"brief": "Retrieve all host reservations for a specified subnet.",
"support": [ "kea-dhcp4", "kea-dhcp6" ],
"hook": "host_cmds",
"avail": "1.6.0",
"cmd-syntax": "{
\"command\": \"reservation-get-all\",
\"arguments\": {
\"subnet-id\": <integer>
}",
"resp-comment": "reservation-get-all command may result in very large responses."
}

View File

@ -51,6 +51,7 @@ network6-subnet-del
reservation-add
reservation-del
reservation-get
reservation-get-all
shutdown
stat-lease4-get
stat-lease6-get

View File

@ -63,6 +63,7 @@
, <command><link linkend="ref-reservation-add">reservation-add</link></command>
, <command><link linkend="ref-reservation-del">reservation-del</link></command>
, <command><link linkend="ref-reservation-get">reservation-get</link></command>
, <command><link linkend="ref-reservation-get-all">reservation-get-all</link></command>
, <command><link linkend="ref-shutdown">shutdown</link></command>
, <command><link linkend="ref-stat-lease4-get">stat-lease4-get</link></command>
, <command><link linkend="ref-stat-lease6-get">stat-lease6-get</link></command>
@ -143,6 +144,7 @@
, <command><link linkend="ref-reservation-add">reservation-add</link></command>
, <command><link linkend="ref-reservation-del">reservation-del</link></command>
, <command><link linkend="ref-reservation-get">reservation-get</link></command>
, <command><link linkend="ref-reservation-get-all">reservation-get-all</link></command>
, <command><link linkend="ref-shutdown">shutdown</link></command>
, <command><link linkend="ref-stat-lease4-get">stat-lease4-get</link></command>
, <command><link linkend="ref-statistic-get">statistic-get</link></command>
@ -198,6 +200,7 @@
, <command><link linkend="ref-reservation-add">reservation-add</link></command>
, <command><link linkend="ref-reservation-del">reservation-del</link></command>
, <command><link linkend="ref-reservation-get">reservation-get</link></command>
, <command><link linkend="ref-reservation-get-all">reservation-get-all</link></command>
, <command><link linkend="ref-shutdown">shutdown</link></command>
, <command><link linkend="ref-stat-lease6-get">stat-lease6-get</link></command>
, <command><link linkend="ref-statistic-get">statistic-get</link></command>
@ -233,6 +236,7 @@
<para xml:id="commands-host_cmds-lib">Commands supported by host_cmds hook library: <command><link linkend="ref-reservation-add">reservation-add</link></command>
, <command><link linkend="ref-reservation-del">reservation-del</link></command>
, <command><link linkend="ref-reservation-get">reservation-get</link></command>
, <command><link linkend="ref-reservation-get-all">reservation-get-all</link></command>
.</para>
<para xml:id="commands-lease_cmds-lib">Commands supported by lease_cmds hook library: <command><link linkend="ref-lease4-add">lease4-add</link></command>
, <command><link linkend="ref-lease4-del">lease4-del</link></command>
@ -2511,6 +2515,61 @@ object appear only if specific field is set.</para>
</section>
<!-- end of reservation-get -->
<!-- start of reservation-get-all -->
<section xml:id="reference-reservation-get-all">
<title>reservation-get reference</title>
<para xml:id="ref-reservation-get-all"><command>reservation-get-all</command> - Retrieve all host reservations for a specified subnet.</para>
<para>Supported by: <command><link linkend="commands-kea-dhcp4">kea-dhcp4</link></command>, <command><link linkend="commands-kea-dhcp6">kea-dhcp6</link></command></para>
<para>Availability: 1.6.0 (<link linkend="commands-host_cmds-lib">host_cmds</link> hook)</para>
<para>Description and examples: See <xref linkend="command-reservation-get-all"/></para>
<para>Command syntax:
<screen>{
"command": "reservation-get-all",
"arguments": {
"subnet-id": &lt;integer&gt;
}
}</screen>
Host reservations can be identified by subnet-id.</para>
<para>Response syntax:
<screen>{
"result": &lt;integer&gt;,
"text": &lt;string&gt;,
"arguments": {
"hosts": [
{
"boot-file-name": &lt;string&gt;,
"comment": &lt;string&gt;
"client-id": &lt;string&gt;,
"circuit-id": &lt;string&gt;,
"duid": &lt;string&gt;,
"flex-id": &lt;string&gt;,
"ip-address": &lt;string (IPv4 address)&gt;,
"ip-addresses": [ &lt;comma separated strings&gt; ],
"hw-address": &lt;string&gt;,
"hostname": &lt;string&gt;,
"next-server": &lt;string (IPv4 address)&gt;,
"option-data-list": [ &lt;comma separated structures defining options&gt; ],
"prefixes": [ &lt;comma separated IPv6 prefixes&gt; ],
"reservation-client-classes": [ &lt;comma separated strings&gt; ],
"server-hostname": &lt;string&gt;,
"subnet-id": &lt;integer&gt;,
"user-context": &lt;any valid JSON&gt;,
},
...
]
}
}</screen>
The reservation-get-all command may result in very large responses.</para>
</section>
<!-- end of reservation-get-all -->
<!-- start of shutdown -->
<section xml:id="reference-shutdown">
<title>shutdown reference</title>

View File

@ -1,5 +1,5 @@
<!--
- Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
- Copyright (C) 2014-2019 Internet Systems Consortium, Inc. ("ISC")
-
- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
@ -1418,9 +1418,11 @@ $
</para>
<para>
Currently three commands are supported: reservation-add (which adds
Currently four commands are supported: reservation-add (which adds
new host reservation), reservation-get (which returns existing
reservation if specified criteria are matched) and reservation-del
reservation if specified criteria are matched), reservation-get-all
(which returns all reservations in a specified subnet) and
reservation-del
(which attempts to delete a reservation matching specified
criteria). To use commands that change the reservation information
(currently these are reservation-add and reservation-del, but this
@ -1585,7 +1587,7 @@ Here is an example of complex IPv6 reservation:
"circuit-id", "client-id" and "flex-id", but additional types may be
added in the future. If any new identifier types are defined in the
future, reservation-get command will support them automatically.
The <command>subnet-id</command> is manadatory. Use a value of zero (0) to
The <command>subnet-id</command> is mandatory. Use a value of zero (0) to
fetch a global reservation, or the id of the subnet to which the reservation
belongs.
</para>
@ -1648,6 +1650,22 @@ An example result returned when the query was malformed:<screen>
</section>
<section xml:id="command-reservation-get-all">
<title>reservation-get-all command</title>
<para><command>reservation-get-all</command> can be used to
query the host database and retrieve all reservations in a
specified subnet. This command uses parameters providing the
mandatory subnet-id. Use a value of zero (0) to fetch global
reservations.
</para>
<!-- Add example? -->
<para>The response returned by <command>reservation-get-all</command>
can be very long.
</para>
</section>
<section xml:id="command-reservation-del">
<title>reservation-del command</title>
<para><command>reservation-del</command> can be used to delete a

View File

@ -1,4 +1,4 @@
// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2018-2019 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2016-2017 Deutsche Telekom AG.
//
// Author: Andrei Pavel <andrei.pavel@qualitance.com>
@ -311,6 +311,16 @@ public:
// Deletes a host reservation.
static constexpr StatementTag DELETE_HOST =
"DELETE_HOST";
// Retrieves host information along with the IPv4 options associated
// with it using a subnet identifier.
static constexpr StatementTag GET_HOST_BY_IPV4_SUBNET_ID =
"GET_HOST_BY_IPV4_SUBNET_ID";
// Retrieves host information; IPv6 reservations and IPv6 options
// associated with a host using subnet identifier.
static constexpr StatementTag GET_HOST_BY_IPV6_SUBNET_ID =
"GET_HOST_BY_IPV6_SUBNET_ID";
/// @}
/// @brief Cassandra statements
@ -420,6 +430,8 @@ constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID_AND_ADDRESS;
constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_PREFIX;
constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID_AND_ADDRESS;
constexpr StatementTag CqlHostExchange::DELETE_HOST;
constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID;
constexpr StatementTag CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID;
StatementMap CqlHostExchange::tagged_statements_ = {
{INSERT_HOST,
@ -762,6 +774,78 @@ StatementMap CqlHostExchange::tagged_statements_ = {
{DELETE_HOST,
"DELETE FROM host_reservations WHERE id = ? "
"IF EXISTS "
}},
{GET_HOST_BY_IPV4_SUBNET_ID,
{GET_HOST_BY_IPV4_SUBNET_ID,
"SELECT "
"id, "
"host_identifier, "
"host_identifier_type, "
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
"host_ipv4_next_server, "
"host_ipv4_server_hostname, "
"host_ipv4_boot_file_name, "
"auth_key, "
"hostname, "
"user_context, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"reserved_ipv6_prefix_length, "
"reserved_ipv6_prefix_address_type, "
"iaid, "
"option_universe, "
"option_code, "
"option_value, "
"option_formatted_value, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
"option_subnet_id, "
"option_user_context, "
"option_scope_id "
"FROM host_reservations "
"WHERE host_ipv4_subnet_id = ? "
"ALLOW FILTERING "
}},
{GET_HOST_BY_IPV6_SUBNET_ID,
{GET_HOST_BY_IPV6_SUBNET_ID,
"SELECT "
"id, "
"host_identifier, "
"host_identifier_type, "
"host_ipv4_subnet_id, "
"host_ipv6_subnet_id, "
"host_ipv4_address, "
"host_ipv4_next_server, "
"host_ipv4_server_hostname, "
"host_ipv4_boot_file_name, "
"auth_key, "
"hostname, "
"user_context, "
"host_ipv4_client_classes, "
"host_ipv6_client_classes, "
"reserved_ipv6_prefix_address, "
"reserved_ipv6_prefix_length, "
"reserved_ipv6_prefix_address_type, "
"iaid, "
"option_universe, "
"option_code, "
"option_value, "
"option_formatted_value, "
"option_space, "
"option_is_persistent, "
"option_client_class, "
"option_subnet_id, "
"option_user_context, "
"option_scope_id "
"FROM host_reservations "
"WHERE host_ipv6_subnet_id = ? "
"ALLOW FILTERING "
}}
};
@ -905,7 +989,7 @@ CqlHostExchange::prepareExchange(const HostPtr& host,
// auth_key: varchar
auth_key_ = host->getKey().ToText();
// hostname: text
hostname_ = host->getHostname();
if (hostname_.size() > HOSTNAME_MAX_LENGTH) {
@ -1428,6 +1512,20 @@ public:
const uint8_t* identifier_begin,
const size_t identifier_len) const;
/// @brief Implementation of @ref CqlHostDataSource::getAll4()
///
/// See @ref CqlHostDataSource::getAll4() for parameter details.
///
/// @param subnet_id identifier of the subnet to which hosts belong
virtual ConstHostCollection getAll4(const SubnetID& subnet_id) const;
/// @brief Implementation of @ref CqlHostDataSource::getAll6()
///
/// See @ref CqlHostDataSource::getAll6() for parameter details.
///
/// @param subnet_id identifier of the subnet to which hosts belong
virtual ConstHostCollection getAll6(const SubnetID& subnet_id) const;
/// @brief Implementation of @ref CqlHostDataSource::getAll4()
///
/// See @ref CqlHostDataSource::getAll4() for parameter details.
@ -1813,6 +1911,40 @@ CqlHostDataSourceImpl::getAll(const Host::IdentifierType& identifier_type,
return (result);
}
ConstHostCollection
CqlHostDataSourceImpl::getAll4(const SubnetID& subnet_id) const {
// Convert to CQL data types.
cass_int32_t host_ipv4_subnet_id = static_cast<cass_int32_t>(subnet_id);
// Bind to array.
AnyArray where_values;
where_values.add(&host_ipv4_subnet_id);
// Run statement.
ConstHostCollection result =
getHostCollection(CqlHostExchange::GET_HOST_BY_IPV4_SUBNET_ID,
where_values);
return (result);
}
ConstHostCollection
CqlHostDataSourceImpl::getAll6(const SubnetID& subnet_id) const {
// Convert to CQL data types.
cass_int32_t host_ipv6_subnet_id = static_cast<cass_int32_t>(subnet_id);
// Bind to array.
AnyArray where_values;
where_values.add(&host_ipv6_subnet_id);
// Run statement.
ConstHostCollection result =
getHostCollection(CqlHostExchange::GET_HOST_BY_IPV6_SUBNET_ID,
where_values);
return (result);
}
ConstHostCollection
CqlHostDataSourceImpl::getAll4(const asiolink::IOAddress& address) const {
// Convert to CQL data types.
@ -2099,6 +2231,20 @@ CqlHostDataSource::getAll(const Host::IdentifierType& identifier_type,
return (impl_->getAll(identifier_type, identifier_begin, identifier_len));
}
ConstHostCollection
CqlHostDataSource::getAll4(const SubnetID& subnet_id) const {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
return (impl_->getAll4(subnet_id));
}
ConstHostCollection
CqlHostDataSource::getAll6(const SubnetID& subnet_id) const {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);
return (impl_->getAll6(subnet_id));
}
ConstHostCollection
CqlHostDataSource::getAll4(const asiolink::IOAddress& address) const {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_HOST_GET_ALL);

View File

@ -1,4 +1,4 @@
// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@ -129,7 +129,7 @@ public:
bind_(columns_num_), columns_(columns_num_),
error_(columns_num_, MLM_FALSE), host_id_(0),
dhcp_identifier_length_(0), dhcp_identifier_type_(0),
dhcp4_subnet_id_(SUBNET_ID_UNUSED),
dhcp4_subnet_id_(SUBNET_ID_UNUSED),
dhcp6_subnet_id_(SUBNET_ID_UNUSED), ipv4_address_(0),
hostname_length_(0), dhcp4_client_classes_length_(0),
dhcp6_client_classes_length_(0),
@ -407,7 +407,7 @@ public:
auth_key_null_ = auth_key.empty() ? MLM_TRUE : MLM_FALSE;
bind_[13].buffer = auth_key_;
bind_[13].buffer_length = auth_key.length();
} catch (const std::exception& ex) {
isc_throw(DbOperationError,
"Could not create bind array from Host: "
@ -542,7 +542,7 @@ public:
bind_[13].buffer_length = auth_key_length_;
bind_[13].length = &auth_key_length_;
bind_[13].is_null = &auth_key_null_;
// Add the error flags
setErrorIndicators(bind_, error_);
@ -800,7 +800,7 @@ private:
/// The length of the string for holding keys
unsigned long auth_key_length_;
/// @name Boolean values indicating if values of specific columns in
/// the database are NULL.
//@{
@ -1951,6 +1951,8 @@ public:
DEL_HOST_ADDR4, // Delete v4 host (subnet-id, addr4)
DEL_HOST_SUBID4_ID, // Delete v4 host (subnet-id, ident.type, identifier)
DEL_HOST_SUBID6_ID, // Delete v6 host (subnet-id, ident.type, identifier)
GET_HOST_SUBID4, // Gets host by IPv4 SubnetID
GET_HOST_SUBID6, // Gets host by IPv6 SubnetID
NUM_STATEMENTS // Number of statements
};
@ -2330,7 +2332,41 @@ TaggedStatementArray tagged_statements = { {
{MySqlHostDataSourceImpl::DEL_HOST_SUBID6_ID,
"DELETE FROM hosts WHERE dhcp6_subnet_id = ? AND dhcp_identifier_type=? "
"AND dhcp_identifier = ?"}
"AND dhcp_identifier = ?"},
{MySqlHostDataSourceImpl::GET_HOST_SUBID4,
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
"h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
"h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
"h.dhcp4_next_server, h.dhcp4_server_hostname, "
"h.dhcp4_boot_file_name, h.auth_key, "
"o.option_id, o.code, o.value, o.formatted_value, o.space, "
"o.persistent, o.user_context "
"FROM hosts AS h "
"LEFT JOIN dhcp4_options AS o "
"ON h.host_id = o.host_id "
"WHERE h.dhcp4_subnet_id = ? "
"ORDER BY h.host_id, o.option_id"},
{MySqlHostDataSourceImpl::GET_HOST_SUBID6,
"SELECT h.host_id, h.dhcp_identifier, "
"h.dhcp_identifier_type, h.dhcp4_subnet_id, "
"h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
"h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
"h.dhcp4_next_server, h.dhcp4_server_hostname, "
"h.dhcp4_boot_file_name, h.auth_key, "
"o.option_id, o.code, o.value, o.formatted_value, o.space, "
"o.persistent, o.user_context, "
"r.reservation_id, r.address, r.prefix_len, r.type, "
"r.dhcp6_iaid "
"FROM hosts AS h "
"LEFT JOIN dhcp6_options AS o "
"ON h.host_id = o.host_id "
"LEFT JOIN ipv6_reservations AS r "
"ON h.host_id = r.host_id "
"WHERE h.dhcp6_subnet_id = ? "
"ORDER BY h.host_id, o.option_id, r.reservation_id"}
}
};
@ -2870,6 +2906,40 @@ MySqlHostDataSource::getAll(const Host::IdentifierType& identifier_type,
return (result);
}
ConstHostCollection
MySqlHostDataSource::getAll4(const SubnetID& subnet_id) const {
// Set up the WHERE clause value
MYSQL_BIND inbind[1];
memset(inbind, 0, sizeof(inbind));
uint32_t subnet = subnet_id;
inbind[0].buffer_type = MYSQL_TYPE_LONG;
inbind[0].buffer = reinterpret_cast<char*>(&subnet);
inbind[0].is_unsigned = MLM_TRUE;
ConstHostCollection result;
impl_->getHostCollection(MySqlHostDataSourceImpl::GET_HOST_SUBID4,
inbind, impl_->host_exchange_,
result, false);
return (result);
}
ConstHostCollection
MySqlHostDataSource::getAll6(const SubnetID& subnet_id) const {
// Set up the WHERE clause value
MYSQL_BIND inbind[1];
memset(inbind, 0, sizeof(inbind));
uint32_t subnet = subnet_id;
inbind[0].buffer_type = MYSQL_TYPE_LONG;
inbind[0].buffer = reinterpret_cast<char*>(&subnet);
inbind[0].is_unsigned = MLM_TRUE;
ConstHostCollection result;
impl_->getHostCollection(MySqlHostDataSourceImpl::GET_HOST_SUBID6,
inbind, impl_->host_ipv6_exchange_,
result, false);
return (result);
}
ConstHostCollection
MySqlHostDataSource::getAll4(const asiolink::IOAddress& address) const {

View File

@ -140,7 +140,7 @@ public:
///
/// @return Collection of const @ref Host objects.
virtual ConstHostCollection
getAll4(const SubnetID& subnet_id) const override;
getAll4(const SubnetID& subnet_id) const;
/// @brief Return all hosts in a DHCPv6 subnet.
///
@ -151,7 +151,7 @@ public:
///
/// @return Collection of const @ref Host objects.
virtual ConstHostCollection
getAll6(const SubnetID& subnet_id) const override;
getAll6(const SubnetID& subnet_id) const;
/// @brief Returns a collection of hosts using the specified IPv4 address.
///

View File

@ -1,4 +1,4 @@
// Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2016-2019 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@ -257,12 +257,12 @@ public:
// add auth keys
std::string key = host->getKey().ToText();
if (key.empty()) {
if (key.empty()) {
bind_array->addNull();
} else {
bind_array->add(key);
}
} catch (const std::exception& ex) {
host_.reset();
isc_throw(DbOperationError,
@ -1293,6 +1293,8 @@ public:
DEL_HOST_ADDR4, // Delete v4 host (subnet-id, addr4)
DEL_HOST_SUBID4_ID, // Delete v4 host (subnet-id, ident.type, identifier)
DEL_HOST_SUBID6_ID, // Delete v6 host (subnet-id, ident.type, identifier)
GET_HOST_SUBID4, // Gets host by IPv4 SubnetID
GET_HOST_SUBID6, // Gets host by IPv6 SubnetID
NUM_STATEMENTS // Number of statements
};
@ -1714,6 +1716,50 @@ TaggedStatementArray tagged_statements = { {
"DELETE FROM hosts WHERE dhcp6_subnet_id = $1 "
"AND dhcp_identifier_type = $2 "
"AND dhcp_identifier = $3"
},
// PgSqlHostDataSourceImpl::GET_HOST_SUBID4
// Retrieves host information along with the DHCPv4 options associated with
// it. Left joining the dhcp4_options table results in multiple rows being
// returned for the same host. The host is retrieved by subnet id.
{1,
{ OID_INT8 }, "get_host_subid4",
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
" h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
" h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
" h.dhcp4_next_server, h.dhcp4_server_hostname, "
" h.dhcp4_boot_file_name, h.auth_key, "
" o.option_id, o.code, o.value, o.formatted_value, o.space, "
" o.persistent, o.user_context "
"FROM hosts AS h "
"LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
"WHERE h.dhcp4_subnet_id = $1 "
"ORDER BY h.host_id, o.option_id"
},
// PgSqlHostDataSourceImpl::GET_HOST_SUBID6
// Retrieves host information, IPv6 reservations and DHCPv6 options
// associated with a host using IPv6 subnet id. This query returns
// host information for a single host. However, multiple rows are
// returned due to left joining IPv6 reservations and DHCPv6 options.
// The number of rows returned is multiplication of number of existing
// IPv6 reservations and DHCPv6 options.
{1,
{ OID_INT8 }, "get_host_subid6",
"SELECT h.host_id, h.dhcp_identifier, "
" h.dhcp_identifier_type, h.dhcp4_subnet_id, "
" h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
" h.dhcp4_client_classes, h.dhcp6_client_classes, h.user_context, "
" h.dhcp4_next_server, h.dhcp4_server_hostname, "
" h.dhcp4_boot_file_name, h.auth_key, "
" o.option_id, o.code, o.value, o.formatted_value, o.space, "
" o.persistent, o.user_context, "
" r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid "
"FROM hosts AS h "
"LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
"LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
"WHERE h.dhcp6_subnet_id = $1 "
"ORDER BY h.host_id, o.option_id, r.reservation_id"
}
}
};
@ -2097,6 +2143,38 @@ PgSqlHostDataSource::getAll(const Host::IdentifierType& identifier_type,
return (result);
}
ConstHostCollection
PgSqlHostDataSource::getAll4(const SubnetID& subnet_id) const {
// Set up the WHERE clause value
PsqlBindArrayPtr bind_array(new PsqlBindArray());
// Add the subnet id.
bind_array->add(subnet_id);
ConstHostCollection result;
impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_SUBID4,
bind_array, impl_->host_exchange_,
result, false);
return (result);
}
ConstHostCollection
PgSqlHostDataSource::getAll6(const SubnetID& subnet_id) const {
// Set up the WHERE clause value
PsqlBindArrayPtr bind_array(new PsqlBindArray());
// Add the subnet id.
bind_array->add(subnet_id);
ConstHostCollection result;
impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_SUBID6,
bind_array, impl_->host_ipv6_exchange_,
result, false);
return (result);
}
ConstHostCollection
PgSqlHostDataSource::getAll4(const asiolink::IOAddress& address) const {

View File

@ -167,7 +167,7 @@ public:
///
/// @return Collection of const @ref Host objects.
virtual ConstHostCollection
getAll4(const SubnetID& subnet_id) const override;
getAll4(const SubnetID& subnet_id) const;
/// @brief Return all hosts in a DHCPv6 subnet.
///
@ -178,7 +178,7 @@ public:
///
/// @return Collection of const @ref Host objects.
virtual ConstHostCollection
getAll6(const SubnetID& subnet_id) const override;
getAll6(const SubnetID& subnet_id) const;
/// @brief Returns a collection of hosts using the specified IPv4 address.
///

View File

@ -206,6 +206,64 @@ TEST_F(CfgHostsTest, getAllRepeatingHosts) {
}
}
// This test checks that hosts in the same subnet can be retrieved from
// the host configuration.
TEST_F(CfgHostsTest, getAll4BySubnet) {
CfgHosts cfg;
// Add 25 hosts identified by HW address in the same subnet.
for (unsigned i = 0; i < 25; ++i) {
cfg.add(HostPtr(new Host(hwaddrs_[i]->toText(false),
"hw-address",
SubnetID(1), SubnetID(1),
addressesa_[i])));
}
// Check that other subnets are empty.
HostCollection hosts = cfg.getAll4(SubnetID(100));
EXPECT_EQ(0, hosts.size());
// Try to retrieve all added reservations.
hosts = cfg.getAll4(SubnetID(1));
ASSERT_EQ(25, hosts.size());
for (unsigned i = 0; i < 25; ++i) {
EXPECT_EQ(1, hosts[i]->getIPv4SubnetID());
EXPECT_EQ(addressesa_[i].toText(),
hosts[i]->getIPv4Reservation().toText());
}
}
// This test checks that hosts in the same subnet can be retrieved from
// the host configuration.
TEST_F(CfgHostsTest, getAll6BySubnet) {
CfgHosts cfg;
// Add 25 hosts identified by DUID in the same subnet.
for (unsigned i = 0; i < 25; ++i) {
HostPtr host = HostPtr(new Host(duids_[i]->toText(), "duid",
SubnetID(1), SubnetID(1),
IOAddress("0.0.0.0")));
host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
increase(IOAddress("2001:db8:1::1"),
i)));
cfg.add(host);
}
// Check that other subnets are empty.
HostCollection hosts = cfg.getAll6(SubnetID(100));
EXPECT_EQ(0, hosts.size());
// Try to retrieve all added reservations.
hosts = cfg.getAll6(SubnetID(1));
ASSERT_EQ(25, hosts.size());
for (unsigned i = 0; i < 25; ++i) {
EXPECT_EQ(1, hosts[i]->getIPv6SubnetID());
IPv6ResrvRange reservations =
hosts[i]->getIPv6Reservations(IPv6Resrv::TYPE_NA);
ASSERT_EQ(1, std::distance(reservations.first, reservations.second));
EXPECT_EQ(increase(IOAddress("2001:db8:1::1"), i),
reservations.first->second.getPrefix());
}
}
// This test checks that all reservations for the specified IPv4 address can
// be retrieved.
TEST_F(CfgHostsTest, getAll4ByAddress) {

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017-2018 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2017-2019 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2016-2017 Deutsche Telekom AG.
//
// Author: Andrei Pavel <andrei.pavel@qualitance.com>
@ -293,6 +293,16 @@ TEST_F(CqlHostDataSourceTest, DISABLED_testReadOnlyDatabase) {
testReadOnlyDatabase(CQL_VALID_TYPE);
}
// Verifies that IPv4 host reservations in the same subnet can be retrieved
TEST_F(CqlHostDataSourceTest, getAll4BySubnet) {
testGetAll4(Host::IDENT_HWADDR);
}
// Verifies that IPv6 host reservations in the same subnet can be retrieved
TEST_F(CqlHostDataSourceTest, getAll6BySubnet) {
testGetAll6(Host::IDENT_DUID);
}
// Test verifies if a host reservation can be added and later retrieved by IPv4
// address. Host uses hw address as identifier.
TEST_F(CqlHostDataSourceTest, basic4HWAddr) {

View File

@ -1,4 +1,4 @@
// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@ -311,6 +311,16 @@ TEST_F(MySqlHostDataSourceTest, maxSubnetId6) {
testMaxSubnetId6();
}
// Verifies that IPv4 host reservations in the same subnet can be retrieved
TEST_F(MySqlHostDataSourceTest, getAll4BySubnet) {
testGetAll4(Host::IDENT_HWADDR);
}
// Verifies that IPv6 host reservations in the same subnet can be retrieved
TEST_F(MySqlHostDataSourceTest, getAll6BySubnet) {
testGetAll6(Host::IDENT_DUID);
}
// Test verifies if a host reservation can be added and later retrieved by IPv4
// address. Host uses client-id (DUID) as identifier.
TEST_F(MySqlHostDataSourceTest, basic4ClientId) {

View File

@ -1,4 +1,4 @@
// Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2016-2019 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@ -296,6 +296,16 @@ TEST_F(PgSqlHostDataSourceTest, maxSubnetId6) {
testMaxSubnetId6();
}
// Verifies that IPv4 host reservations in the same subnet can be retrieved
TEST_F(PgSqlHostDataSourceTest, getAll4BySubnet) {
testGetAll4(Host::IDENT_HWADDR);
}
// Verifies that IPv6 host reservations in the same subnet can be retrieved
TEST_F(PgSqlHostDataSourceTest, getAll6BySubnet) {
testGetAll6(Host::IDENT_DUID);
}
// Test verifies if a host reservation can be added and later retrieved by IPv4
// address. Host uses client-id (DUID) as identifier.
TEST_F(PgSqlHostDataSourceTest, basic4ClientId) {

View File

@ -356,6 +356,92 @@ void GenericHostDataSourceTest::testMaxSubnetId6() {
EXPECT_FALSE(host_by_id);
}
void
GenericHostDataSourceTest::testGetAll4(const Host::IdentifierType& id) {
// Make sure we have a pointer to the host data source.
ASSERT_TRUE(hdsptr_);
// Let's create a couple of hosts...
HostPtr host1 = HostDataSourceUtils::initializeHost4("192.0.2.1", id);
HostPtr host2 = HostDataSourceUtils::initializeHost4("192.0.2.2", id);
HostPtr host3 = HostDataSourceUtils::initializeHost4("192.0.2.3", id);
HostPtr host4 = HostDataSourceUtils::initializeHost4("192.0.2.4", id);
// Set them in the same subnets.
SubnetID subnet4 = host1->getIPv4SubnetID();
host2->setIPv4SubnetID(subnet4);
host3->setIPv4SubnetID(subnet4);
host4->setIPv4SubnetID(subnet4);
SubnetID subnet6 = host1->getIPv6SubnetID();
host2->setIPv6SubnetID(subnet6);
host3->setIPv6SubnetID(subnet6);
host4->setIPv6SubnetID(subnet6);
// ... and add them to the data source.
ASSERT_NO_THROW(hdsptr_->add(host1));
ASSERT_NO_THROW(hdsptr_->add(host2));
ASSERT_NO_THROW(hdsptr_->add(host3));
ASSERT_NO_THROW(hdsptr_->add(host4));
// And then try to retrieve them back.
ConstHostCollection from_hds = hdsptr_->getAll4(subnet4);
// Make sure we got something back.
ASSERT_EQ(4, from_hds.size());
// Then let's check that what we got seems correct.
// There is no ORDER BY in Cassandra so skip it.
if (hdsptr_->getType() != "cql") {
HostDataSourceUtils::compareHosts(host1, from_hds[0]);
HostDataSourceUtils::compareHosts(host2, from_hds[1]);
HostDataSourceUtils::compareHosts(host3, from_hds[2]);
HostDataSourceUtils::compareHosts(host4, from_hds[3]);
}
}
void
GenericHostDataSourceTest::testGetAll6(const Host::IdentifierType& id) {
// Make sure we have a pointer to the host data source.
ASSERT_TRUE(hdsptr_);
// Let's create a couple of hosts...
HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8::1", id, false);
HostPtr host2 = HostDataSourceUtils::initializeHost6("2001:db8::2", id, false);
HostPtr host3 = HostDataSourceUtils::initializeHost6("2001:db8::3", id, false);
HostPtr host4 = HostDataSourceUtils::initializeHost6("2001:db8::4", id, false);
// Set them in the same subnets.
SubnetID subnet4 = host1->getIPv4SubnetID();
host2->setIPv4SubnetID(subnet4);
host3->setIPv4SubnetID(subnet4);
host4->setIPv4SubnetID(subnet4);
SubnetID subnet6 = host1->getIPv6SubnetID();
host2->setIPv6SubnetID(subnet6);
host3->setIPv6SubnetID(subnet6);
host4->setIPv6SubnetID(subnet6);
// ... and add them to the data source.
ASSERT_NO_THROW(hdsptr_->add(host1));
ASSERT_NO_THROW(hdsptr_->add(host2));
ASSERT_NO_THROW(hdsptr_->add(host3));
ASSERT_NO_THROW(hdsptr_->add(host4));
// And then try to retrieve them back.
ConstHostCollection from_hds = hdsptr_->getAll6(subnet6);
// Make sure we got something back.
ASSERT_EQ(4, from_hds.size());
// Then let's check that what we got seems correct.
// There is no ORDER BY in Cassandra so skip it.
if (hdsptr_->getType() != "cql") {
HostDataSourceUtils::compareHosts(host1, from_hds[0]);
HostDataSourceUtils::compareHosts(host2, from_hds[1]);
HostDataSourceUtils::compareHosts(host3, from_hds[2]);
HostDataSourceUtils::compareHosts(host4, from_hds[3]);
}
}
void
GenericHostDataSourceTest::testGetByIPv4(const Host::IdentifierType& id) {
// Make sure we have a pointer to the host data source.
@ -1024,8 +1110,8 @@ void GenericHostDataSourceTest::testOptionsReservations4(const bool formatted,
// getAll4(subnet_id)
ConstHostCollection hosts_by_subnet = hdsptr_->getAll4(subnet_id);
// Not yet implemented.
EXPECT_EQ(0, hosts_by_subnet.size());
ASSERT_EQ(1, hosts_by_subnet.size());
ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, *hosts_by_subnet.begin()));
// getAll4(address)
ConstHostCollection hosts_by_addr =
@ -1079,8 +1165,8 @@ GenericHostDataSourceTest::testOptionsReservations46(const bool formatted) {
// getAll6(subnet_id)
ConstHostCollection hosts_by_subnet = hdsptr_->getAll6(subnet_id);
// Not yet implemented.
EXPECT_EQ(0, hosts_by_subnet.size());
EXPECT_EQ(1, hosts_by_subnet.size());
// Don't compare as getAll6() returns the v6 part only.
// getAll(identifier_type, identifier, identifier_size)
ConstHostCollection hosts_by_id =

View File

@ -1,4 +1,4 @@
// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2019 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@ -178,6 +178,20 @@ public:
/// Uses gtest macros to report failures.
void testMaxSubnetId6();
/// @brief Test that Verifies that IPv4 host reservations in the
/// same subnet can be retrieved properly.
///
/// Uses gtest macros to report failures.
/// @param id Identifier type.
void testGetAll4(const Host::IdentifierType& id);
/// @brief Test that Verifies that IPv6 host reservations in the
/// same subnet can be retrieved properly.
///
/// Uses gtest macros to report failures.
/// @param id Identifier type.
void testGetAll6(const Host::IdentifierType& id);
/// @brief Test inserts several hosts with unique IPv4 address and
/// checks that they can be retrieved properly.
///

View File

@ -23,13 +23,27 @@ MemHostDataSource::getAll(const Host::IdentifierType& /*identifier_type*/,
}
ConstHostCollection
MemHostDataSource::getAll4(const SubnetID& /*subnet_id*/) const {
return (ConstHostCollection());
MemHostDataSource::getAll4(const SubnetID& subnet_id) const {
ConstHostCollection hosts;
for (auto h = store_.begin(); h != store_.end(); ++h) {
// Keep it when subnet_id matchs.
if ((*h)->getIPv4SubnetID() == subnet_id) {
hosts.push_back(*h);
}
}
return (hosts);
}
ConstHostCollection
MemHostDataSource::getAll6(const SubnetID& /*subnet_id*/) const {
return (ConstHostCollection());
MemHostDataSource::getAll6(const SubnetID& subnet_id) const {
ConstHostCollection hosts;
for (auto h = store_.begin(); h != store_.end(); ++h) {
// Keep it when subnet_id matchs.
if ((*h)->getIPv6SubnetID() == subnet_id) {
hosts.push_back(*h);
}
}
return (hosts);
}
ConstHostCollection
@ -129,6 +143,7 @@ MemHostDataSource::get6(const SubnetID& subnet_id,
void
MemHostDataSource::add(const HostPtr& host) {
host->setHostId(++next_host_id_);
store_.push_back(host);
}

View File

@ -48,16 +48,12 @@ public:
/// @brief Return all hosts in a DHCPv4 subnet.
///
/// Currently not implemented.
///
/// @param subnet_id Subnet identifier.
virtual ConstHostCollection
getAll4(const SubnetID& subnet_id) const;
/// @brief Return all hosts in a DHCPv6 subnet.
///
/// Currently not implemented.
///
/// @param subnet_id Subnet identifier.
virtual ConstHostCollection
getAll6(const SubnetID& subnet_id) const;
@ -211,6 +207,9 @@ protected:
/// @brief Store
std::vector<HostPtr> store_;
/// @brief Next host id
uint64_t next_host_id_;
};
/// Pointer to the Mem host data source.