Commit e37606fd authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[master] Merge branch 'github37' (Cassandra host reservations)

# Conflicts:
#	src/lib/dhcpsrv/tests/generic_host_data_source_unittest.cc
parents 11d70ca9 8060cb78
......@@ -1313,6 +1313,7 @@ AC_CONFIG_FILES([Makefile
src/share/database/Makefile
src/share/database/scripts/Makefile
src/share/database/scripts/cql/Makefile
src/share/database/scripts/cql/upgrade_1.0_to_2.0.sh
src/share/database/scripts/mysql/Makefile
src/share/database/scripts/mysql/upgrade_1.0_to_2.0.sh
src/share/database/scripts/mysql/upgrade_2.0_to_3.0.sh
......
......@@ -160,19 +160,19 @@
<para>
<table frame="all" id="backends">
<title>List of available backends</title>
<tgroup cols='2'>
<tgroup cols='5'>
<colspec colname='feature'/>
<colspec colname='memfile'/>
<colspec colname='mysql'/>
<colspec colname='pgsql'/>
<colspec colname='cql'/>
<colspec colname='cql' colwidth='1.5*'/>
<thead>
<row>
<entry>Feature</entry>
<entry>Memfile</entry>
<entry>MySQL</entry>
<entry>PostgreSQL</entry>
<entry>CQL(Cassandra)</entry>
<entry>CQL (Cassandra)</entry>
</row>
</thead>
<tbody>
......@@ -206,7 +206,7 @@
<entry>no</entry>
<entry>yes</entry>
<entry>yes</entry>
<entry>no</entry>
<entry>yes</entry>
</row>
<row>
......@@ -214,7 +214,7 @@
<entry>no</entry>
<entry>yes</entry>
<entry>yes</entry>
<entry>no</entry>
<entry>yes</entry>
</row>
</tbody>
......@@ -409,6 +409,8 @@ $ <userinput>kea-admin lease-upgrade mysql -u <replaceable>database-user</replac
<title>PostgreSQL</title>
<para>
PostgreSQL is able to store leases, host reservations and options
defined on a per host basis.
A PostgreSQL database must be set up if you want Kea to store
lease and other information in PostgreSQL. This step can be
safely ignored if you are using other database backends.
......@@ -590,10 +592,9 @@ $ <userinput>kea-admin lease-upgrade pgsql -u <replaceable>database-user</replac
<para>
Cassandra, or Cassandra Query Language (CQL), is the newest backend
added to Kea. Since it was added recently and has not undergone as much
testing as other backends, it is considered experimental: please use
with caution. The CQL backend is currently able to store leases only. The
ability to store host reservations will likely be added some time in the
future.
testing as other backends, it is considered experimental. Please use
with caution. The Cassandra backend is able to store leases,
host reservations and options defined on a per host basis.
</para>
<para>
......
......@@ -517,8 +517,7 @@ If a timeout is given though, it should be an integer greater than zero.
purpose, be it lease or hosts information. This arrangement gives the most
flexibility. Kea can be used to keep leases and host reservations
separately, but can also point to the same database. Currently the
supported hosts database types are MySQL and PostgreSQL. The Cassandra
backend does not support host reservations yet.</para>
supported hosts database types are MySQL, PostgreSQL and Cassandra.</para>
<para>Please note that usage of hosts storage is optional. A user can define
all host reservations in the configuration file. That is the recommended way
......@@ -3387,13 +3386,13 @@ It is merely echoed by the server
with classification using expressions.</para>
</section>
<section id="reservations4-mysql-pgsql">
<title>Storing Host Reservations in MySQL or PostgreSQL</title>
<section id="reservations4-mysql-pgsql-cql">
<title>Storing Host Reservations in MySQL, PostgreSQL or Cassandra</title>
<para>
It is possible to store host reservations in MySQL or PostgreSQL. See <xref
linkend="hosts6-storage" /> for information on how to configure Kea to use
reservations stored in MySQL or PostgreSQL. Kea provides dedicated hook for
It is possible to store host reservations in MySQL, PostgreSQL or Cassandra. See
<xref linkend="hosts6-storage" /> for information on how to configure Kea to use
reservations stored in MySQL, PostgreSQL or Cassandra. Kea provides dedicated hook for
managing reservations in a database, section <xref linkend="host-cmds" /> provide
detailed information.
</para>
......@@ -3402,12 +3401,6 @@ It is merely echoed by the server
arbitrarily set to 4096 bytes.</simpara></note>
</section>
<section id="reservations4-cql">
<title>Storing host reservations in CQL (Cassandra)</title>
<para>Kea currently does not support storing reservations in
Cassandra (CQL).</para>
</section>
<section id="reservations4-tuning">
<title>Fine Tuning DHCPv4 Host Reservation</title>
......
......@@ -2905,13 +2905,13 @@ should include options from the isc option space:
with classification using expressions.</para>
</section>
<section id="reservations6-mysql-pgsql">
<title>Storing Host Reservations in MySQL or PostgreSQL</title>
<section id="reservations6-mysql-pgsql-cql">
<title>Storing Host Reservations in MySQL, PostgreSQL or Cassandra</title>
<para>
It is possible to store host reservations in MySQL or PostgreSQL. See <xref
linkend="hosts6-storage" /> for information on how to configure Kea to use
reservations stored in MySQL or PostgreSQL. Kea provides dedicated hook for
It is possible to store host reservations in MySQL, PostgreSQL or Cassandra. See
<xref linkend="hosts6-storage" /> for information on how to configure Kea to use
reservations stored in MySQL, PostgreSQL or Cassandra. Kea provides dedicated hook for
managing reservations in a database, section <xref linkend="host-cmds" /> provide
detailed information.
</para>
......@@ -2920,12 +2920,6 @@ should include options from the isc option space:
arbitrarily set to 4096 bytes.</simpara></note>
</section>
<section id="reservations6-cql">
<title>Storing Host Reservations in CQL (Cassandra)</title>
<para>Kea currently does not support storing reservations in
Cassandra (CQL).</para>
</section>
<section id="reservations6-tuning">
<title>Fine Tuning DHCPv6 Host Reservation</title>
......
......@@ -82,7 +82,7 @@ cql_lease_version_test() {
# Verify that kea-admin lease-version returns the correct version.
version=$($keaadmin lease-version cql -u $db_user -p $db_password -n $db_name)
assert_str_eq "1.0" $version "Expected kea-admin to return %s, returned value was %s"
assert_str_eq "2.0" $version "Expected kea-admin to return %s, returned value was %s"
# Wipe the database.
cql_execute_script $db_scripts_dir/cql/dhcpdb_drop.cql
......
// Copyright (C) 2010-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2010-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -23,11 +23,20 @@
namespace isc {
namespace asiolink {
/// Defines length of IPv6 address.
const static size_t V6ADDRESS_LEN = 16;
/// Defines length of IPv6 address (in binary format).
static constexpr size_t V6ADDRESS_LEN = 16;
/// Defines length of IPv4 address.
const static size_t V4ADDRESS_LEN = 4;
/// Defines length of IPv4 address (in binary format).
static constexpr size_t V4ADDRESS_LEN = 4;
/// @brief Maximum size of an IPv4 address represented as a text string. 12
/// digits plus 3 full stops (dots).
static constexpr size_t V4ADDRESS_TEXT_MAX_LEN = 15u;
/// @brief Maximum size of an IPv6 address represented as a text string. 32
/// hexadecimal characters written in 8 groups of four, plus 7 colon
/// separators.
static constexpr size_t V6ADDRESS_TEXT_MAX_LEN = 39u;
/// \brief The \c IOAddress class represents an IP addresses (version
/// agnostic)
......
......@@ -153,6 +153,7 @@ endif
if HAVE_CQL
libkea_dhcpsrv_la_SOURCES += cql_connection.cc cql_connection.h
libkea_dhcpsrv_la_SOURCES += cql_exchange.cc cql_exchange.h
libkea_dhcpsrv_la_SOURCES += cql_host_data_source.cc cql_host_data_source.h
libkea_dhcpsrv_la_SOURCES += cql_lease_mgr.cc cql_lease_mgr.h
endif
......
......@@ -48,9 +48,9 @@ constexpr uint32_t CQL_DRIVER_VERSION_MAJOR = CASS_VERSION_MAJOR;
constexpr uint32_t CQL_DRIVER_VERSION_MINOR = CASS_VERSION_MINOR;
/// @}
/// Define CQL schema version: 1.0
/// Define CQL schema version: 2.0
/// @{
constexpr uint32_t CQL_SCHEMA_VERSION_MAJOR = 1u;
constexpr uint32_t CQL_SCHEMA_VERSION_MAJOR = 2u;
constexpr uint32_t CQL_SCHEMA_VERSION_MINOR = 0u;
/// @}
......@@ -142,11 +142,13 @@ public:
///
/// Opens the database using the information supplied in the parameters
/// passed to the constructor. If no parameters are supplied, the default
/// values will be used. The defaults are:
/// - contact points: 127.0.0.1
/// - port 9042
/// - no user, no password
/// - keyspace keatest
/// values will be used. The parameters supported as as follows (default
/// values specified in parentheses):
/// - keyspace: name of the database to which to connect (keatest)
/// - contact-points: IP addresses of the nodes to connect to (127.0.0.1)
/// - port: The TCP port to use (9042)
/// - user - credentials to use when connecting (no username)
/// - password - credentails to use when connecting (no password)
/// - reconnect-wait-time 2000
/// - connect-timeout 5000
/// - request-timeout 12000
......
This diff is collapsed.
// Copyright (C) 2016-2017 Deutsche Telekom AG.
//
// Author: Andrei Pavel <andrei.pavel@qualitance.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CQL_HOST_DATA_SOURCE_H
#define CQL_HOST_DATA_SOURCE_H
#include <dhcpsrv/base_host_data_source.h>
#include <dhcpsrv/cql_connection.h>
#include <string>
#include <vector>
namespace isc {
namespace dhcp {
/// @brief Forward declaration to the implementation of @ref CqlHostDataSource.
class CqlHostDataSourceImpl;
/// @brief Cassandra host data source
///
/// Implements @ref isc::dhcp::BaseHostDataSource interface customized to
/// Cassandra. Use of this backend implies that a Cassandra database is
/// available and that the Kea schema has been created within it.
///
/// The database schema is radically different than the MySQL and the
/// PostgreSQL schemas. Rather than creating a different table for
/// hosts, reservations, DHCPv4 options and DHCPv6 options
/// respectively, the data is denormalized into a single table to
/// benefit from Cassandra's non-relational nature. To make up for the
/// lack of relations, on insertion, the reservations and options are
/// matched against hosts on the server and merged into database
/// entries. When retrieving, each database row is split into the
/// corresponding host, reservation and options.
///
/// There can be an inconsistency in the database due to the order of
/// the changes e.g. if you insert a host with no reservations and no
/// options followed by the same host with one reservation will result
/// in 2 entries versus inserting the host with reservation from the
/// beginning which will result in a single entry. In spite of this,
/// retrieving the host will give you the attached reservation in both
/// cases.
class CqlHostDataSource : public BaseHostDataSource {
public:
/// @brief Constructor
///
/// Uses the following keywords in the parameters passed to it to connect
/// to the database:
/// - keyspace
/// - host
/// - user
/// - password
/// - contact-points
/// - reconnect-wait-time
/// - connect-timeout
/// - request-timeout
/// - tcp-keepalive
/// - tcp-nodelay
///
/// For details regarding those paraemters, see
/// @ref isc::dhcp::CqlConnection::openDatabase.
///
/// Finally, all the CQL commands are pre-compiled.
///
/// @param parameters a data structure relating keywords and values
/// concerned with the database.
///
/// @throw isc::dhcp::NoDatabaseName Mandatory database name not given
/// @throw isc::dhcp::DbOpenError Error opening the database
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
explicit CqlHostDataSource(const DatabaseConnection::ParameterMap& parameters);
/// @brief Virtual destructor.
///
/// Releases prepared CQL statements used by the backend.
virtual ~CqlHostDataSource();
/// @brief Adds a new host to the collection.
///
/// The implementations of this method should guard against duplicate
/// reservations for the same @ref Host, where possible. For example, when
/// the reservation for the same @ref HWAddr and @ref SubnetID is added
/// twice, @ref add() should throw a @ref DuplicateEntry exception. Note,
/// that usually it is impossible to guard against adding duplicated @ref
/// Host, where one instance is identified by different identifier types.
///
/// @param host pointer to the new @ref Host being added.
virtual void add(const HostPtr& host) override;
/// @brief Retrieves a single @ref Host connected to an IPv4 subnet.
///
/// Implementations of this method should guard against the case when
/// multiple instances of the @ref Host are present, e.g. when two @ref
/// Host objects are found, one for the @ref DUID, another one for the @ref
/// HWAddr. In such case, throw a @ref MultipleRecords exception.
///
/// @param subnet_id subnet identifier to filter by
/// @param hwaddr hardware address of the client to filter by or NULL if not
/// available
/// @param duid client identifier to filter by or NULL if not available
///
/// @return @ref ConstHostPtr to a @ref Host object using a specified @ref
/// HWAddr or @ref DUID
///
/// @throw BadValue if both or neither of subnet_id and duid are specified
virtual ConstHostPtr get4(const SubnetID& subnet_id,
const HWAddrPtr& hwaddr,
const DuidPtr& duid = DuidPtr()) const override;
/// @brief Retrieves a @ref Host connected to an IPv4 subnet.
///
/// The host is identified by specific identifier.
///
/// @param subnet_id subnet identifier to filter by
/// @param identifier_type identifier type to filter by
/// @param identifier_begin pointer to the beginning of a buffer containing
/// a host identifier to filter by
/// @param identifier_len length of the host identifier buffer
///
/// @return @ref Host object for which a reservation has been made using the
/// specified identifier
virtual ConstHostPtr get4(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const override;
/// @brief Retrieves a @ref Host connected to an IPv4 subnet.
///
/// The host is identifier by specified IPv4 address.
///
/// @param subnet_id Subnet identifier.
/// @param address reserved IPv4 address.
///
/// @return Const @ref Host object
///
/// @throw BadValue if address in not a valid IPv4address
virtual ConstHostPtr
get4(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const override;
/// @brief Retrieves a @ref Host connected to an IPv6 subnet.
///
/// Implementations of this method should guard against the case when
/// multiple instances of the @ref Host are present, e.g. when two
/// @ref Host objects are found, one for the @ref DUID, another one for the
/// @ref HWAddr. In such case, throw a @ref MultipleRecords exception.
///
/// @param subnet_id subnet identifier to filter by
/// @param hwaddr hardware address of the client to filter by or NULL if not
/// available
/// @param duid client identifier to filter by or NULL if not available
///
/// @return @ref Host object using a specified @ref HWAddr or @ref DUID
///
/// @throw BadValue if both or neither of subnet_id and duid are specified
virtual ConstHostPtr
get6(const SubnetID& subnet_id,
const DuidPtr& duid,
const HWAddrPtr& hwaddr = HWAddrPtr()) const override;
/// @brief Returns a @ref Host connected to an IPv6 subnet.
///
/// @param subnet_id subnet identifier to filter by
/// @param identifier_type identifier type to filter by
/// @param identifier_begin pointer to the beginning of a buffer containing
/// a host identifier to filter by
/// @param identifier_len length of the host identifier buffer
///
/// @return Const @ref Host object for which reservation has been made using
/// the specified identifier.
virtual ConstHostPtr get6(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const override;
/// @brief Returns a @ref Host with the specified reservation prefix.
///
/// @param prefix IPv6 prefix for which the @ref Host object is searched.
/// @param prefix_len IPv6 prefix length.
///
/// @return Const @ref Host object using a specified HW address or DUID.
///
/// @throw MultipleRecords if two or more rows are returned from the
/// Cassandra database
virtual ConstHostPtr get6(const asiolink::IOAddress& prefix,
const uint8_t prefix_len) const override;
/// @brief Returns a host connected to the IPv6 subnet and having
/// a reservation for a specified IPv6 address or prefix.
///
/// @param subnet_id Subnet identifier.
/// @param address reserved IPv6 address/prefix.
///
/// @return Const @c Host object using a specified IPv6 address/prefix.
virtual ConstHostPtr
get6(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const override;
/// @brief Return all @ref Host objects for the specified @ref HWAddr or
/// @ref DUID.
///
/// Returns all @ref Host objects which represent reservations
/// for the specified HW address or DUID. Note, that this method may
/// return multiple reservations because a particular client may have
/// reservations in multiple subnets and the same client may be identified
/// by HW address or DUID. The server is unable to verify that the specific
/// DUID and HW address belong to the same client, until the client sends
/// a DHCP message.
///
/// Specifying both @ref HWAddr and @ref DUID is allowed for this method
/// and results in returning all objects that are associated with hardware
/// address OR duid. For example: if one @ref Host is associated with the
/// specified @ref HWAddr and another @ref Host is associated with the
/// specified @ref DUID, two hosts will be returned.
///
/// @param hwaddr HW address of the client or NULL if no HW address
/// available.
/// @param duid client id or NULL if not available, e.g. DHCPv4 client case.
///
/// @return collection of const @ref Host objects.
virtual ConstHostCollection
getAll(const HWAddrPtr& hwaddr,
const DuidPtr& duid = DuidPtr()) const override;
/// @brief Return all hosts connected to any subnet for which reservations
/// have been made using a specified identifier.
///
/// This method returns all @ref Host objects which represent reservations
/// for a specified identifier. This method may return multiple hosts
/// because a particular client may have reservations in multiple subnets.
///
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
///
/// @return Collection of const @ref Host objects.
virtual ConstHostCollection
getAll(const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len) const override;
/// @brief Returns a collection of hosts using the specified IPv4 address.
///
/// This method may return multiple @ref Host objects if they are connected
/// to different subnets.
///
/// @param address IPv4 address for which the @ref Host object is searched.
///
/// @return Collection of const @ref Host objects.
virtual ConstHostCollection
getAll4(const asiolink::IOAddress& address) const override;
/// @brief Attempts to delete a host by (subnet-id, address)
///
/// This method supports both v4 and v6.
///
/// @param subnet_id subnet identfier.
/// @param addr specified address.
/// @return true if deletion was successful, false if the host was not
/// there.
/// @throw various exceptions in case of errors
virtual bool del(const SubnetID& subnet_id,
const asiolink::IOAddress& addr);
/// @brief Attempts to delete a host by (subnet-id4, identifier-type,
/// identifier).
///
/// This method supports v4 hosts only.
///
/// @param subnet_id IPv4 Subnet identifier.
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
/// @return true if deletion was successful, false if the host was not
/// there.
/// @throw various exceptions in case of errors
virtual bool del4(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len);
/// @brief Attempts to delete a host by (subnet-id6, identifier-type,
/// identifier).
///
/// This method supports v6 hosts only.
///
/// @param subnet_id IPv6 Subnet identifier.
/// @param identifier_type Identifier type.
/// @param identifier_begin Pointer to a beginning of a buffer containing
/// an identifier.
/// @param identifier_len Identifier length.
/// @return true if deletion was successful, false if the host was not
/// there.
/// @throw various exceptions in case of errors
virtual bool del6(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const uint8_t* identifier_begin,
const size_t identifier_len);
/// @brief Returns textual description of the backend.
///
/// @return Description of the backend.
virtual std::string getDescription() const;
/// @brief Returns the name of the database.
///
/// @return database name
virtual std::string getName() const;
/// @brief Return backend type
///
/// @return backend type "cql"
virtual std::string getType() const override;
/// @brief Retrieves schema version from the DB.
///
/// @return Version number stored in the database, as a pair of unsigned
/// integers. "first" is the major version number, "second" is the
/// minor version number.
///
/// @throw isc::dhcp::DbOperationError An operation on the open database
/// has failed.
virtual VersionPair getVersion() const;
/// @brief Commit Transactions
///
/// Commits all pending database operations (no-op for Cassandra)
virtual void commit() override;
/// @brief Rollback Transactions
///
/// Rolls back all pending database operations (no-op for Cassandra)
virtual void rollback() override;
private:
/// @brief Pointer to the implementation of the @ref CqlHostDataSource.
CqlHostDataSourceImpl* impl_;
}; // class CqlHostDataSource
} // namespace dhcp
} // namespace isc
#endif // CQL_HOST_DATA_SOURCE_H
......@@ -24,7 +24,7 @@
namespace isc {
namespace dhcp {
/// @brief HostID (used only when storing in MySQL or Postgres)
/// @brief HostID (used only when storing in MySQL, PostgreSQL or Cassandra)
typedef uint64_t HostID;
/// @brief IPv6 reservation for a host.
......@@ -534,13 +534,13 @@ public:
/// @brief Returns information about the host in the textual format.
std::string toText() const;
/// @brief Sets Host ID (primary key in MySQL and Postgres backends)
/// @brief Sets Host ID (primary key in MySQL, PostgreSQL and Cassandra backends)
/// @param id HostId value
void setHostId(HostID id) {
host_id_ = id;
}
/// @brief Returns Host ID (primary key in MySQL and Postgres backends)
/// @brief Returns Host ID (primary key in MySQL, PostgreSQL and Cassandra backends)
/// @return id HostId value (or 0 if not set)
HostID getHostId() const {
return (host_id_);
......@@ -597,7 +597,7 @@ private:
std::string boot_file_name_;
/// @brief HostID (a unique identifier assigned when the host is stored in
/// MySQL or Pgsql)
/// MySQL, PostgreSQL or Cassandra)
uint64_t host_id_;
/// @brief Pointer to the DHCPv4 option data configuration for this host.
......
......@@ -4,7 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this