2
0
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:
Tomek Mrugalski
2018-01-11 15:43:59 +01:00
26 changed files with 3365 additions and 285 deletions

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View 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

View File

@@ -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.

View File

@@ -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

View File

@@ -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];

View File

@@ -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

View 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

View File

@@ -728,3 +728,4 @@ TEST_F(CqlLeaseMgrTest, DISABLED_wipeLeases6) {
}
} // namespace

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -0,0 +1,2 @@
upgrade_1.0_to_2.0.sh

View File

@@ -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}

View File

@@ -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

View File

@@ -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;

View 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 $?

View File

@@ -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