mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 14:05:33 +00:00
[master] Merge branch 'github37' (Cassandra host reservations)
# Conflicts: # src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc
This commit is contained in:
@@ -1313,6 +1313,7 @@ AC_CONFIG_FILES([Makefile
|
||||
src/share/database/Makefile
|
||||
src/share/database/scripts/Makefile
|
||||
src/share/database/scripts/cql/Makefile
|
||||
src/share/database/scripts/cql/upgrade_1.0_to_2.0.sh
|
||||
src/share/database/scripts/mysql/Makefile
|
||||
src/share/database/scripts/mysql/upgrade_1.0_to_2.0.sh
|
||||
src/share/database/scripts/mysql/upgrade_2.0_to_3.0.sh
|
||||
|
@@ -160,19 +160,19 @@
|
||||
<para>
|
||||
<table frame="all" id="backends">
|
||||
<title>List of available backends</title>
|
||||
<tgroup cols='2'>
|
||||
<tgroup cols='5'>
|
||||
<colspec colname='feature'/>
|
||||
<colspec colname='memfile'/>
|
||||
<colspec colname='mysql'/>
|
||||
<colspec colname='pgsql'/>
|
||||
<colspec colname='cql'/>
|
||||
<colspec colname='cql' colwidth='1.5*'/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Feature</entry>
|
||||
<entry>Memfile</entry>
|
||||
<entry>MySQL</entry>
|
||||
<entry>PostgreSQL</entry>
|
||||
<entry>CQL(Cassandra)</entry>
|
||||
<entry>CQL (Cassandra)</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -206,7 +206,7 @@
|
||||
<entry>no</entry>
|
||||
<entry>yes</entry>
|
||||
<entry>yes</entry>
|
||||
<entry>no</entry>
|
||||
<entry>yes</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
@@ -214,7 +214,7 @@
|
||||
<entry>no</entry>
|
||||
<entry>yes</entry>
|
||||
<entry>yes</entry>
|
||||
<entry>no</entry>
|
||||
<entry>yes</entry>
|
||||
</row>
|
||||
|
||||
</tbody>
|
||||
@@ -409,6 +409,8 @@ $ <userinput>kea-admin lease-upgrade mysql -u <replaceable>database-user</replac
|
||||
<title>PostgreSQL</title>
|
||||
|
||||
<para>
|
||||
PostgreSQL is able to store leases, host reservations and options
|
||||
defined on a per host basis.
|
||||
A PostgreSQL database must be set up if you want Kea to store
|
||||
lease and other information in PostgreSQL. This step can be
|
||||
safely ignored if you are using other database backends.
|
||||
@@ -590,10 +592,9 @@ $ <userinput>kea-admin lease-upgrade pgsql -u <replaceable>database-user</replac
|
||||
<para>
|
||||
Cassandra, or Cassandra Query Language (CQL), is the newest backend
|
||||
added to Kea. Since it was added recently and has not undergone as much
|
||||
testing as other backends, it is considered experimental: please use
|
||||
with caution. The CQL backend is currently able to store leases only. The
|
||||
ability to store host reservations will likely be added some time in the
|
||||
future.
|
||||
testing as other backends, it is considered experimental. Please use
|
||||
with caution. The Cassandra backend is able to store leases,
|
||||
host reservations and options defined on a per host basis.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@@ -517,8 +517,7 @@ If a timeout is given though, it should be an integer greater than zero.
|
||||
purpose, be it lease or hosts information. This arrangement gives the most
|
||||
flexibility. Kea can be used to keep leases and host reservations
|
||||
separately, but can also point to the same database. Currently the
|
||||
supported hosts database types are MySQL and PostgreSQL. The Cassandra
|
||||
backend does not support host reservations yet.</para>
|
||||
supported hosts database types are MySQL, PostgreSQL and Cassandra.</para>
|
||||
|
||||
<para>Please note that usage of hosts storage is optional. A user can define
|
||||
all host reservations in the configuration file. That is the recommended way
|
||||
@@ -3387,13 +3386,13 @@ It is merely echoed by the server
|
||||
with classification using expressions.</para>
|
||||
</section>
|
||||
|
||||
<section id="reservations4-mysql-pgsql">
|
||||
<title>Storing Host Reservations in MySQL or PostgreSQL</title>
|
||||
<section id="reservations4-mysql-pgsql-cql">
|
||||
<title>Storing Host Reservations in MySQL, PostgreSQL or Cassandra</title>
|
||||
|
||||
<para>
|
||||
It is possible to store host reservations in MySQL or PostgreSQL. See <xref
|
||||
linkend="hosts6-storage" /> for information on how to configure Kea to use
|
||||
reservations stored in MySQL or PostgreSQL. Kea provides dedicated hook for
|
||||
It is possible to store host reservations in MySQL, PostgreSQL or Cassandra. See
|
||||
<xref linkend="hosts6-storage" /> for information on how to configure Kea to use
|
||||
reservations stored in MySQL, PostgreSQL or Cassandra. Kea provides dedicated hook for
|
||||
managing reservations in a database, section <xref linkend="host-cmds" /> provide
|
||||
detailed information.
|
||||
</para>
|
||||
@@ -3402,12 +3401,6 @@ It is merely echoed by the server
|
||||
arbitrarily set to 4096 bytes.</simpara></note>
|
||||
</section>
|
||||
|
||||
<section id="reservations4-cql">
|
||||
<title>Storing host reservations in CQL (Cassandra)</title>
|
||||
<para>Kea currently does not support storing reservations in
|
||||
Cassandra (CQL).</para>
|
||||
</section>
|
||||
|
||||
<section id="reservations4-tuning">
|
||||
<title>Fine Tuning DHCPv4 Host Reservation</title>
|
||||
|
||||
|
@@ -2905,13 +2905,13 @@ should include options from the isc option space:
|
||||
with classification using expressions.</para>
|
||||
</section>
|
||||
|
||||
<section id="reservations6-mysql-pgsql">
|
||||
<title>Storing Host Reservations in MySQL or PostgreSQL</title>
|
||||
<section id="reservations6-mysql-pgsql-cql">
|
||||
<title>Storing Host Reservations in MySQL, PostgreSQL or Cassandra</title>
|
||||
|
||||
<para>
|
||||
It is possible to store host reservations in MySQL or PostgreSQL. See <xref
|
||||
linkend="hosts6-storage" /> for information on how to configure Kea to use
|
||||
reservations stored in MySQL or PostgreSQL. Kea provides dedicated hook for
|
||||
It is possible to store host reservations in MySQL, PostgreSQL or Cassandra. See
|
||||
<xref linkend="hosts6-storage" /> for information on how to configure Kea to use
|
||||
reservations stored in MySQL, PostgreSQL or Cassandra. Kea provides dedicated hook for
|
||||
managing reservations in a database, section <xref linkend="host-cmds" /> provide
|
||||
detailed information.
|
||||
</para>
|
||||
@@ -2920,12 +2920,6 @@ should include options from the isc option space:
|
||||
arbitrarily set to 4096 bytes.</simpara></note>
|
||||
</section>
|
||||
|
||||
<section id="reservations6-cql">
|
||||
<title>Storing Host Reservations in CQL (Cassandra)</title>
|
||||
<para>Kea currently does not support storing reservations in
|
||||
Cassandra (CQL).</para>
|
||||
</section>
|
||||
|
||||
<section id="reservations6-tuning">
|
||||
<title>Fine Tuning DHCPv6 Host Reservation</title>
|
||||
|
||||
|
@@ -82,7 +82,7 @@ cql_lease_version_test() {
|
||||
|
||||
# Verify that kea-admin lease-version returns the correct version.
|
||||
version=$($keaadmin lease-version cql -u $db_user -p $db_password -n $db_name)
|
||||
assert_str_eq "1.0" $version "Expected kea-admin to return %s, returned value was %s"
|
||||
assert_str_eq "2.0" $version "Expected kea-admin to return %s, returned value was %s"
|
||||
|
||||
# Wipe the database.
|
||||
cql_execute_script $db_scripts_dir/cql/dhcpdb_drop.cql
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2010-2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2010-2018 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
|
||||
@@ -23,11 +23,20 @@
|
||||
namespace isc {
|
||||
namespace asiolink {
|
||||
|
||||
/// Defines length of IPv6 address.
|
||||
const static size_t V6ADDRESS_LEN = 16;
|
||||
/// Defines length of IPv6 address (in binary format).
|
||||
static constexpr size_t V6ADDRESS_LEN = 16;
|
||||
|
||||
/// Defines length of IPv4 address.
|
||||
const static size_t V4ADDRESS_LEN = 4;
|
||||
/// Defines length of IPv4 address (in binary format).
|
||||
static constexpr size_t V4ADDRESS_LEN = 4;
|
||||
|
||||
/// @brief Maximum size of an IPv4 address represented as a text string. 12
|
||||
/// digits plus 3 full stops (dots).
|
||||
static constexpr size_t V4ADDRESS_TEXT_MAX_LEN = 15u;
|
||||
|
||||
/// @brief Maximum size of an IPv6 address represented as a text string. 32
|
||||
/// hexadecimal characters written in 8 groups of four, plus 7 colon
|
||||
/// separators.
|
||||
static constexpr size_t V6ADDRESS_TEXT_MAX_LEN = 39u;
|
||||
|
||||
/// \brief The \c IOAddress class represents an IP addresses (version
|
||||
/// agnostic)
|
||||
|
@@ -153,6 +153,7 @@ endif
|
||||
if HAVE_CQL
|
||||
libkea_dhcpsrv_la_SOURCES += cql_connection.cc cql_connection.h
|
||||
libkea_dhcpsrv_la_SOURCES += cql_exchange.cc cql_exchange.h
|
||||
libkea_dhcpsrv_la_SOURCES += cql_host_data_source.cc cql_host_data_source.h
|
||||
libkea_dhcpsrv_la_SOURCES += cql_lease_mgr.cc cql_lease_mgr.h
|
||||
endif
|
||||
|
||||
|
@@ -48,9 +48,9 @@ constexpr uint32_t CQL_DRIVER_VERSION_MAJOR = CASS_VERSION_MAJOR;
|
||||
constexpr uint32_t CQL_DRIVER_VERSION_MINOR = CASS_VERSION_MINOR;
|
||||
/// @}
|
||||
|
||||
/// Define CQL schema version: 1.0
|
||||
/// Define CQL schema version: 2.0
|
||||
/// @{
|
||||
constexpr uint32_t CQL_SCHEMA_VERSION_MAJOR = 1u;
|
||||
constexpr uint32_t CQL_SCHEMA_VERSION_MAJOR = 2u;
|
||||
constexpr uint32_t CQL_SCHEMA_VERSION_MINOR = 0u;
|
||||
/// @}
|
||||
|
||||
@@ -142,11 +142,13 @@ public:
|
||||
///
|
||||
/// Opens the database using the information supplied in the parameters
|
||||
/// passed to the constructor. If no parameters are supplied, the default
|
||||
/// values will be used. The defaults are:
|
||||
/// - contact points: 127.0.0.1
|
||||
/// - port 9042
|
||||
/// - no user, no password
|
||||
/// - keyspace keatest
|
||||
/// values will be used. The parameters supported as as follows (default
|
||||
/// values specified in parentheses):
|
||||
/// - keyspace: name of the database to which to connect (keatest)
|
||||
/// - contact-points: IP addresses of the nodes to connect to (127.0.0.1)
|
||||
/// - port: The TCP port to use (9042)
|
||||
/// - user - credentials to use when connecting (no username)
|
||||
/// - password - credentails to use when connecting (no password)
|
||||
/// - reconnect-wait-time 2000
|
||||
/// - connect-timeout 5000
|
||||
/// - request-timeout 12000
|
||||
|
1964
src/lib/dhcpsrv/cql_host_data_source.cc
Normal file
1964
src/lib/dhcpsrv/cql_host_data_source.cc
Normal file
File diff suppressed because it is too large
Load Diff
358
src/lib/dhcpsrv/cql_host_data_source.h
Normal file
358
src/lib/dhcpsrv/cql_host_data_source.h
Normal file
@@ -0,0 +1,358 @@
|
||||
// Copyright (C) 2016-2017 Deutsche Telekom AG.
|
||||
//
|
||||
// Author: Andrei Pavel <andrei.pavel@qualitance.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CQL_HOST_DATA_SOURCE_H
|
||||
#define CQL_HOST_DATA_SOURCE_H
|
||||
|
||||
#include <dhcpsrv/base_host_data_source.h>
|
||||
#include <dhcpsrv/cql_connection.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
/// @brief Forward declaration to the implementation of @ref CqlHostDataSource.
|
||||
class CqlHostDataSourceImpl;
|
||||
|
||||
/// @brief Cassandra host data source
|
||||
///
|
||||
/// Implements @ref isc::dhcp::BaseHostDataSource interface customized to
|
||||
/// Cassandra. Use of this backend implies that a Cassandra database is
|
||||
/// available and that the Kea schema has been created within it.
|
||||
///
|
||||
/// The database schema is radically different than the MySQL and the
|
||||
/// PostgreSQL schemas. Rather than creating a different table for
|
||||
/// hosts, reservations, DHCPv4 options and DHCPv6 options
|
||||
/// respectively, the data is denormalized into a single table to
|
||||
/// benefit from Cassandra's non-relational nature. To make up for the
|
||||
/// lack of relations, on insertion, the reservations and options are
|
||||
/// matched against hosts on the server and merged into database
|
||||
/// entries. When retrieving, each database row is split into the
|
||||
/// corresponding host, reservation and options.
|
||||
///
|
||||
/// There can be an inconsistency in the database due to the order of
|
||||
/// the changes e.g. if you insert a host with no reservations and no
|
||||
/// options followed by the same host with one reservation will result
|
||||
/// in 2 entries versus inserting the host with reservation from the
|
||||
/// beginning which will result in a single entry. In spite of this,
|
||||
/// retrieving the host will give you the attached reservation in both
|
||||
/// cases.
|
||||
class CqlHostDataSource : public BaseHostDataSource {
|
||||
public:
|
||||
/// @brief Constructor
|
||||
///
|
||||
/// Uses the following keywords in the parameters passed to it to connect
|
||||
/// to the database:
|
||||
/// - keyspace
|
||||
/// - host
|
||||
/// - user
|
||||
/// - password
|
||||
/// - contact-points
|
||||
/// - reconnect-wait-time
|
||||
/// - connect-timeout
|
||||
/// - request-timeout
|
||||
/// - tcp-keepalive
|
||||
/// - tcp-nodelay
|
||||
///
|
||||
/// For details regarding those paraemters, see
|
||||
/// @ref isc::dhcp::CqlConnection::openDatabase.
|
||||
///
|
||||
/// Finally, all the CQL commands are pre-compiled.
|
||||
///
|
||||
/// @param parameters a data structure relating keywords and values
|
||||
/// concerned with the database.
|
||||
///
|
||||
/// @throw isc::dhcp::NoDatabaseName Mandatory database name not given
|
||||
/// @throw isc::dhcp::DbOpenError Error opening the database
|
||||
/// @throw isc::dhcp::DbOperationError An operation on the open database has
|
||||
/// failed.
|
||||
explicit CqlHostDataSource(const DatabaseConnection::ParameterMap& parameters);
|
||||
|
||||
/// @brief Virtual destructor.
|
||||
///
|
||||
/// Releases prepared CQL statements used by the backend.
|
||||
virtual ~CqlHostDataSource();
|
||||
|
||||
/// @brief Adds a new host to the collection.
|
||||
///
|
||||
/// The implementations of this method should guard against duplicate
|
||||
/// reservations for the same @ref Host, where possible. For example, when
|
||||
/// the reservation for the same @ref HWAddr and @ref SubnetID is added
|
||||
/// twice, @ref add() should throw a @ref DuplicateEntry exception. Note,
|
||||
/// that usually it is impossible to guard against adding duplicated @ref
|
||||
/// Host, where one instance is identified by different identifier types.
|
||||
///
|
||||
/// @param host pointer to the new @ref Host being added.
|
||||
virtual void add(const HostPtr& host) override;
|
||||
|
||||
/// @brief Retrieves a single @ref Host connected to an IPv4 subnet.
|
||||
///
|
||||
/// Implementations of this method should guard against the case when
|
||||
/// multiple instances of the @ref Host are present, e.g. when two @ref
|
||||
/// Host objects are found, one for the @ref DUID, another one for the @ref
|
||||
/// HWAddr. In such case, throw a @ref MultipleRecords exception.
|
||||
///
|
||||
/// @param subnet_id subnet identifier to filter by
|
||||
/// @param hwaddr hardware address of the client to filter by or NULL if not
|
||||
/// available
|
||||
/// @param duid client identifier to filter by or NULL if not available
|
||||
///
|
||||
/// @return @ref ConstHostPtr to a @ref Host object using a specified @ref
|
||||
/// HWAddr or @ref DUID
|
||||
///
|
||||
/// @throw BadValue if both or neither of subnet_id and duid are specified
|
||||
virtual ConstHostPtr get4(const SubnetID& subnet_id,
|
||||
const HWAddrPtr& hwaddr,
|
||||
const DuidPtr& duid = DuidPtr()) const override;
|
||||
|
||||
/// @brief Retrieves a @ref Host connected to an IPv4 subnet.
|
||||
///
|
||||
/// The host is identified by specific identifier.
|
||||
///
|
||||
/// @param subnet_id subnet identifier to filter by
|
||||
/// @param identifier_type identifier type to filter by
|
||||
/// @param identifier_begin pointer to the beginning of a buffer containing
|
||||
/// a host identifier to filter by
|
||||
/// @param identifier_len length of the host identifier buffer
|
||||
///
|
||||
/// @return @ref Host object for which a reservation has been made using the
|
||||
/// specified identifier
|
||||
virtual ConstHostPtr get4(const SubnetID& subnet_id,
|
||||
const Host::IdentifierType& identifier_type,
|
||||
const uint8_t* identifier_begin,
|
||||
const size_t identifier_len) const override;
|
||||
|
||||
/// @brief Retrieves a @ref Host connected to an IPv4 subnet.
|
||||
///
|
||||
/// The host is identifier by specified IPv4 address.
|
||||
///
|
||||
/// @param subnet_id Subnet identifier.
|
||||
/// @param address reserved IPv4 address.
|
||||
///
|
||||
/// @return Const @ref Host object
|
||||
///
|
||||
/// @throw BadValue if address in not a valid IPv4address
|
||||
virtual ConstHostPtr
|
||||
get4(const SubnetID& subnet_id,
|
||||
const asiolink::IOAddress& address) const override;
|
||||
|
||||
/// @brief Retrieves a @ref Host connected to an IPv6 subnet.
|
||||
///
|
||||
/// Implementations of this method should guard against the case when
|
||||
/// multiple instances of the @ref Host are present, e.g. when two
|
||||
/// @ref Host objects are found, one for the @ref DUID, another one for the
|
||||
/// @ref HWAddr. In such case, throw a @ref MultipleRecords exception.
|
||||
///
|
||||
/// @param subnet_id subnet identifier to filter by
|
||||
/// @param hwaddr hardware address of the client to filter by or NULL if not
|
||||
/// available
|
||||
/// @param duid client identifier to filter by or NULL if not available
|
||||
///
|
||||
/// @return @ref Host object using a specified @ref HWAddr or @ref DUID
|
||||
///
|
||||
/// @throw BadValue if both or neither of subnet_id and duid are specified
|
||||
virtual ConstHostPtr
|
||||
get6(const SubnetID& subnet_id,
|
||||
const DuidPtr& duid,
|
||||
const HWAddrPtr& hwaddr = HWAddrPtr()) const override;
|
||||
|
||||
/// @brief Returns a @ref Host connected to an IPv6 subnet.
|
||||
///
|
||||
/// @param subnet_id subnet identifier to filter by
|
||||
/// @param identifier_type identifier type to filter by
|
||||
/// @param identifier_begin pointer to the beginning of a buffer containing
|
||||
/// a host identifier to filter by
|
||||
/// @param identifier_len length of the host identifier buffer
|
||||
///
|
||||
/// @return Const @ref Host object for which reservation has been made using
|
||||
/// the specified identifier.
|
||||
virtual ConstHostPtr get6(const SubnetID& subnet_id,
|
||||
const Host::IdentifierType& identifier_type,
|
||||
const uint8_t* identifier_begin,
|
||||
const size_t identifier_len) const override;
|
||||
|
||||
/// @brief Returns a @ref Host with the specified reservation prefix.
|
||||
///
|
||||
/// @param prefix IPv6 prefix for which the @ref Host object is searched.
|
||||
/// @param prefix_len IPv6 prefix length.
|
||||
///
|
||||
/// @return Const @ref Host object using a specified HW address or DUID.
|
||||
///
|
||||
/// @throw MultipleRecords if two or more rows are returned from the
|
||||
/// Cassandra database
|
||||
virtual ConstHostPtr get6(const asiolink::IOAddress& prefix,
|
||||
const uint8_t prefix_len) const override;
|
||||
|
||||
/// @brief Returns a host connected to the IPv6 subnet and having
|
||||
/// a reservation for a specified IPv6 address or prefix.
|
||||
///
|
||||
/// @param subnet_id Subnet identifier.
|
||||
/// @param address reserved IPv6 address/prefix.
|
||||
///
|
||||
/// @return Const @c Host object using a specified IPv6 address/prefix.
|
||||
virtual ConstHostPtr
|
||||
get6(const SubnetID& subnet_id,
|
||||
const asiolink::IOAddress& address) const override;
|
||||
|
||||
/// @brief Return all @ref Host objects for the specified @ref HWAddr or
|
||||
/// @ref DUID.
|
||||
///
|
||||
/// Returns all @ref Host objects which represent reservations
|
||||
/// for the specified HW address or DUID. Note, that this method may
|
||||
/// return multiple reservations because a particular client may have
|
||||
/// reservations in multiple subnets and the same client may be identified
|
||||
/// by HW address or DUID. The server is unable to verify that the specific
|
||||
/// DUID and HW address belong to the same client, until the client sends
|
||||
/// a DHCP message.
|
||||
///
|
||||
/// Specifying both @ref HWAddr and @ref DUID is allowed for this method
|
||||
/// and results in returning all objects that are associated with hardware
|
||||
/// address OR duid. For example: if one @ref Host is associated with the
|
||||
/// specified @ref HWAddr and another @ref Host is associated with the
|
||||
/// specified @ref DUID, two hosts will be returned.
|
||||
///
|
||||
/// @param hwaddr HW address of the client or NULL if no HW address
|
||||
/// available.
|
||||
/// @param duid client id or NULL if not available, e.g. DHCPv4 client case.
|
||||
///
|
||||
/// @return collection of const @ref Host objects.
|
||||
virtual ConstHostCollection
|
||||
getAll(const HWAddrPtr& hwaddr,
|
||||
const DuidPtr& duid = DuidPtr()) const override;
|
||||
|
||||
/// @brief Return all hosts connected to any subnet for which reservations
|
||||
/// have been made using a specified identifier.
|
||||
///
|
||||
/// This method returns all @ref Host objects which represent reservations
|
||||
/// for a specified identifier. This method may return multiple hosts
|
||||
/// because a particular client may have reservations in multiple subnets.
|
||||
///
|
||||
/// @param identifier_type Identifier type.
|
||||
/// @param identifier_begin Pointer to a beginning of a buffer containing
|
||||
/// an identifier.
|
||||
/// @param identifier_len Identifier length.
|
||||
///
|
||||
/// @return Collection of const @ref Host objects.
|
||||
virtual ConstHostCollection
|
||||
getAll(const Host::IdentifierType& identifier_type,
|
||||
const uint8_t* identifier_begin,
|
||||
const size_t identifier_len) const override;
|
||||
|
||||
/// @brief Returns a collection of hosts using the specified IPv4 address.
|
||||
///
|
||||
/// This method may return multiple @ref Host objects if they are connected
|
||||
/// to different subnets.
|
||||
///
|
||||
/// @param address IPv4 address for which the @ref Host object is searched.
|
||||
///
|
||||
/// @return Collection of const @ref Host objects.
|
||||
virtual ConstHostCollection
|
||||
getAll4(const asiolink::IOAddress& address) const override;
|
||||
|
||||
/// @brief Attempts to delete a host by (subnet-id, address)
|
||||
///
|
||||
/// This method supports both v4 and v6.
|
||||
///
|
||||
/// @param subnet_id subnet identfier.
|
||||
/// @param addr specified address.
|
||||
/// @return true if deletion was successful, false if the host was not
|
||||
/// there.
|
||||
/// @throw various exceptions in case of errors
|
||||
virtual bool del(const SubnetID& subnet_id,
|
||||
const asiolink::IOAddress& addr);
|
||||
|
||||
/// @brief Attempts to delete a host by (subnet-id4, identifier-type,
|
||||
/// identifier).
|
||||
///
|
||||
/// This method supports v4 hosts only.
|
||||
///
|
||||
/// @param subnet_id IPv4 Subnet identifier.
|
||||
/// @param identifier_type Identifier type.
|
||||
/// @param identifier_begin Pointer to a beginning of a buffer containing
|
||||
/// an identifier.
|
||||
/// @param identifier_len Identifier length.
|
||||
/// @return true if deletion was successful, false if the host was not
|
||||
/// there.
|
||||
/// @throw various exceptions in case of errors
|
||||
virtual bool del4(const SubnetID& subnet_id,
|
||||
const Host::IdentifierType& identifier_type,
|
||||
const uint8_t* identifier_begin,
|
||||
const size_t identifier_len);
|
||||
|
||||
/// @brief Attempts to delete a host by (subnet-id6, identifier-type,
|
||||
/// identifier).
|
||||
///
|
||||
/// This method supports v6 hosts only.
|
||||
///
|
||||
/// @param subnet_id IPv6 Subnet identifier.
|
||||
/// @param identifier_type Identifier type.
|
||||
/// @param identifier_begin Pointer to a beginning of a buffer containing
|
||||
/// an identifier.
|
||||
/// @param identifier_len Identifier length.
|
||||
/// @return true if deletion was successful, false if the host was not
|
||||
/// there.
|
||||
/// @throw various exceptions in case of errors
|
||||
virtual bool del6(const SubnetID& subnet_id,
|
||||
const Host::IdentifierType& identifier_type,
|
||||
const uint8_t* identifier_begin,
|
||||
const size_t identifier_len);
|
||||
|
||||
/// @brief Returns textual description of the backend.
|
||||
///
|
||||
/// @return Description of the backend.
|
||||
virtual std::string getDescription() const;
|
||||
|
||||
/// @brief Returns the name of the database.
|
||||
///
|
||||
/// @return database name
|
||||
virtual std::string getName() const;
|
||||
|
||||
/// @brief Return backend type
|
||||
///
|
||||
/// @return backend type "cql"
|
||||
virtual std::string getType() const override;
|
||||
|
||||
/// @brief Retrieves schema version from the DB.
|
||||
///
|
||||
/// @return Version number stored in the database, as a pair of unsigned
|
||||
/// integers. "first" is the major version number, "second" is the
|
||||
/// minor version number.
|
||||
///
|
||||
/// @throw isc::dhcp::DbOperationError An operation on the open database
|
||||
/// has failed.
|
||||
virtual VersionPair getVersion() const;
|
||||
|
||||
/// @brief Commit Transactions
|
||||
///
|
||||
/// Commits all pending database operations (no-op for Cassandra)
|
||||
virtual void commit() override;
|
||||
|
||||
/// @brief Rollback Transactions
|
||||
///
|
||||
/// Rolls back all pending database operations (no-op for Cassandra)
|
||||
virtual void rollback() override;
|
||||
|
||||
private:
|
||||
/// @brief Pointer to the implementation of the @ref CqlHostDataSource.
|
||||
CqlHostDataSourceImpl* impl_;
|
||||
}; // class CqlHostDataSource
|
||||
|
||||
} // namespace dhcp
|
||||
} // namespace isc
|
||||
|
||||
#endif // CQL_HOST_DATA_SOURCE_H
|
@@ -24,7 +24,7 @@
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
/// @brief HostID (used only when storing in MySQL or Postgres)
|
||||
/// @brief HostID (used only when storing in MySQL, PostgreSQL or Cassandra)
|
||||
typedef uint64_t HostID;
|
||||
|
||||
/// @brief IPv6 reservation for a host.
|
||||
@@ -534,13 +534,13 @@ public:
|
||||
/// @brief Returns information about the host in the textual format.
|
||||
std::string toText() const;
|
||||
|
||||
/// @brief Sets Host ID (primary key in MySQL and Postgres backends)
|
||||
/// @brief Sets Host ID (primary key in MySQL, PostgreSQL and Cassandra backends)
|
||||
/// @param id HostId value
|
||||
void setHostId(HostID id) {
|
||||
host_id_ = id;
|
||||
}
|
||||
|
||||
/// @brief Returns Host ID (primary key in MySQL and Postgres backends)
|
||||
/// @brief Returns Host ID (primary key in MySQL, PostgreSQL and Cassandra backends)
|
||||
/// @return id HostId value (or 0 if not set)
|
||||
HostID getHostId() const {
|
||||
return (host_id_);
|
||||
@@ -597,7 +597,7 @@ private:
|
||||
std::string boot_file_name_;
|
||||
|
||||
/// @brief HostID (a unique identifier assigned when the host is stored in
|
||||
/// MySQL or Pgsql)
|
||||
/// MySQL, PostgreSQL or Cassandra)
|
||||
uint64_t host_id_;
|
||||
|
||||
/// @brief Pointer to the DHCPv4 option data configuration for this host.
|
||||
|
@@ -4,7 +4,7 @@
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "config.h"
|
||||
#include <config.h>
|
||||
|
||||
#include <dhcpsrv/dhcpsrv_log.h>
|
||||
#include <dhcpsrv/host_data_source_factory.h>
|
||||
@@ -18,6 +18,10 @@
|
||||
#include <dhcpsrv/pgsql_host_data_source.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CQL
|
||||
#include <dhcpsrv/cql_host_data_source.h>
|
||||
#endif
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
@@ -34,7 +38,6 @@ using namespace std;
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
|
||||
HostDataSourcePtr&
|
||||
HostDataSourceFactory::getHostDataSourcePtr() {
|
||||
static HostDataSourcePtr hostDataSourcePtr;
|
||||
@@ -76,8 +79,10 @@ HostDataSourceFactory::create(const std::string& dbaccess) {
|
||||
|
||||
#ifdef HAVE_CQL
|
||||
if (db_type == "cql") {
|
||||
isc_throw(NotImplemented, "Sorry, CQL backend for host reservations "
|
||||
"is not implemented yet.");
|
||||
LOG_INFO(dhcpsrv_logger, DHCPSRV_CQL_HOST_DB)
|
||||
.arg(DatabaseConnection::redactedAccessString(parameters));
|
||||
getHostDataSourcePtr().reset(new CqlHostDataSource(parameters));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -109,5 +114,5 @@ HostDataSourceFactory::instance() {
|
||||
}
|
||||
#endif
|
||||
|
||||
}; // namespace dhcp
|
||||
}; // namespace isc
|
||||
} // namespace dhcp
|
||||
} // namespace isc
|
||||
|
@@ -2823,7 +2823,11 @@ MySqlHostDataSource::get4(const SubnetID& subnet_id,
|
||||
ConstHostPtr
|
||||
MySqlHostDataSource::get4(const SubnetID& subnet_id,
|
||||
const asiolink::IOAddress& address) const {
|
||||
/// @todo: check that address is really v4, not v6.
|
||||
// Check that address is IPv4, not IPv6.
|
||||
if (!address.isV4()) {
|
||||
isc_throw(BadValue, "MySqlHostDataSource::get4(2): wrong address type, "
|
||||
"address supplied is not an IPv4 address");
|
||||
}
|
||||
|
||||
// Set up the WHERE clause value
|
||||
MYSQL_BIND inbind[2];
|
||||
|
@@ -122,6 +122,7 @@ endif
|
||||
if HAVE_CQL
|
||||
libdhcpsrv_unittests_SOURCES += cql_connection_unittest.cc
|
||||
libdhcpsrv_unittests_SOURCES += cql_lease_mgr_unittest.cc
|
||||
libdhcpsrv_unittests_SOURCES += cql_host_data_source_unittest.cc
|
||||
endif
|
||||
libdhcpsrv_unittests_SOURCES += pool_unittest.cc
|
||||
libdhcpsrv_unittests_SOURCES += shared_network_parser_unittest.cc
|
||||
|
566
src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc
Normal file
566
src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc
Normal file
@@ -0,0 +1,566 @@
|
||||
// Copyright (C) 2017-2018 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
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <asiolink/io_address.h>
|
||||
#include <dhcpsrv/cql_connection.h>
|
||||
#include <dhcpsrv/cql_host_data_source.h>
|
||||
#include <dhcpsrv/cql_lease_mgr.h>
|
||||
#include <dhcpsrv/host.h>
|
||||
#include <dhcpsrv/host_data_source_factory.h>
|
||||
#include <dhcpsrv/tests/generic_host_data_source_unittest.h>
|
||||
#include <dhcpsrv/tests/test_utils.h>
|
||||
#include <dhcpsrv/testutils/cql_schema.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace isc;
|
||||
using namespace isc::asiolink;
|
||||
using namespace isc::dhcp;
|
||||
using namespace isc::dhcp::test;
|
||||
|
||||
/// @brief Fixture class for testing Cassandra host data source
|
||||
class CqlHostDataSourceTest : public GenericHostDataSourceTest {
|
||||
public:
|
||||
/// @brief Clears the database and opens connection to it.
|
||||
void initializeTest() {
|
||||
// Ensure schema is the correct one.
|
||||
destroyCqlSchema(false, true);
|
||||
createCqlSchema(false, true);
|
||||
|
||||
// Connect to the database
|
||||
try {
|
||||
HostDataSourceFactory::create(validCqlConnectionString());
|
||||
} catch (...) {
|
||||
std::cerr << "*** ERROR: unable to open database. The test"
|
||||
"*** environment is broken and must be fixed before"
|
||||
"*** the CQL tests will run correctly."
|
||||
"*** The reason for the problem is described in the"
|
||||
"*** accompanying exception output.";
|
||||
throw;
|
||||
}
|
||||
|
||||
hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
|
||||
}
|
||||
|
||||
/// @brief Destroys the HDS and the schema.
|
||||
void destroyTest() {
|
||||
try {
|
||||
hdsptr_->rollback();
|
||||
} catch (...) {
|
||||
// Rollback should never fail, as Cassandra doesn't support transactions
|
||||
// (commit and rollback are both no-op).
|
||||
}
|
||||
HostDataSourceFactory::destroy();
|
||||
destroyCqlSchema(false, true);
|
||||
}
|
||||
|
||||
/// @brief Constructor
|
||||
///
|
||||
/// Deletes everything from the database and opens it.
|
||||
CqlHostDataSourceTest() {
|
||||
initializeTest();
|
||||
}
|
||||
|
||||
/// @brief Destructor
|
||||
///
|
||||
/// Rolls back all pending transactions. The deletion of myhdsptr_ will
|
||||
/// close the database. Then reopen it and delete everything created by the
|
||||
/// test.
|
||||
virtual ~CqlHostDataSourceTest() {
|
||||
destroyTest();
|
||||
}
|
||||
|
||||
/// @brief Reopen the database
|
||||
///
|
||||
/// Closes the database and re-open it. Anything committed should be
|
||||
/// visible.
|
||||
///
|
||||
/// Parameter is ignored for CQL backend as the v4 and v6 leases share
|
||||
/// the same database.
|
||||
void reopen(Universe) {
|
||||
HostDataSourceFactory::destroy();
|
||||
HostDataSourceFactory::create(validCqlConnectionString());
|
||||
hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Check that database can be opened
|
||||
///
|
||||
/// This test checks if the CqlHostDataSource can be instantiated. This happens
|
||||
/// only if the database can be opened. Note that this is not part of the
|
||||
/// CqlLeaseMgr test fixure set. This test checks that the database can be
|
||||
/// opened: the fixtures assume that and check basic operations.
|
||||
|
||||
TEST(CqlHostDataSource, OpenDatabase) {
|
||||
// Schema needs to be created for the test to work.
|
||||
destroyCqlSchema(false, true);
|
||||
createCqlSchema(false, true);
|
||||
|
||||
// Check that lease manager open the database opens correctly and tidy up.
|
||||
// If it fails, print the error message.
|
||||
try {
|
||||
HostDataSourceFactory::create(validCqlConnectionString());
|
||||
EXPECT_NO_THROW((void)HostDataSourceFactory::getHostDataSourcePtr());
|
||||
HostDataSourceFactory::destroy();
|
||||
} catch (const isc::Exception& ex) {
|
||||
FAIL() << "*** ERROR: unable to open database, reason:\n"
|
||||
<< " " << ex.what() << "\n"
|
||||
<< "*** The test environment is broken and must be fixed\n"
|
||||
<< "*** before the CQL tests will run correctly.\n";
|
||||
}
|
||||
|
||||
// Check that lease manager open the database opens correctly with a longer
|
||||
// timeout. If it fails, print the error message.
|
||||
try {
|
||||
std::string connection_string = validCqlConnectionString() + std::string(" ") +
|
||||
std::string(VALID_TIMEOUT);
|
||||
HostDataSourceFactory::create(connection_string);
|
||||
EXPECT_NO_THROW((void)HostDataSourceFactory::getHostDataSourcePtr());
|
||||
HostDataSourceFactory::destroy();
|
||||
} catch (const isc::Exception& ex) {
|
||||
FAIL() << "*** ERROR: unable to open database, reason:\n"
|
||||
<< " " << ex.what() << "\n"
|
||||
<< "*** The test environment is broken and must be fixed\n"
|
||||
<< "*** before the CQL tests will run correctly.\n";
|
||||
}
|
||||
|
||||
// Check that attempting to get an instance of the host data source when
|
||||
// none is set throws an exception.
|
||||
EXPECT_FALSE(HostDataSourceFactory::getHostDataSourcePtr());
|
||||
|
||||
// Check that wrong specification of backend throws an exception.
|
||||
// (This is really a check on HostDataSourceFactory, but is convenient to
|
||||
// perform here.)
|
||||
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
|
||||
NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
|
||||
InvalidParameter);
|
||||
EXPECT_THROW(HostDataSourceFactory::create(connectionString(
|
||||
INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
|
||||
InvalidType);
|
||||
|
||||
// Check that invalid login data does not cause an exception, CQL should use
|
||||
// default values.
|
||||
EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
|
||||
INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)));
|
||||
EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
|
||||
VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)));
|
||||
EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
|
||||
VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
|
||||
EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
|
||||
VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)));
|
||||
|
||||
// Check that invalid timeouts throw DbOperationError.
|
||||
EXPECT_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
|
||||
VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
|
||||
DbOperationError);
|
||||
EXPECT_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
|
||||
VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)),
|
||||
DbOperationError);
|
||||
|
||||
// Check that CQL allows the hostname to not be specified.
|
||||
EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
|
||||
NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
|
||||
|
||||
// Tidy up after the test
|
||||
destroyCqlSchema(false, true);
|
||||
}
|
||||
|
||||
/// @brief Check conversion methods
|
||||
///
|
||||
/// The server works using cltt and valid_filetime. In the database, the
|
||||
/// information is stored as expire_time and valid-lifetime, which are
|
||||
/// related by
|
||||
///
|
||||
/// expire_time = cltt + valid_lifetime
|
||||
///
|
||||
/// This test checks that the conversion is correct. It does not check that the
|
||||
/// data is entered into the database correctly, only that the CQL_TIME
|
||||
/// structure used for the entry is correctly set up.
|
||||
TEST(CqlConnection, checkTimeConversion) {
|
||||
const time_t cltt = time(NULL);
|
||||
const uint32_t valid_lft = 86400; // 1 day
|
||||
cass_int64_t cql_expire;
|
||||
|
||||
// Convert to the database time
|
||||
CqlExchange::convertToDatabaseTime(cltt, valid_lft, cql_expire);
|
||||
|
||||
// Convert back
|
||||
time_t converted_cltt = 0;
|
||||
CqlExchange::convertFromDatabaseTime(cql_expire, valid_lft, converted_cltt);
|
||||
EXPECT_EQ(cltt, converted_cltt);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
testBasic4(Host::IDENT_HWADDR);
|
||||
}
|
||||
|
||||
// Test verifies if a host reservation can be added and later retrieved by IPv4
|
||||
// address. Host uses client-id (DUID) as identifier.
|
||||
TEST_F(CqlHostDataSourceTest, basic4ClientId) {
|
||||
testBasic4(Host::IDENT_DUID);
|
||||
}
|
||||
|
||||
// Test verifies that multiple hosts can be added and later retrieved by their
|
||||
// reserved IPv4 address. This test uses HW addresses as identifiers.
|
||||
TEST_F(CqlHostDataSourceTest, getByIPv4HWaddr) {
|
||||
testGetByIPv4(Host::IDENT_HWADDR);
|
||||
}
|
||||
|
||||
// Test verifies that multiple hosts can be added and later retrieved by their
|
||||
// reserved IPv4 address. This test uses client-id (DUID) as identifiers.
|
||||
TEST_F(CqlHostDataSourceTest, getByIPv4ClientId) {
|
||||
testGetByIPv4(Host::IDENT_DUID);
|
||||
}
|
||||
|
||||
// Test verifies if a host reservation can be added and later retrieved by
|
||||
// hardware address.
|
||||
TEST_F(CqlHostDataSourceTest, get4ByHWaddr) {
|
||||
testGet4ByIdentifier(Host::IDENT_HWADDR);
|
||||
}
|
||||
|
||||
// Test verifies if a host reservation can be added and later retrieved by
|
||||
// DUID.
|
||||
TEST_F(CqlHostDataSourceTest, get4ByDUID) {
|
||||
testGet4ByIdentifier(Host::IDENT_DUID);
|
||||
}
|
||||
|
||||
// Test verifies if a host reservation can be added and later retrieved by
|
||||
// circuit id.
|
||||
TEST_F(CqlHostDataSourceTest, get4ByCircuitId) {
|
||||
testGet4ByIdentifier(Host::IDENT_CIRCUIT_ID);
|
||||
}
|
||||
|
||||
// Test verifies if hardware address and client identifier are not confused.
|
||||
TEST_F(CqlHostDataSourceTest, hwaddrNotClientId1) {
|
||||
testHWAddrNotClientId();
|
||||
}
|
||||
|
||||
// Test verifies if hardware address and client identifier are not confused.
|
||||
TEST_F(CqlHostDataSourceTest, hwaddrNotClientId2) {
|
||||
testClientIdNotHWAddr();
|
||||
}
|
||||
|
||||
// Test verifies if a host with FQDN hostname can be stored and later retrieved.
|
||||
TEST_F(CqlHostDataSourceTest, hostnameFQDN) {
|
||||
testHostname("foo.example.org", 1);
|
||||
}
|
||||
|
||||
// Test verifies if 100 hosts with unique FQDN hostnames can be stored and later
|
||||
// retrieved.
|
||||
TEST_F(CqlHostDataSourceTest, hostnameFQDN100) {
|
||||
testHostname("foo.example.org", 100);
|
||||
}
|
||||
|
||||
// Test verifies if a host without any hostname specified can be stored and
|
||||
// later retrieved.
|
||||
TEST_F(CqlHostDataSourceTest, noHostname) {
|
||||
testHostname("", 1);
|
||||
}
|
||||
|
||||
// Test verifies if the hardware or client-id query can match hardware address.
|
||||
TEST_F(CqlHostDataSourceTest, DISABLED_hwaddrOrClientId1) {
|
||||
/// @todo: The logic behind ::get4(subnet_id, hwaddr, duid) call needs to
|
||||
/// be discussed.
|
||||
///
|
||||
/// @todo: Add host reservation with hardware address X, try to retrieve
|
||||
/// host for hardware address X or client identifier Y, verify that the
|
||||
/// reservation is returned.
|
||||
}
|
||||
|
||||
// Test verifies if the hardware or client-id query can match client-id.
|
||||
TEST_F(CqlHostDataSourceTest, DISABLED_hwaddrOrClientId2) {
|
||||
/// @todo: The logic behind ::get4(subnet_id, hwaddr, duid) call needs to
|
||||
/// be discussed.
|
||||
///
|
||||
/// @todo: Add host reservation with client identifier Y, try to retrieve
|
||||
/// host for hardware address X or client identifier Y, verify that the
|
||||
/// reservation is returned.
|
||||
}
|
||||
|
||||
// Test verifies that host with IPv6 address and DUID can be added and
|
||||
// later retrieved by IPv6 address.
|
||||
TEST_F(CqlHostDataSourceTest, get6AddrWithDuid) {
|
||||
testGetByIPv6(Host::IDENT_DUID, false);
|
||||
}
|
||||
|
||||
// Test verifies that host with IPv6 address and HWAddr can be added and
|
||||
// later retrieved by IPv6 address.
|
||||
TEST_F(CqlHostDataSourceTest, get6AddrWithHWAddr) {
|
||||
testGetByIPv6(Host::IDENT_HWADDR, false);
|
||||
}
|
||||
|
||||
// Test verifies that host with IPv6 prefix and DUID can be added and
|
||||
// later retrieved by IPv6 prefix.
|
||||
TEST_F(CqlHostDataSourceTest, get6PrefixWithDuid) {
|
||||
testGetByIPv6(Host::IDENT_DUID, true);
|
||||
}
|
||||
|
||||
// Test verifies that host with IPv6 prefix and HWAddr can be added and
|
||||
// later retrieved by IPv6 prefix.
|
||||
TEST_F(CqlHostDataSourceTest, get6PrefixWithHWaddr) {
|
||||
testGetByIPv6(Host::IDENT_HWADDR, true);
|
||||
}
|
||||
|
||||
// Test verifies that host with IPv6 prefix reservation can be retrieved
|
||||
// by subnet id and prefix value.
|
||||
TEST_F(CqlHostDataSourceTest, get6SubnetPrefix) {
|
||||
testGetBySubnetIPv6();
|
||||
}
|
||||
|
||||
// Test verifies if a host reservation can be added and later retrieved by
|
||||
// hardware address.
|
||||
TEST_F(CqlHostDataSourceTest, get6ByHWaddr) {
|
||||
testGet6ByHWAddr();
|
||||
}
|
||||
|
||||
// Test verifies if a host reservation can be added and later retrieved by
|
||||
// client identifier.
|
||||
TEST_F(CqlHostDataSourceTest, get6ByClientId) {
|
||||
testGet6ByClientId();
|
||||
}
|
||||
|
||||
// Test verifies if a host reservation can be stored with both IPv6 address and
|
||||
// prefix.
|
||||
TEST_F(CqlHostDataSourceTest, addr6AndPrefix) {
|
||||
testAddr6AndPrefix();
|
||||
}
|
||||
|
||||
// Tests if host with multiple IPv6 reservations can be added and then
|
||||
// retrieved correctly. Test checks reservations comparing.
|
||||
TEST_F(CqlHostDataSourceTest, multipleReservations) {
|
||||
testMultipleReservations();
|
||||
}
|
||||
|
||||
// Tests if compareIPv6Reservations() method treats same pool of reservations
|
||||
// but added in different order as equal.
|
||||
TEST_F(CqlHostDataSourceTest, multipleReservationsDifferentOrder) {
|
||||
testMultipleReservationsDifferentOrder();
|
||||
}
|
||||
|
||||
// Test verifies if multiple client classes for IPv4 can be stored.
|
||||
TEST_F(CqlHostDataSourceTest, DISABLED_multipleClientClasses4) {
|
||||
/// @todo: Implement this test as part of #5503.
|
||||
|
||||
/// Add host reservation with a multiple v4 client-classes, retrieve it and
|
||||
/// make sure that all client classes are retrieved properly.
|
||||
}
|
||||
|
||||
// Test verifies if multiple client classes for IPv6 can be stored.
|
||||
TEST_F(CqlHostDataSourceTest, DISABLED_multipleClientClasses6) {
|
||||
/// @todo: Implement this test as part of #5503.
|
||||
|
||||
/// Add host reservation with a multiple v6 client-classes, retrieve it and
|
||||
/// make sure that all client classes are retrieved properly.
|
||||
}
|
||||
|
||||
// Test verifies if multiple client classes for both IPv4 and IPv6 can be
|
||||
// stored.
|
||||
TEST_F(CqlHostDataSourceTest, DISABLED_multipleClientClassesBoth) {
|
||||
/// @todo: Implement this test as part of #5503.
|
||||
|
||||
/// Add host reservation with a multiple v4 and v6 client-classes, retrieve
|
||||
/// it and make sure that all client classes are retrieved properly. Also,
|
||||
/// check that the classes are not confused.
|
||||
}
|
||||
|
||||
// Test if the same host can have reservations in different subnets (with the
|
||||
// same hardware address). The test logic is as follows:
|
||||
// Insert 10 host reservations for a given physical host (the same
|
||||
// hardware address), but for different subnets (different subnet-ids).
|
||||
// Make sure that getAll() returns them all correctly.
|
||||
TEST_F(CqlHostDataSourceTest, multipleSubnetsHWAddr) {
|
||||
testMultipleSubnets(10, Host::IDENT_HWADDR);
|
||||
}
|
||||
|
||||
// Test if the same host can have reservations in different subnets (with the
|
||||
// same client identifier). The test logic is as follows:
|
||||
//
|
||||
// Insert 10 host reservations for a given physical host (the same
|
||||
// client-identifier), but for different subnets (different subnet-ids).
|
||||
// Make sure that getAll() returns them correctly.
|
||||
TEST_F(CqlHostDataSourceTest, multipleSubnetsClientId) {
|
||||
testMultipleSubnets(10, Host::IDENT_DUID);
|
||||
}
|
||||
|
||||
// Test if host reservations made for different IPv6 subnets are handled
|
||||
// correctly. The test logic is as follows:
|
||||
//
|
||||
// Insert 10 host reservations for different subnets. Make sure that
|
||||
// get6(subnet-id, ...) calls return correct reservation.
|
||||
TEST_F(CqlHostDataSourceTest, subnetId6) {
|
||||
testSubnetId6(10, Host::IDENT_HWADDR);
|
||||
}
|
||||
|
||||
// Test if the duplicate host instances can't be inserted. The test logic is as
|
||||
// follows: try to add multiple instances of the same host reservation and
|
||||
// verify that the second and following attempts will throw exceptions.
|
||||
// Hosts with same DUID.
|
||||
TEST_F(CqlHostDataSourceTest, addDuplicate6WithDUID) {
|
||||
testAddDuplicate6WithSameDUID();
|
||||
}
|
||||
|
||||
// Test if the duplicate host instances can't be inserted. The test logic is as
|
||||
// follows: try to add multiple instances of the same host reservation and
|
||||
// verify that the second and following attempts will throw exceptions.
|
||||
// Hosts with same HWAddr.
|
||||
TEST_F(CqlHostDataSourceTest, addDuplicate6WithHWAddr) {
|
||||
testAddDuplicate6WithSameHWAddr();
|
||||
}
|
||||
|
||||
// Test if the duplicate IPv4 host instances can't be inserted. The test logic
|
||||
// is as follows: try to add multiple instances of the same host reservation and
|
||||
// verify that the second and following attempts will throw exceptions.
|
||||
TEST_F(CqlHostDataSourceTest, addDuplicate4) {
|
||||
testAddDuplicate4();
|
||||
}
|
||||
|
||||
// This test verifies that DHCPv4 options can be inserted in a binary format
|
||||
/// and retrieved from the CQL host database.
|
||||
TEST_F(CqlHostDataSourceTest, optionsReservations4) {
|
||||
testOptionsReservations4(false);
|
||||
}
|
||||
|
||||
// This test verifies that DHCPv6 options can be inserted in a binary format
|
||||
/// and retrieved from the CQL host database.
|
||||
TEST_F(CqlHostDataSourceTest, optionsReservations6) {
|
||||
testOptionsReservations6(false);
|
||||
}
|
||||
|
||||
// This test verifies that DHCPv4 and DHCPv6 options can be inserted in a
|
||||
/// binary format and retrieved with a single query to the database.
|
||||
TEST_F(CqlHostDataSourceTest, optionsReservations46) {
|
||||
testOptionsReservations46(false);
|
||||
}
|
||||
|
||||
// This test verifies that DHCPv4 options can be inserted in a textual format
|
||||
/// and retrieved from the CQL host database.
|
||||
TEST_F(CqlHostDataSourceTest, formattedOptionsReservations4) {
|
||||
testOptionsReservations4(true);
|
||||
}
|
||||
|
||||
// This test verifies that DHCPv6 options can be inserted in a textual format
|
||||
/// and retrieved from the CQL host database.
|
||||
TEST_F(CqlHostDataSourceTest, formattedOptionsReservations6) {
|
||||
testOptionsReservations6(true);
|
||||
}
|
||||
|
||||
// This test verifies that DHCPv4 and DHCPv6 options can be inserted in a
|
||||
// textual format and retrieved with a single query to the database.
|
||||
TEST_F(CqlHostDataSourceTest, formattedOptionsReservations46) {
|
||||
testOptionsReservations46(true);
|
||||
}
|
||||
|
||||
// This test checks transactional insertion of the host information
|
||||
// into the database. The failure to insert host information at
|
||||
// any stage should cause the whole transaction to be rolled back.
|
||||
TEST_F(CqlHostDataSourceTest, testAddRollback) {
|
||||
// Make sure we have the pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
// To test the transaction rollback mechanism we need to cause the
|
||||
// insertion of host information to fail at some stage. The 'hosts'
|
||||
// table should be updated correctly but the failure should occur
|
||||
// when inserting reservations or options. The simplest way to
|
||||
// achieve that is to simply drop one of the tables. To do so, we
|
||||
// connect to the database and issue a DROP query.
|
||||
CqlConnection::ParameterMap params;
|
||||
params["name"] = "keatest";
|
||||
params["user"] = "keatest";
|
||||
params["password"] = "keatest";
|
||||
CqlConnection connection(params);
|
||||
ASSERT_NO_THROW(connection.openDatabase());
|
||||
|
||||
// Drop every table so we make sure host_reservations doesn't exist anymore.
|
||||
destroyCqlSchema(false, true);
|
||||
|
||||
// Create a host with a reservation.
|
||||
HostPtr host = initializeHost6("2001:db8:1::1", Host::IDENT_HWADDR, false);
|
||||
// Let's assign some DHCPv4 subnet to the host, because we will use the
|
||||
// DHCPv4 subnet to try to retrieve the host after failed insertion.
|
||||
host->setIPv4SubnetID(SubnetID(4));
|
||||
|
||||
// There is no ipv6_reservations table, so the insertion should fail.
|
||||
ASSERT_THROW(hdsptr_->add(host), DbOperationError);
|
||||
|
||||
// Even though we have created a DHCPv6 host, we can't use get6()
|
||||
// method to retrieve the host from the database, because the
|
||||
// query would expect that the ipv6_reservations table is present.
|
||||
// Therefore, the query would fail. Instead, we use the get4 method
|
||||
// which uses the same client identifier, but doesn't attempt to
|
||||
// retrieve the data from ipv6_reservations table. The query should
|
||||
// pass but return no host because the (insert) transaction is expected
|
||||
// to be rolled back.
|
||||
ASSERT_THROW(
|
||||
hdsptr_->get4(host->getIPv4SubnetID(), host->getIdentifierType(),
|
||||
&host->getIdentifier()[0], host->getIdentifier().size()),
|
||||
DbOperationError);
|
||||
}
|
||||
|
||||
// This test checks that siaddr, sname, file fields can be retrieved
|
||||
/// from a database for a host.
|
||||
/// @todo: Uncomment this after 5507 is implemented.
|
||||
TEST_F(CqlHostDataSourceTest, DISABLED_messageFields) {
|
||||
testMessageFields4();
|
||||
}
|
||||
|
||||
// Check that delete(subnet-id, addr4) works.
|
||||
/// @todo: Uncomment this after #5506 is implemented.
|
||||
TEST_F(CqlHostDataSourceTest, DISABLED_deleteByAddr4) {
|
||||
testDeleteByAddr4();
|
||||
}
|
||||
|
||||
// Check that delete(subnet4-id, identifier-type, identifier) works.
|
||||
/// @todo: Uncomment this after #5506 is implemented.
|
||||
TEST_F(CqlHostDataSourceTest, DISABLED_deleteById4) {
|
||||
testDeleteById4();
|
||||
}
|
||||
|
||||
// Check that delete(subnet4-id, identifier-type, identifier) works,
|
||||
// even when options are present.
|
||||
/// @todo: Uncomment this after #5506 is implemented.
|
||||
TEST_F(CqlHostDataSourceTest, DISABLED_deleteById4Options) {
|
||||
testDeleteById4Options();
|
||||
}
|
||||
|
||||
// Check that delete(subnet6-id, identifier-type, identifier) works.
|
||||
/// @todo: Uncomment this after #5506 is implemented.
|
||||
TEST_F(CqlHostDataSourceTest, DISABLED_deleteById6) {
|
||||
testDeleteById6();
|
||||
}
|
||||
|
||||
// Check that delete(subnet6-id, identifier-type, identifier) works,
|
||||
// even when options are present.
|
||||
/// @todo: Uncomment this after #5506 is implemented.
|
||||
TEST_F(CqlHostDataSourceTest, DISABLED_deleteById6Options) {
|
||||
testDeleteById6Options();
|
||||
}
|
||||
|
||||
// Tests that multiple reservations without IPv4 addresses can be
|
||||
// specified within a subnet.
|
||||
/// @todo: Uncomment this after #5506 is implemented.
|
||||
TEST_F(CqlHostDataSourceTest, DISABLED_testMultipleHostsNoAddress4) {
|
||||
testMultipleHostsNoAddress4();
|
||||
}
|
||||
|
||||
// Tests that multiple hosts can be specified within an IPv6 subnet.
|
||||
/// @todo: Uncomment this after #5506 is implemented.
|
||||
TEST_F(CqlHostDataSourceTest, DISABLED_testMultipleHosts6) {
|
||||
testMultipleHosts6();
|
||||
}
|
||||
|
||||
} // namespace
|
@@ -728,3 +728,4 @@ TEST_F(CqlLeaseMgrTest, DISABLED_wipeLeases6) {
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@@ -4,26 +4,30 @@
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <asiolink/io_address.h>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <dhcp/dhcp6.h>
|
||||
#include <dhcp/libdhcp++.h>
|
||||
#include <dhcp/option4_addrlst.h>
|
||||
#include <dhcp/option6_addrlst.h>
|
||||
#include <dhcp/option_string.h>
|
||||
#include <dhcp/option_int.h>
|
||||
#include <dhcp/option_string.h>
|
||||
#include <dhcp/option_vendor.h>
|
||||
#include <dhcpsrv/database_connection.h>
|
||||
#include <dhcpsrv/host_data_source_factory.h>
|
||||
#include <dhcpsrv/tests/generic_host_data_source_unittest.h>
|
||||
#include <dhcpsrv/tests/test_utils.h>
|
||||
#include <dhcpsrv/testutils/schema.h>
|
||||
#include <dhcpsrv/database_connection.h>
|
||||
#include <asiolink/io_address.h>
|
||||
#include <util/buffer.h>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <util/buffer.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
|
||||
using namespace std;
|
||||
@@ -35,13 +39,13 @@ namespace isc {
|
||||
namespace dhcp {
|
||||
namespace test {
|
||||
|
||||
GenericHostDataSourceTest::GenericHostDataSourceTest()
|
||||
:hdsptr_() {
|
||||
GenericHostDataSourceTest::GenericHostDataSourceTest() : hdsptr_() {
|
||||
LibDHCP::clearRuntimeOptionDefs();
|
||||
}
|
||||
|
||||
GenericHostDataSourceTest::~GenericHostDataSourceTest() {
|
||||
LibDHCP::clearRuntimeOptionDefs();
|
||||
hdsptr_.reset();
|
||||
}
|
||||
|
||||
std::vector<uint8_t>
|
||||
@@ -70,12 +74,11 @@ GenericHostDataSourceTest::generateIdentifier(const bool new_identifier) {
|
||||
|
||||
// Let's use something that is easily printable. That's convenient
|
||||
// if you need to enter MySQL queries by hand.
|
||||
static uint8_t ident[] = { 65, 66, 67, 68, 69, 70, 71, 72, 73, 74 };
|
||||
static uint8_t ident[] = {65, 66, 67, 68, 69, 70, 71, 72, 73, 74};
|
||||
|
||||
// Increase the identifier for the next time we use it.
|
||||
// This is primitive, but will work for 65k unique
|
||||
// identifiers.
|
||||
if (new_identifier) {
|
||||
// Increase the identifier for the next time we use it.
|
||||
// This is primitive, but will work for 65k unique identifiers.
|
||||
ident[sizeof(ident) - 1]++;
|
||||
if (ident[sizeof(ident) - 1] == 0) {
|
||||
ident[sizeof(ident) - 2]++;
|
||||
@@ -90,7 +93,6 @@ GenericHostDataSourceTest::initializeHost4(const std::string& address,
|
||||
std::vector<uint8_t> ident;
|
||||
if (id == Host::IDENT_HWADDR) {
|
||||
ident = generateHWAddr();
|
||||
|
||||
} else {
|
||||
ident = generateIdentifier();
|
||||
}
|
||||
@@ -109,10 +111,11 @@ GenericHostDataSourceTest::initializeHost4(const std::string& address,
|
||||
return (host);
|
||||
}
|
||||
|
||||
HostPtr GenericHostDataSourceTest::initializeHost6(std::string address,
|
||||
Host::IdentifierType identifier,
|
||||
bool prefix,
|
||||
bool new_identifier) {
|
||||
HostPtr
|
||||
GenericHostDataSourceTest::initializeHost6(std::string address,
|
||||
Host::IdentifierType identifier,
|
||||
bool prefix,
|
||||
bool new_identifier) {
|
||||
std::vector<uint8_t> ident;
|
||||
switch (identifier) {
|
||||
case Host::IDENT_HWADDR:
|
||||
@@ -134,8 +137,8 @@ HostPtr GenericHostDataSourceTest::initializeHost6(std::string address,
|
||||
subnet4++;
|
||||
subnet6++;
|
||||
|
||||
HostPtr host(new Host(&ident[0], ident.size(), identifier, subnet4,
|
||||
subnet6, IOAddress("0.0.0.0")));
|
||||
HostPtr host(new Host(&ident[0], ident.size(), identifier, subnet4, subnet6,
|
||||
IOAddress("0.0.0.0")));
|
||||
|
||||
if (!prefix) {
|
||||
// Create IPv6 reservation (for an address)
|
||||
@@ -149,6 +152,17 @@ HostPtr GenericHostDataSourceTest::initializeHost6(std::string address,
|
||||
return (host);
|
||||
}
|
||||
|
||||
bool
|
||||
GenericHostDataSourceTest::reservationExists(const IPv6Resrv& resrv,
|
||||
const IPv6ResrvRange& range) {
|
||||
for (IPv6ResrvIterator it = range.first; it != range.second; ++it) {
|
||||
if (resrv == it->second) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
GenericHostDataSourceTest::compareHwaddrs(const ConstHostPtr& host1,
|
||||
const ConstHostPtr& host2,
|
||||
@@ -159,13 +173,12 @@ GenericHostDataSourceTest::compareHwaddrs(const ConstHostPtr& host1,
|
||||
// Compare if both have or have not HWaddress set.
|
||||
if ((host1->getHWAddress() && !host2->getHWAddress()) ||
|
||||
(!host1->getHWAddress() && host2->getHWAddress())) {
|
||||
|
||||
// One host has hardware address set while the other has not.
|
||||
// Let's see if it's a problem.
|
||||
if (expect_match) {
|
||||
ADD_FAILURE() << "Host comparison failed: host1 hwaddress="
|
||||
<< host1->getHWAddress() << ", host2 hwaddress="
|
||||
<< host2->getHWAddress();
|
||||
<< host1->getHWAddress()
|
||||
<< ", host2 hwaddress=" << host2->getHWAddress();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -173,7 +186,6 @@ GenericHostDataSourceTest::compareHwaddrs(const ConstHostPtr& host1,
|
||||
// Now we know that either both or neither have hw address set.
|
||||
// If host1 has it, we can proceed to value comparison.
|
||||
if (host1->getHWAddress()) {
|
||||
|
||||
if (expect_match) {
|
||||
// Compare the actual address if they match.
|
||||
EXPECT_TRUE(*host1->getHWAddress() == *host2->getHWAddress());
|
||||
@@ -197,13 +209,12 @@ GenericHostDataSourceTest::compareDuids(const ConstHostPtr& host1,
|
||||
// compare if both have or have not DUID set
|
||||
if ((host1->getDuid() && !host2->getDuid()) ||
|
||||
(!host1->getDuid() && host2->getDuid())) {
|
||||
|
||||
// One host has a DUID and the other doesn't.
|
||||
// Let's see if it's a problem.
|
||||
if (expect_match) {
|
||||
ADD_FAILURE() << "DUID comparison failed: host1 duid="
|
||||
<< host1->getDuid() << ", host2 duid="
|
||||
<< host2->getDuid();
|
||||
<< host1->getDuid()
|
||||
<< ", host2 duid=" << host2->getDuid();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -211,7 +222,6 @@ GenericHostDataSourceTest::compareDuids(const ConstHostPtr& host1,
|
||||
// Now we know that either both or neither have DUID set.
|
||||
// If host1 has it, we can proceed to value comparison.
|
||||
if (host1->getDuid()) {
|
||||
|
||||
if (expect_match) {
|
||||
EXPECT_TRUE(*host1->getDuid() == *host2->getDuid());
|
||||
} else {
|
||||
@@ -224,9 +234,9 @@ GenericHostDataSourceTest::compareDuids(const ConstHostPtr& host1,
|
||||
}
|
||||
}
|
||||
|
||||
void GenericHostDataSourceTest::compareHosts(const ConstHostPtr& host1,
|
||||
const ConstHostPtr& host2) {
|
||||
|
||||
void
|
||||
GenericHostDataSourceTest::compareHosts(const ConstHostPtr& host1,
|
||||
const ConstHostPtr& host2) {
|
||||
// Let's compare HW addresses and expect match.
|
||||
compareHwaddrs(host1, host2, true);
|
||||
|
||||
@@ -272,6 +282,24 @@ void GenericHostDataSourceTest::compareHosts(const ConstHostPtr& host1,
|
||||
compareOptions(host1->getCfgOption6(), host2->getCfgOption6());
|
||||
}
|
||||
|
||||
bool
|
||||
GenericHostDataSourceTest::compareHostsForSort4(const ConstHostPtr& host1,
|
||||
const ConstHostPtr& host2) {
|
||||
if (host1->getIPv4SubnetID() < host2->getIPv4SubnetID()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
GenericHostDataSourceTest::compareHostsForSort6(const ConstHostPtr& host1,
|
||||
const ConstHostPtr& host2) {
|
||||
if (host1->getIPv6SubnetID() < host2->getIPv6SubnetID()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DuidPtr
|
||||
GenericHostDataSourceTest::HWAddrToDuid(const HWAddrPtr& hwaddr) {
|
||||
if (!hwaddr) {
|
||||
@@ -290,16 +318,14 @@ GenericHostDataSourceTest::DuidToHWAddr(const DuidPtr& duid) {
|
||||
return (HWAddrPtr(new HWAddr(duid->getDuid(), HTYPE_ETHER)));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GenericHostDataSourceTest::compareReservations6(IPv6ResrvRange resrv1,
|
||||
IPv6ResrvRange resrv2) {
|
||||
|
||||
// Compare number of reservations for both hosts
|
||||
if (std::distance(resrv1.first, resrv1.second) !=
|
||||
std::distance(resrv2.first, resrv2.second)){
|
||||
std::distance(resrv2.first, resrv2.second)) {
|
||||
ADD_FAILURE() << "Reservation comparison failed, "
|
||||
"hosts got different number of reservations.";
|
||||
"hosts got different number of reservations.";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -325,16 +351,19 @@ GenericHostDataSourceTest::compareReservations6(IPv6ResrvRange resrv1,
|
||||
for (; resrv1.first != resrv1.second; resrv1.first++) {
|
||||
IPv6ResrvIterator iter = resrv2.first;
|
||||
while (iter != resrv2.second) {
|
||||
if((resrv1.first->second.getType() == iter->second.getType()) &&
|
||||
(resrv1.first->second.getPrefixLen() == iter->second.getPrefixLen()) &&
|
||||
(resrv1.first->second.getPrefix() == iter->second.getPrefix())) {
|
||||
if ((resrv1.first->second.getType() ==
|
||||
iter->second.getType()) &&
|
||||
(resrv1.first->second.getPrefixLen() ==
|
||||
iter->second.getPrefixLen()) &&
|
||||
(resrv1.first->second.getPrefix() ==
|
||||
iter->second.getPrefix())) {
|
||||
break;
|
||||
}
|
||||
iter++;
|
||||
if (iter == resrv2.second) {
|
||||
ADD_FAILURE()<< "Reservation comparison failed, "
|
||||
"no match for reservation: "
|
||||
<< resrv1.first->second.getPrefix().toText();
|
||||
ADD_FAILURE() << "Reservation comparison failed, "
|
||||
"no match for reservation: "
|
||||
<< resrv1.first->second.getPrefix().toText();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -365,7 +394,7 @@ GenericHostDataSourceTest::compareOptions(const ConstCfgOptionPtr& cfg1,
|
||||
EXPECT_EQ(vendor_spaces.size(), cfg1->getVendorIdsSpaceNames().size());
|
||||
|
||||
// Iterate over all option spaces existing in cfg2.
|
||||
BOOST_FOREACH(std::string space, option_spaces) {
|
||||
BOOST_FOREACH (std::string space, option_spaces) {
|
||||
// Retrieve options belonging to the current option space.
|
||||
OptionContainerPtr options1 = cfg1->getAll(space);
|
||||
OptionContainerPtr options2 = cfg2->getAll(space);
|
||||
@@ -377,14 +406,16 @@ GenericHostDataSourceTest::compareOptions(const ConstCfgOptionPtr& cfg1,
|
||||
<< "failed for option space " << space;
|
||||
|
||||
// Iterate over all options within this option space.
|
||||
BOOST_FOREACH(OptionDescriptor desc1, *options1) {
|
||||
BOOST_FOREACH (OptionDescriptor desc1, *options1) {
|
||||
OptionDescriptor desc2 = cfg2->get(space, desc1.option_->getType());
|
||||
// Compare persistent flag.
|
||||
EXPECT_EQ(desc1.persistent_, desc2.persistent_)
|
||||
<< "failed for option " << space << "." << desc1.option_->getType();
|
||||
<< "failed for option " << space << "."
|
||||
<< desc1.option_->getType();
|
||||
// Compare formatted value.
|
||||
EXPECT_EQ(desc1.formatted_value_, desc2.formatted_value_)
|
||||
<< "failed for option " << space << "." << desc1.option_->getType();
|
||||
<< "failed for option " << space << "."
|
||||
<< desc1.option_->getType();
|
||||
|
||||
// Compare user context.
|
||||
ConstElementPtr ctx1 = desc1.getContext();
|
||||
@@ -407,11 +438,10 @@ GenericHostDataSourceTest::compareOptions(const ConstCfgOptionPtr& cfg1,
|
||||
// the Option class.
|
||||
EXPECT_TRUE(typeid(*option1) == typeid(*option2))
|
||||
<< "Compared DHCP options, having option code "
|
||||
<< desc1.option_->getType() << " and belonging to the "
|
||||
<< space << " option space, are represented "
|
||||
"by different C++ classes: "
|
||||
<< typeid(*option1).name() << " vs "
|
||||
<< typeid(*option2).name();
|
||||
<< desc1.option_->getType() << " and belonging to the " << space
|
||||
<< " option space, are represented "
|
||||
"by different C++ classes: "
|
||||
<< typeid(*option1).name() << " vs " << typeid(*option2).name();
|
||||
|
||||
// Because we use different C++ classes to represent different
|
||||
// options, the simplest way to make sure that the options are
|
||||
@@ -422,9 +452,12 @@ GenericHostDataSourceTest::compareOptions(const ConstCfgOptionPtr& cfg1,
|
||||
ASSERT_NO_THROW(option2->pack(buf2));
|
||||
|
||||
ASSERT_EQ(buf1.getLength(), buf2.getLength())
|
||||
<< "failed for option " << space << "." << desc1.option_->getType();
|
||||
EXPECT_EQ(0, memcmp(buf1.getData(), buf2.getData(), buf1.getLength()))
|
||||
<< "failed for option " << space << "." << desc1.option_->getType();
|
||||
<< "failed for option " << space << "."
|
||||
<< desc1.option_->getType();
|
||||
EXPECT_EQ(0,
|
||||
memcmp(buf1.getData(), buf2.getData(), buf1.getLength()))
|
||||
<< "failed for option " << space << "."
|
||||
<< desc1.option_->getType();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -438,7 +471,6 @@ GenericHostDataSourceTest::createEmptyOption(const Option::Universe& universe,
|
||||
return (desc);
|
||||
}
|
||||
|
||||
|
||||
OptionDescriptor
|
||||
GenericHostDataSourceTest::createVendorOption(const Option::Universe& universe,
|
||||
const bool persist,
|
||||
@@ -478,24 +510,21 @@ GenericHostDataSourceTest::addTestOptions(const HostPtr& host,
|
||||
DHCP4_OPTION_SPACE);
|
||||
opts->add(createOption<OptionUint32>(Option::V4, 1, false, formatted, 312131),
|
||||
"vendor-encapsulated-options");
|
||||
opts->add(createAddressOption<Option4AddrLst>(254, false, formatted, "192.0.2.3"),
|
||||
DHCP4_OPTION_SPACE);
|
||||
opts->add(createAddressOption<Option4AddrLst>(254, false, formatted,
|
||||
"192.0.2.3"), DHCP4_OPTION_SPACE);
|
||||
opts->add(createEmptyOption(Option::V4, 1, true), "isc");
|
||||
opts->add(createAddressOption<Option4AddrLst>(2, false, formatted, "10.0.0.5",
|
||||
"10.0.0.3", "10.0.3.4"),
|
||||
"isc");
|
||||
"10.0.0.3", "10.0.3.4"), "isc");
|
||||
|
||||
// Add definitions for DHCPv4 non-standard options.
|
||||
defs.addItem(OptionDefinitionPtr(new OptionDefinition("vendor-encapsulated-1",
|
||||
1, "uint32")),
|
||||
defs.addItem(OptionDefinitionPtr(new OptionDefinition(
|
||||
"vendor-encapsulated-1", 1, "uint32")),
|
||||
"vendor-encapsulated-options");
|
||||
defs.addItem(OptionDefinitionPtr(new OptionDefinition("option-254", 254,
|
||||
"ipv4-address", true)),
|
||||
defs.addItem(OptionDefinitionPtr(new OptionDefinition(
|
||||
"option-254", 254, "ipv4-address", true)),
|
||||
DHCP4_OPTION_SPACE);
|
||||
defs.addItem(OptionDefinitionPtr(new OptionDefinition("isc-1", 1, "empty")),
|
||||
"isc");
|
||||
defs.addItem(OptionDefinitionPtr(new OptionDefinition("isc-2", 2,
|
||||
"ipv4-address", true)),
|
||||
defs.addItem(OptionDefinitionPtr(new OptionDefinition("isc-1", 1, "empty")), "isc");
|
||||
defs.addItem(OptionDefinitionPtr(new OptionDefinition("isc-2", 2, "ipv4-address", true)),
|
||||
"isc");
|
||||
}
|
||||
|
||||
@@ -517,17 +546,14 @@ GenericHostDataSourceTest::addTestOptions(const HostPtr& host,
|
||||
DHCP6_OPTION_SPACE);
|
||||
opts->add(createEmptyOption(Option::V6, 1, true), "isc2");
|
||||
opts->add(createAddressOption<Option6AddrLst>(2, false, formatted, "3000::1",
|
||||
"3000::2", "3000::3"),
|
||||
"isc2");
|
||||
"3000::2", "3000::3"), "isc2");
|
||||
|
||||
// Add definitions for DHCPv6 non-standard options.
|
||||
defs.addItem(OptionDefinitionPtr(new OptionDefinition("option-1024", 1024,
|
||||
"ipv6-address", true)),
|
||||
defs.addItem(OptionDefinitionPtr(new OptionDefinition(
|
||||
"option-1024", 1024, "ipv6-address", true)),
|
||||
DHCP6_OPTION_SPACE);
|
||||
defs.addItem(OptionDefinitionPtr(new OptionDefinition("option-1", 1, "empty")),
|
||||
"isc2");
|
||||
defs.addItem(OptionDefinitionPtr(new OptionDefinition("option-2", 2,
|
||||
"ipv6-address", true)),
|
||||
defs.addItem(OptionDefinitionPtr(new OptionDefinition("option-1", 1, "empty")), "isc2");
|
||||
defs.addItem(OptionDefinitionPtr(new OptionDefinition("option-2", 2, "ipv6-address", true)),
|
||||
"isc2");
|
||||
}
|
||||
|
||||
@@ -552,21 +578,18 @@ GenericHostDataSourceTest::testReadOnlyDatabase(const char* valid_db_type) {
|
||||
|
||||
// Make sure that the host has been inserted and that the data can be
|
||||
// retrieved.
|
||||
ConstHostPtr host_by_id = hdsptr_->get6(subnet_id, host->getIdentifierType(),
|
||||
&host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ConstHostPtr host_by_id =
|
||||
hdsptr_->get6(subnet_id, host->getIdentifierType(),
|
||||
&host->getIdentifier()[0], host->getIdentifier().size());
|
||||
ASSERT_TRUE(host_by_id);
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, host_by_id));
|
||||
|
||||
// Close the database connection and reopen in "read-only" mode as
|
||||
// specified by the "VALID_READONLY_DB" parameter.
|
||||
HostDataSourceFactory::destroy();
|
||||
HostDataSourceFactory::create(connectionString(valid_db_type,
|
||||
VALID_NAME,
|
||||
VALID_HOST,
|
||||
VALID_READONLY_USER,
|
||||
VALID_PASSWORD,
|
||||
VALID_READONLY_DB));
|
||||
HostDataSourceFactory::create(connectionString(
|
||||
valid_db_type, VALID_NAME, VALID_HOST, VALID_READONLY_USER,
|
||||
VALID_PASSWORD, VALID_READONLY_DB));
|
||||
|
||||
hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
|
||||
|
||||
@@ -579,20 +602,21 @@ GenericHostDataSourceTest::testReadOnlyDatabase(const char* valid_db_type) {
|
||||
ASSERT_THROW(hdsptr_->rollback(), ReadOnlyDb);
|
||||
|
||||
// Reading from the database should still be possible, though.
|
||||
host_by_id = hdsptr_->get6(subnet_id, host->getIdentifierType(),
|
||||
&host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
host_by_id =
|
||||
hdsptr_->get6(subnet_id, host->getIdentifierType(),
|
||||
&host->getIdentifier()[0], host->getIdentifier().size());
|
||||
ASSERT_TRUE(host_by_id);
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, host_by_id));
|
||||
}
|
||||
|
||||
void GenericHostDataSourceTest::testBasic4(const Host::IdentifierType& id) {
|
||||
void
|
||||
GenericHostDataSourceTest::testBasic4(const Host::IdentifierType& id) {
|
||||
// Make sure we have the pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
// Create a host reservation.
|
||||
HostPtr host = initializeHost4("192.0.2.1", id);
|
||||
ASSERT_TRUE(host); // Make sure the host is generate properly.
|
||||
ASSERT_TRUE(host); // Make sure the host is generate properly.
|
||||
SubnetID subnet = host->getIPv4SubnetID();
|
||||
|
||||
// Try to add it to the host data source.
|
||||
@@ -610,8 +634,8 @@ void GenericHostDataSourceTest::testBasic4(const Host::IdentifierType& id) {
|
||||
compareHosts(host, from_hds);
|
||||
}
|
||||
|
||||
|
||||
void GenericHostDataSourceTest::testGetByIPv4(const Host::IdentifierType& id) {
|
||||
void
|
||||
GenericHostDataSourceTest::testGetByIPv4(const Host::IdentifierType& id) {
|
||||
// Make sure we have a pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
@@ -656,7 +680,8 @@ void GenericHostDataSourceTest::testGetByIPv4(const Host::IdentifierType& id) {
|
||||
}
|
||||
|
||||
void
|
||||
GenericHostDataSourceTest::testGet4ByIdentifier(const Host::IdentifierType& identifier_type) {
|
||||
GenericHostDataSourceTest::testGet4ByIdentifier(
|
||||
const Host::IdentifierType& identifier_type) {
|
||||
// Make sure we have a pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
@@ -673,15 +698,13 @@ GenericHostDataSourceTest::testGet4ByIdentifier(const Host::IdentifierType& iden
|
||||
SubnetID subnet1 = host1->getIPv4SubnetID();
|
||||
SubnetID subnet2 = host2->getIPv4SubnetID();
|
||||
|
||||
ConstHostPtr from_hds1 = hdsptr_->get4(subnet1,
|
||||
identifier_type,
|
||||
&host1->getIdentifier()[0],
|
||||
host1->getIdentifier().size());
|
||||
ConstHostPtr from_hds1 =
|
||||
hdsptr_->get4(subnet1, identifier_type, &host1->getIdentifier()[0],
|
||||
host1->getIdentifier().size());
|
||||
|
||||
ConstHostPtr from_hds2 = hdsptr_->get4(subnet2,
|
||||
identifier_type,
|
||||
&host2->getIdentifier()[0],
|
||||
host2->getIdentifier().size());
|
||||
ConstHostPtr from_hds2 =
|
||||
hdsptr_->get4(subnet2, identifier_type, &host2->getIdentifier()[0],
|
||||
host2->getIdentifier().size());
|
||||
|
||||
// Now let's check if we got what we expected.
|
||||
ASSERT_TRUE(from_hds1);
|
||||
@@ -690,7 +713,8 @@ GenericHostDataSourceTest::testGet4ByIdentifier(const Host::IdentifierType& iden
|
||||
compareHosts(host2, from_hds2);
|
||||
}
|
||||
|
||||
void GenericHostDataSourceTest::testHWAddrNotClientId() {
|
||||
void
|
||||
GenericHostDataSourceTest::testHWAddrNotClientId() {
|
||||
// Make sure we have a pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
@@ -707,21 +731,22 @@ void GenericHostDataSourceTest::testHWAddrNotClientId() {
|
||||
DuidPtr duid = HWAddrToDuid(host->getHWAddress());
|
||||
|
||||
// Get the host by HW address (should succeed)
|
||||
ConstHostPtr by_hwaddr = hdsptr_->get4(subnet, Host::IDENT_HWADDR,
|
||||
&host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ConstHostPtr by_hwaddr =
|
||||
hdsptr_->get4(subnet, Host::IDENT_HWADDR, &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
|
||||
// Get the host by DUID (should fail)
|
||||
ConstHostPtr by_duid = hdsptr_->get4(subnet, Host::IDENT_DUID,
|
||||
&host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ConstHostPtr by_duid =
|
||||
hdsptr_->get4(subnet, Host::IDENT_DUID, &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
|
||||
// Now let's check if we got what we expected.
|
||||
EXPECT_TRUE(by_hwaddr);
|
||||
EXPECT_FALSE(by_duid);
|
||||
}
|
||||
|
||||
void GenericHostDataSourceTest::testClientIdNotHWAddr() {
|
||||
void
|
||||
GenericHostDataSourceTest::testClientIdNotHWAddr() {
|
||||
// Make sure we have a pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
@@ -738,15 +763,14 @@ void GenericHostDataSourceTest::testClientIdNotHWAddr() {
|
||||
HWAddrPtr hwaddr = DuidToHWAddr(host->getDuid());
|
||||
|
||||
// Get the host by DUID (should succeed)
|
||||
ConstHostPtr by_duid = hdsptr_->get4(subnet, Host::IDENT_DUID,
|
||||
&host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
|
||||
ConstHostPtr by_duid =
|
||||
hdsptr_->get4(subnet, Host::IDENT_DUID, &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
|
||||
// Get the host by HW address (should fail)
|
||||
ConstHostPtr by_hwaddr = hdsptr_->get4(subnet, Host::IDENT_HWADDR,
|
||||
&host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ConstHostPtr by_hwaddr =
|
||||
hdsptr_->get4(subnet, Host::IDENT_HWADDR, &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
|
||||
// Now let's check if we got what we expected.
|
||||
EXPECT_TRUE(by_duid);
|
||||
@@ -755,7 +779,6 @@ void GenericHostDataSourceTest::testClientIdNotHWAddr() {
|
||||
|
||||
void
|
||||
GenericHostDataSourceTest::testHostname(std::string name, int num) {
|
||||
|
||||
// Make sure we have a pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
@@ -767,7 +790,6 @@ GenericHostDataSourceTest::testHostname(std::string name, int num) {
|
||||
|
||||
// Prepare a vector of hosts with unique hostnames
|
||||
for (int i = 0; i < num; ++i) {
|
||||
|
||||
addr = IOAddress::increase(addr);
|
||||
|
||||
HostPtr host = initializeHost4(addr.toText(), Host::IDENT_DUID);
|
||||
@@ -784,21 +806,19 @@ GenericHostDataSourceTest::testHostname(std::string name, int num) {
|
||||
}
|
||||
|
||||
// Now add them all to the host data source.
|
||||
for (vector<HostPtr>::const_iterator it = hosts.begin();
|
||||
it != hosts.end(); ++it) {
|
||||
for (vector<HostPtr>::const_iterator it = hosts.begin(); it != hosts.end();
|
||||
++it) {
|
||||
// Try to add both of the to the host data source.
|
||||
ASSERT_NO_THROW(hdsptr_->add(*it));
|
||||
}
|
||||
|
||||
// And finally retrieve them one by one and check
|
||||
// if the hostname was preserved.
|
||||
for (vector<HostPtr>::const_iterator it = hosts.begin();
|
||||
it != hosts.end(); ++it) {
|
||||
|
||||
for (vector<HostPtr>::const_iterator it = hosts.begin(); it != hosts.end();
|
||||
++it) {
|
||||
ConstHostPtr from_hds;
|
||||
ASSERT_NO_THROW(from_hds = hdsptr_->get4(
|
||||
(*it)->getIPv4SubnetID(),
|
||||
(*it)->getIPv4Reservation()));
|
||||
ASSERT_NO_THROW(from_hds = hdsptr_->get4((*it)->getIPv4SubnetID(),
|
||||
(*it)->getIPv4Reservation()));
|
||||
ASSERT_TRUE(from_hds);
|
||||
|
||||
EXPECT_EQ((*it)->getHostname(), from_hds->getHostname());
|
||||
@@ -848,7 +868,6 @@ GenericHostDataSourceTest::testUserContext(ConstElementPtr user_context) {
|
||||
void
|
||||
GenericHostDataSourceTest::testMultipleSubnets(int subnets,
|
||||
const Host::IdentifierType& id) {
|
||||
|
||||
// Make sure we have a pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
@@ -865,16 +884,15 @@ GenericHostDataSourceTest::testMultipleSubnets(int subnets,
|
||||
// Now check that the reservations can be retrieved by IPv4 address from
|
||||
// each subnet separately.
|
||||
for (int i = 0; i < subnets; ++i) {
|
||||
|
||||
// Try to retrieve the host by IPv4 address.
|
||||
ConstHostPtr from_hds = hdsptr_->get4(i + 1000, host->getIPv4Reservation());
|
||||
ConstHostPtr from_hds =
|
||||
hdsptr_->get4(i + 1000, host->getIPv4Reservation());
|
||||
|
||||
ASSERT_TRUE(from_hds);
|
||||
EXPECT_EQ(i + 1000, from_hds->getIPv4SubnetID());
|
||||
|
||||
// Try to retrieve the host by either HW address of client-id
|
||||
from_hds = hdsptr_->get4(i + 1000,
|
||||
id, &host->getIdentifier()[0],
|
||||
from_hds = hdsptr_->get4(i + 1000, id, &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ASSERT_TRUE(from_hds);
|
||||
EXPECT_EQ(i + 1000, from_hds->getIPv4SubnetID());
|
||||
@@ -886,6 +904,12 @@ GenericHostDataSourceTest::testMultipleSubnets(int subnets,
|
||||
|
||||
// Verify that the values returned are proper.
|
||||
int i = 0;
|
||||
if (hdsptr_->getType() == "cql") {
|
||||
// There is no ORDER BY in Cassandra. Order here. Remove this if entries
|
||||
// are eventually implemented as ordered in the Cassandra host data
|
||||
// source.
|
||||
std::sort(all_by_addr.begin(), all_by_addr.end(), compareHostsForSort4);
|
||||
}
|
||||
for (ConstHostCollection::const_iterator it = all_by_addr.begin();
|
||||
it != all_by_addr.end(); ++it) {
|
||||
EXPECT_EQ(IOAddress("192.0.2.1"), (*it)->getIPv4Reservation());
|
||||
@@ -893,13 +917,18 @@ GenericHostDataSourceTest::testMultipleSubnets(int subnets,
|
||||
}
|
||||
|
||||
// Finally, check that the hosts can be retrieved by HW address or DUID
|
||||
ConstHostCollection all_by_id =
|
||||
hdsptr_->getAll(id, &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ConstHostCollection all_by_id = hdsptr_->getAll(
|
||||
id, &host->getIdentifier()[0], host->getIdentifier().size());
|
||||
ASSERT_EQ(subnets, all_by_id.size());
|
||||
|
||||
// Check that the returned values are as expected.
|
||||
i = 0;
|
||||
if (hdsptr_->getType() == "cql") {
|
||||
// There is no ORDER BY in Cassandra. Order here. Remove this if entries
|
||||
// are eventually implemented as ordered in the Cassandra host data
|
||||
// source.
|
||||
std::sort(all_by_id.begin(), all_by_id.end(), compareHostsForSort4);
|
||||
}
|
||||
for (ConstHostCollection::const_iterator it = all_by_id.begin();
|
||||
it != all_by_id.end(); ++it) {
|
||||
EXPECT_EQ(IOAddress("192.0.2.1"), (*it)->getIPv4Reservation());
|
||||
@@ -907,7 +936,8 @@ GenericHostDataSourceTest::testMultipleSubnets(int subnets,
|
||||
}
|
||||
}
|
||||
|
||||
void GenericHostDataSourceTest::testGet6ByHWAddr() {
|
||||
void
|
||||
GenericHostDataSourceTest::testGet6ByHWAddr() {
|
||||
// Make sure we have the pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
@@ -943,7 +973,8 @@ void GenericHostDataSourceTest::testGet6ByHWAddr() {
|
||||
compareHosts(host2, from_hds2);
|
||||
}
|
||||
|
||||
void GenericHostDataSourceTest::testGet6ByClientId() {
|
||||
void
|
||||
GenericHostDataSourceTest::testGet6ByClientId() {
|
||||
// Make sure we have the pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
@@ -981,7 +1012,6 @@ void GenericHostDataSourceTest::testGet6ByClientId() {
|
||||
|
||||
void
|
||||
GenericHostDataSourceTest::testSubnetId6(int subnets, Host::IdentifierType id) {
|
||||
|
||||
// Make sure we have a pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
@@ -1005,7 +1035,6 @@ GenericHostDataSourceTest::testSubnetId6(int subnets, Host::IdentifierType id) {
|
||||
|
||||
// Check that the reservations can be retrieved from each subnet separately.
|
||||
for (int i = 0; i < subnets; ++i) {
|
||||
|
||||
// Try to retrieve the host
|
||||
ConstHostPtr from_hds = hdsptr_->get6(i + 1000, id, &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
@@ -1021,6 +1050,11 @@ GenericHostDataSourceTest::testSubnetId6(int subnets, Host::IdentifierType id) {
|
||||
|
||||
// Check that the returned values are as expected.
|
||||
int i = 0;
|
||||
if (hdsptr_->getType() == "cql") {
|
||||
// There is no ORDER BY in Cassandra. Order here. Remove this if entries
|
||||
// are implemented as ordered in the Cassandra host data source.
|
||||
std::sort(all_by_id.begin(), all_by_id.end(), compareHostsForSort6);
|
||||
}
|
||||
for (ConstHostCollection::const_iterator it = all_by_id.begin();
|
||||
it != all_by_id.end(); ++it) {
|
||||
EXPECT_EQ(IOAddress("0.0.0.0"), (*it)->getIPv4Reservation());
|
||||
@@ -1028,8 +1062,8 @@ GenericHostDataSourceTest::testSubnetId6(int subnets, Host::IdentifierType id) {
|
||||
}
|
||||
}
|
||||
|
||||
void GenericHostDataSourceTest::testGetByIPv6(Host::IdentifierType id,
|
||||
bool prefix) {
|
||||
void
|
||||
GenericHostDataSourceTest::testGetByIPv6(Host::IdentifierType id, bool prefix) {
|
||||
// Make sure we have a pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
@@ -1071,7 +1105,8 @@ void GenericHostDataSourceTest::testGetByIPv6(Host::IdentifierType id,
|
||||
EXPECT_FALSE(hdsptr_->get6(IOAddress("2001:db8::5"), len));
|
||||
}
|
||||
|
||||
void GenericHostDataSourceTest::testGetBySubnetIPv6() {
|
||||
void
|
||||
GenericHostDataSourceTest::testGetBySubnetIPv6() {
|
||||
// Make sure we have a pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
@@ -1088,14 +1123,10 @@ void GenericHostDataSourceTest::testGetBySubnetIPv6() {
|
||||
ASSERT_NO_THROW(hdsptr_->add(host4));
|
||||
|
||||
// And then try to retrieve them back.
|
||||
ConstHostPtr from_hds1 = hdsptr_->get6(host1->getIPv6SubnetID(),
|
||||
IOAddress("2001:db8:1::"));
|
||||
ConstHostPtr from_hds2 = hdsptr_->get6(host2->getIPv6SubnetID(),
|
||||
IOAddress("2001:db8:2::"));
|
||||
ConstHostPtr from_hds3 = hdsptr_->get6(host3->getIPv6SubnetID(),
|
||||
IOAddress("2001:db8:3::"));
|
||||
ConstHostPtr from_hds4 = hdsptr_->get6(host4->getIPv6SubnetID(),
|
||||
IOAddress("2001:db8:4::"));
|
||||
ConstHostPtr from_hds1 = hdsptr_->get6(host1->getIPv6SubnetID(), IOAddress("2001:db8:1::"));
|
||||
ConstHostPtr from_hds2 = hdsptr_->get6(host2->getIPv6SubnetID(), IOAddress("2001:db8:2::"));
|
||||
ConstHostPtr from_hds3 = hdsptr_->get6(host3->getIPv6SubnetID(), IOAddress("2001:db8:3::"));
|
||||
ConstHostPtr from_hds4 = hdsptr_->get6(host4->getIPv6SubnetID(), IOAddress("2001:db8:4::"));
|
||||
|
||||
// Make sure we got something back.
|
||||
ASSERT_TRUE(from_hds1);
|
||||
@@ -1110,8 +1141,8 @@ void GenericHostDataSourceTest::testGetBySubnetIPv6() {
|
||||
compareHosts(host4, from_hds4);
|
||||
}
|
||||
|
||||
|
||||
void GenericHostDataSourceTest::testAddDuplicate6WithSameDUID() {
|
||||
void
|
||||
GenericHostDataSourceTest::testAddDuplicate6WithSameDUID() {
|
||||
// Make sure we have the pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
@@ -1125,7 +1156,8 @@ void GenericHostDataSourceTest::testAddDuplicate6WithSameDUID() {
|
||||
ASSERT_THROW(hdsptr_->add(host), DuplicateEntry);
|
||||
}
|
||||
|
||||
void GenericHostDataSourceTest::testAddDuplicate6WithSameHWAddr() {
|
||||
void
|
||||
GenericHostDataSourceTest::testAddDuplicate6WithSameHWAddr() {
|
||||
// Make sure we have the pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
@@ -1139,7 +1171,8 @@ void GenericHostDataSourceTest::testAddDuplicate6WithSameHWAddr() {
|
||||
ASSERT_THROW(hdsptr_->add(host), DuplicateEntry);
|
||||
}
|
||||
|
||||
void GenericHostDataSourceTest::testAddDuplicate4() {
|
||||
void
|
||||
GenericHostDataSourceTest::testAddDuplicate4() {
|
||||
// Make sure we have the pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
@@ -1164,7 +1197,8 @@ void GenericHostDataSourceTest::testAddDuplicate4() {
|
||||
EXPECT_NO_THROW(hdsptr_->add(host));
|
||||
}
|
||||
|
||||
void GenericHostDataSourceTest::testAddr6AndPrefix(){
|
||||
void
|
||||
GenericHostDataSourceTest::testAddr6AndPrefix() {
|
||||
// Make sure we have the pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
|
||||
@@ -1179,10 +1213,9 @@ void GenericHostDataSourceTest::testAddr6AndPrefix(){
|
||||
ASSERT_NO_THROW(hdsptr_->add(host));
|
||||
|
||||
// Get this host by DUID
|
||||
ConstHostPtr from_hds = hdsptr_->get6(host->getIPv6SubnetID(),
|
||||
Host::IDENT_DUID,
|
||||
&host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ConstHostPtr from_hds =
|
||||
hdsptr_->get6(host->getIPv6SubnetID(), Host::IDENT_DUID,
|
||||
&host->getIdentifier()[0], host->getIdentifier().size());
|
||||
|
||||
// Make sure we got something back
|
||||
ASSERT_TRUE(from_hds);
|
||||
@@ -1192,7 +1225,8 @@ void GenericHostDataSourceTest::testAddr6AndPrefix(){
|
||||
from_hds->getIPv6Reservations());
|
||||
}
|
||||
|
||||
void GenericHostDataSourceTest::testMultipleReservations(){
|
||||
void
|
||||
GenericHostDataSourceTest::testMultipleReservations() {
|
||||
// Make sure we have the pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
uint8_t len = 128;
|
||||
@@ -1212,7 +1246,6 @@ void GenericHostDataSourceTest::testMultipleReservations(){
|
||||
|
||||
ASSERT_NO_THROW(hdsptr_->add(host));
|
||||
|
||||
|
||||
ConstHostPtr from_hds = hdsptr_->get6(IOAddress("2001:db8::1"), len);
|
||||
|
||||
// Make sure we got something back
|
||||
@@ -1222,7 +1255,8 @@ void GenericHostDataSourceTest::testMultipleReservations(){
|
||||
compareHosts(host, from_hds);
|
||||
}
|
||||
|
||||
void GenericHostDataSourceTest::testMultipleReservationsDifferentOrder(){
|
||||
void
|
||||
GenericHostDataSourceTest::testMultipleReservationsDifferentOrder() {
|
||||
// Make sure we have the pointer to the host data source.
|
||||
ASSERT_TRUE(hdsptr_);
|
||||
uint8_t len = 128;
|
||||
@@ -1247,8 +1281,8 @@ void GenericHostDataSourceTest::testMultipleReservationsDifferentOrder(){
|
||||
host2->addReservation(resv1);
|
||||
|
||||
// Check if reservations are the same
|
||||
compareReservations6(host1->getIPv6Reservations(), host2->getIPv6Reservations());
|
||||
|
||||
compareReservations6(host1->getIPv6Reservations(),
|
||||
host2->getIPv6Reservations());
|
||||
}
|
||||
|
||||
void GenericHostDataSourceTest::testOptionsReservations4(const bool formatted,
|
||||
@@ -1262,19 +1296,20 @@ void GenericHostDataSourceTest::testOptionsReservations4(const bool formatted,
|
||||
SubnetID subnet_id = host->getIPv4SubnetID();
|
||||
|
||||
// getAll4(address)
|
||||
ConstHostCollection hosts_by_addr = hdsptr_->getAll4(host->getIPv4Reservation());
|
||||
ConstHostCollection hosts_by_addr =
|
||||
hdsptr_->getAll4(host->getIPv4Reservation());
|
||||
ASSERT_EQ(1, hosts_by_addr.size());
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, *hosts_by_addr.begin()));
|
||||
|
||||
// get4(subnet_id, identifier_type, identifier, identifier_size)
|
||||
ConstHostPtr host_by_id = hdsptr_->get4(subnet_id,
|
||||
host->getIdentifierType(),
|
||||
&host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ConstHostPtr host_by_id =
|
||||
hdsptr_->get4(subnet_id, host->getIdentifierType(),
|
||||
&host->getIdentifier()[0], host->getIdentifier().size());
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, host_by_id));
|
||||
|
||||
// get4(subnet_id, address)
|
||||
ConstHostPtr host_by_addr = hdsptr_->get4(subnet_id, IOAddress("192.0.2.5"));
|
||||
ConstHostPtr host_by_addr =
|
||||
hdsptr_->get4(subnet_id, IOAddress("192.0.2.5"));
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, host_by_addr));
|
||||
}
|
||||
|
||||
@@ -1289,9 +1324,9 @@ void GenericHostDataSourceTest::testOptionsReservations6(const bool formatted,
|
||||
SubnetID subnet_id = host->getIPv6SubnetID();
|
||||
|
||||
// get6(subnet_id, identifier_type, identifier, identifier_size)
|
||||
ConstHostPtr host_by_id = hdsptr_->get6(subnet_id, host->getIdentifierType(),
|
||||
&host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ConstHostPtr host_by_id =
|
||||
hdsptr_->get6(subnet_id, host->getIdentifierType(),
|
||||
&host->getIdentifier()[0], host->getIdentifier().size());
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, host_by_id));
|
||||
|
||||
// get6(address, prefix_len)
|
||||
@@ -1299,7 +1334,8 @@ void GenericHostDataSourceTest::testOptionsReservations6(const bool formatted,
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, host_by_addr));
|
||||
}
|
||||
|
||||
void GenericHostDataSourceTest::testOptionsReservations46(const bool formatted) {
|
||||
void
|
||||
GenericHostDataSourceTest::testOptionsReservations46(const bool formatted) {
|
||||
HostPtr host = initializeHost6("2001:db8::1", Host::IDENT_HWADDR, false);
|
||||
|
||||
// Add a bunch of DHCPv4 and DHCPv6 options for the host.
|
||||
@@ -1308,9 +1344,9 @@ void GenericHostDataSourceTest::testOptionsReservations46(const bool formatted)
|
||||
ASSERT_NO_THROW(hdsptr_->add(host));
|
||||
|
||||
// getAll(identifier_type, identifier, identifier_size)
|
||||
ConstHostCollection hosts_by_id = hdsptr_->getAll(host->getIdentifierType(),
|
||||
&host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ConstHostCollection hosts_by_id =
|
||||
hdsptr_->getAll(host->getIdentifierType(), &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ASSERT_EQ(1, hosts_by_id.size());
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, *hosts_by_id.begin()));
|
||||
}
|
||||
@@ -1344,8 +1380,9 @@ GenericHostDataSourceTest::testMultipleClientClasses4() {
|
||||
// Fetch the host via:
|
||||
// getAll(const Host::IdentifierType, const uint8_t* identifier_begin,
|
||||
// const size_t identifier_len) const;
|
||||
hosts_by_id = hdsptr_->getAll(host->getIdentifierType(), &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
hosts_by_id =
|
||||
hdsptr_->getAll(host->getIdentifierType(), &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ASSERT_EQ(1, hosts_by_id.size());
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, *hosts_by_id.begin()));
|
||||
|
||||
@@ -1363,10 +1400,12 @@ GenericHostDataSourceTest::testMultipleClientClasses4() {
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, from_hds));
|
||||
|
||||
// Fetch the host via
|
||||
// get4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
|
||||
// get4(const SubnetID& subnet_id, const Host::IdentifierType&
|
||||
// identifier_type,
|
||||
// const uint8_t* identifier_begin, const size_t identifier_len) const;
|
||||
from_hds = hdsptr_->get4(subnet_id, host->getIdentifierType(), &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
from_hds =
|
||||
hdsptr_->get4(subnet_id, host->getIdentifierType(),
|
||||
&host->getIdentifier()[0], host->getIdentifier().size());
|
||||
ASSERT_TRUE(from_hds);
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, from_hds));
|
||||
|
||||
@@ -1406,23 +1445,26 @@ GenericHostDataSourceTest::testMultipleClientClasses6() {
|
||||
// getAll(const Host::IdentifierType& identifier_type,
|
||||
// const uint8_t* identifier_begin,
|
||||
// const size_t identifier_len) const;
|
||||
hosts_by_id = hdsptr_->getAll(host->getIdentifierType(), &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
hosts_by_id =
|
||||
hdsptr_->getAll(host->getIdentifierType(), &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ASSERT_EQ(1, hosts_by_id.size());
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, *hosts_by_id.begin()));
|
||||
|
||||
// get6(const SubnetID& subnet_id, const DuidPtr& duid,
|
||||
// const HWAddrPtr& hwaddr = HWAddrPtr()) const;
|
||||
ConstHostPtr from_hds = hdsptr_->get6(subnet_id, DuidPtr(), host->getHWAddress());
|
||||
ConstHostPtr from_hds =
|
||||
hdsptr_->get6(subnet_id, DuidPtr(), host->getHWAddress());
|
||||
ASSERT_TRUE(from_hds);
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, from_hds));
|
||||
|
||||
// Fetch the host via:
|
||||
// get6(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
|
||||
// get6(const SubnetID& subnet_id, const Host::IdentifierType&
|
||||
// identifier_type,
|
||||
// const uint8_t* identifier_begin, const size_t identifier_len) const;
|
||||
from_hds = hdsptr_->get6(subnet_id, Host::IDENT_HWADDR,
|
||||
&host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
from_hds =
|
||||
hdsptr_->get6(subnet_id, Host::IDENT_HWADDR, &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ASSERT_TRUE(from_hds);
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, from_hds));
|
||||
|
||||
@@ -1464,9 +1506,9 @@ GenericHostDataSourceTest::testMultipleClientClassesBoth() {
|
||||
SubnetID subnet_id = host->getIPv6SubnetID();
|
||||
|
||||
// Fetch the host from the source.
|
||||
ConstHostPtr from_hds = hdsptr_->get6(subnet_id, Host::IDENT_HWADDR,
|
||||
&host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ConstHostPtr from_hds =
|
||||
hdsptr_->get6(subnet_id, Host::IDENT_HWADDR, &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ASSERT_TRUE(from_hds);
|
||||
|
||||
// Verify they match.
|
||||
@@ -1501,8 +1543,9 @@ GenericHostDataSourceTest::testMessageFields4() {
|
||||
// Fetch the host via:
|
||||
// getAll(const Host::IdentifierType, const uint8_t* identifier_begin,
|
||||
// const size_t identifier_len) const;
|
||||
hosts_by_id = hdsptr_->getAll(host->getIdentifierType(), &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
hosts_by_id =
|
||||
hdsptr_->getAll(host->getIdentifierType(), &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
ASSERT_EQ(1, hosts_by_id.size());
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, *hosts_by_id.begin()));
|
||||
|
||||
@@ -1520,10 +1563,12 @@ GenericHostDataSourceTest::testMessageFields4() {
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, from_hds));
|
||||
|
||||
// Fetch the host via
|
||||
// get4(const SubnetID& subnet_id, const Host::IdentifierType& identifier_type,
|
||||
// get4(const SubnetID& subnet_id, const Host::IdentifierType&
|
||||
// identifier_type,
|
||||
// const uint8_t* identifier_begin, const size_t identifier_len) const;
|
||||
from_hds = hdsptr_->get4(subnet_id, host->getIdentifierType(), &host->getIdentifier()[0],
|
||||
host->getIdentifier().size());
|
||||
from_hds =
|
||||
hdsptr_->get4(subnet_id, host->getIdentifierType(),
|
||||
&host->getIdentifier()[0], host->getIdentifier().size());
|
||||
ASSERT_TRUE(from_hds);
|
||||
ASSERT_NO_FATAL_FAILURE(compareHosts(host, from_hds));
|
||||
|
||||
@@ -1774,6 +1819,6 @@ GenericHostDataSourceTest::testMultipleHosts6() {
|
||||
ASSERT_NO_THROW(hdsptr_->add(host2));
|
||||
}
|
||||
|
||||
}; // namespace test
|
||||
}; // namespace dhcp
|
||||
}; // namespace isc
|
||||
} // namespace test
|
||||
} // namespace dhcp
|
||||
} // namespace isc
|
||||
|
@@ -86,6 +86,13 @@ public:
|
||||
/// @return Identifier in textual form acceptable by Host constructor
|
||||
std::vector<uint8_t> generateIdentifier(const bool new_identifier = true);
|
||||
|
||||
/// @brief Checks if the reservation is in the range of reservations.
|
||||
///
|
||||
/// @param resrv Reservation to be searched for.
|
||||
/// @param range Range of reservations returned by the @c Host object
|
||||
/// in which the reservation will be searched
|
||||
bool reservationExists(const IPv6Resrv& resrv, const IPv6ResrvRange& range);
|
||||
|
||||
/// @brief Compares hardware addresses of the two hosts.
|
||||
///
|
||||
/// This method compares two hardware address and uses gtest
|
||||
@@ -96,9 +103,8 @@ public:
|
||||
/// @param host2 second host to be compared
|
||||
/// @param expect_match true = HW addresses expected to be the same,
|
||||
/// false = HW addresses expected to be different
|
||||
void
|
||||
compareHwaddrs(const ConstHostPtr& host1, const ConstHostPtr& host2,
|
||||
bool expect_match);
|
||||
void compareHwaddrs(const ConstHostPtr& host1, const ConstHostPtr& host2,
|
||||
bool expect_match);
|
||||
|
||||
/// @brief Compares DUIDs of the two hosts.
|
||||
///
|
||||
@@ -110,9 +116,8 @@ public:
|
||||
/// @param host2 second host to be compared
|
||||
/// @param expect_match true = DUIDs expected to be the same,
|
||||
/// false = DUIDs expected to be different
|
||||
void
|
||||
compareDuids(const ConstHostPtr& host1, const ConstHostPtr& host2,
|
||||
bool expect_match);
|
||||
void compareDuids(const ConstHostPtr& host1, const ConstHostPtr& host2,
|
||||
bool expect_match);
|
||||
|
||||
/// @brief Compares two hosts
|
||||
///
|
||||
@@ -122,6 +127,18 @@ public:
|
||||
/// @param host2 second host to compare
|
||||
void compareHosts(const ConstHostPtr& host1, const ConstHostPtr& host2);
|
||||
|
||||
/// @brief Used to sort a host collection by IPv4 subnet id.
|
||||
/// @param host1 first host to be compared
|
||||
/// @param host2 second host to be compared
|
||||
static bool compareHostsForSort4(const ConstHostPtr& host1,
|
||||
const ConstHostPtr& host2);
|
||||
|
||||
/// @brief Used to sort a host collection by IPv6 subnet id.
|
||||
/// @param host1 first host to be compared
|
||||
/// @param host2 second host to be compared
|
||||
static bool compareHostsForSort6(const ConstHostPtr& host1,
|
||||
const ConstHostPtr& host2);
|
||||
|
||||
/// @brief Compares two IPv6 reservation lists.
|
||||
///
|
||||
/// This method uses gtest macros to signal errors.
|
||||
@@ -429,7 +446,7 @@ public:
|
||||
void testClientIdNotHWAddr();
|
||||
|
||||
/// @brief Test adds specified number of hosts with unique hostnames, then
|
||||
/// retrieves them and checks that the hostnames are set properly.
|
||||
/// retrives them and checks that the hostnames are set properly.
|
||||
///
|
||||
/// Uses gtest macros to report failures.
|
||||
///
|
||||
@@ -628,8 +645,8 @@ public:
|
||||
|
||||
};
|
||||
|
||||
}; // namespace test
|
||||
}; // namespace dhcp
|
||||
}; // namespace isc
|
||||
} // namespace test
|
||||
} // namespace dhcp
|
||||
} // namespace isc
|
||||
|
||||
#endif
|
||||
|
@@ -5,15 +5,19 @@
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <config.h>
|
||||
#include <string>
|
||||
|
||||
#include <cassandra.h>
|
||||
|
||||
#include <dhcpsrv/cql_connection.h>
|
||||
#include <dhcpsrv/testutils/cql_schema.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -25,11 +29,12 @@ const char* CQL_VALID_TYPE = "type=cql";
|
||||
|
||||
string
|
||||
validCqlConnectionString() {
|
||||
return (connectionString(CQL_VALID_TYPE, VALID_NAME, VALID_HOST,
|
||||
VALID_USER, VALID_PASSWORD));
|
||||
return (connectionString(CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER,
|
||||
VALID_PASSWORD));
|
||||
}
|
||||
|
||||
bool softWipeEnabled() {
|
||||
bool
|
||||
softWipeEnabled() {
|
||||
const char* const env = getenv("KEA_TEST_CASSANDRA_WIPE");
|
||||
if (env && (string(env) == string("soft"))) {
|
||||
return (true);
|
||||
@@ -38,26 +43,28 @@ bool softWipeEnabled() {
|
||||
return (false);
|
||||
}
|
||||
|
||||
void destroyCqlSchema(bool force_wipe, bool show_err) {
|
||||
void
|
||||
destroyCqlSchema(bool force_wipe, bool show_err) {
|
||||
if (force_wipe || !softWipeEnabled()) {
|
||||
// Do full wipe
|
||||
runCqlScript(DATABASE_SCRIPTS_DIR, "cql/dhcpdb_drop.cql", show_err);
|
||||
} else {
|
||||
|
||||
// do soft wipe (just remove the data, not the structures)
|
||||
runCqlScript(DATABASE_SCRIPTS_DIR, "cql/soft_wipe.cql", show_err);
|
||||
}
|
||||
}
|
||||
|
||||
void createCqlSchema(bool force_wipe, bool show_err) {
|
||||
void
|
||||
createCqlSchema(bool force_wipe, bool show_err) {
|
||||
if (force_wipe || !softWipeEnabled()) {
|
||||
runCqlScript(DATABASE_SCRIPTS_DIR, "cql/dhcpdb_create.cql",
|
||||
show_err);
|
||||
runCqlScript(DATABASE_SCRIPTS_DIR, "cql/dhcpdb_create.cql", show_err);
|
||||
}
|
||||
}
|
||||
|
||||
void runCqlScript(const std::string& path, const std::string& script_name,
|
||||
bool show_err) {
|
||||
void
|
||||
runCqlScript(const std::string& path,
|
||||
const std::string& script_name,
|
||||
bool show_err) {
|
||||
std::ostringstream cmd;
|
||||
cmd << "cqlsh -u keatest -p keatest -k keatest";
|
||||
if (!show_err) {
|
||||
@@ -76,7 +83,6 @@ void runCqlScript(const std::string& path, const std::string& script_name,
|
||||
ASSERT_EQ(0, retval) << "runCqlSchema failed:" << cmd.str();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
} // namespace test
|
||||
} // namespace dhcp
|
||||
} // namespace isc
|
||||
|
@@ -54,7 +54,7 @@ void createCqlSchema(bool force_wipe, bool show_err = false);
|
||||
|
||||
/// @brief Run a CQL script against the CQL unit test database
|
||||
///
|
||||
/// Submits the given SQL script to CQL via cqlsh CLI. The output of
|
||||
/// Submits the given CQL script to CQL via cqlsh CLI. The output of
|
||||
/// stderr is suppressed unless the parameter, show_err is true. The is done
|
||||
/// to suppress warnings that might otherwise make test output needlessly
|
||||
/// noisy. A gtest assertion occurs if the script fails to execute.
|
||||
|
2
src/share/database/scripts/cql/.gitignore
vendored
2
src/share/database/scripts/cql/.gitignore
vendored
@@ -0,0 +1,2 @@
|
||||
upgrade_1.0_to_2.0.sh
|
||||
|
||||
|
@@ -3,7 +3,7 @@ SUBDIRS = .
|
||||
sqlscriptsdir = ${datarootdir}/${PACKAGE_NAME}/scripts/cql
|
||||
sqlscripts_DATA = dhcpdb_create.cql
|
||||
sqlscripts_DATA += dhcpdb_drop.cql
|
||||
sqlscripts_DATA += upgrade_1.0_to_2.0.sh
|
||||
sqlscripts_DATA += soft_wipe.cql
|
||||
|
||||
|
||||
EXTRA_DIST = ${sqlscripts_DATA}
|
||||
|
@@ -185,3 +185,49 @@ CREATE TABLE IF NOT EXISTS schema_version (
|
||||
INSERT INTO schema_version (version, minor) VALUES (1, 0);
|
||||
|
||||
-- This line concludes database initialization to version 1.0.
|
||||
|
||||
-- This line starts database upgrade to version 2.0
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `host_reservations`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS host_reservations (
|
||||
host_identifier blob,
|
||||
host_identifier_type int,
|
||||
host_ipv4_subnet_id int,
|
||||
host_ipv6_subnet_id int,
|
||||
host_ipv4_address int,
|
||||
hostname text,
|
||||
host_ipv4_client_classes text,
|
||||
host_ipv6_client_classes text,
|
||||
-- reservation
|
||||
reserved_ipv6_prefix_address text,
|
||||
reserved_ipv6_prefix_length int,
|
||||
reserved_ipv6_prefix_address_type int,
|
||||
iaid int,
|
||||
-- option
|
||||
option_universe int,
|
||||
option_code int,
|
||||
option_value blob,
|
||||
option_formatted_value text,
|
||||
option_space text,
|
||||
option_is_persistent boolean,
|
||||
option_client_class text,
|
||||
option_subnet_id int,
|
||||
id bigint,
|
||||
PRIMARY KEY ((id))
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS host_reservationsindex1 ON host_reservations (host_identifier);
|
||||
CREATE INDEX IF NOT EXISTS host_reservationsindex2 ON host_reservations (host_identifier_type);
|
||||
CREATE INDEX IF NOT EXISTS host_reservationsindex3 ON host_reservations (host_ipv4_subnet_id);
|
||||
CREATE INDEX IF NOT EXISTS host_reservationsindex4 ON host_reservations (host_ipv6_subnet_id);
|
||||
CREATE INDEX IF NOT EXISTS host_reservationsindex5 ON host_reservations (host_ipv4_address);
|
||||
CREATE INDEX IF NOT EXISTS host_reservationsindex6 ON host_reservations (reserved_ipv6_prefix_address);
|
||||
CREATE INDEX IF NOT EXISTS host_reservationsindex7 ON host_reservations (reserved_ipv6_prefix_length);
|
||||
|
||||
TRUNCATE SCHEMA_VERSION;
|
||||
INSERT INTO schema_version (version, minor) VALUES(2, 0);
|
||||
|
||||
-- This line concludes database upgrade to version 2.0
|
||||
|
||||
|
@@ -19,6 +19,8 @@
|
||||
|
||||
TRUNCATE TABLE lease4;
|
||||
TRUNCATE TABLE lease6;
|
||||
TRUNCATE TABLE hosts;
|
||||
TRUNCATE TABLE dhcp4_options;
|
||||
TRUNCATE TABLE dhcp6_options;
|
||||
TRUNCATE TABLE lease6_types;
|
||||
TRUNCATE TABLE lease_hwaddr_source;
|
||||
TRUNCATE TABLE lease_state;
|
||||
TRUNCATE TABLE schema_version;
|
||||
TRUNCATE TABLE host_reservations;
|
||||
|
63
src/share/database/scripts/cql/upgrade_1.0_to_2.0.sh.in
Normal file
63
src/share/database/scripts/cql/upgrade_1.0_to_2.0.sh.in
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
|
||||
prefix=@prefix@
|
||||
# Include utilities. Use installed version if available and
|
||||
# use build version if it isn't.
|
||||
if [ -e @datarootdir@/@PACKAGE_NAME@/scripts/admin-utils.sh ]; then
|
||||
. @datarootdir@/@PACKAGE_NAME@/scripts/admin-utils.sh
|
||||
else
|
||||
. @abs_top_builddir@/src/bin/admin/admin-utils.sh
|
||||
fi
|
||||
|
||||
version=$(cql_version "$@")
|
||||
|
||||
if [ "${version}" != "1.0" ]; then
|
||||
printf "This script upgrades 1.0 to 2.0. Reported version is %s. Skipping upgrade.\n" "${version}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cqlsh "$@" <<EOF
|
||||
-- This line starts database upgrade to version 2.0
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table \`host_reservations\`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE host_reservations (
|
||||
id bigint,
|
||||
host_identifier blob,
|
||||
host_identifier_type int,
|
||||
host_ipv4_subnet_id int,
|
||||
host_ipv6_subnet_id int,
|
||||
host_ipv4_address int,
|
||||
hostname text,
|
||||
host_ipv4_client_classes text,
|
||||
host_ipv6_client_classes text,
|
||||
reserved_ipv6_prefix_address text,
|
||||
reserved_ipv6_prefix_length int,
|
||||
reserved_ipv6_prefix_address_type int,
|
||||
iaid int,
|
||||
option_universe int,
|
||||
option_code int,
|
||||
option_value blob,
|
||||
option_formatted_value text,
|
||||
option_space text,
|
||||
option_is_persistent boolean,
|
||||
option_client_class text,
|
||||
option_subnet_id int,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS host_reservationsindex1 ON host_reservations (host_identifier);
|
||||
CREATE INDEX IF NOT EXISTS host_reservationsindex2 ON host_reservations (host_identifier_type);
|
||||
CREATE INDEX IF NOT EXISTS host_reservationsindex3 ON host_reservations (host_ipv4_subnet_id);
|
||||
CREATE INDEX IF NOT EXISTS host_reservationsindex4 ON host_reservations (host_ipv6_subnet_id);
|
||||
CREATE INDEX IF NOT EXISTS host_reservationsindex5 ON host_reservations (host_ipv4_address);
|
||||
CREATE INDEX IF NOT EXISTS host_reservationsindex6 ON host_reservations (reserved_ipv6_prefix_address);
|
||||
CREATE INDEX IF NOT EXISTS host_reservationsindex7 ON host_reservations (reserved_ipv6_prefix_length);
|
||||
|
||||
DELETE FROM schema_version WHERE version=1;
|
||||
INSERT INTO schema_version (version, minor) VALUES(2, 0);
|
||||
|
||||
-- This line concludes database upgrade to version 2.0
|
||||
EOF
|
||||
|
||||
exit $?
|
@@ -11,7 +11,6 @@ sqlscripts_DATA += upgrade_4.1_to_5.0.sh
|
||||
sqlscripts_DATA += upgrade_5.0_to_5.1.sh
|
||||
sqlscripts_DATA += upgrade_5.1_to_6.0.sh
|
||||
|
||||
|
||||
DISTCLEANFILES = upgrade_1.0_to_2.0.sh
|
||||
DISTCLEANFILES += upgrade_2.0_to_3.0.sh
|
||||
DISTCLEANFILES += upgrade_3.0_to_4.0.sh
|
||||
|
Reference in New Issue
Block a user