mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 21:45:37 +00:00
[116-interface-id-dhcpv4] Merge branch '116-interface-id-dhcpv4' of gitlab.isc.org:isc-projects/kea into 116-interface-id-dhcpv4
This commit is contained in:
10
ChangeLog
10
ChangeLog
@@ -1,3 +1,13 @@
|
||||
1453. [func] marcin
|
||||
Updated MySQL schema to facilitate Kea Configuration Backend
|
||||
feature.
|
||||
(Gitlab #89,!22, git e28c0c7b3e7a7729167cdad993f634ed1f0ac53b)
|
||||
|
||||
1452. [func] marcin
|
||||
Implemented libkea-cb library which includes basic class
|
||||
hierarchy for the Kea Configuration Backend.
|
||||
(Gitlab #28,!20, git fb5c031ecaf4182e56f62874e9a6bd4c1d755a77)
|
||||
|
||||
1451. [build] tmark
|
||||
Resolved a namespace issue with std::distance() in libdhcp++.cc
|
||||
when building with Boost 1.68. Thanks to Huy Vu and Khem Raj
|
||||
|
@@ -74,6 +74,9 @@ if test "$cross_compiling" = "yes"; then
|
||||
fi
|
||||
AM_CONDITIONAL([CROSS_COMPILING], [test "$cross_compiling" = "yes"])
|
||||
|
||||
# pkg-config can be required.
|
||||
AC_PATH_PROG([PKG_CONFIG], [pkg-config])
|
||||
|
||||
# Enable low-performing debugging facilities? This option optionally
|
||||
# enables some debugging aids that perform slowly and hence aren't built
|
||||
# by default.
|
||||
@@ -817,7 +820,6 @@ AC_ARG_WITH([cql],
|
||||
[cql_config="$withval"])
|
||||
|
||||
if test "${cql_config}" = "yes" ; then
|
||||
AC_PATH_PROG([PKG_CONFIG], [pkg-config])
|
||||
CQL_CONFIG="$PKG_CONFIG"
|
||||
elif test "${cql_config}" != "no" ; then
|
||||
CQL_CONFIG="${cql_config}"
|
||||
@@ -1532,6 +1534,8 @@ AC_CONFIG_FILES([Makefile
|
||||
src/lib/config/tests/Makefile
|
||||
src/lib/config/tests/data_def_unittests_config.h
|
||||
src/lib/config/tests/testdata/Makefile
|
||||
src/lib/config_backend/Makefile
|
||||
src/lib/config_backend/tests/Makefile
|
||||
src/lib/cryptolink/Makefile
|
||||
src/lib/cryptolink/tests/Makefile
|
||||
src/lib/database/Makefile
|
||||
@@ -1597,6 +1601,8 @@ AC_CONFIG_FILES([Makefile
|
||||
src/lib/util/threads/Makefile
|
||||
src/lib/util/threads/tests/Makefile
|
||||
src/lib/util/unittests/Makefile
|
||||
src/lib/yang/Makefile
|
||||
src/lib/yang/tests/Makefile
|
||||
src/share/Makefile
|
||||
src/share/database/Makefile
|
||||
src/share/database/scripts/Makefile
|
||||
|
@@ -810,6 +810,7 @@ INPUT = ../src/bin/agent \
|
||||
../src/lib/util/random \
|
||||
../src/lib/util/threads \
|
||||
../src/lib/util/unittests \
|
||||
../src/lib/yang \
|
||||
devel
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
|
@@ -41,6 +41,7 @@
|
||||
* - @subpage unitTestsIntroduction
|
||||
* - @subpage unitTestsEnvironmentVariables
|
||||
* - @subpage unitTestsDatabaseConfig
|
||||
* - @subpage unitTestsSysrepo
|
||||
*
|
||||
* @section performance Performance
|
||||
* - @subpage benchmarks
|
||||
@@ -129,6 +130,7 @@
|
||||
* - @subpage libprocess
|
||||
* - @subpage cpl
|
||||
* - @subpage cplSignals
|
||||
* - @subpage libyang
|
||||
*
|
||||
* @section miscellaneousTopics Miscellaneous Topics
|
||||
* - @subpage terminology
|
||||
|
@@ -38,12 +38,12 @@ $ sudo apt-get install git cmake build-essential bison flex libpcre3-dev libev-d
|
||||
</para>
|
||||
|
||||
<para>STEP 2. Install libyang. Download libyang from
|
||||
https://github.com/CESNET/libyang/releases. As of writing this document, the latest
|
||||
version was 0.15-r1.
|
||||
https://github.com/CESNET/libyang.git. Checkout the devel branch.
|
||||
|
||||
<screen>
|
||||
tar zxvf libyang-0.15-r1.tar.gz
|
||||
cd libyang-0.15-r1/
|
||||
git clone https://github.com/CESNET/libyang.git
|
||||
cd libyang
|
||||
git checkout devel
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
@@ -53,12 +53,13 @@ $ sudo apt-get install git cmake build-essential bison flex libpcre3-dev libev-d
|
||||
|
||||
For detailed build instructions, see https://github.com/CESNET/libyang/.</para>
|
||||
|
||||
<para>STEP 3. Install syrepo. Download sysrepo from https://github.com/sysrepo/sysrepo/releases.
|
||||
As of writing this document, the 0.7.4 as the latest version.
|
||||
<para>STEP 3. Install syrepo. Download sysrepo from
|
||||
https://github.com/sysrepo/sysrepo.git. Checkout the last devel branch.
|
||||
|
||||
<screen>
|
||||
tar zxvf sysrepo-0.7.4.tar.gz
|
||||
cd sysrepo-0.7.4
|
||||
git clone https://github.com/sysrepo/sysrepo.git
|
||||
cd sysrepo
|
||||
git checkout devel
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Debug -DGEN_LANGUAGE_BINDINGS=ON -DGEN_CPP_BINDINGS=ON\
|
||||
|
@@ -245,7 +245,7 @@ mysql_upgrade_schema_to_version() {
|
||||
|
||||
mysql_upgrade_test() {
|
||||
|
||||
test_start "mysql.host_reservation-upgrade"
|
||||
test_start "mysql.upgrade"
|
||||
|
||||
# Let's wipe the whole database
|
||||
mysql_wipe
|
||||
@@ -469,11 +469,126 @@ EOF
|
||||
ERRCODE=$?
|
||||
assert_eq 0 $ERRCODE "logs table is missing or broken. (expected status code %d, returned %d)"
|
||||
|
||||
# table: modification (upgrade 6.0 -> 7.0)
|
||||
qry="select id, modification_type from modification"
|
||||
run_statement "modification" "$qry"
|
||||
|
||||
# table: modification table should have 3 entries (upgrade 6.0 -> 7.0)
|
||||
qry="select count(*) from modification"
|
||||
run_statement "modification count" "$qry" 3
|
||||
|
||||
# table: dhcp4_server
|
||||
qry="select id, tag, description, modification_ts from dhcp4_server"
|
||||
run_statement "dhcp4_server" "$qry"
|
||||
|
||||
# table: dhcp4_audit
|
||||
qry="select id, object_type, object_id, modification_type, modification_ts, log_message from dhcp4_audit"
|
||||
run_statement "dhcp4_audit" "$qry"
|
||||
|
||||
# table: dhcp4_global_parameter
|
||||
qry="select id, name, value, modification_ts from dhcp4_global_parameter"
|
||||
run_statement "dhcp4_global_parameter" "$qry"
|
||||
|
||||
# table: dhcp4_global_parameter_server
|
||||
qry="select parameter_id, server_id, modification_ts from dhcp4_global_parameter_server"
|
||||
run_statement "dhcp4_global_parameter_server" "$qry"
|
||||
|
||||
# table: dhcp4_option_def
|
||||
qry="select id, code, space, modification_ts, array, encapsulate, record_types, user_context from dhcp4_option_def"
|
||||
run_statement "dhcp4_option_def" "$qry"
|
||||
|
||||
# table: dhcp4_option_def_server
|
||||
qry="select option_def_id, server_id, modification_ts from dhcp4_option_def_server"
|
||||
run_statement "dhcp4_option_def_server" "$qry"
|
||||
|
||||
# table: dhcp4_shared_network
|
||||
qry="select id, name, client_class, interface, match_client_id, modification_ts, rebind_timer, relay, renew_timer, require_client_classes, reservation_mode, server_hostname, user_context, valid_lifetime from dhcp4_shared_network"
|
||||
run_statement "dhcp4_shared_network" "$qry"
|
||||
|
||||
# table: dhcp4_shared_network_server
|
||||
qry="select shared_network_id, server_id, modification_ts from dhcp4_shared_network_server"
|
||||
run_statement "dhcp4_shared_network_server" "$qry"
|
||||
|
||||
# table: dhcp4_subnet
|
||||
qry="select subnet_prefix, 4o6_interface, 4o6_interface_id, 4o6_subnet, boot_file_name, client_class, interface, match_client_id, modification_ts, next_server, rebind_timer, relay, renew_timer, require_client_classes, reservation_mode, server_hostname, shared_network_name, subnet_id, user_context, valid_lifetime from dhcp4_subnet"
|
||||
run_statement "dhcp4_subnet" "$qry"
|
||||
|
||||
# table: dhcp4_pool
|
||||
qry="select id, start_address, end_address, subnet_id, modification_ts from dhcp4_pool"
|
||||
run_statement "dhcp4_pool" "$qry"
|
||||
|
||||
# table: dhcp4_subnet_server
|
||||
qry="select subnet_id, server_id, modification_ts from dhcp4_subnet_server"
|
||||
run_statement "dhcp4_subnet_server" "$qry"
|
||||
|
||||
# table: dhcp4_options (should include three new columns)
|
||||
qry="select shared_network_name, pool_id, modification_ts from dhcp4_options"
|
||||
run_statement "dhcp4_options" "$qry"
|
||||
|
||||
# table: dhcp4_options_server
|
||||
qry="select option_id, server_id, modification_ts from dhcp4_options_server"
|
||||
run_statement "dhcp4_options_server" "$qry"
|
||||
|
||||
# table: dhcp6_server
|
||||
qry="select id, tag, description, modification_ts from dhcp6_server"
|
||||
run_statement "dhcp6_server" "$qry"
|
||||
|
||||
# table: dhcp6_audit
|
||||
qry="select id, object_type, object_id, modification_type, modification_ts, log_message from dhcp6_audit"
|
||||
run_statement "dhcp6_audit" "$qry"
|
||||
|
||||
# table: dhcp6_global_parameter
|
||||
qry="select id, name, value, modification_ts from dhcp6_global_parameter"
|
||||
run_statement "dhcp6_global_parameter" "$qry"
|
||||
|
||||
# table: dhcp6_global_parameter_server
|
||||
qry="select parameter_id, server_id, modification_ts from dhcp6_global_parameter_server"
|
||||
run_statement "dhcp6_global_parameter_server" "$qry"
|
||||
|
||||
# table: dhcp6_option_def
|
||||
qry="select id, code, space, modification_ts, array, encapsulate, record_types, user_context from dhcp6_option_def"
|
||||
run_statement "dhcp6_option_def" "$qry"
|
||||
|
||||
# table: dhcp6_option_def_server
|
||||
qry="select option_def_id, server_id, modification_ts from dhcp6_option_def_server"
|
||||
run_statement "dhcp6_option_def_server" "$qry"
|
||||
|
||||
# table: dhcp6_shared_network
|
||||
qry="select id, name, client_class, interface, modification_ts, preferred_lifetime, rapid_commit, rebind_timer, relay, renew_timer, require_client_classes, reservation_mode, server_hostname, user_context, valid_lifetime from dhcp6_shared_network"
|
||||
run_statement "dhcp6_shared_network" "$qry"
|
||||
|
||||
# table: dhcp6_shared_network_server
|
||||
qry="select shared_network_id, server_id, modification_ts from dhcp6_shared_network_server"
|
||||
run_statement "dhcp6_shared_network" "$qry"
|
||||
|
||||
# table: dhcp6_subnet
|
||||
qry="select subnet_prefix, client_class, interface, modification_ts, preferred_lifetime, rapid_commit, rebind_timer, relay, renew_timer, require_client_classes, reservation_mode, shared_network_name, subnet_id, user_context, valid_lifetime from dhcp6_subnet"
|
||||
run_statement "dhcp6_subnet" "$qry"
|
||||
|
||||
# table: dhcp6_subnet_server
|
||||
qry="select subnet_id, server_id, modification_ts from dhcp6_subnet_server"
|
||||
run_statement "dhcp6_subnet_server" "$qry"
|
||||
|
||||
# table: dhcp6_pd_pool
|
||||
qry="select id, prefix_length, delegated_prefix_length, dhcp6_subnet_id, modification_ts from dhcp6_pd_pool"
|
||||
run_statement "dhcp6_pd_pool" "$qry"
|
||||
|
||||
# table: dhcp6_pool
|
||||
qry="select id, start_address, end_address, dhcp6_subnet_id, modification_ts from dhcp6_pool"
|
||||
run_statement "dhcp6_pool" "$qry"
|
||||
|
||||
# table: dhcp6_options (should include four new columns)
|
||||
qry="select shared_network_name, pool_id, pd_pool_id, modification_ts from dhcp6_options"
|
||||
run_statement "dhcp6_options" "$qry"
|
||||
|
||||
# table: dhcp6_options_server
|
||||
qry="select option_id, server_id, modification_ts from dhcp6_options_server"
|
||||
run_statement "dhcp6_options_server" "$qry"
|
||||
|
||||
# Verify upgraded schema reports version 7.0
|
||||
version=$(${keaadmin} lease-version mysql -u $db_user -p $db_password -n $db_name -d $db_scripts_dir)
|
||||
assert_str_eq "7.0" ${version} "Expected kea-admin to return %s, returned value was %s"
|
||||
|
||||
|
||||
# Let's wipe the whole database
|
||||
mysql_wipe
|
||||
|
||||
|
@@ -57,7 +57,7 @@ sbin_PROGRAMS = kea-netconf
|
||||
kea_netconf_SOURCES = main.cc
|
||||
|
||||
kea_netconf_LDADD = libnetconf.la
|
||||
kea_netconf_LDADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
|
||||
kea_netconf_LDADD += $(top_builddir)/src/lib/process/libkea-process.la
|
||||
kea_netconf_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
|
||||
kea_netconf_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
|
||||
kea_netconf_LDADD += $(LOG4CPLUS_LIBS) $(CRYPTO_LIBS) $(BOOST_LIBS) $(SYSREPO_LIBS)
|
||||
|
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <netconf/netconf_log.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
#include <dhcpsrv/daemon.h>
|
||||
#include <process/daemon.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
@@ -36,7 +36,7 @@ usage() {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/// @name Temporary code until isc::dhcp::Daemon is used.
|
||||
/// @name Temporary code until isc::process::Daemon is used.
|
||||
///
|
||||
/// @{
|
||||
const char* PID_FILENAME = "kea-netconf.test_config.pid";
|
||||
@@ -46,7 +46,7 @@ volatile bool SHUTDOWN_FLAG = false;
|
||||
void
|
||||
createPIDFile(int pid) {
|
||||
// This is not a real implemented. We will soon use the one coming
|
||||
// from isc::dhcp::Daemon AFTER it's moved to libprocess.
|
||||
// from isc::process::Daemon AFTER it's moved to libprocess.
|
||||
|
||||
ofstream file(PID_FILENAME, ios::trunc);
|
||||
file << pid;
|
||||
@@ -101,7 +101,7 @@ main(int argc, char* argv[]) {
|
||||
int ret = EXIT_SUCCESS;
|
||||
try {
|
||||
|
||||
// Temporary code. This will be replaced with isc::dhcp::Daemon
|
||||
// Temporary code. This will be replaced with isc::process::Daemon
|
||||
// once it is migrated to libprocess. We DO NOT want to bring
|
||||
// the whole libdhcpsrv into netconf.
|
||||
createPIDFile(getpid());
|
||||
@@ -111,7 +111,7 @@ main(int argc, char* argv[]) {
|
||||
|
||||
// Initialize logging. If verbose, we'll use maximum verbosity.
|
||||
bool verbose_mode = true;
|
||||
isc::dhcp::Daemon::loggerInit(NETCONF_LOGGER_NAME, verbose_mode);
|
||||
isc::process::Daemon::loggerInit(NETCONF_LOGGER_NAME, verbose_mode);
|
||||
LOG_INFO(netconf_logger, NETCONF_STARTING).arg(VERSION).arg(getpid());
|
||||
|
||||
Connection conn("kea-netconf");
|
||||
|
@@ -13,5 +13,10 @@ if HAVE_CQL
|
||||
SUBDIRS += cql
|
||||
endif
|
||||
|
||||
SUBDIRS += testutils hooks dhcp config stats asiodns dhcp_ddns eval \
|
||||
cfgrpt process dhcpsrv http
|
||||
SUBDIRS += config_backend testutils hooks dhcp config stats
|
||||
|
||||
if HAVE_SYSREPO
|
||||
SUBDIRS += yang
|
||||
endif
|
||||
|
||||
SUBDIRS += asiodns dhcp_ddns eval cfgrpt process dhcpsrv http
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2012-2015,2017 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2012-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
|
||||
@@ -21,8 +21,6 @@ namespace dhcp {
|
||||
/// Example: For 2001:db8:1\::deaf:beef and length /120 the function will return
|
||||
/// 2001:db8:1\::dead:be00. See also @ref lastAddrInPrefix.
|
||||
///
|
||||
/// @todo It currently works for v6 only and will throw if v4 address is passed.
|
||||
///
|
||||
/// @param prefix and address that belongs to a prefix
|
||||
/// @param len prefix length
|
||||
///
|
||||
@@ -35,8 +33,6 @@ isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefi
|
||||
/// Example: For 2001:db8:1\::deaf:beef and length /112 the function will return
|
||||
/// 2001:db8:1\::dead:ffff. See also @ref firstAddrInPrefix.
|
||||
///
|
||||
/// @todo It currently works for v6 only and will throw if v4 address is passed.
|
||||
///
|
||||
/// @param prefix and address that belongs to a prefix
|
||||
/// @param len prefix length
|
||||
///
|
||||
|
23
src/lib/config_backend/Makefile.am
Normal file
23
src/lib/config_backend/Makefile.am
Normal file
@@ -0,0 +1,23 @@
|
||||
SUBDIRS = . tests
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
|
||||
AM_CPPFLAGS += $(BOOST_INCLUDES)
|
||||
|
||||
AM_CXXFLAGS = $(KEA_CXXFLAGS)
|
||||
|
||||
EXTRA_DIST = base_config_backend.h
|
||||
EXTRA_DIST += base_config_backend_mgr.h
|
||||
EXTRA_DIST += base_config_backend_pool.h
|
||||
|
||||
# The message file should be in the distribution.
|
||||
#EXTRA_DIST += config_backend.dox
|
||||
|
||||
CLEANFILES = *.gcno *.gcda
|
||||
|
||||
# Specify the headers for copying into the installation directory tree.
|
||||
libkea_cb_includedir = $(pkgincludedir)/config_backend
|
||||
libkea_cb_include_HEADERS = \
|
||||
base_config_backend.h \
|
||||
base_config_backend_mgr.h \
|
||||
base_config_backend_pool.h
|
||||
|
67
src/lib/config_backend/base_config_backend.h
Normal file
67
src/lib/config_backend/base_config_backend.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright (C) 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/.
|
||||
|
||||
#ifndef BASE_CONFIG_BACKEND_H
|
||||
#define BASE_CONFIG_BACKEND_H
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace isc {
|
||||
namespace cb {
|
||||
|
||||
/// @brief Interface for Kea server specific configuration backend
|
||||
/// implementations.
|
||||
///
|
||||
/// Each Kea server (e.g. DHCPv4 server) needs to implement its own
|
||||
/// interface to store and fetch its configuration from the databases.
|
||||
/// This is because each Kea server uses a different set of
|
||||
/// configuration information. This is a base interface which should
|
||||
/// be implemented (and extended) by respective Kea servers to provide
|
||||
/// API to store and fetch configuration information from a database.
|
||||
/// Such implementation is called configuration backend. Each
|
||||
/// configuration backend faciliates a single database type, e.g. MySQL
|
||||
/// database. In order to support multiple database types, i.e. MySQL,
|
||||
/// Posrgres, Cassandra, each Kea server will have to implement
|
||||
/// 3 separate configuration backends, one for each database type.
|
||||
class BaseConfigBackend {
|
||||
public:
|
||||
|
||||
/// @brief Virtual destructor.
|
||||
virtual ~BaseConfigBackend() { }
|
||||
|
||||
/// @brief Returns backend type in the textual format.
|
||||
///
|
||||
/// @return Name of the storage for configurations, e.g. "mysql",
|
||||
/// "pgsql" and so forth.
|
||||
virtual std::string getType() const = 0;
|
||||
|
||||
/// @brief Returns backend host.
|
||||
///
|
||||
/// This is used by the @c BaseConfigBackendPool to select backend
|
||||
/// when @c BackendSelector is specified.
|
||||
///
|
||||
/// @return host on which the database is located.
|
||||
virtual std::string getHost() const = 0;
|
||||
|
||||
/// @brief Returns backend port number.
|
||||
///
|
||||
/// This is used by the @c BaseConfigBackendPool to select backend
|
||||
/// when @c BackendSelector is specified.
|
||||
///
|
||||
/// @return Port number on which database service is available.
|
||||
virtual uint16_t getPort() const = 0;
|
||||
};
|
||||
|
||||
/// @brief Shared pointer to the @c BaseConfigBackend.
|
||||
typedef boost::shared_ptr<BaseConfigBackend> BaseConfigBackendPtr;
|
||||
|
||||
} // end of namespace isc::cb
|
||||
} // end of namespace isc
|
||||
|
||||
#endif // BASE_CONFIG_BACKEND_H
|
175
src/lib/config_backend/base_config_backend_mgr.h
Normal file
175
src/lib/config_backend/base_config_backend_mgr.h
Normal file
@@ -0,0 +1,175 @@
|
||||
// Copyright (C) 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/.
|
||||
|
||||
#ifndef BASE_CONFIG_BACKEND_MGR_H
|
||||
#define BASE_CONFIG_BACKEND_MGR_H
|
||||
|
||||
#include <config_backend/base_config_backend.h>
|
||||
#include <database/database_connection.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace isc {
|
||||
namespace cb {
|
||||
|
||||
/// @brief Base class for Configuration Backend Managers (CBM).
|
||||
///
|
||||
/// Each Kea server supporting Configuration Backend feature implements
|
||||
/// a "manager" class which holds information about supported and
|
||||
/// configured backends and provides access to the backends. This is
|
||||
/// similar to @c HostMgr and @c LeaseMgr singletons being used by the
|
||||
/// DHCP servers.
|
||||
///
|
||||
/// The Config Backend Managers are typically implemented as singletons
|
||||
/// which can be accessed from any place within the server code. This
|
||||
/// includes server configuration, data fetching during normal server
|
||||
/// operation and data management, including processing of control
|
||||
/// commands implemented within hooks libraries.
|
||||
///
|
||||
/// The @c BaseConfigBackendMgr is a base class for all CBMs implemented
|
||||
/// for respective Kea servers. It includes mechanisms to register config
|
||||
/// backend factory functions and to create instances of the backends using
|
||||
/// those factory functions as a result of server configuration. The mechanism
|
||||
/// of factory functions registration is useful in cases when the config
|
||||
/// backend is implemented within the hook library. Such hook library
|
||||
/// registers factory function in its @c load function and the server
|
||||
/// simply calls this function to create the instance of this backend when
|
||||
/// instructed to do so via configuration. Similar mechanism exists in
|
||||
/// DHCP @c HostMgr.
|
||||
///
|
||||
/// Unlike @c HostMgr, the CBMs do not directly expose API to fetch and
|
||||
/// manipulate the data in the database. This is done via, so called,
|
||||
/// Configuration Backends Pools. See @c BaseConfigBackendPool for
|
||||
/// details. The @c BaseConfigBackendMgr is provided with the pool type
|
||||
/// via class template parameter. Respective CBM implementations
|
||||
/// use their own pools, which provide APIs appropriate for those
|
||||
/// implementation.
|
||||
///
|
||||
/// @tparam ConfgBackendPoolType Type of the configuration backend pool
|
||||
/// to be used by the manager. It must derive from @c BaseConfigBackendPool
|
||||
/// template class.
|
||||
template<typename ConfigBackendPoolType>
|
||||
class BaseConfigBackendMgr {
|
||||
public:
|
||||
|
||||
/// @brief Pointer to the configuration backend pool.
|
||||
typedef boost::shared_ptr<ConfigBackendPoolType> ConfigBackendPoolPtr;
|
||||
|
||||
/// @brief Type of the backend factory function.
|
||||
///
|
||||
/// Factory function returns a pointer to the instance of the configuration
|
||||
/// backend created.
|
||||
typedef std::function<typename ConfigBackendPoolType::ConfigBackendTypePtr
|
||||
(const db::DatabaseConnection::ParameterMap&)> Factory;
|
||||
|
||||
/// @brief Constructor.
|
||||
BaseConfigBackendMgr()
|
||||
: factories_(), pool_(new ConfigBackendPoolType()) {
|
||||
}
|
||||
|
||||
/// @brief Registers new backend factory function for a given backend type.
|
||||
///
|
||||
/// The typical usage of this function is to make the CBM aware of a
|
||||
/// configuration backend implementation. This implementation may exist
|
||||
/// in a hooks library. In such case, this function should be called from
|
||||
/// the @c load function in this library. When the backend is registered,
|
||||
/// the server will use it when required by the configuration, i.e. a
|
||||
/// user includes configuration backend of that type in the
|
||||
/// "config-databases" list.
|
||||
///
|
||||
/// If the backend of the given type has already been registered, perhaps
|
||||
/// by another hooks library, the CBM will refuse to register another
|
||||
/// backend of the same type.
|
||||
///
|
||||
/// @param db_type Backend type, e.g. "mysql".
|
||||
/// @param factory Pointer to the backend factory function.
|
||||
///
|
||||
/// @return true if the backend has been successfully registered, false
|
||||
/// if another backend of this type already exists.
|
||||
bool registerBackendFactory(const std::string& db_type,
|
||||
const Factory& factory) {
|
||||
// Check if this backend has been already registered.
|
||||
if (factories_.count(db_type)) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Register the new backend.
|
||||
factories_.insert(std::make_pair(db_type, factory));
|
||||
return (true);
|
||||
}
|
||||
|
||||
/// @brief Create an instance of a configuration backend.
|
||||
///
|
||||
/// This method uses provided @c dbaccess string representing database
|
||||
/// connection information to create an instance of the database
|
||||
/// backend. If the specified backend type is not supported, i.e. there
|
||||
/// is no relevant factory function registered, an exception is thrown.
|
||||
///
|
||||
/// @param dbaccess Database access string being a collection of
|
||||
/// key=value pairs.
|
||||
///
|
||||
/// @throw InvalidParameter if access string lacks database type value.
|
||||
/// @throw db::InvalidType if the type of the database backend is not
|
||||
/// supported.
|
||||
/// @throw Unexpected if the backend factory function returned NULL.
|
||||
void addBackend(const std::string& dbaccess) {
|
||||
// Parse the access string into a map of parameters.
|
||||
db::DatabaseConnection::ParameterMap parameters =
|
||||
db::DatabaseConnection::parse(dbaccess);
|
||||
|
||||
// Get the database type to locate a factory function.
|
||||
db::DatabaseConnection::ParameterMap::iterator it = parameters.find("type");
|
||||
if (it == parameters.end()) {
|
||||
isc_throw(InvalidParameter, "Config backend specification lacks the "
|
||||
"'type' keyword");
|
||||
}
|
||||
|
||||
std::string db_type = it->second;
|
||||
auto index = factories_.find(db_type);
|
||||
|
||||
// No match?
|
||||
if (index == factories_.end()) {
|
||||
isc_throw(db::InvalidType, "The type of the configuration backend: '" <<
|
||||
db_type << "' is not supported");
|
||||
}
|
||||
|
||||
// Call the factory and push the pointer on sources.
|
||||
auto backend = index->second(parameters);
|
||||
if (!backend) {
|
||||
isc_throw(Unexpected, "Config database " << db_type <<
|
||||
" factory returned NULL");
|
||||
}
|
||||
|
||||
// Backend instance created successfully.
|
||||
pool_->addBackend(backend);
|
||||
}
|
||||
|
||||
/// @brief Removes all backends from the pool.
|
||||
void delAllBackends() {
|
||||
pool_->delAllBackends();
|
||||
}
|
||||
|
||||
/// @brief Returns underlying config backend pool.
|
||||
ConfigBackendPoolPtr getPool() const {
|
||||
return (pool_);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief A map holding registered backend factory functions.
|
||||
std::map<std::string, Factory> factories_;
|
||||
|
||||
/// @brief Pointer to the configuration backends pool.
|
||||
ConfigBackendPoolPtr pool_;
|
||||
};
|
||||
|
||||
} // end of namespace isc::cb
|
||||
} // end of namespace isc
|
||||
|
||||
#endif // BASE_CONFIG_BACKEND_MGR_H
|
504
src/lib/config_backend/base_config_backend_pool.h
Normal file
504
src/lib/config_backend/base_config_backend_pool.h
Normal file
@@ -0,0 +1,504 @@
|
||||
// Copyright (C) 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/.
|
||||
|
||||
#ifndef BASE_CONFIG_BACKEND_POOL_H
|
||||
#define BASE_CONFIG_BACKEND_POOL_H
|
||||
|
||||
#include <cc/data.h>
|
||||
#include <config_backend/base_config_backend.h>
|
||||
#include <database/backend_selector.h>
|
||||
#include <database/db_exceptions.h>
|
||||
#include <database/server_selector.h>
|
||||
#include <util/optional_value.h>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
namespace isc {
|
||||
namespace cb {
|
||||
|
||||
|
||||
/// @brief Base class for configuration backend pools.
|
||||
///
|
||||
/// Each Kea server supporting databases as a configuration repository can
|
||||
/// use multiple database instances simultaneously. A pool is a collection
|
||||
/// of database backends used by a particular server. Different Kea servers
|
||||
/// use different pools because they store and fetch different configuration
|
||||
/// information. For example: DHCPv4 server stores and fetches IPv4 subnets,
|
||||
/// and DHCPv6 server stores and fetches IPv6 subnets. Therefore, each pool
|
||||
/// type will expose a different API calls.
|
||||
///
|
||||
/// This template class is a base class for all pools used by various servers.
|
||||
/// It implements mechanisms for managing multiple backends and for forwarding
|
||||
/// API calls to one or many database backends depending on the selections
|
||||
/// made via @c BackendSelector class.
|
||||
///
|
||||
/// @tparam ConfigBackendType Type of the configuration backend. This must
|
||||
/// be a class deriving from @c BaseConfigBackend class. It is a class
|
||||
/// dedicated to a particular server type, e.g. DHCPv4 server, and from
|
||||
/// which database specific backends derive.
|
||||
template<typename ConfigBackendType>
|
||||
class BaseConfigBackendPool {
|
||||
public:
|
||||
|
||||
/// @brief Shared pointer to the Configuration Backend used.
|
||||
typedef boost::shared_ptr<ConfigBackendType> ConfigBackendTypePtr;
|
||||
|
||||
/// @brief Virtual destructor.
|
||||
virtual ~BaseConfigBackendPool() { }
|
||||
|
||||
/// @brief Adds a backend to the pool.
|
||||
///
|
||||
/// @param backend Pointer to a backend to be added.
|
||||
void addBackend(ConfigBackendTypePtr backend) {
|
||||
backends_.push_back(backend);
|
||||
}
|
||||
|
||||
/// @brief Deletes all backends from the pool.
|
||||
void delAllBackends() {
|
||||
backends_.clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief Retrieve a single configuration property from the pool.
|
||||
///
|
||||
/// This is common method for retrieving a single configuration property
|
||||
/// from the databases. The server specific backends call this method to
|
||||
/// retrieve a single object. For example, the DHCPv4 configuration backend
|
||||
/// pool may use this function to implement a @c getSubnet4 method:
|
||||
///
|
||||
/// @code
|
||||
/// Subnet4Ptr getSubnet4(const SubnetID& subnet_id,
|
||||
/// const BackendSelector& backend_selector,
|
||||
/// const ServerSelector& server_selector) const {
|
||||
/// Subnet4Ptr subnet;
|
||||
/// getPropertyPtrConst<Subnet4Ptr, const SubnetID&>
|
||||
/// (&ConfigBackendDHCPv4::getSubnet4, backend_selector,
|
||||
/// server_selector, subnet, subnet_id);
|
||||
/// return (subnet);
|
||||
/// }
|
||||
/// @endcode
|
||||
///
|
||||
/// where @c ConfigBackendDHCPv4::getSubnet4 has the following signature:
|
||||
///
|
||||
/// @code
|
||||
/// Subnet4Ptr getSubnet4(const ServerSelector&, const SubnetID&) const;
|
||||
/// @endcode
|
||||
///
|
||||
/// If the backend selector is set to "unspecified", this method will iterate
|
||||
/// over the existing backends and call the @c MethodPointer method on each
|
||||
/// backend. It will return the first non-null (or non-zero) value returned
|
||||
/// by this call. For example: if the first backend returns non-null value,
|
||||
/// this value is returned via @c property argument and the calls for the
|
||||
/// rest of the backends are skipped.
|
||||
///
|
||||
/// @tparam PropertyType Type of the object returned by the backend call.
|
||||
/// @tparam FnPtrArgs Parameter pack holding argument types of the backend
|
||||
/// method to be invoked.
|
||||
/// @tparam Args Parameter pack holding types of the arguments provided
|
||||
/// in the call to this method.
|
||||
///
|
||||
/// @param MethodPointer Pointer to the backend method to be called.
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param [out] property Reference to the shared pointer where retrieved
|
||||
/// property should be assigned.
|
||||
/// @param input Values to be used as input to the backend call.
|
||||
///
|
||||
/// @throw db::NoSuchDatabase if no database matching the given selector
|
||||
/// was found.
|
||||
template<typename PropertyType, typename... FnPtrArgs, typename... Args>
|
||||
void getPropertyPtrConst(PropertyType (ConfigBackendType::*MethodPointer)
|
||||
(const db::ServerSelector&, FnPtrArgs...) const,
|
||||
const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
PropertyType& property,
|
||||
Args... input) const {
|
||||
|
||||
// If no particular backend is selected, call each backend and return
|
||||
// the first non-null (non zero) value.
|
||||
if (backend_selector.amUnspecified()) {
|
||||
for (auto backend : backends_) {
|
||||
property = ((*backend).*MethodPointer)(server_selector, input...);
|
||||
if (property) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Backend selected, find the one that matches selection.
|
||||
auto backends = selectBackends(backend_selector);
|
||||
if (!backends.empty()) {
|
||||
for (auto backend : backends) {
|
||||
property = ((*backend).*MethodPointer)(server_selector, input...);
|
||||
if (property) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
isc_throw(db::NoSuchDatabase, "no such database found for selector: "
|
||||
<< backend_selector.toText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Retrieve a single value encapsulated in the @c OptionalValue
|
||||
/// template.
|
||||
///
|
||||
/// This is common method for retrieving a single configuration property
|
||||
/// from the databases. The property is encapsulated in the @c OptionalValue
|
||||
/// class. The value is set to "unspecified" if it is null in the database.
|
||||
/// The following is the example implementation of the method retrieving
|
||||
/// global conifguration value:
|
||||
///
|
||||
/// @code
|
||||
/// OptionalValue<std::string>
|
||||
/// getGlobalParameter4(const std::string& parameter_name,
|
||||
/// const BackendSelector& backend_selector,
|
||||
/// const ServerSelector& server_selector) const {
|
||||
/// std::string parameter;
|
||||
/// getOptionalPropertyConst<std::string, const std::string&>
|
||||
/// (&ConfigBackendDHCPv4::getGlobalParameter4, backend_selector,
|
||||
/// server_selector, parameter, parameter_name);
|
||||
/// return (parameter);
|
||||
/// }
|
||||
/// @endcode
|
||||
///
|
||||
/// where @c ConfigBackendDHCPv4::getGlobalParameter has the following signature:
|
||||
///
|
||||
/// @code
|
||||
/// std::string getGlobalParameter4(const ServerSelector&, const std::string&) const;
|
||||
/// @endcode
|
||||
///
|
||||
///
|
||||
/// @tparam PropertyType Type of the object returned by the backend call.
|
||||
/// @tparam FnPtrArgs Parameter pack holding argument types of the backend
|
||||
/// method to be invoked.
|
||||
/// @tparam Args Parameter pack holding types of the arguments provided
|
||||
/// in the call to this method.
|
||||
///
|
||||
/// @param MethodPointer Pointer to the backend method to be called.
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param [out] property Reference to the shared pointer where retrieved
|
||||
/// property should be assigned.
|
||||
/// @param input Values to be used as input to the backend call.
|
||||
///
|
||||
/// @throw db::NoSuchDatabase if no database matching the given selector
|
||||
/// was found.
|
||||
template<typename PropertyType, typename... FnPtrArgs, typename... Args>
|
||||
void getOptionalPropertyConst(util::OptionalValue<PropertyType>
|
||||
(ConfigBackendType::*MethodPointer)
|
||||
(const db::ServerSelector&, FnPtrArgs...) const,
|
||||
const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
util::OptionalValue<PropertyType>& property,
|
||||
Args... input) const {
|
||||
|
||||
// If no particular backend is selected, call each backend and return
|
||||
// the first non-null (non zero) value.
|
||||
if (backend_selector.amUnspecified()) {
|
||||
for (auto backend : backends_) {
|
||||
property = ((*backend).*MethodPointer)(server_selector, input...);
|
||||
if (property.isSpecified()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Backend selected, find the one that matches selection.
|
||||
auto backends = selectBackends(backend_selector);
|
||||
if (!backends.empty()) {
|
||||
for (auto backend : backends) {
|
||||
property = ((*backend).*MethodPointer)(server_selector, input...);
|
||||
if (property.isSpecified()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
isc_throw(db::NoSuchDatabase, "no such database found for selector: "
|
||||
<< backend_selector.toText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Retrieve multiple configuration properties from the pool.
|
||||
///
|
||||
/// This is a common method for retrieving multiple configuration properties
|
||||
/// from the databases. The server specific backends call this method to
|
||||
/// retrieve multiple objects of the same type. For example, the DHCPv6
|
||||
/// configuration backend pool may use this function to implement a
|
||||
/// @c getSubnets6 method:
|
||||
///
|
||||
/// @code
|
||||
/// Subnet6Collection getModifiedSubnets6(const BackendSelector& backend_selector,
|
||||
/// const ServerSelector& server_selector,
|
||||
/// const ptime& modification_time) const {
|
||||
/// Subnet6Collection subnets;
|
||||
/// getMultiplePropertiesConst<Subnet6Collection, const ptime&>
|
||||
/// (&ConfigBackendDHCPv6::getSubnets6, backend_selector, server_selector,
|
||||
/// subnets, modification_time);
|
||||
/// return (subnets);
|
||||
/// }
|
||||
/// @endcode
|
||||
///
|
||||
/// where @c ConfigBackendDHCPv6::getSubnets6 has the following signature:
|
||||
///
|
||||
/// @code
|
||||
/// Subnet6Collection getSubnets6(const ServerSelector&, const ptime&) const;
|
||||
/// @endcode
|
||||
///
|
||||
/// If the backend selector is set to "unspecified", this method will iterate
|
||||
/// over existing backends and call the @c MethodPointer method on each
|
||||
/// backend. It will return the first non-empty list returned by one of the
|
||||
/// backends.
|
||||
///
|
||||
/// @tparam PropertyCollectionType Type of the container into which the
|
||||
/// properties are stored.
|
||||
/// @tparam FnPtrArgs Parameter pack holding argument types of the backend
|
||||
/// method to be invoked.
|
||||
/// @tparam Args Parameter pack holding types of the arguments provided
|
||||
/// in the call to this method.
|
||||
///
|
||||
/// @param MethodPointer Pointer to the backend method to be called.
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param [out] properties Reference to the collection of retrieved properties.
|
||||
/// @param input Values to be used as input to the backend call.
|
||||
///
|
||||
/// @throw db::NoSuchDatabase if no database matching the given selector
|
||||
/// was found.
|
||||
template<typename PropertyCollectionType, typename... FnPtrArgs, typename... Args>
|
||||
void getMultiplePropertiesConst(PropertyCollectionType (ConfigBackendType::*MethodPointer)
|
||||
(const db::ServerSelector&, FnPtrArgs...) const,
|
||||
const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
PropertyCollectionType& properties,
|
||||
Args... input) const {
|
||||
if (backend_selector.amUnspecified()) {
|
||||
for (auto backend : backends_) {
|
||||
properties = ((*backend).*MethodPointer)(server_selector, input...);
|
||||
if (!properties.empty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
auto backends = selectBackends(backend_selector);
|
||||
if (!backends.empty()) {
|
||||
for (auto backend : backends) {
|
||||
properties = ((*backend).*MethodPointer)(server_selector, input...);
|
||||
if (!properties.empty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
isc_throw(db::NoSuchDatabase, "no database found for selector: "
|
||||
<< backend_selector.toText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Retrieve all configuration properties from the pool.
|
||||
///
|
||||
/// This is a common method for retrieving all configuration properties
|
||||
/// from the databases. The server specific backends call this method
|
||||
/// to retrieve all objects of the same type. For example, the DHCPv4
|
||||
/// configuration backend pool may use this function to implement a
|
||||
/// @c getAllSubnets4 method:
|
||||
///
|
||||
/// @code
|
||||
/// Subnet4Collection getAllSubnets4(const BackendSelector&, const ServerSelector&) const {
|
||||
/// Subnet4Collection subnets;
|
||||
/// getAllPropertiesConst<Subnet6Collection>
|
||||
/// (&ConfigBackendDHCPv4::getAllSubnets4, subnets, backend_selector,
|
||||
/// server_selector);
|
||||
/// return (subnets);
|
||||
/// }
|
||||
/// @endcode
|
||||
///
|
||||
/// where @c ConfigBackendDHCPv4::getAllSubnets4 has the following signature:
|
||||
///
|
||||
/// @code
|
||||
/// Subnet4Collection getAllSubnets4(const ServerSelector&) const;
|
||||
/// @endcode
|
||||
///
|
||||
/// If the backend selector is set to "unspecified", this method will iterate
|
||||
/// over existing backends and call the @c MethodPointer method on each
|
||||
/// backend. It will return the first non-empty list returned by one of the
|
||||
/// backends.
|
||||
///
|
||||
/// @tparam PropertyCollectionType Type of the container into which the
|
||||
/// properties are stored.
|
||||
///
|
||||
/// @param MethodPointer Pointer to the backend method to be called.
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param [out] properties Reference to the collection of retrieved properties.
|
||||
///
|
||||
/// @throw db::NoSuchDatabase if no database matching the given selector
|
||||
/// was found.
|
||||
template<typename PropertyCollectionType>
|
||||
void getAllPropertiesConst(PropertyCollectionType (ConfigBackendType::*MethodPointer)
|
||||
(const db::ServerSelector&) const,
|
||||
const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
PropertyCollectionType& properties) const {
|
||||
if (backend_selector.amUnspecified()) {
|
||||
for (auto backend : backends_) {
|
||||
properties = ((*backend).*MethodPointer)(server_selector);
|
||||
if (!properties.empty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
auto backends = selectBackends(backend_selector);
|
||||
if (!backends.empty()) {
|
||||
for (auto backend : backends) {
|
||||
properties = ((*backend).*MethodPointer)(server_selector);
|
||||
if (!properties.empty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
isc_throw(db::NoSuchDatabase, "no database found for selector: "
|
||||
<< backend_selector.toText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @brief Add, update or delete property from the backend.
|
||||
///
|
||||
/// This is a common method for storing a single configuration property in
|
||||
/// a database, updating an existing property or deleting the property.
|
||||
/// The server specific backends call this method. For example,
|
||||
/// the DHCPv6 configuration backend pool may use this function to implement
|
||||
/// a @c createUpdateSubnet6 method:
|
||||
///
|
||||
/// @code
|
||||
/// void createUpdateSubnet6(const Subnet6Ptr& subnet,
|
||||
/// const BackendSelector& backend_selector,
|
||||
/// const ServerSelector& server_selector) {
|
||||
/// createUpdateDeleteProperty<const Subnet6Ptr&>
|
||||
/// (&ConfigBackendDHCPv6::createUpdateSubnet6, backend_selector,
|
||||
/// server_selector, subnet, selector);
|
||||
/// }
|
||||
/// @endcode
|
||||
///
|
||||
/// where @c ConfigBackendDHCPv6::createUpdateSubnet6 has the following
|
||||
/// signature:
|
||||
///
|
||||
/// @code
|
||||
/// void createUpdateSubnet6(const ServerSelector&, const Subnet6Ptr&);
|
||||
/// @endcode
|
||||
///
|
||||
/// The backend selector must point to exactly one backend. If more than one
|
||||
/// backend is selected, an exception is thrown. If no backend is selected
|
||||
/// an exception is thrown either.
|
||||
///
|
||||
/// @tparam FnPtrArgs Parameter pack holding argument types of the backend
|
||||
/// method to be invoked.
|
||||
/// @tparam Args Parameter pack holding types of the arguments provided
|
||||
/// in the call to this method.
|
||||
///
|
||||
/// @param MethodPointer Pointer to the backend method to be called.
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param input Objects used as arguments to the backend method to be
|
||||
/// called.
|
||||
///
|
||||
/// @throw db::NoSuchDatabase if no database matching the given selector
|
||||
/// was found.
|
||||
/// @throw db::AmbiguousDatabase if multiple databases matching the selector
|
||||
/// were found.
|
||||
template<typename... FnPtrArgs, typename... Args>
|
||||
void createUpdateDeleteProperty(void (ConfigBackendType::*MethodPointer)
|
||||
(const db::ServerSelector&, FnPtrArgs...),
|
||||
const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
Args... input) {
|
||||
auto backends = selectBackends(backend_selector);
|
||||
if (backends.empty()) {
|
||||
isc_throw(db::NoSuchDatabase, "no database found for selector: "
|
||||
<< backend_selector.toText());
|
||||
|
||||
} else if (backends.size() > 1) {
|
||||
isc_throw(db::AmbiguousDatabase, "more than 1 database found for "
|
||||
"selector: " << backend_selector.toText());
|
||||
}
|
||||
|
||||
(*(*(backends.begin())).*MethodPointer)(server_selector, input...);
|
||||
}
|
||||
|
||||
/// @brief Selects existing backends matching the selector.
|
||||
///
|
||||
/// This method selects backends matching the selector. If the selector is
|
||||
/// "unspecified" or there is no backend in the pool, an empty list is returned.
|
||||
///
|
||||
/// @param selector Selector for which matching backends should be selected.
|
||||
std::list<ConfigBackendTypePtr>
|
||||
selectBackends(const db::BackendSelector& backend_selector) const {
|
||||
|
||||
std::list<ConfigBackendTypePtr> selected;
|
||||
|
||||
// In case there is only one backend and the caller hasn't specified
|
||||
// any particular backend, simply return it.
|
||||
if ((backends_.size() == 1) && backend_selector.amUnspecified()) {
|
||||
selected.push_back(*backends_.begin());
|
||||
return (selected);
|
||||
}
|
||||
|
||||
// For other cases we return empty list.
|
||||
if (backends_.empty() || backend_selector.amUnspecified()) {
|
||||
return (selected);
|
||||
}
|
||||
|
||||
// Go over all backends.
|
||||
for (auto backend : backends_) {
|
||||
// If backend type is specified and it is not matching,
|
||||
// do not select this backend.
|
||||
if ((backend_selector.getBackendType() != db::BackendSelector::Type::UNSPEC) &&
|
||||
(backend_selector.getBackendType() !=
|
||||
db::BackendSelector::stringToBackendType(backend->getType()))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the host has been specified by the backend's host is not
|
||||
// matching, do not select this backend.
|
||||
if ((!backend_selector.getBackendHost().empty()) &&
|
||||
(backend_selector.getBackendHost() != backend->getHost())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the port has been specified by the backend's port is not
|
||||
// matching, do not select this backend.
|
||||
if ((backend_selector.getBackendPort() != 0) &&
|
||||
(backend_selector.getBackendPort() != backend->getPort())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Passed all checks, so the backend is matching. Add it to the list.
|
||||
selected.push_back(backend);
|
||||
}
|
||||
|
||||
return (selected);
|
||||
}
|
||||
|
||||
/// @brief Holds configuration backends belonging to the pool.
|
||||
std::list<ConfigBackendTypePtr> backends_;
|
||||
};
|
||||
|
||||
} // end of namespace isc::cb
|
||||
} // end of namespace isc
|
||||
|
||||
#endif // BASE_CONFIG_BACKEND_POOL_H
|
1
src/lib/config_backend/tests/.gitignore
vendored
Normal file
1
src/lib/config_backend/tests/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/libcb_unittests
|
39
src/lib/config_backend/tests/Makefile.am
Normal file
39
src/lib/config_backend/tests/Makefile.am
Normal file
@@ -0,0 +1,39 @@
|
||||
SUBDIRS = .
|
||||
|
||||
AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
|
||||
AM_CPPFLAGS += $(BOOST_INCLUDES)
|
||||
AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/config/tests\"
|
||||
|
||||
AM_CXXFLAGS = $(KEA_CXXFLAGS)
|
||||
|
||||
if USE_STATIC_LINK
|
||||
AM_LDFLAGS = -static
|
||||
endif
|
||||
|
||||
CLEANFILES = *.gcno *.gcda
|
||||
|
||||
TESTS_ENVIRONMENT = \
|
||||
$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
|
||||
|
||||
TESTS =
|
||||
if HAVE_GTEST
|
||||
TESTS += libcb_unittests
|
||||
|
||||
libcb_unittests_SOURCES = config_backend_mgr_unittest.cc
|
||||
libcb_unittests_SOURCES += run_unittests.cc
|
||||
|
||||
libcb_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
|
||||
libcb_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
|
||||
|
||||
libcb_unittests_LDADD = $(top_builddir)/src/lib/database/libkea-database.la
|
||||
libcb_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la
|
||||
libcb_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
|
||||
libcb_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
|
||||
libcb_unittests_LDADD += $(top_builddir)/src/lib/util/threads/libkea-threads.la
|
||||
libcb_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
|
||||
libcb_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
|
||||
libcb_unittests_LDADD += $(LOG4CPLUS_LIBS) $(BOOST_LIBS) $(GTEST_LDADD)
|
||||
|
||||
endif
|
||||
|
||||
noinst_PROGRAMS = $(TESTS)
|
529
src/lib/config_backend/tests/config_backend_mgr_unittest.cc
Normal file
529
src/lib/config_backend/tests/config_backend_mgr_unittest.cc
Normal file
@@ -0,0 +1,529 @@
|
||||
// Copyright (C) 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 <config_backend/base_config_backend_mgr.h>
|
||||
#include <config_backend/base_config_backend_pool.h>
|
||||
#include <config_backend/base_config_backend.h>
|
||||
#include <database/database_connection.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
using namespace isc;
|
||||
using namespace isc::cb;
|
||||
using namespace isc::db;
|
||||
|
||||
namespace {
|
||||
|
||||
/// @brief Defines list of properties retrieved by @c TestConfigBackend.
|
||||
///
|
||||
/// A single property is a name/value pair, where value is an integer.
|
||||
typedef std::list<std::pair<std::string, int> > PropertiesList;
|
||||
|
||||
/// @brief Implements configuration backend used in tests.
|
||||
///
|
||||
/// @c BaseConfigBackend is an abstract class that must be implemented
|
||||
/// in order to allow us to test mechanisms implemented in
|
||||
/// @c BaseConfigBackendMgr and @c BaseConfigBackendPool.
|
||||
///
|
||||
/// Normally, a class derived directly from the @c BaseConfigBackend
|
||||
/// will merely provide an interface for server specific operations,
|
||||
/// e.g. DHCPv4 specific operations, and the database specific classes
|
||||
/// will implement this interface. However, for the test purposes it
|
||||
/// is convenient to implement them here and let the derivations
|
||||
/// only provide the implementations of the @c getType, @c getHost
|
||||
/// and @c getPort functions. That way, the logic for adding and
|
||||
/// retrieving the data from the backend is implemented only once and
|
||||
/// is common accross all test backends.
|
||||
///
|
||||
/// This class provides a logic for managing test data being a collection
|
||||
/// of name/value pairs, i.e. "properties". It contains a list of
|
||||
/// properties and the functions for adding the properties, retrieving
|
||||
/// a single property and retrieving a collection of properties.
|
||||
class TestConfigBackend : public BaseConfigBackend {
|
||||
public:
|
||||
|
||||
/// @brief Retrieves first property having a given name.
|
||||
///
|
||||
/// @param property_name Name of the property to be retrieved.
|
||||
/// @return Value of the property or 0 if property doesn't exist.
|
||||
virtual int getProperty(const ServerSelector&,
|
||||
const std::string& property_name) const {
|
||||
for (auto property : properties_) {
|
||||
if (property.first == property_name) {
|
||||
return (property.second);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/// @brief Retrieves first property matching the name and value.
|
||||
///
|
||||
/// @param property_name Name of the property to be retrieved.
|
||||
/// @param property_value Value of the property to be retrieved.
|
||||
/// @return Value of the property or 0 if the property doesn't exist.
|
||||
virtual int getProperty(const ServerSelector&,
|
||||
const std::string& property_name,
|
||||
const int property_value) const {
|
||||
for (auto property : properties_) {
|
||||
if ((property.first == property_name) &&
|
||||
(property.second == property_value)) {
|
||||
return (property.second);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/// @brief Retrieves all properties having a given name.
|
||||
///
|
||||
/// @param property_name Name of the properties to be retrieved.
|
||||
/// @return List of the properties having a given name. This list is
|
||||
/// empty if no property was found.
|
||||
virtual PropertiesList getProperties(const ServerSelector&,
|
||||
const std::string& property_name) const {
|
||||
PropertiesList properties;
|
||||
for (auto property : properties_) {
|
||||
if (property.first == property_name) {
|
||||
properties.push_back(property);
|
||||
}
|
||||
}
|
||||
return (properties);
|
||||
}
|
||||
|
||||
/// @brief Retrieves all properties.
|
||||
///
|
||||
/// @return List of all properties held in the backend.
|
||||
virtual PropertiesList getAllProperties(const ServerSelector&) const {
|
||||
return (properties_);
|
||||
}
|
||||
|
||||
/// @brief Creates new property.
|
||||
///
|
||||
/// @param new_property Property to be added to the backend.
|
||||
virtual void createProperty(const ServerSelector&,
|
||||
const std::pair<std::string, int>& new_property) {
|
||||
properties_.push_back(new_property);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief Holds list of properties (simulates database).
|
||||
PropertiesList properties_;
|
||||
|
||||
};
|
||||
|
||||
/// @brief Shared pointer to the @c TestConfigBackend.
|
||||
typedef boost::shared_ptr<TestConfigBackend> TestConfigBackendPtr;
|
||||
|
||||
/// @brief First implementation of the test config backend.
|
||||
///
|
||||
/// It simulates being a MySQL backend installed on the
|
||||
/// "mysql-host" host and running on port 2345.
|
||||
class TestConfigBackendImpl1 : public TestConfigBackend {
|
||||
public:
|
||||
|
||||
/// @brief Returns backend type.
|
||||
///
|
||||
/// @return "mysql".
|
||||
virtual std::string getType() const {
|
||||
return (std::string("mysql"));
|
||||
}
|
||||
|
||||
/// @brief Returns backend host.
|
||||
///
|
||||
/// @return "mysql-host".
|
||||
virtual std::string getHost() const {
|
||||
return (std::string("mysql-host"));
|
||||
}
|
||||
|
||||
/// @brief Returns backend port.
|
||||
///
|
||||
/// @return Port number 2345.
|
||||
virtual uint16_t getPort() const {
|
||||
return (2345);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// @brief Shared pointer to the @c TestConfigBackendImpl1.
|
||||
typedef boost::shared_ptr<TestConfigBackendImpl1> TestConfigBackendImpl1Ptr;
|
||||
|
||||
/// @brief Second implementation of the test config backend.
|
||||
///
|
||||
/// It simulates being a Postgres backend installed on the
|
||||
/// "pgsql-host" host and running on port 1234.
|
||||
class TestConfigBackendImpl2 : public TestConfigBackend {
|
||||
public:
|
||||
|
||||
/// @brief Returns backend type.
|
||||
///
|
||||
/// @return "pgsql".
|
||||
virtual std::string getType() const {
|
||||
return (std::string("pgsql"));
|
||||
}
|
||||
|
||||
/// @brief Returns backend host.
|
||||
///
|
||||
/// @return "pgsql-host".
|
||||
virtual std::string getHost() const {
|
||||
return (std::string("pgsql-host"));
|
||||
}
|
||||
|
||||
/// @brief Returns backend port.
|
||||
///
|
||||
/// @return Port number 1234.
|
||||
virtual uint16_t getPort() const {
|
||||
return (1234);
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Shared pointer to the @c TestConfigBackendImpl2.
|
||||
typedef boost::shared_ptr<TestConfigBackendImpl2> TestConfigBackendImpl2Ptr;
|
||||
|
||||
/// @brief Implements test pool of configuration backends.
|
||||
///
|
||||
/// @c BaseConfigBackendPool template provides mechanics for managing the data
|
||||
/// stored in multiple backends. Server specific pools must extend this class
|
||||
/// with methods for managing the data appropriate for the server types.
|
||||
/// This class provides an example pool implementation for managing the
|
||||
/// "properties" being name/value pairs. It extends the base class with
|
||||
/// new methods to retrieve a single property and multiple properties. It
|
||||
/// also adds a method to create new property. Those methods correspond to
|
||||
/// the ones implemented in the @c TestConfigBackend, but also each of
|
||||
/// them includes a "database selector" used to indicate the backend to
|
||||
/// be used.
|
||||
class TestConfigBackendPool : public BaseConfigBackendPool<TestConfigBackend> {
|
||||
public:
|
||||
|
||||
/// @brief Retrieves a value of the property.
|
||||
///
|
||||
/// @param property_name Name of the property which value should be returned.
|
||||
/// @param backend_selector Backend selector. The default value of the selector
|
||||
/// is @c UNSPEC which means that the property will be searched in all backends
|
||||
/// and the first value found will be returned.
|
||||
/// @param server_selector Server selector. The default value is set to @c ALL,
|
||||
/// which means that the property for all servers will be returned.
|
||||
virtual int getProperty(const std::string& property_name,
|
||||
const BackendSelector& backend_selector =
|
||||
BackendSelector::UNSPEC(),
|
||||
const ServerSelector& server_selector =
|
||||
ServerSelector::ALL()) const {
|
||||
int property;
|
||||
|
||||
// If the selector is specified, this method will pick the appropriate
|
||||
// backend and will call getProperty method on this backend. If the
|
||||
// selector is not specified, this method will iterate over existing
|
||||
// backends and call getProperty on them. It will return after finding
|
||||
// the first non-zero value of the property. For example, if the first
|
||||
// backend contains a non-zero value this value will be returned and
|
||||
// the value held in the second backend (if any) won't be fetched.
|
||||
// The template arguments specify the returned value type and the
|
||||
// argument of the getProperty method.
|
||||
getPropertyPtrConst<int, const std::string&>
|
||||
(&TestConfigBackend::getProperty, backend_selector, server_selector,
|
||||
property, property_name);
|
||||
return (property);
|
||||
}
|
||||
|
||||
/// @brief Retrieves value of the property.
|
||||
///
|
||||
/// @param property_name Name of the property which value should be returned.
|
||||
/// @param property_value Value of the property to be retrieved.
|
||||
/// @param backend_selector Backend selector. The default value of the selector
|
||||
/// is @c UNSPEC which means that the property will be searched in all backends
|
||||
/// and the first value found will be returned.
|
||||
/// @param server_selector Server selector. The default value is set to @c ALL,
|
||||
/// which means that the property for all servers will be returned.
|
||||
virtual int getProperty(const std::string& property_name,
|
||||
const int property_value,
|
||||
const BackendSelector& backend_selector =
|
||||
BackendSelector::UNSPEC(),
|
||||
const ServerSelector& server_selector =
|
||||
ServerSelector::ALL()) const {
|
||||
int property;
|
||||
getPropertyPtrConst<int, const std::string&, int>
|
||||
(&TestConfigBackend::getProperty, backend_selector, server_selector,
|
||||
property, property_name, property_value);
|
||||
return (property);
|
||||
}
|
||||
|
||||
|
||||
/// @brief Retrieves multiple properties.
|
||||
///
|
||||
/// @param property_name Name of the properties which should be retrieved.
|
||||
/// @param backend_selector Backend selector. The default value of the selector
|
||||
/// is @c UNSPEC which means that the properties will be searched in all
|
||||
/// backends and the first non-empty list will be returned.
|
||||
/// @param server_selector Server selector. The default value is set to @c ALL,
|
||||
/// which means that the properties for all servers will be returned.
|
||||
virtual PropertiesList getProperties(const std::string& property_name,
|
||||
const BackendSelector& backend_selector =
|
||||
BackendSelector::UNSPEC(),
|
||||
const ServerSelector& server_selector =
|
||||
ServerSelector::ALL()) const {
|
||||
PropertiesList properties;
|
||||
|
||||
// If the selector is specified, this method will pick the appropriate
|
||||
// backend and will call getProperties method on this backend. If the
|
||||
// selector is not specified, this method will iterate over existing
|
||||
// backends and call getProperties on them. It will return after finding
|
||||
// the first non-empty list of properties in one of the backends.
|
||||
// The template arguments specify the type of the list of properties
|
||||
// and the argument of the getProperties method.
|
||||
getMultiplePropertiesConst<PropertiesList, const std::string&>
|
||||
(&TestConfigBackend::getProperties, backend_selector, server_selector,
|
||||
properties, property_name);
|
||||
return (properties);
|
||||
}
|
||||
|
||||
/// @brief Retrieves all properties.
|
||||
///
|
||||
/// @param backend_selector Backend selector. The default value of the selector
|
||||
/// is @c UNSPEC which means that the properties will be searched in all
|
||||
/// backends and the first non-empty list will be returned.
|
||||
/// @param server_selector Server selector. The default value is set to @c ALL,
|
||||
/// which means that the properties for all servers will be returned.
|
||||
virtual PropertiesList getAllProperties(const BackendSelector& backend_selector =
|
||||
BackendSelector::UNSPEC(),
|
||||
const ServerSelector& server_selector =
|
||||
ServerSelector::ALL()) const {
|
||||
PropertiesList properties;
|
||||
|
||||
// This method is similar to getMultiplePropertiesConst but it lacks
|
||||
// an argument and it simply returns all properties.
|
||||
getAllPropertiesConst<PropertiesList>
|
||||
(&TestConfigBackend::getAllProperties, backend_selector, server_selector,
|
||||
properties);
|
||||
return (properties);
|
||||
}
|
||||
|
||||
/// @brief Creates new property in a selected backend.
|
||||
///
|
||||
/// @param new_property New property to be added to a backend.
|
||||
/// @param backend_selector Backend selector. It has no default value.
|
||||
/// @param server_selector The default value is @c ALL which means that
|
||||
/// new property is going to be shared by all servers.
|
||||
virtual void createProperty(const std::pair<std::string, int>& new_property,
|
||||
const BackendSelector& backend_selector,
|
||||
const ServerSelector& server_selector =
|
||||
ServerSelector::ALL()) {
|
||||
createUpdateDeleteProperty<const std::pair<std::string, int>&>
|
||||
(&TestConfigBackend::createProperty, backend_selector, server_selector,
|
||||
new_property);
|
||||
}
|
||||
};
|
||||
|
||||
using TestConfigBackendMgr = BaseConfigBackendMgr<TestConfigBackendPool>;
|
||||
|
||||
/// @brief Test fixture class for testing @c ConfigBackendMgr.
|
||||
class ConfigBackendMgrTest : public ::testing::Test {
|
||||
public:
|
||||
|
||||
/// @brief Constructor.
|
||||
ConfigBackendMgrTest()
|
||||
: config_mgr_() {
|
||||
}
|
||||
|
||||
/// @brief Destructor.
|
||||
///
|
||||
/// Removes backend instances.
|
||||
~ConfigBackendMgrTest() {
|
||||
config_mgr_.delAllBackends();
|
||||
}
|
||||
|
||||
/// @brief Creates example database backend called "mysql".
|
||||
///
|
||||
/// It uses @c TestConfigBackendImpl1.
|
||||
void addTestMySQLBackend() {
|
||||
config_mgr_.registerBackendFactory("mysql", [](const DatabaseConnection::ParameterMap&)
|
||||
-> TestConfigBackendPtr {
|
||||
return (TestConfigBackendImpl1Ptr(new TestConfigBackendImpl1()));
|
||||
});
|
||||
|
||||
config_mgr_.addBackend("type=mysql");
|
||||
}
|
||||
|
||||
/// @brief Creates example database backend called "pgsql".
|
||||
///
|
||||
/// It uses @c TestConfigBackendImpl2.
|
||||
void addTestPgSQLBackend() {
|
||||
config_mgr_.registerBackendFactory("pgsql", [](const DatabaseConnection::ParameterMap&)
|
||||
-> TestConfigBackendPtr {
|
||||
return (TestConfigBackendImpl2Ptr(new TestConfigBackendImpl2()));
|
||||
});
|
||||
|
||||
// Actually create the backends.
|
||||
config_mgr_.addBackend("type=pgsql");
|
||||
}
|
||||
|
||||
/// @brief Creates two example database backends called "mysql" and "pgsql".
|
||||
///
|
||||
/// It uses @c TestConfigBackendImpl1 and @c TestConfigBackendImpl2.
|
||||
void addTestBackends() {
|
||||
addTestMySQLBackend();
|
||||
addTestPgSQLBackend();
|
||||
}
|
||||
|
||||
/// @brief Adds test data into the backends.
|
||||
void addTestData() {
|
||||
// Add two properties with different names into the first backend.
|
||||
config_mgr_.getPool()->createProperty(std::make_pair("dogs", 1),
|
||||
BackendSelector(BackendSelector::Type::MYSQL));
|
||||
config_mgr_.getPool()->createProperty(std::make_pair("wolves", 3),
|
||||
BackendSelector(BackendSelector::Type::MYSQL));
|
||||
|
||||
// Add two properties into the second backend. Both properties share the
|
||||
// name so as we can test retrieving multiple records from the same backend.
|
||||
config_mgr_.getPool()->createProperty(std::make_pair("cats", 2),
|
||||
BackendSelector(BackendSelector::Type::PGSQL));
|
||||
config_mgr_.getPool()->createProperty(std::make_pair("cats", 4),
|
||||
BackendSelector(BackendSelector::Type::PGSQL));
|
||||
}
|
||||
|
||||
/// Instance of the test configuration manager.
|
||||
TestConfigBackendMgr config_mgr_;
|
||||
};
|
||||
|
||||
// Test that selector can be left "unspecified" if there is only one backend,
|
||||
// when manipulating the data.
|
||||
TEST_F(ConfigBackendMgrTest, createPropertySingleBackendUnspec) {
|
||||
addTestMySQLBackend();
|
||||
|
||||
ASSERT_NO_THROW(
|
||||
config_mgr_.getPool()->createProperty(std::make_pair("dogs", 1),
|
||||
BackendSelector(BackendSelector::Type::UNSPEC))
|
||||
);
|
||||
|
||||
// We should be able to retrieve stored value without having to specify
|
||||
// the backend.
|
||||
EXPECT_EQ(1, config_mgr_.getPool()->getProperty("dogs"));
|
||||
}
|
||||
|
||||
// Test that selector must be specified if there is more than one backend,
|
||||
// when manipulating the data.
|
||||
TEST_F(ConfigBackendMgrTest, createPropertyTwoBackendsUnspec) {
|
||||
addTestBackends();
|
||||
|
||||
// Backend must be selected if there is more than one backend present.
|
||||
EXPECT_THROW(
|
||||
config_mgr_.getPool()->createProperty(std::make_pair("dogs", 1),
|
||||
BackendSelector(BackendSelector::Type::UNSPEC)),
|
||||
NoSuchDatabase
|
||||
);
|
||||
}
|
||||
|
||||
// Test that exception is thrown when multiple backends are selected.
|
||||
TEST_F(ConfigBackendMgrTest, createPropertyAmbiguousSelection) {
|
||||
addTestBackends();
|
||||
|
||||
// Add another MySQL backend to cause the selection to give ambiguous
|
||||
// result.
|
||||
config_mgr_.addBackend("type=mysql");
|
||||
|
||||
EXPECT_THROW(
|
||||
config_mgr_.getPool()->createProperty(std::make_pair("dogs", 1),
|
||||
BackendSelector(BackendSelector::Type::MYSQL)),
|
||||
AmbiguousDatabase
|
||||
);
|
||||
}
|
||||
|
||||
// Test that a single property can be retrieved from a selected backend.
|
||||
TEST_F(ConfigBackendMgrTest, getSingleProperty) {
|
||||
|
||||
addTestBackends();
|
||||
addTestData();
|
||||
|
||||
// Backend is not specified, so it should find the dogs in first one and
|
||||
// cats in the second one.
|
||||
EXPECT_EQ(1, config_mgr_.getPool()->getProperty("dogs"));
|
||||
EXPECT_EQ(2, config_mgr_.getPool()->getProperty("cats"));
|
||||
|
||||
// No dogs in the pgsql backend and no cats in mysql backend.
|
||||
EXPECT_EQ(0, config_mgr_.getPool()->getProperty("dogs",
|
||||
BackendSelector(BackendSelector::Type::PGSQL)));
|
||||
EXPECT_EQ(0, config_mgr_.getPool()->getProperty("cats",
|
||||
BackendSelector(BackendSelector::Type::MYSQL)));
|
||||
|
||||
// If the selectors are pointing to the right databases, the dogs and cats
|
||||
// should be returned properly.
|
||||
EXPECT_EQ(1, config_mgr_.getPool()->getProperty("dogs",
|
||||
BackendSelector(BackendSelector::Type::MYSQL)));
|
||||
EXPECT_EQ(2, config_mgr_.getPool()->getProperty("cats",
|
||||
BackendSelector(BackendSelector::Type::PGSQL)));
|
||||
|
||||
// Also make sure that the variant of getProperty function taking two arguments
|
||||
// would return the value.
|
||||
EXPECT_EQ(1, config_mgr_.getPool()->getProperty("dogs", 1,
|
||||
BackendSelector(BackendSelector::Type::MYSQL)));
|
||||
|
||||
// If the value is not matching it should return 0.
|
||||
EXPECT_EQ(0, config_mgr_.getPool()->getProperty("dogs", 2,
|
||||
BackendSelector(BackendSelector::Type::MYSQL)));
|
||||
|
||||
// Try to use the backend that is not present.
|
||||
EXPECT_THROW(config_mgr_.getPool()->getProperty("cats",
|
||||
BackendSelector(BackendSelector::Type::CQL)),
|
||||
NoSuchDatabase);
|
||||
}
|
||||
|
||||
// Test that multiple properties can be retrieved with filtering.
|
||||
TEST_F(ConfigBackendMgrTest, getMultipleProperties) {
|
||||
|
||||
addTestBackends();
|
||||
addTestData();
|
||||
|
||||
// There is one dogs entry in mysql.
|
||||
PropertiesList mysql_list =
|
||||
config_mgr_.getPool()->getProperties("dogs",
|
||||
BackendSelector(BackendSelector::Type::MYSQL));
|
||||
ASSERT_EQ(1, mysql_list.size());
|
||||
|
||||
// There is also one wolves entry in mysql.
|
||||
mysql_list = config_mgr_.getPool()->getProperties("wolves",
|
||||
BackendSelector(BackendSelector::Type::MYSQL));
|
||||
ASSERT_EQ(1, mysql_list.size());
|
||||
|
||||
// There are two cats entries in pgsql.
|
||||
PropertiesList pgsql_list =
|
||||
config_mgr_.getPool()->getProperties("cats",
|
||||
BackendSelector(BackendSelector::Type::PGSQL));
|
||||
ASSERT_EQ(2, pgsql_list.size());
|
||||
|
||||
// Try to use the backend that is not present.
|
||||
EXPECT_THROW(config_mgr_.getPool()->getProperties("cats",
|
||||
BackendSelector(BackendSelector::Type::CQL)),
|
||||
NoSuchDatabase);
|
||||
|
||||
}
|
||||
|
||||
// Test that all properties can be retrieved from each backend.
|
||||
TEST_F(ConfigBackendMgrTest, getAllProperties) {
|
||||
|
||||
addTestBackends();
|
||||
addTestData();
|
||||
|
||||
// The mysql backend holds two entries.
|
||||
PropertiesList mysql_list =
|
||||
config_mgr_.getPool()->getAllProperties(BackendSelector(BackendSelector::Type::MYSQL));
|
||||
ASSERT_EQ(2, mysql_list.size());
|
||||
|
||||
// The pgsql backends also holds two entries.
|
||||
PropertiesList pgsql_list =
|
||||
config_mgr_.getPool()->getAllProperties(BackendSelector(BackendSelector::Type::PGSQL));
|
||||
ASSERT_EQ(2, pgsql_list.size());
|
||||
|
||||
// Try to use the backend that is not present.
|
||||
EXPECT_THROW(config_mgr_.getPool()->getProperties("cats",
|
||||
BackendSelector(BackendSelector::Type::CQL)),
|
||||
NoSuchDatabase);
|
||||
}
|
||||
|
||||
}
|
||||
|
19
src/lib/config_backend/tests/run_unittests.cc
Normal file
19
src/lib/config_backend/tests/run_unittests.cc
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (C) 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 <log/logger_support.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
int
|
||||
main(int argc, char* argv[]) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
int result = RUN_ALL_TESTS();
|
||||
|
||||
return (result);
|
||||
}
|
@@ -23,10 +23,12 @@ EXTRA_DIST = db_messages.mes
|
||||
CLEANFILES = *.gcno *.gcda db_messages.h db_messages.cc s-messages
|
||||
|
||||
lib_LTLIBRARIES = libkea-database.la
|
||||
libkea_database_la_SOURCES = database_connection.cc database_connection.h
|
||||
libkea_database_la_SOURCES = backend_selector.cc backend_selector.h
|
||||
libkea_database_la_SOURCES += database_connection.cc database_connection.h
|
||||
libkea_database_la_SOURCES += dbaccess_parser.h dbaccess_parser.cc
|
||||
libkea_database_la_SOURCES += db_exceptions.h
|
||||
libkea_database_la_SOURCES += db_log.cc db_log.h
|
||||
libkea_database_la_SOURCES += server_selector.h
|
||||
|
||||
nodist_libkea_database_la_SOURCES = db_messages.cc db_messages.h
|
||||
|
||||
@@ -43,6 +45,7 @@ libkea_database_la_LDFLAGS = -no-undefined -version-info 0:0:0
|
||||
# Specify the headers for copying into the installation directory tree.
|
||||
libkea_database_includedir = $(pkgincludedir)/database
|
||||
libkea_database_include_HEADERS = \
|
||||
backend_selector.h \
|
||||
database_connection.h \
|
||||
db_exceptions.h \
|
||||
db_log.h
|
||||
|
152
src/lib/database/backend_selector.cc
Normal file
152
src/lib/database/backend_selector.cc
Normal file
@@ -0,0 +1,152 @@
|
||||
// Copyright (C) 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 <database/backend_selector.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
#include <climits>
|
||||
#include <sstream>
|
||||
|
||||
using namespace isc::data;
|
||||
|
||||
namespace isc {
|
||||
namespace db {
|
||||
|
||||
BackendSelector::BackendSelector()
|
||||
: backend_type_(BackendSelector::Type::UNSPEC),
|
||||
host_(), port_(0) {
|
||||
}
|
||||
|
||||
BackendSelector::BackendSelector(const Type& backend_type)
|
||||
: backend_type_(backend_type),
|
||||
host_(), port_(0) {
|
||||
}
|
||||
|
||||
BackendSelector::BackendSelector(const std::string& host,
|
||||
const uint16_t port)
|
||||
: backend_type_(BackendSelector::Type::UNSPEC),
|
||||
host_(host), port_(port) {
|
||||
validate();
|
||||
}
|
||||
|
||||
BackendSelector::BackendSelector(const data::ConstElementPtr& access_map)
|
||||
: backend_type_(BackendSelector::Type::UNSPEC),
|
||||
host_(), port_(0) {
|
||||
if (access_map->getType() != Element::map) {
|
||||
isc_throw(BadValue, "database access information must be a map");
|
||||
}
|
||||
|
||||
ConstElementPtr t = access_map->get("type");
|
||||
if (t) {
|
||||
if (t->getType() != Element::string) {
|
||||
isc_throw(BadValue, "'type' parameter must be a string");
|
||||
}
|
||||
backend_type_ = stringToBackendType(t->stringValue());
|
||||
}
|
||||
|
||||
ConstElementPtr h = access_map->get("host");
|
||||
if (h) {
|
||||
if (h->getType() != Element::string) {
|
||||
isc_throw(BadValue, "'host' parameter must be a string");
|
||||
}
|
||||
host_ = h->stringValue();
|
||||
}
|
||||
|
||||
ConstElementPtr p = access_map->get("port");
|
||||
if (p) {
|
||||
if ((p->getType() != Element::integer) ||
|
||||
(p->intValue() < 0) ||
|
||||
(p->intValue() > std::numeric_limits<uint16_t>::max())) {
|
||||
isc_throw(BadValue, "'port' parameter must be a number in range from 0 "
|
||||
"to " << std::numeric_limits<uint16_t>::max());
|
||||
}
|
||||
port_ = static_cast<uint16_t>(p->intValue());
|
||||
}
|
||||
|
||||
validate();
|
||||
}
|
||||
|
||||
const BackendSelector&
|
||||
BackendSelector::BackendSelector::UNSPEC() {
|
||||
static BackendSelector selector;
|
||||
return (selector);
|
||||
}
|
||||
|
||||
bool
|
||||
BackendSelector::amUnspecified() const {
|
||||
return ((backend_type_ == BackendSelector::Type::UNSPEC) &&
|
||||
(host_.empty()) &&
|
||||
(port_ == 0));
|
||||
}
|
||||
|
||||
std::string
|
||||
BackendSelector::toText() const {
|
||||
std::ostringstream s;
|
||||
if (amUnspecified()) {
|
||||
s << "unspecified";
|
||||
|
||||
} else {
|
||||
if (backend_type_ != BackendSelector::Type::UNSPEC) {
|
||||
s << "type=" << backendTypeToString(backend_type_) << ",";
|
||||
}
|
||||
|
||||
if (!host_.empty()) {
|
||||
s << "host=" << host_ << ",";
|
||||
|
||||
if (port_ > 0) {
|
||||
s << "port=" << port_ << ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string text = s.str();
|
||||
if ((!text.empty() && (text.back() == ','))) {
|
||||
text.pop_back();
|
||||
}
|
||||
|
||||
return (text);
|
||||
}
|
||||
|
||||
BackendSelector::Type
|
||||
BackendSelector::stringToBackendType(const std::string& type) {
|
||||
if (type == "mysql") {
|
||||
return (BackendSelector::Type::MYSQL);
|
||||
|
||||
} else if (type == "pgsql") {
|
||||
return (BackendSelector::Type::PGSQL);
|
||||
|
||||
} else if (type == "cql") {
|
||||
return (BackendSelector::Type::CQL);
|
||||
|
||||
} else {
|
||||
isc_throw(BadValue, "unsupported configuration backend type '" << type << "'");
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
BackendSelector::backendTypeToString(const BackendSelector::Type& type) {
|
||||
switch (type) {
|
||||
case BackendSelector::Type::MYSQL:
|
||||
return ("mysql");
|
||||
case BackendSelector::Type::PGSQL:
|
||||
return ("pgsql");
|
||||
case BackendSelector::Type::CQL:
|
||||
return ("cql");
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
return (std::string());
|
||||
}
|
||||
|
||||
void
|
||||
BackendSelector::validate() const {
|
||||
if ((port_ != 0) && (host_.empty())) {
|
||||
isc_throw(BadValue, "'host' must be specified along with 'port' parameter");
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace isc::db
|
||||
} // end of namespace isc
|
208
src/lib/database/backend_selector.h
Normal file
208
src/lib/database/backend_selector.h
Normal file
@@ -0,0 +1,208 @@
|
||||
// Copyright (C) 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/.
|
||||
|
||||
#ifndef BACKEND_SELECTOR_H
|
||||
#define BACKEND_SELECTOR_H
|
||||
|
||||
#include <cc/data.h>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace isc {
|
||||
namespace db {
|
||||
|
||||
/// @brief Config Backend selector.
|
||||
///
|
||||
/// Each Kea server using database as a configuration respository
|
||||
/// may use multiple configuration backends simultaneously. The most
|
||||
/// typical case is to use a single configuration backend per server,
|
||||
/// but there are use cases when configuration information is distributed
|
||||
/// accross multiple database instances. In the future, there may be
|
||||
/// also caching mechanisms implemented, which will allow for storing
|
||||
/// results of certain database queries in memory.
|
||||
///
|
||||
/// From the server perspective, the most common use of the configuration
|
||||
/// backend is to fetch entire configuration information from the
|
||||
/// databases (upon startup) or fetch the latest updates to the
|
||||
/// configuration, e.g. new subnet added, DHCP option modified etc.
|
||||
/// In those cases, it is not so important from the server which backend
|
||||
/// this data come from. Therefore, the server would fetch this information
|
||||
/// from all available backends.
|
||||
///
|
||||
/// When the server administrator wants to insert some new data into
|
||||
/// the database, modify existing data or simply wants to check the
|
||||
/// contents of one of the database instance, he would specify which
|
||||
/// database backend he wants to direct queries to.
|
||||
///
|
||||
/// The @c BackendSelector class provides means to specify whether
|
||||
/// the queries should be directed to any backend (see server case
|
||||
/// above) or to a specific backend (data insertion case above).
|
||||
/// In addition, the @c BackendSelector allows for using various
|
||||
/// criteria for selecting a backend to use. Currently those criteria
|
||||
/// are: database type (e.g. mysql), database host and database port.
|
||||
/// In order to use a specific port, the database host must also be
|
||||
/// specified. Note that in a general case multiple backends of the
|
||||
/// same type can be used simultaneously, e.g. multiple MySQL backends.
|
||||
/// In that case, it may be necessary to specify host (and port) to
|
||||
/// issue a query to the right one.
|
||||
///
|
||||
/// The @c BackendSelector class may be extended in the future to provide
|
||||
/// additional backend selection criteria.
|
||||
class BackendSelector {
|
||||
public:
|
||||
|
||||
/// @brief Supported database types.
|
||||
///
|
||||
/// The @c UNSPEC indicates that the database type is not specified
|
||||
/// as selection criteria.
|
||||
enum class Type {
|
||||
MYSQL,
|
||||
PGSQL,
|
||||
CQL,
|
||||
UNSPEC
|
||||
};
|
||||
|
||||
/// @brief Default constructor.
|
||||
///
|
||||
/// It sets the selector to "unspecified". When this selector is used
|
||||
/// the backend pool will use "any" backend. This has a different meaning
|
||||
/// for each type of query. See the @c BaseConfigBackendPool for details.
|
||||
explicit BackendSelector();
|
||||
|
||||
/// @brief Constructor specifying backend type as a selection criteria.
|
||||
///
|
||||
/// @param backend_type Type of the backend to be selected.
|
||||
explicit BackendSelector(const Type& backend_type);
|
||||
|
||||
/// @brief Constructor for specifying host and optionally port as a
|
||||
/// selection criteria.
|
||||
///
|
||||
/// @param host Hostname to be used for selecting a backend.
|
||||
/// @param port Port number to be used for selecting a backend. This value
|
||||
/// is optional and is ignored when set to 0. It must be used on conjuction
|
||||
/// with hostname.
|
||||
explicit BackendSelector(const std::string& host, const uint16_t port = 0);
|
||||
|
||||
/// @brief Constructor for selecting a backend using JSON access map.
|
||||
///
|
||||
/// The provided access map must have the same structure as an element
|
||||
/// of the "config-databases" configuration parameter. However, it merely
|
||||
/// takes into account: "type", "host" and "port" parameters. In addition,
|
||||
/// these parameters are optional. The following are valid combinations:
|
||||
///
|
||||
/// @code
|
||||
/// {
|
||||
/// "type": "mysql"
|
||||
/// }
|
||||
/// @endcode
|
||||
///
|
||||
/// @code
|
||||
/// {
|
||||
/// "host": "somehost.example.org"
|
||||
/// }
|
||||
/// @endcode
|
||||
///
|
||||
/// @code
|
||||
/// {
|
||||
/// "host": "somehost.example.org",
|
||||
/// "port": 1234
|
||||
/// }
|
||||
/// @endcode
|
||||
///
|
||||
/// @code
|
||||
/// {
|
||||
/// "type": "mysql"
|
||||
/// "host": "somehost.example.org",
|
||||
/// }
|
||||
/// @endcode
|
||||
///
|
||||
/// @code
|
||||
/// {
|
||||
/// "type": "mysql"
|
||||
/// "host": "somehost.example.org",
|
||||
/// "port": 1234
|
||||
/// }
|
||||
/// @endcode
|
||||
///
|
||||
/// where "type" can be any of the supported backend types.
|
||||
///
|
||||
/// This constructor is useful for creating backend selectors from the
|
||||
/// received control commands.
|
||||
///
|
||||
/// @param access_map Access map as provided above.
|
||||
explicit BackendSelector(const data::ConstElementPtr& access_map);
|
||||
|
||||
/// @brief Returns instance of the "unspecified" backend selector.
|
||||
static const BackendSelector& UNSPEC();
|
||||
|
||||
/// @brief Checks if selector is "unspecified".
|
||||
///
|
||||
/// @return true if backend type is @c UNSPEC, hostname is empty and
|
||||
/// port number 0, false otherwise.
|
||||
bool amUnspecified() const;
|
||||
|
||||
/// @brief Returns backend type selected.
|
||||
Type getBackendType() const {
|
||||
return (backend_type_);
|
||||
}
|
||||
|
||||
/// @brief Returns host selected.
|
||||
///
|
||||
/// @return host if specified or empty string if host is not
|
||||
/// specified.
|
||||
std::string getBackendHost() const {
|
||||
return (host_);
|
||||
}
|
||||
|
||||
/// @brief Returns port selected.
|
||||
///
|
||||
/// @return port number of the selected backend or 0 if port number
|
||||
/// is not specified.
|
||||
uint16_t getBackendPort() const {
|
||||
return (port_);
|
||||
}
|
||||
|
||||
/// @brief Returns selections as text.
|
||||
///
|
||||
/// @return Collection of comma separated selections, e.g.
|
||||
/// "type=mysql,host=somehost.example.org,port=1234".
|
||||
std::string toText() const;
|
||||
|
||||
/// @brief Converts string to backend type.
|
||||
///
|
||||
/// @param type Backend type as string.
|
||||
static Type stringToBackendType(const std::string& type);
|
||||
|
||||
/// @brief Converts backend type to string.
|
||||
///
|
||||
/// @param type Backend type to be converted.
|
||||
static std::string backendTypeToString(const Type& type);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Checks if the specified selector is valid.
|
||||
///
|
||||
/// It checks if the port number is specified in conjuction with
|
||||
/// host.
|
||||
/// @throw BadValue if selector validation fails.
|
||||
void validate() const;
|
||||
|
||||
/// @brief Backend type selected.
|
||||
Type backend_type_;
|
||||
|
||||
/// @brief Host selected.
|
||||
std::string host_;
|
||||
|
||||
/// @brief Port number selected.
|
||||
uint16_t port_;
|
||||
};
|
||||
|
||||
|
||||
} // end of namespace isc::db
|
||||
} // end of namespace isc
|
||||
|
||||
#endif
|
@@ -74,6 +74,22 @@ public:
|
||||
isc::Exception(file, line, what) {}
|
||||
};
|
||||
|
||||
/// @brief Error when specified database could not be found in the server
|
||||
/// configuration.
|
||||
class NoSuchDatabase : public Exception {
|
||||
public:
|
||||
NoSuchDatabase(const char* file, size_t line, const char* what) :
|
||||
isc::Exception(file, line, what) {}
|
||||
};
|
||||
|
||||
/// @brief Specification of the database backend to be used yields
|
||||
/// multiple results.
|
||||
class AmbiguousDatabase : public Exception {
|
||||
public:
|
||||
AmbiguousDatabase(const char* file, size_t line, const char* what) :
|
||||
isc::Exception(file, line, what) {}
|
||||
};
|
||||
|
||||
} // namespace isc
|
||||
} // namespace db
|
||||
|
||||
|
126
src/lib/database/server_selector.h
Normal file
126
src/lib/database/server_selector.h
Normal file
@@ -0,0 +1,126 @@
|
||||
// Copyright (C) 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/.
|
||||
|
||||
#ifndef SERVER_SELECTOR_H
|
||||
#define SERVER_SELECTOR_H
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace isc {
|
||||
namespace db {
|
||||
|
||||
/// @brief Server selector for associating objects in a database with
|
||||
/// specific servers.
|
||||
///
|
||||
/// Configuration information stored in the configuration backends can be
|
||||
/// associated with selected servers, all servers or no particular server.
|
||||
/// For example: a particular subnet definition in the database may be
|
||||
/// associated with one server or can be shared by multiple servers.
|
||||
/// In the latter case, a subnet may be associated with a subset of
|
||||
/// servers or all servers. An administrator may also add the
|
||||
/// configuration data into the database and do not associate this data
|
||||
/// with any patrticular server.
|
||||
///
|
||||
/// When fetching the configuration data from a databse or when storing
|
||||
/// data in the database there is a need to specify which servers this
|
||||
/// data is associated with. The @c ServerSelector class represents
|
||||
/// such associations.
|
||||
///
|
||||
/// It includes three modes of selection: UNASSIGNED, ALL and SUBSET and
|
||||
/// several factory functions making associations described above.
|
||||
///
|
||||
/// The @c ServerSelector class should be used in objects derived from
|
||||
/// @c BaseConfigBackendPool and in objects derived from
|
||||
/// @c BaseConfigBackend to indicate which servers the specific calls
|
||||
/// exposed by these objects refer to.
|
||||
class ServerSelector {
|
||||
public:
|
||||
|
||||
/// @brief Type of the server selection.
|
||||
enum class Type {
|
||||
UNASSIGNED,
|
||||
ALL,
|
||||
SUBSET
|
||||
};
|
||||
|
||||
/// @brief Factory returning "unassigned" server selector.
|
||||
static ServerSelector& UNASSIGNED() {
|
||||
static ServerSelector selector(Type::UNASSIGNED);
|
||||
return (selector);
|
||||
}
|
||||
|
||||
/// @brief Factory returning "all servers" selector.
|
||||
static ServerSelector& ALL() {
|
||||
static ServerSelector selector(Type::ALL);
|
||||
return (selector);
|
||||
}
|
||||
|
||||
/// @brief Factory returning selector of one server.
|
||||
///
|
||||
/// @param server_tag tag of the single server to be selected.
|
||||
static ServerSelector& ONE(const std::string& server_tag) {
|
||||
static ServerSelector selector(server_tag);
|
||||
return (selector);
|
||||
}
|
||||
|
||||
/// @brief Factory returning "multiple servers" selector.
|
||||
///
|
||||
/// @param server_tags set of server tags to be selected.
|
||||
static ServerSelector& MULTIPLE(const std::set<std::string>& server_tags) {
|
||||
static ServerSelector selector(server_tags);
|
||||
return (selector);
|
||||
}
|
||||
|
||||
/// @brief Returns type of the selector.
|
||||
Type getType() const {
|
||||
return (type_);
|
||||
}
|
||||
|
||||
/// @brief Returns tags associated with the selector.
|
||||
///
|
||||
/// @return server tags for mutliple selections and for one server,
|
||||
/// empty set for all servers and and unassigned.
|
||||
std::set<std::string> getTags() const {
|
||||
return (tags_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Constructor used for "unassigned" and "all" slection types.
|
||||
///
|
||||
/// @param type selector type.
|
||||
explicit ServerSelector(const Type& type)
|
||||
: type_(type), tags_() {
|
||||
}
|
||||
|
||||
/// @brief Constructor used for selecting a single server.
|
||||
///
|
||||
/// @param server_tag tag of the server to be selected.
|
||||
explicit ServerSelector(const std::string& server_tag)
|
||||
: type_(Type::SUBSET), tags_() {
|
||||
tags_.insert(server_tag);
|
||||
}
|
||||
|
||||
/// @brief Constructor used for selecting multiple servers.
|
||||
///
|
||||
/// @param server_tags set of server tags.
|
||||
explicit ServerSelector(const std::set<std::string>& server_tags)
|
||||
: type_(Type::SUBSET), tags_(server_tags) {
|
||||
}
|
||||
|
||||
/// @brief Selection type used.
|
||||
Type type_;
|
||||
|
||||
/// @brief Holds tags of explicitly selected servers.
|
||||
std::set<std::string> tags_;
|
||||
};
|
||||
|
||||
|
||||
} // end of namespace isc::db
|
||||
} // end of namespace isc
|
||||
|
||||
#endif
|
@@ -19,9 +19,11 @@ TESTS =
|
||||
if HAVE_GTEST
|
||||
TESTS += libdatabase_unittests
|
||||
|
||||
libdatabase_unittests_SOURCES = database_connection_unittest.cc
|
||||
libdatabase_unittests_SOURCES = backend_selector_unittest.cc
|
||||
libdatabase_unittests_SOURCES += database_connection_unittest.cc
|
||||
libdatabase_unittests_SOURCES += dbaccess_parser_unittest.cc
|
||||
libdatabase_unittests_SOURCES += run_unittests.cc
|
||||
libdatabase_unittests_SOURCES += server_selector_unittest.cc
|
||||
|
||||
libdatabase_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
|
||||
libdatabase_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
|
||||
|
174
src/lib/database/tests/backend_selector_unittest.cc
Normal file
174
src/lib/database/tests/backend_selector_unittest.cc
Normal file
@@ -0,0 +1,174 @@
|
||||
// Copyright (C) 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 <database/backend_selector.h>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace isc;
|
||||
using namespace isc::db;
|
||||
using namespace isc::data;
|
||||
|
||||
namespace {
|
||||
|
||||
// Verifies defaults of the backend selector.
|
||||
TEST(BackendSelectorTest, defaults) {
|
||||
BackendSelector sel;
|
||||
EXPECT_EQ(BackendSelector::Type::UNSPEC, sel.getBackendType());
|
||||
EXPECT_TRUE(sel.getBackendHost().empty());
|
||||
EXPECT_EQ(0, sel.getBackendPort());
|
||||
EXPECT_TRUE(sel.amUnspecified());
|
||||
EXPECT_EQ("unspecified", sel.toText());
|
||||
}
|
||||
|
||||
// Verifies that the backend selector can be set to "unspecified".
|
||||
TEST(BackendSelectorTest, unspec) {
|
||||
BackendSelector sel = BackendSelector::UNSPEC();
|
||||
EXPECT_EQ(BackendSelector::Type::UNSPEC, sel.getBackendType());
|
||||
EXPECT_TRUE(sel.getBackendHost().empty());
|
||||
EXPECT_EQ(0, sel.getBackendPort());
|
||||
EXPECT_TRUE(sel.amUnspecified());
|
||||
EXPECT_EQ("unspecified", sel.toText());
|
||||
}
|
||||
|
||||
// Verifies that it is possible to select backend by type.
|
||||
TEST(BackendSelectorTest, backendTypeSpec) {
|
||||
boost::scoped_ptr<BackendSelector> sel;
|
||||
ASSERT_NO_THROW(
|
||||
sel.reset(new BackendSelector(BackendSelector::Type::MYSQL))
|
||||
);
|
||||
EXPECT_EQ(BackendSelector::Type::MYSQL, sel->getBackendType());
|
||||
EXPECT_TRUE(sel->getBackendHost().empty());
|
||||
EXPECT_EQ(0, sel->getBackendPort());
|
||||
EXPECT_FALSE(sel->amUnspecified());
|
||||
EXPECT_EQ("type=mysql", sel->toText());
|
||||
}
|
||||
|
||||
// Verifies that backend can be selected by host and port.
|
||||
TEST(BackendSelectorTest, backendHostPortSpec) {
|
||||
boost::scoped_ptr<BackendSelector> sel;
|
||||
ASSERT_NO_THROW(
|
||||
sel.reset(new BackendSelector("myhost", 1234))
|
||||
);
|
||||
EXPECT_EQ(BackendSelector::Type::UNSPEC, sel->getBackendType());
|
||||
EXPECT_EQ("myhost", sel->getBackendHost());
|
||||
EXPECT_EQ(1234, sel->getBackendPort());
|
||||
EXPECT_FALSE(sel->amUnspecified());
|
||||
EXPECT_EQ("host=myhost,port=1234", sel->toText());
|
||||
}
|
||||
|
||||
// Verifies that backend can be selected by host.
|
||||
TEST(BackendSelectorTest, backendHostSpec) {
|
||||
boost::scoped_ptr<BackendSelector> sel;
|
||||
ASSERT_NO_THROW(
|
||||
sel.reset(new BackendSelector("otherhost"))
|
||||
);
|
||||
EXPECT_EQ(BackendSelector::Type::UNSPEC, sel->getBackendType());
|
||||
EXPECT_EQ("otherhost", sel->getBackendHost());
|
||||
EXPECT_EQ(0, sel->getBackendPort());
|
||||
EXPECT_FALSE(sel->amUnspecified());
|
||||
EXPECT_EQ("host=otherhost", sel->toText());
|
||||
}
|
||||
|
||||
// Verifies that backend becomes unspecified if the access
|
||||
// map is empty.
|
||||
TEST(BackendSelectorTest, accessMapTypeUnSpec) {
|
||||
ElementPtr access_map = Element::createMap();
|
||||
boost::scoped_ptr<BackendSelector> sel;
|
||||
ASSERT_NO_THROW(
|
||||
sel.reset(new BackendSelector(access_map))
|
||||
);
|
||||
EXPECT_EQ(BackendSelector::Type::UNSPEC, sel->getBackendType());
|
||||
EXPECT_TRUE(sel->getBackendHost().empty());
|
||||
EXPECT_EQ(0, sel->getBackendPort());
|
||||
EXPECT_TRUE(sel->amUnspecified());
|
||||
EXPECT_EQ("unspecified", sel->toText());
|
||||
}
|
||||
|
||||
// Verifies that backend can be selected by type using access map.
|
||||
TEST(BackendSelectorTest, accessMapTypeSpec) {
|
||||
ElementPtr access_map = Element::createMap();
|
||||
access_map->set("type", Element::create("mysql"));
|
||||
boost::scoped_ptr<BackendSelector> sel;
|
||||
ASSERT_NO_THROW(
|
||||
sel.reset(new BackendSelector(access_map))
|
||||
);
|
||||
EXPECT_EQ(BackendSelector::Type::MYSQL, sel->getBackendType());
|
||||
EXPECT_TRUE(sel->getBackendHost().empty());
|
||||
EXPECT_EQ(0, sel->getBackendPort());
|
||||
EXPECT_FALSE(sel->amUnspecified());
|
||||
EXPECT_EQ("type=mysql", sel->toText());
|
||||
}
|
||||
|
||||
// Verifies that backend can be selected by host and port using
|
||||
// access map.
|
||||
TEST(BackendSelectorTest, accessMapHostPortSpec) {
|
||||
ElementPtr access_map = Element::createMap();
|
||||
access_map->set("host", Element::create("myhost"));
|
||||
access_map->set("port", Element::create(int64_t(1234)));
|
||||
boost::scoped_ptr<BackendSelector> sel;
|
||||
ASSERT_NO_THROW(
|
||||
sel.reset(new BackendSelector(access_map))
|
||||
);
|
||||
EXPECT_EQ(BackendSelector::Type::UNSPEC, sel->getBackendType());
|
||||
EXPECT_EQ("myhost", sel->getBackendHost());
|
||||
EXPECT_EQ(1234, sel->getBackendPort());
|
||||
EXPECT_FALSE(sel->amUnspecified());
|
||||
EXPECT_EQ("host=myhost,port=1234", sel->toText());
|
||||
}
|
||||
|
||||
// Verifies that the backend can be selected by host using access
|
||||
// map.
|
||||
TEST(BackendSelectorTest, accessMapHostSpec) {
|
||||
ElementPtr access_map = Element::createMap();
|
||||
access_map->set("host", Element::create("myhost"));
|
||||
boost::scoped_ptr<BackendSelector> sel;
|
||||
ASSERT_NO_THROW(
|
||||
sel.reset(new BackendSelector(access_map))
|
||||
);
|
||||
EXPECT_EQ(BackendSelector::Type::UNSPEC, sel->getBackendType());
|
||||
EXPECT_EQ("myhost", sel->getBackendHost());
|
||||
EXPECT_EQ(0, sel->getBackendPort());
|
||||
EXPECT_FALSE(sel->amUnspecified());
|
||||
EXPECT_EQ("host=myhost", sel->toText());
|
||||
}
|
||||
|
||||
// Verifies that selecting backend by port only is not possible.
|
||||
TEST(BackendSelectorTest, accessMapPortSpec) {
|
||||
ElementPtr access_map = Element::createMap();
|
||||
access_map->set("port", Element::create(int64_t(1234)));
|
||||
boost::scoped_ptr<BackendSelector> sel;
|
||||
EXPECT_THROW(sel.reset(new BackendSelector(access_map)),
|
||||
BadValue);
|
||||
}
|
||||
|
||||
// Tests conversions of strings to backend types.
|
||||
TEST(BackendSelectorTest, stringToBackendType) {
|
||||
EXPECT_EQ(BackendSelector::Type::MYSQL,
|
||||
BackendSelector::stringToBackendType("mysql"));
|
||||
EXPECT_EQ(BackendSelector::Type::PGSQL,
|
||||
BackendSelector::stringToBackendType("pgsql"));
|
||||
EXPECT_EQ(BackendSelector::Type::CQL,
|
||||
BackendSelector::stringToBackendType("cql"));
|
||||
EXPECT_THROW(BackendSelector::stringToBackendType("unsupported"),
|
||||
BadValue);
|
||||
}
|
||||
|
||||
// Tests conversions of backend types to strings.
|
||||
TEST(BackendSelectorTest, backendTypeToString) {
|
||||
EXPECT_EQ("mysql",
|
||||
BackendSelector::backendTypeToString(BackendSelector::Type::MYSQL));
|
||||
EXPECT_EQ("pgsql",
|
||||
BackendSelector::backendTypeToString(BackendSelector::Type::PGSQL));
|
||||
EXPECT_EQ("cql",
|
||||
BackendSelector::backendTypeToString(BackendSelector::Type::CQL));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
51
src/lib/database/tests/server_selector_unittest.cc
Normal file
51
src/lib/database/tests/server_selector_unittest.cc
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (C) 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 <database/server_selector.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace isc::db;
|
||||
|
||||
namespace {
|
||||
|
||||
// Check that server selector can be set to UNASSIGNED.
|
||||
TEST(ServerSelectorTest, unassigned) {
|
||||
ServerSelector selector = ServerSelector::UNASSIGNED();
|
||||
EXPECT_EQ(ServerSelector::Type::UNASSIGNED, selector.getType());
|
||||
EXPECT_TRUE(selector.getTags().empty());
|
||||
}
|
||||
|
||||
// Check that server selector can be set to ALL.
|
||||
TEST(ServerSelectorTest, all) {
|
||||
ServerSelector selector = ServerSelector::ALL();
|
||||
EXPECT_EQ(ServerSelector::Type::ALL, selector.getType());
|
||||
EXPECT_TRUE(selector.getTags().empty());
|
||||
}
|
||||
|
||||
// Check that a single server can be selected.
|
||||
TEST(ServerSelectorTest, one) {
|
||||
ServerSelector selector = ServerSelector::ONE("some-tag");
|
||||
EXPECT_EQ(ServerSelector::Type::SUBSET, selector.getType());
|
||||
|
||||
std::set<std::string> tags = selector.getTags();
|
||||
ASSERT_EQ(1, tags.size());
|
||||
EXPECT_EQ(1, tags.count("some-tag"));
|
||||
}
|
||||
|
||||
// Check that multiple servers can be selected.
|
||||
TEST(ServerSelectorTest, multiple) {
|
||||
ServerSelector selector = ServerSelector::MULTIPLE({ "tag1", "tag2", "tag3" });
|
||||
EXPECT_EQ(ServerSelector::Type::SUBSET, selector.getType());
|
||||
|
||||
std::set<std::string> tags = selector.getTags();
|
||||
ASSERT_EQ(3, tags.size());
|
||||
EXPECT_EQ(1, tags.count("tag1"));
|
||||
EXPECT_EQ(1, tags.count("tag2"));
|
||||
EXPECT_EQ(1, tags.count("tag3"));
|
||||
}
|
||||
|
||||
}
|
@@ -31,8 +31,6 @@ AM_CXXFLAGS = $(KEA_CXXFLAGS)
|
||||
EXTRA_DIST =
|
||||
EXTRA_DIST += parsers/client_class_def_parser.cc
|
||||
EXTRA_DIST += parsers/client_class_def_parser.h
|
||||
EXTRA_DIST += parsers/dbaccess_parser.cc
|
||||
EXTRA_DIST += parsers/dbaccess_parser.h
|
||||
EXTRA_DIST += parsers/dhcp_parsers.cc
|
||||
EXTRA_DIST += parsers/dhcp_parsers.h
|
||||
EXTRA_DIST += parsers/expiration_config_parser.cc
|
||||
@@ -110,11 +108,12 @@ libkea_dhcpsrv_la_SOURCES += cfg_subnets6.cc cfg_subnets6.h
|
||||
libkea_dhcpsrv_la_SOURCES += cfg_mac_source.cc cfg_mac_source.h
|
||||
libkea_dhcpsrv_la_SOURCES += cfgmgr.cc cfgmgr.h
|
||||
libkea_dhcpsrv_la_SOURCES += client_class_def.cc client_class_def.h
|
||||
libkea_dhcpsrv_la_SOURCES += config_backend_dhcp4.h
|
||||
libkea_dhcpsrv_la_SOURCES += config_backend_pool_dhcp4.cc config_backend_pool_dhcp4.h
|
||||
libkea_dhcpsrv_la_SOURCES += csv_lease_file4.cc csv_lease_file4.h
|
||||
libkea_dhcpsrv_la_SOURCES += csv_lease_file6.cc csv_lease_file6.h
|
||||
libkea_dhcpsrv_la_SOURCES += d2_client_cfg.cc d2_client_cfg.h
|
||||
libkea_dhcpsrv_la_SOURCES += d2_client_mgr.cc d2_client_mgr.h
|
||||
libkea_dhcpsrv_la_SOURCES += db_exceptions.h
|
||||
libkea_dhcpsrv_la_SOURCES += db_type.h
|
||||
libkea_dhcpsrv_la_SOURCES += dhcp4o6_ipc.cc dhcp4o6_ipc.h
|
||||
libkea_dhcpsrv_la_SOURCES += dhcpsrv_exceptions.h
|
||||
@@ -199,7 +198,7 @@ libkea_dhcpsrv_la_CXXFLAGS = $(AM_CXXFLAGS)
|
||||
libkea_dhcpsrv_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
libkea_dhcpsrv_la_LIBADD = $(top_builddir)/src/lib/eval/libkea-eval.la
|
||||
libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/dhcp_ddns/libkea-dhcp_ddns.la
|
||||
#libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/process/libkea-process.la
|
||||
libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/process/libkea-process.la
|
||||
libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/stats/libkea-stats.la
|
||||
libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/config/libkea-cfgclient.la
|
||||
libkea_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
|
||||
@@ -273,6 +272,8 @@ libkea_dhcpsrv_include_HEADERS = \
|
||||
cfg_subnets6.h \
|
||||
cfgmgr.h \
|
||||
client_class_def.h \
|
||||
config_backend_dhcp4.h \
|
||||
config_backend_pool_dhcp4.h \
|
||||
csv_lease_file4.h \
|
||||
csv_lease_file6.h \
|
||||
dhcpsrv_exceptions.h \
|
||||
|
323
src/lib/dhcpsrv/config_backend_dhcp4.h
Normal file
323
src/lib/dhcpsrv/config_backend_dhcp4.h
Normal file
@@ -0,0 +1,323 @@
|
||||
// Copyright (C) 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/.
|
||||
|
||||
#ifndef CONFIG_BACKEND_DHCP4_H
|
||||
#define CONFIG_BACKEND_DHCP4_H
|
||||
|
||||
#include <config_backend/base_config_backend.h>
|
||||
#include <database/server_selector.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <dhcp/option_definition.h>
|
||||
#include <dhcpsrv/shared_network.h>
|
||||
#include <dhcpsrv/subnet.h>
|
||||
#include <util/optional_value.h>
|
||||
#include <boost/date_time/posix_time/ptime.hpp>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
/// @brief Interface implemented by DHCPv4 configuration backends.
|
||||
class ConfigBackendDHCPv4 : public cb::BaseConfigBackend {
|
||||
public:
|
||||
|
||||
/// @brief Virtual destructor.
|
||||
virtual ~ConfigBackendDHCPv4() { }
|
||||
|
||||
/// @brief Retrieves a single subnet by subnet_prefix.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param subnet_prefix Prefix of the subnet to be retrieved.
|
||||
/// @return Pointer to the retrieved subnet or NULL if not found.
|
||||
virtual Subnet4Ptr
|
||||
getSubnet4(const db::ServerSelector& selector,
|
||||
const std::string& subnet_prefix) const = 0;
|
||||
|
||||
/// @brief Retrieves a single subnet by subnet identifier.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param subnet_id Identifier of a subnet to be retrieved.
|
||||
/// @return Pointer to the retrieved subnet or NULL if not found.
|
||||
virtual Subnet4Ptr
|
||||
getSubnet4(const db::ServerSelector& selector, const SubnetID& subnet_id) const = 0;
|
||||
|
||||
/// @brief Retrieves all subnets.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @return Collection of subnets or empty collection if no subnet found.
|
||||
virtual Subnet4Collection
|
||||
getAllSubnets4(const db::ServerSelector& selector) const = 0;
|
||||
|
||||
/// @brief Retrieves subnets modified after specified time.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param modification_time Lower bound subnet modification time.
|
||||
/// @return Collection of subnets or empty collection if no subnet found.
|
||||
virtual Subnet4Collection
|
||||
getModifiedSubnets4(const db::ServerSelector& selector,
|
||||
const boost::posix_time::ptime& modification_time) const = 0;
|
||||
|
||||
/// @brief Retrieves shared network by name.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param name Name of the shared network to be retrieved.
|
||||
/// @return Pointer to the shared network or NULL if not found.
|
||||
virtual SharedNetwork4Ptr
|
||||
getSharedNetwork4(const db::ServerSelector& selector,
|
||||
const std::string& name) const = 0;
|
||||
|
||||
/// @brief Retrieves all shared networks.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @return Collection of shared network or empty collection if
|
||||
/// no shared network found.
|
||||
virtual SharedNetwork4Collection
|
||||
getAllSharedNetworks4(const db::ServerSelector& selector) const = 0;
|
||||
|
||||
/// @brief Retrieves shared networks modified after specified time.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param modification_time Lower bound shared network modification time.
|
||||
/// @return Collection of shared network or empty collection if
|
||||
/// no shared network found.
|
||||
virtual SharedNetwork4Collection
|
||||
getModifiedSharedNetworks4(const db::ServerSelector& selector,
|
||||
const boost::posix_time::ptime& modification_time) const = 0;
|
||||
|
||||
/// @brief Retrieves single option definition by code and space.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param code Code of the option to be retrieved.
|
||||
/// @param space Option space of the option to be retrieved.
|
||||
/// @return Pointer to the option definition or NULL if not found.
|
||||
virtual OptionDefinitionPtr
|
||||
getOptionDef4(const db::ServerSelector& selector, const uint16_t code,
|
||||
const std::string& space) const = 0;
|
||||
|
||||
/// @brief Retrieves all option definitions.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @return Collection of option definitions or empty collection if
|
||||
/// no option definition found.
|
||||
virtual OptionDefContainer
|
||||
getAllOptionDefs4(const db::ServerSelector& selector) const = 0;
|
||||
|
||||
/// @brief Retrieves option definitions modified after specified time.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param modification_time Lower bound option definition modification
|
||||
/// time.
|
||||
/// @return Collection of option definitions or empty collection if
|
||||
/// no option definition found.
|
||||
virtual OptionDefContainer
|
||||
getModifiedOptionDefs4(const db::ServerSelector& selector,
|
||||
const boost::posix_time::ptime& modification_time) const = 0;
|
||||
|
||||
/// @brief Retrieves global string parameter value.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param name Name of the global parameter to be retrieved.
|
||||
/// @return Value of the global string parameter.
|
||||
virtual util::OptionalValue<std::string>
|
||||
getGlobalStringParameter4(const db::ServerSelector& selector,
|
||||
const std::string& name) const = 0;
|
||||
|
||||
/// @brief Retrieves global number parameter.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param name Name of the parameter to be retrieved.
|
||||
virtual util::OptionalValue<int64_t>
|
||||
getGlobalNumberParameter4(const db::ServerSelector& selector,
|
||||
const std::string& name) const = 0;
|
||||
|
||||
/// @brief Retrieves all global parameters as strings.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
virtual std::map<std::string, std::string>
|
||||
getAllGlobalParameters4(const db::ServerSelector& selector) const = 0;
|
||||
|
||||
/// @brief Creates or updates a subnet.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param subnet Subnet to be added or updated.
|
||||
virtual void
|
||||
createUpdateSubnet4(const db::ServerSelector& selector,
|
||||
const Subnet4Ptr& subnet) = 0;
|
||||
|
||||
/// @brief Creates or updates a shared network.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param shared_network Shared network to be added or updated.
|
||||
virtual void
|
||||
createUpdateSharedNetwork4(const db::ServerSelector& selector,
|
||||
const SharedNetwork4Ptr& shared_network) = 0;
|
||||
|
||||
/// @brief Creates or updates an option definition.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param option_def Option definition to be added or updated.
|
||||
virtual void
|
||||
createUpdateOptionDef4(const db::ServerSelector& selector,
|
||||
const OptionDefinitionPtr& option_def) = 0;
|
||||
|
||||
/// @brief Creates or updates global option.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param option Option to be added or updated.
|
||||
virtual void
|
||||
createUpdateOption4(const db::ServerSelector& selector,
|
||||
const OptionPtr& option) = 0;
|
||||
|
||||
/// @brief Creates or updates subnet level option.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param subnet_id Identifier of a subnet to which option belongs.
|
||||
/// @param option Option to be added or updated.
|
||||
virtual void
|
||||
createUpdateOption4(const db::ServerSelector& selector,
|
||||
const SubnetID& subnet_id,
|
||||
const OptionPtr& option) = 0;
|
||||
|
||||
/// @brief Creates or updates pool level option.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param pool_start_address Lower bound address of the pool to which
|
||||
/// the option belongs.
|
||||
/// @param pool_end_address Upper bound address of the pool to which the
|
||||
/// option belongs.
|
||||
/// @param option Option to be added or updated.
|
||||
virtual void
|
||||
createUpdateOption4(const db::ServerSelector& selector,
|
||||
const asiolink::IOAddress& pool_start_address,
|
||||
const asiolink::IOAddress& pool_end_address,
|
||||
const OptionPtr& option) = 0;
|
||||
|
||||
/// @brief Creates or updates global string parameter.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param name Name of the global parameter.
|
||||
/// @param value Value of the global parameter.
|
||||
virtual void
|
||||
createUpdateGlobalParameter4(const db::ServerSelector& selector,
|
||||
const std::string& name,
|
||||
const std::string& value) = 0;
|
||||
|
||||
/// @brief Creates or updates global number parameter.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param name Name of the global parameter.
|
||||
/// @param value Value of the global parameter.
|
||||
virtual void
|
||||
createUpdateGlobalParameter4(const db::ServerSelector& selector,
|
||||
const std::string& name,
|
||||
const int64_t value) = 0;
|
||||
|
||||
/// @brief Deletes subnet by prefix.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param subnet_prefix Prefix of the subnet to be deleted.
|
||||
virtual void
|
||||
deleteSubnet4(const db::ServerSelector& selector,
|
||||
const std::string& subnet_prefix) = 0;
|
||||
|
||||
/// @brief Deletes subnet by identifier.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param subnet_id Identifier of the subnet to be deleted.
|
||||
virtual void
|
||||
deleteSubnet4(const db::ServerSelector& selector, const SubnetID& subnet_id) = 0;
|
||||
|
||||
/// @brief Deletes all subnets.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
virtual void
|
||||
deleteAllSubnets4(const db::ServerSelector& selector) = 0;
|
||||
|
||||
/// @brief Deletes shared network by name.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param name Name of the shared network to be deleted.
|
||||
virtual void
|
||||
deleteSharedNetwork4(const db::ServerSelector& selector,
|
||||
const std::string& name) = 0;
|
||||
|
||||
/// @brief Deletes all shared networks.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
virtual void
|
||||
deleteAllSharedNetworks4(const db::ServerSelector& selector) = 0;
|
||||
|
||||
/// @brief Deletes option definition.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param code Code of the option to be deleted.
|
||||
/// @param space Option space of the option to be deleted.
|
||||
virtual void
|
||||
deleteOptionDef4(const db::ServerSelector& selector, const uint16_t code,
|
||||
const std::string& space) = 0;
|
||||
|
||||
/// @brief Deletes all option definitions.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
virtual void
|
||||
deleteAllOptionDefs4(const db::ServerSelector& selector) = 0;
|
||||
|
||||
/// @brief Deletes global option.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param code Code of the option to be deleted.
|
||||
/// @param space Option space of the option to be deleted.
|
||||
virtual void
|
||||
deleteOption4(const db::ServerSelector& selector, const uint16_t code,
|
||||
const std::string& space) = 0;
|
||||
|
||||
/// @brief Deletes subnet level option.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param subnet_id Identifier of the subnet to which deleted option
|
||||
/// belongs.
|
||||
/// @param code Code of the deleted option.
|
||||
/// @param space Option space of the deleted option.
|
||||
virtual void
|
||||
deleteOption4(const db::ServerSelector& selector, const SubnetID& subnet_id,
|
||||
const uint16_t code, const std::string& space) = 0;
|
||||
|
||||
/// @brief Deletes pool level option.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param pool_start_address Lower bound address of the pool to which
|
||||
/// deleted option belongs.
|
||||
/// @param pool_end_address Upper bound address of the pool to which the
|
||||
/// deleted option belongs.
|
||||
/// @param code Code of the deleted option.
|
||||
/// @param space Option space of the deleted option.
|
||||
virtual void
|
||||
deleteOption4(const db::ServerSelector& selector,
|
||||
const asiolink::IOAddress& pool_start_address,
|
||||
const asiolink::IOAddress& pool_end_address,
|
||||
const uint16_t code,
|
||||
const std::string& space) = 0;
|
||||
|
||||
/// @brief Deletes global parameter.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
/// @param name Name of the global parameter to be deleted.
|
||||
virtual void
|
||||
deleteGlobalParameter4(const db::ServerSelector& selector,
|
||||
const std::string& name) = 0;
|
||||
|
||||
/// @brief Deletes all global parameters.
|
||||
///
|
||||
/// @param selector Server selector.
|
||||
virtual void
|
||||
deleteAllGlobalParameters4(const db::ServerSelector& selector) = 0;
|
||||
};
|
||||
|
||||
} // end of namespace isc::dhcp
|
||||
} // end of namespace isc
|
||||
|
||||
#endif // CONFIG_BACKEND_DHCP4_H
|
346
src/lib/dhcpsrv/config_backend_pool_dhcp4.cc
Normal file
346
src/lib/dhcpsrv/config_backend_pool_dhcp4.cc
Normal file
@@ -0,0 +1,346 @@
|
||||
// Copyright (C) 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 <dhcpsrv/config_backend_pool_dhcp4.h>
|
||||
|
||||
using namespace isc::asiolink;
|
||||
using namespace isc::db;
|
||||
using namespace isc::util;
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
Subnet4Ptr
|
||||
ConfigBackendPoolDHCPv4::getSubnet4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& subnet_prefix) const {
|
||||
Subnet4Ptr subnet;
|
||||
getPropertyPtrConst<Subnet4Ptr, const std::string&>
|
||||
(&ConfigBackendDHCPv4::getSubnet4, backend_selector, server_selector,
|
||||
subnet, subnet_prefix);
|
||||
return (subnet);
|
||||
}
|
||||
|
||||
Subnet4Ptr
|
||||
ConfigBackendPoolDHCPv4::getSubnet4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const SubnetID& subnet_id) const {
|
||||
Subnet4Ptr subnet;
|
||||
getPropertyPtrConst<Subnet4Ptr, const SubnetID&>
|
||||
(&ConfigBackendDHCPv4::getSubnet4, backend_selector, server_selector,
|
||||
subnet, subnet_id);
|
||||
return (subnet);
|
||||
}
|
||||
|
||||
Subnet4Collection
|
||||
ConfigBackendPoolDHCPv4::getAllSubnets4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector) const {
|
||||
Subnet4Collection subnets;
|
||||
getAllPropertiesConst<Subnet4Collection>
|
||||
(&ConfigBackendDHCPv4::getAllSubnets4, backend_selector, server_selector,
|
||||
subnets);
|
||||
return (subnets);
|
||||
}
|
||||
|
||||
Subnet4Collection
|
||||
ConfigBackendPoolDHCPv4::getModifiedSubnets4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const boost::posix_time::ptime& modification_time) const {
|
||||
Subnet4Collection subnets;
|
||||
getMultiplePropertiesConst<Subnet4Collection, const boost::posix_time::ptime&>
|
||||
(&ConfigBackendDHCPv4::getModifiedSubnets4, backend_selector, server_selector,
|
||||
subnets, modification_time);
|
||||
return (subnets);
|
||||
}
|
||||
|
||||
SharedNetwork4Ptr
|
||||
ConfigBackendPoolDHCPv4::getSharedNetwork4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& name) const {
|
||||
SharedNetwork4Ptr shared_network;
|
||||
getPropertyPtrConst<SharedNetwork4Ptr, const std::string&>
|
||||
(&ConfigBackendDHCPv4::getSharedNetwork4, backend_selector, server_selector,
|
||||
shared_network, name);
|
||||
return (shared_network);
|
||||
}
|
||||
|
||||
SharedNetwork4Collection
|
||||
ConfigBackendPoolDHCPv4::getAllSharedNetworks4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector) const {
|
||||
SharedNetwork4Collection shared_networks;
|
||||
getAllPropertiesConst<SharedNetwork4Collection>
|
||||
(&ConfigBackendDHCPv4::getAllSharedNetworks4, backend_selector, server_selector,
|
||||
shared_networks);
|
||||
return (shared_networks);
|
||||
}
|
||||
|
||||
SharedNetwork4Collection
|
||||
ConfigBackendPoolDHCPv4::
|
||||
getModifiedSharedNetworks4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const boost::posix_time::ptime& modification_time) const {
|
||||
SharedNetwork4Collection shared_networks;
|
||||
getMultiplePropertiesConst<SharedNetwork4Collection, const boost::posix_time::ptime&>
|
||||
(&ConfigBackendDHCPv4::getModifiedSharedNetworks4, backend_selector, server_selector,
|
||||
shared_networks, modification_time);
|
||||
return (shared_networks);
|
||||
}
|
||||
|
||||
OptionDefinitionPtr
|
||||
ConfigBackendPoolDHCPv4::getOptionDef4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const uint16_t code,
|
||||
const std::string& space) const {
|
||||
OptionDefinitionPtr option_def;
|
||||
getPropertyPtrConst<OptionDefinitionPtr, uint16_t, const std::string&>
|
||||
(&ConfigBackendDHCPv4::getOptionDef4, backend_selector, server_selector,
|
||||
option_def, code, space);
|
||||
return (option_def);
|
||||
}
|
||||
|
||||
OptionDefContainer
|
||||
ConfigBackendPoolDHCPv4::getAllOptionDefs4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector) const {
|
||||
OptionDefContainer option_defs;
|
||||
getAllPropertiesConst<OptionDefContainer>
|
||||
(&ConfigBackendDHCPv4::getAllOptionDefs4, backend_selector, server_selector,
|
||||
option_defs);
|
||||
return (option_defs);
|
||||
}
|
||||
|
||||
OptionDefContainer
|
||||
ConfigBackendPoolDHCPv4::getModifiedOptionDefs4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const boost::posix_time::ptime& modification_time) const {
|
||||
OptionDefContainer option_defs;
|
||||
getMultiplePropertiesConst<OptionDefContainer, const boost::posix_time::ptime&>
|
||||
(&ConfigBackendDHCPv4::getModifiedOptionDefs4, backend_selector, server_selector,
|
||||
option_defs, modification_time);
|
||||
return (option_defs);
|
||||
}
|
||||
|
||||
util::OptionalValue<std::string>
|
||||
ConfigBackendPoolDHCPv4::getGlobalStringParameter4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& name) const {
|
||||
OptionalValue<std::string> parameter;
|
||||
getOptionalPropertyConst<std::string, const std::string&>
|
||||
(&ConfigBackendDHCPv4::getGlobalStringParameter4, backend_selector,
|
||||
server_selector, parameter, name);
|
||||
return (parameter);
|
||||
}
|
||||
|
||||
util::OptionalValue<int64_t>
|
||||
ConfigBackendPoolDHCPv4::getGlobalNumberParameter4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& name) const {
|
||||
OptionalValue<int64_t> parameter;
|
||||
getOptionalPropertyConst<int64_t, const std::string&>
|
||||
(&ConfigBackendDHCPv4::getGlobalNumberParameter4, backend_selector,
|
||||
server_selector, parameter, name);
|
||||
return (parameter);
|
||||
}
|
||||
|
||||
std::map<std::string, std::string>
|
||||
ConfigBackendPoolDHCPv4::getAllGlobalParameters4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector) const {
|
||||
std::map<std::string, std::string> parameters;
|
||||
getAllPropertiesConst<std::map<std::string, std::string> >
|
||||
(&ConfigBackendDHCPv4::getAllGlobalParameters4, backend_selector,
|
||||
server_selector, parameters);
|
||||
return (parameters);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::createUpdateSubnet4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const Subnet4Ptr& subnet) {
|
||||
createUpdateDeleteProperty<const Subnet4Ptr&>
|
||||
(&ConfigBackendDHCPv4::createUpdateSubnet4, backend_selector,
|
||||
server_selector, subnet);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::createUpdateSharedNetwork4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const SharedNetwork4Ptr& shared_network) {
|
||||
createUpdateDeleteProperty<const SharedNetwork4Ptr&>
|
||||
(&ConfigBackendDHCPv4::createUpdateSharedNetwork4, backend_selector,
|
||||
server_selector, shared_network);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::createUpdateOptionDef4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const OptionDefinitionPtr& option_def) {
|
||||
createUpdateDeleteProperty<const OptionDefinitionPtr&>
|
||||
(&ConfigBackendDHCPv4::createUpdateOptionDef4, backend_selector,
|
||||
server_selector, option_def);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::createUpdateOption4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const OptionPtr& option) {
|
||||
createUpdateDeleteProperty<const OptionPtr&>
|
||||
(&ConfigBackendDHCPv4::createUpdateOption4, backend_selector,
|
||||
server_selector, option);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::createUpdateOption4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const SubnetID& subnet_id,
|
||||
const OptionPtr& option) {
|
||||
createUpdateDeleteProperty<const SubnetID&, const OptionPtr&>
|
||||
(&ConfigBackendDHCPv4::createUpdateOption4, backend_selector,
|
||||
server_selector, subnet_id, option);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::createUpdateOption4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const IOAddress& pool_start_address,
|
||||
const IOAddress& pool_end_address,
|
||||
const OptionPtr& option) {
|
||||
createUpdateDeleteProperty<const IOAddress&, const IOAddress&, const OptionPtr&>
|
||||
(&ConfigBackendDHCPv4::createUpdateOption4, backend_selector,
|
||||
server_selector, pool_start_address, pool_end_address, option);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::createUpdateGlobalParameter4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& name,
|
||||
const std::string& value) {
|
||||
createUpdateDeleteProperty<const std::string&, const std::string&>
|
||||
(&ConfigBackendDHCPv4::createUpdateGlobalParameter4, backend_selector,
|
||||
server_selector, name, value);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::createUpdateGlobalParameter4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& name,
|
||||
const int64_t value) {
|
||||
createUpdateDeleteProperty<const std::string&, int64_t>
|
||||
(&ConfigBackendDHCPv4::createUpdateGlobalParameter4, backend_selector,
|
||||
server_selector, name, value);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::deleteSubnet4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& subnet_prefix) {
|
||||
createUpdateDeleteProperty<const std::string&>
|
||||
(&ConfigBackendDHCPv4::deleteSubnet4, backend_selector, server_selector,
|
||||
subnet_prefix);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::deleteSubnet4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const SubnetID& subnet_id) {
|
||||
createUpdateDeleteProperty<const SubnetID&>
|
||||
(&ConfigBackendDHCPv4::deleteSubnet4, backend_selector, server_selector,
|
||||
subnet_id);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::deleteAllSubnets4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector) {
|
||||
createUpdateDeleteProperty<>
|
||||
(&ConfigBackendDHCPv4::deleteAllSubnets4, backend_selector, server_selector);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::deleteSharedNetwork4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& name) {
|
||||
createUpdateDeleteProperty<const std::string&>
|
||||
(&ConfigBackendDHCPv4::deleteSharedNetwork4, backend_selector,
|
||||
server_selector, name);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::deleteAllSharedNetworks4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector) {
|
||||
createUpdateDeleteProperty<>
|
||||
(&ConfigBackendDHCPv4::deleteAllSharedNetworks4, backend_selector, server_selector);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::deleteOptionDef4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const uint16_t code,
|
||||
const std::string& space) {
|
||||
createUpdateDeleteProperty<uint16_t, const std::string&>
|
||||
(&ConfigBackendDHCPv4::deleteOptionDef4, backend_selector,
|
||||
server_selector, code, space);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::deleteAllOptionDefs4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector) {
|
||||
createUpdateDeleteProperty<>
|
||||
(&ConfigBackendDHCPv4::deleteAllOptionDefs4, backend_selector, server_selector);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::deleteOption4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const uint16_t code,
|
||||
const std::string& space) {
|
||||
createUpdateDeleteProperty<uint16_t, const std::string&>
|
||||
(&ConfigBackendDHCPv4::deleteOption4, backend_selector, server_selector,
|
||||
code, space);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::deleteOption4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const SubnetID& subnet_id,
|
||||
const uint16_t code,
|
||||
const std::string& space) {
|
||||
createUpdateDeleteProperty<const SubnetID&, uint16_t, const std::string&>
|
||||
(&ConfigBackendDHCPv4::deleteOption4, backend_selector, server_selector,
|
||||
subnet_id, code, space);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::deleteOption4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const asiolink::IOAddress& pool_start_address,
|
||||
const asiolink::IOAddress& pool_end_address,
|
||||
const uint16_t code,
|
||||
const std::string& space) {
|
||||
createUpdateDeleteProperty<const IOAddress&, const IOAddress&, uint16_t,
|
||||
const std::string&>
|
||||
(&ConfigBackendDHCPv4::deleteOption4, backend_selector, server_selector,
|
||||
pool_start_address, pool_end_address, code, space);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::deleteGlobalParameter4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& name) {
|
||||
createUpdateDeleteProperty<const std::string&>
|
||||
(&ConfigBackendDHCPv4::deleteGlobalParameter4, backend_selector,
|
||||
server_selector, name);
|
||||
}
|
||||
|
||||
void
|
||||
ConfigBackendPoolDHCPv4::deleteAllGlobalParameters4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector) {
|
||||
createUpdateDeleteProperty<>
|
||||
(&ConfigBackendDHCPv4::deleteAllGlobalParameters4, backend_selector,
|
||||
server_selector);
|
||||
}
|
||||
|
||||
|
||||
} // end of namespace isc::dhcp
|
||||
} // end of namespace isc
|
394
src/lib/dhcpsrv/config_backend_pool_dhcp4.h
Normal file
394
src/lib/dhcpsrv/config_backend_pool_dhcp4.h
Normal file
@@ -0,0 +1,394 @@
|
||||
// Copyright (C) 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/.
|
||||
|
||||
#ifndef CONFIG_BACKEND_POOL_DHCP4_H
|
||||
#define CONFIG_BACKEND_POOL_DHCP4_H
|
||||
|
||||
#include <config_backend/base_config_backend_pool.h>
|
||||
#include <database/backend_selector.h>
|
||||
#include <database/server_selector.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <dhcp/option_definition.h>
|
||||
#include <dhcpsrv/config_backend_dhcp4.h>
|
||||
#include <dhcpsrv/shared_network.h>
|
||||
#include <dhcpsrv/subnet.h>
|
||||
#include <util/optional_value.h>
|
||||
#include <boost/date_time/posix_time/ptime.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
/// @brief Implementation of the Configuration Backend Pool for DHCPv4.
|
||||
class ConfigBackendPoolDHCPv4 : cb::BaseConfigBackendPool<ConfigBackendDHCPv4> {
|
||||
public:
|
||||
|
||||
/// @brief Retrieves a single subnet by subnet_prefix.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param subnet_prefix Prefix of the subnet to be retrieved.
|
||||
/// @return Pointer to the retrieved subnet or NULL if not found.
|
||||
virtual Subnet4Ptr
|
||||
getSubnet4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& subnet_prefix) const;
|
||||
|
||||
/// @brief Retrieves a single subnet by subnet identifier.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param subnet_id Identifier of a subnet to be retrieved.
|
||||
/// @return Pointer to the retrieved subnet or NULL if not found.
|
||||
virtual Subnet4Ptr
|
||||
getSubnet4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const SubnetID& subnet_id) const;
|
||||
|
||||
/// @brief Retrieves all subnets.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @return Collection of subnets or empty collection if no subnet found.
|
||||
virtual Subnet4Collection
|
||||
getAllSubnets4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector) const;
|
||||
|
||||
/// @brief Retrieves subnets modified after specified time.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param modification_time Lower bound subnet modification time.
|
||||
/// @return Collection of subnets or empty collection if no subnet found.
|
||||
virtual Subnet4Collection
|
||||
getModifiedSubnets4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const boost::posix_time::ptime& modification_time) const;
|
||||
|
||||
/// @brief Retrieves shared network by name.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param name Name of the shared network to be retrieved.
|
||||
/// @return Pointer to the shared network or NULL if not found.
|
||||
virtual SharedNetwork4Ptr
|
||||
getSharedNetwork4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& name) const;
|
||||
|
||||
/// @brief Retrieves all shared networks.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @return Collection of shared network or empty collection if
|
||||
/// no shared network found.
|
||||
virtual SharedNetwork4Collection
|
||||
getAllSharedNetworks4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector) const;
|
||||
|
||||
/// @brief Retrieves shared networks modified after specified time.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param modification_time Lower bound shared network modification time.
|
||||
/// @return Collection of shared network or empty collection if
|
||||
/// no shared network found.
|
||||
virtual SharedNetwork4Collection
|
||||
getModifiedSharedNetworks4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const boost::posix_time::ptime& modification_time) const;
|
||||
|
||||
/// @brief Retrieves single option definition by code and space.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param code Code of the option to be retrieved.
|
||||
/// @param space Option space of the option to be retrieved.
|
||||
/// @return Pointer to the option definition or NULL if not found.
|
||||
virtual OptionDefinitionPtr
|
||||
getOptionDef4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const uint16_t code,
|
||||
const std::string& space) const;
|
||||
|
||||
/// @brief Retrieves all option definitions.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @return Collection of option definitions or empty collection if
|
||||
/// no option definition found.
|
||||
virtual OptionDefContainer
|
||||
getAllOptionDefs4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector) const;
|
||||
|
||||
/// @brief Retrieves option definitions modified after specified time.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param modification_time Lower bound option definition modification
|
||||
/// time.
|
||||
/// @return Collection of option definitions or empty collection if
|
||||
/// no option definition found.
|
||||
virtual OptionDefContainer
|
||||
getModifiedOptionDefs4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const boost::posix_time::ptime& modification_time) const;
|
||||
|
||||
/// @brief Retrieves global string parameter value.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param name Name of the global parameter to be retrieved.
|
||||
/// @return Value of the global string parameter.
|
||||
virtual util::OptionalValue<std::string>
|
||||
getGlobalStringParameter4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& name) const;
|
||||
|
||||
/// @brief Retrieves global number parameter.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param name Name of the parameter to be retrieved.
|
||||
virtual util::OptionalValue<int64_t>
|
||||
getGlobalNumberParameter4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& name) const;
|
||||
|
||||
/// @brief Retrieves all global parameters as strings.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
virtual std::map<std::string, std::string>
|
||||
getAllGlobalParameters4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector) const;
|
||||
|
||||
/// @brief Creates or updates a subnet.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param subnet Subnet to be added or updated.
|
||||
virtual void
|
||||
createUpdateSubnet4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const Subnet4Ptr& subnet);
|
||||
|
||||
/// @brief Creates or updates a shared network.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param shared_network Shared network to be added or updated.
|
||||
virtual void
|
||||
createUpdateSharedNetwork4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const SharedNetwork4Ptr& shared_network);
|
||||
|
||||
/// @brief Creates or updates an option definition.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param option_def Option definition to be added or updated.
|
||||
virtual void
|
||||
createUpdateOptionDef4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const OptionDefinitionPtr& option_def);
|
||||
|
||||
/// @brief Creates or updates global option.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param option Option to be added or updated.
|
||||
virtual void
|
||||
createUpdateOption4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const OptionPtr& option);
|
||||
|
||||
/// @brief Creates or updates subnet level option.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param subnet_id Identifier of a subnet to which option belongs.
|
||||
/// @param option Option to be added or updated.
|
||||
virtual void
|
||||
createUpdateOption4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const SubnetID& subnet_id,
|
||||
const OptionPtr& option);
|
||||
|
||||
/// @brief Creates or updates pool level option.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param pool_start_address Lower bound address of the pool to which
|
||||
/// the option belongs.
|
||||
/// @param pool_end_address Upper bound address of the pool to which the
|
||||
/// option belongs.
|
||||
/// @param option Option to be added or updated.
|
||||
virtual void
|
||||
createUpdateOption4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const asiolink::IOAddress& pool_start_address,
|
||||
const asiolink::IOAddress& pool_end_address,
|
||||
const OptionPtr& option);
|
||||
|
||||
/// @brief Creates or updates global string parameter.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param name Name of the global parameter.
|
||||
/// @param value Value of the global parameter.
|
||||
virtual void
|
||||
createUpdateGlobalParameter4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& name,
|
||||
const std::string& value);
|
||||
|
||||
/// @brief Creates or updates global number parameter.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param name Name of the global parameter.
|
||||
/// @param value Value of the global parameter.
|
||||
virtual void
|
||||
createUpdateGlobalParameter4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& name,
|
||||
const int64_t value);
|
||||
|
||||
/// @brief Deletes subnet by prefix.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param subnet_prefix Prefix of the subnet to be deleted.
|
||||
virtual void
|
||||
deleteSubnet4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& subnet_prefix);
|
||||
|
||||
/// @brief Deletes subnet by identifier.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param subnet_id Identifier of the subnet to be deleted.
|
||||
virtual void
|
||||
deleteSubnet4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const SubnetID& subnet_id);
|
||||
|
||||
/// @brief Deletes all subnets.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
virtual void
|
||||
deleteAllSubnets4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector);
|
||||
|
||||
/// @brief Deletes shared network by name.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param name Name of the shared network to be deleted.
|
||||
virtual void
|
||||
deleteSharedNetwork4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& name);
|
||||
|
||||
/// @brief Deletes all shared networks.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
virtual void
|
||||
deleteAllSharedNetworks4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector);
|
||||
|
||||
/// @brief Deletes option definition.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param code Code of the option to be deleted.
|
||||
/// @param space Option space of the option to be deleted.
|
||||
virtual void
|
||||
deleteOptionDef4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const uint16_t code,
|
||||
const std::string& space);
|
||||
|
||||
/// @brief Deletes all option definitions.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
virtual void
|
||||
deleteAllOptionDefs4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector);
|
||||
|
||||
/// @brief Deletes global option.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param code Code of the option to be deleted.
|
||||
/// @param space Option space of the option to be deleted.
|
||||
virtual void
|
||||
deleteOption4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const uint16_t code,
|
||||
const std::string& space);
|
||||
|
||||
/// @brief Deletes subnet level option.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param subnet_id Identifier of the subnet to which deleted option
|
||||
/// belongs.
|
||||
/// @param code Code of the deleted option.
|
||||
/// @param space Option space of the deleted option.
|
||||
virtual void
|
||||
deleteOption4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const SubnetID& subnet_id,
|
||||
const uint16_t code, const std::string& space);
|
||||
|
||||
/// @brief Deletes pool level option.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param pool_start_address Lower bound address of the pool to which
|
||||
/// deleted option belongs.
|
||||
/// @param pool_end_address Upper bound address of the pool to which the
|
||||
/// deleted option belongs.
|
||||
/// @param code Code of the deleted option.
|
||||
/// @param space Option space of the deleted option.
|
||||
virtual void
|
||||
deleteOption4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const asiolink::IOAddress& pool_start_address,
|
||||
const asiolink::IOAddress& pool_end_address,
|
||||
const uint16_t code,
|
||||
const std::string& space);
|
||||
|
||||
/// @brief Deletes global parameter.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param name Name of the global parameter to be deleted.
|
||||
virtual void
|
||||
deleteGlobalParameter4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const std::string& name);
|
||||
|
||||
/// @brief Deletes all global parameters.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
virtual void
|
||||
deleteAllGlobalParameters4(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector);
|
||||
};
|
||||
|
||||
|
||||
} // end of namespace isc::dhcp
|
||||
} // end of namespace isc
|
||||
|
||||
#endif // CONFIG_BACKEND_POOL_DHCP4_H
|
31
src/lib/yang/Makefile.am
Normal file
31
src/lib/yang/Makefile.am
Normal file
@@ -0,0 +1,31 @@
|
||||
SUBDIRS = . tests
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
|
||||
AM_CPPFLAGS += $(BOOST_INCLUDES) $(SYSREPO_CPPFLAGS)
|
||||
AM_CXXFLAGS = $(KEA_CXXFLAGS)
|
||||
|
||||
lib_LTLIBRARIES = libkea-yang.la
|
||||
libkea_yang_la_SOURCES = adaptor.cc adaptor.h
|
||||
libkea_yang_la_SOURCES += sysrepo_error.h
|
||||
libkea_yang_la_SOURCES += translator.cc translator.h
|
||||
|
||||
libkea_yang_la_LIBADD = $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
|
||||
libkea_yang_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la
|
||||
libkea_yang_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la
|
||||
libkea_yang_la_LIBADD += $(top_builddir)/src/lib/util/threads/libkea-threads.la
|
||||
libkea_yang_la_LIBADD += $(top_builddir)/src/lib/util/libkea-util.la
|
||||
libkea_yang_la_LIBADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
|
||||
libkea_yang_la_LIBADD += $(LOG4CPLUS_LIBS) $(BOOST_LIBS) $(SYSREPO_LIBS)
|
||||
|
||||
libkea_yang_la_LDFLAGS = -no-undefined -version-info 0:0:0
|
||||
|
||||
# Specify the headers for copying into the installation directory tree.
|
||||
libkea_yang_includedir = $(pkgincludedir)/yang
|
||||
libkea_yang_include_HEADERS = \
|
||||
adaptor.h \
|
||||
sysrepo_error.h \
|
||||
translator.h
|
||||
|
||||
EXTRA_DIST = yang.dox
|
||||
|
||||
CLEANFILES = *.gcno *.gcda
|
306
src/lib/yang/adaptor.cc
Normal file
306
src/lib/yang/adaptor.cc
Normal file
@@ -0,0 +1,306 @@
|
||||
// Copyright (C) 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 <yang/adaptor.h>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace isc::data;
|
||||
|
||||
namespace isc {
|
||||
namespace yang {
|
||||
|
||||
Adaptor::Adaptor() {
|
||||
}
|
||||
|
||||
Adaptor::~Adaptor() {
|
||||
}
|
||||
|
||||
ConstElementPtr
|
||||
Adaptor::getContext(ConstElementPtr parent)
|
||||
{
|
||||
ConstElementPtr context = parent->get("user-context");
|
||||
ConstElementPtr comment = parent->get("comment");
|
||||
if (!comment) {
|
||||
return (context);
|
||||
}
|
||||
ElementPtr result;
|
||||
if (context) {
|
||||
result = copy(context);
|
||||
} else {
|
||||
result = Element::createMap();
|
||||
}
|
||||
result->set("comment", comment);
|
||||
return (result);
|
||||
}
|
||||
|
||||
void
|
||||
Adaptor::fromParent(const string& name, ConstElementPtr parent,
|
||||
ConstElementPtr list) {
|
||||
ConstElementPtr param = parent->get(name);
|
||||
if (!param) {
|
||||
return;
|
||||
}
|
||||
BOOST_FOREACH(ElementPtr item, list->listValue()) {
|
||||
// don't override. Skip this entry if it already has the parameter.
|
||||
if (item->contains(name)) {
|
||||
continue;
|
||||
}
|
||||
item->set(name, param);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Adaptor::toParent(const string& name, ElementPtr parent,
|
||||
ConstElementPtr list) {
|
||||
ConstElementPtr param;
|
||||
bool first = true;
|
||||
BOOST_FOREACH(ElementPtr item, list->listValue()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
param = item->get(name);
|
||||
} else if ((!param && item->contains(name)) ||
|
||||
(param && !item->contains(name)) ||
|
||||
(param && item->contains(name) &&
|
||||
!param->equals(*item->get(name)))) {
|
||||
isc_throw(BadValue,
|
||||
"inconsistent value of " << name
|
||||
<< " in " << list->str());
|
||||
}
|
||||
}
|
||||
if (!first && param) {
|
||||
BOOST_FOREACH(ElementPtr item, list->listValue()) {
|
||||
if (param) {
|
||||
item->remove(name);
|
||||
}
|
||||
}
|
||||
parent->set(name, param);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/// @brief Apply insert.
|
||||
///
|
||||
/// This function applies an insert action at the given scope:
|
||||
/// - in a map it adds the value at the key when the key does not exist
|
||||
/// - in a list it appends the value
|
||||
/// - in other scope type it does nothing
|
||||
/// @note a copy of the value is used to avoid unwanted sharing/side effects.
|
||||
///
|
||||
/// @param key The key of the modification.
|
||||
/// @param value The value of the modification.
|
||||
/// @param scope The place to apply the insert.
|
||||
void applyInsert(ConstElementPtr key, ConstElementPtr value,
|
||||
ElementPtr scope) {
|
||||
if (scope->getType() == Element::map) {
|
||||
if (!key || !value || (key->getType() != Element::string)) {
|
||||
return;
|
||||
}
|
||||
string name = key->stringValue();
|
||||
if (!name.empty() && !scope->contains(name)) {
|
||||
scope->set(name, copy(value));
|
||||
}
|
||||
} else if (scope->getType() == Element::list) {
|
||||
if (value) {
|
||||
scope->add(copy(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Apply replace.
|
||||
///
|
||||
/// This function works only on map scopes and acts as insert at the
|
||||
/// exception the new value is set even if the key already exists.
|
||||
///
|
||||
/// @param key The key of the modification.
|
||||
/// @param value The value of the modification.
|
||||
/// @param scope The place to apply the replace.
|
||||
void applyReplace(ConstElementPtr key, ConstElementPtr value,
|
||||
ElementPtr scope) {
|
||||
if ((scope->getType() != Element::map) ||
|
||||
!key || !value || (key->getType() != Element::string)) {
|
||||
return;
|
||||
}
|
||||
string name = key->stringValue();
|
||||
if (!name.empty()) {
|
||||
scope->set(name, copy(value));
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Apply delete.
|
||||
///
|
||||
/// This function deletes the value designed by the key from the given scope:
|
||||
/// - in a map the key is the key of the value to remove
|
||||
/// - in a list the key is:
|
||||
/// * when it is an integer the index of the value to remove
|
||||
/// * when it is a map the key / value pair which belongs to the value
|
||||
/// to remove
|
||||
/// - in other scope type it does nothing
|
||||
///
|
||||
/// @param key The key item of the path.
|
||||
/// @param scope The place to apply the delete.
|
||||
void applyDelete(ConstElementPtr key, ElementPtr scope) {
|
||||
if (scope->getType() == Element::map) {
|
||||
if (!key || (key->getType() != Element::string)) {
|
||||
return;
|
||||
}
|
||||
string name = key->stringValue();
|
||||
if (!name.empty()) {
|
||||
scope->remove(name);
|
||||
}
|
||||
} else if (scope->getType() == Element::list) {
|
||||
if (!key) {
|
||||
return;
|
||||
} else if (key->getType() == Element::integer) {
|
||||
int index = key->intValue();
|
||||
if ((index >= 0) && (index < scope->size())) {
|
||||
scope->remove(index);
|
||||
}
|
||||
} else if (key->getType() == Element::map) {
|
||||
ConstElementPtr entry = key->get("key");
|
||||
ConstElementPtr value = key->get("value");
|
||||
if (!entry || !value || (entry->getType() != Element::string)) {
|
||||
return;
|
||||
}
|
||||
string name = entry->stringValue();
|
||||
if (name.empty()) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < scope->size(); ++i) {
|
||||
ConstElementPtr item = scope->get(i);
|
||||
if (!item || (item->getType() != Element::map)) {
|
||||
continue;
|
||||
}
|
||||
ConstElementPtr compare = item->get(name);
|
||||
if (compare && value->equals(*compare)) {
|
||||
scope->remove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Apply action.
|
||||
///
|
||||
/// This function applies one action (insert, replace or delete) using
|
||||
/// applyInsert, applyReplace or applyDelete.
|
||||
///
|
||||
/// @param actions The action list.
|
||||
/// @param scope The current scope.
|
||||
/// @param next The index of the next action.
|
||||
void applyAction(ConstElementPtr actions, ElementPtr scope, size_t next) {
|
||||
if (next == actions->size()) {
|
||||
return;
|
||||
}
|
||||
ConstElementPtr action = actions->get(next);
|
||||
++next;
|
||||
if (!action || (action->getType() != Element::map) ||
|
||||
!action->contains("action")) {
|
||||
applyAction(actions, scope, next);
|
||||
return;
|
||||
}
|
||||
string name = action->get("action")->stringValue();
|
||||
if (name == "insert") {
|
||||
applyInsert(action->get("key"), action->get("value"), scope);
|
||||
} else if (name == "replace") {
|
||||
applyReplace(action->get("key"), action->get("value"), scope);
|
||||
} else if (name == "delete") {
|
||||
applyDelete(action->get("key"), scope);
|
||||
}
|
||||
applyAction(actions, scope, next);
|
||||
}
|
||||
|
||||
/// @brief Apply recursively actions following the path and going down
|
||||
/// in the to-be-modified structure.
|
||||
///
|
||||
/// The recursive call when the end of the path is not reached is done:
|
||||
/// - in a map on the value at the key
|
||||
/// - in a list the next path item is:
|
||||
/// * if it is a positive integer on the value at the index
|
||||
/// * if it is -1 on all elements of the list
|
||||
/// * if a map on the element where the key / value pair belongs to
|
||||
///
|
||||
/// @param path The search list.
|
||||
/// @param actions The action list.
|
||||
/// @param scope The current scope.
|
||||
/// @param next The index of the next item to use in the path.
|
||||
void applyDown(ConstElementPtr path, ConstElementPtr actions, ElementPtr scope,
|
||||
size_t next) {
|
||||
if (!scope) {
|
||||
return;
|
||||
}
|
||||
if (next == path->size()) {
|
||||
applyAction(actions, scope, 0);
|
||||
return;
|
||||
}
|
||||
ConstElementPtr step = path->get(next);
|
||||
++next;
|
||||
if (scope->getType() == Element::map) {
|
||||
if (!step || (step->getType() != Element::string)) {
|
||||
return;
|
||||
}
|
||||
string name = step->stringValue();
|
||||
if (name.empty() || !scope->contains(name)) {
|
||||
return;
|
||||
}
|
||||
ElementPtr down = boost::const_pointer_cast<Element>(scope->get(name));
|
||||
if (down) {
|
||||
applyDown(path, actions, down, next);
|
||||
}
|
||||
} else if (scope->getType() == Element::list) {
|
||||
if (!step) {
|
||||
return;
|
||||
}
|
||||
auto downs = scope->listValue();
|
||||
if (step->getType() == Element::map) {
|
||||
ConstElementPtr key = step->get("key");
|
||||
ConstElementPtr value = step->get("value");
|
||||
if (!key || !value || (key->getType() != Element::string)) {
|
||||
return;
|
||||
}
|
||||
string name = key->stringValue();
|
||||
if (name.empty()) {
|
||||
return;
|
||||
}
|
||||
for (ElementPtr down : downs) {
|
||||
if (!down || (down->getType() != Element::map)) {
|
||||
continue;
|
||||
}
|
||||
ConstElementPtr compare = down->get(name);
|
||||
if (compare && value->equals(*compare)) {
|
||||
applyDown(path, actions, down, next);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (step->getType() != Element::integer) {
|
||||
return;
|
||||
}
|
||||
int index = step->intValue();
|
||||
if (index == -1) {
|
||||
for (ElementPtr down : downs) {
|
||||
applyDown(path, actions, down, next);
|
||||
}
|
||||
} else if ((index >= 0) && (index < scope->size())) {
|
||||
applyDown(path, actions, scope->getNonConst(index), next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
/// Apply recursively starting at the beginning of the path.
|
||||
void
|
||||
Adaptor::modify(ConstElementPtr path, ConstElementPtr actions,
|
||||
ElementPtr config) {
|
||||
applyDown(path, actions, config, 0);
|
||||
}
|
||||
|
||||
}; // end of namespace isc::yang
|
||||
}; // end of namespace isc
|
133
src/lib/yang/adaptor.h
Normal file
133
src/lib/yang/adaptor.h
Normal file
@@ -0,0 +1,133 @@
|
||||
// Copyright (C) 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/.
|
||||
|
||||
#ifndef ISC_ADAPTOR_H
|
||||
#define ISC_ADAPTOR_H 1
|
||||
|
||||
#include <exceptions/exceptions.h>
|
||||
#include <cc/data.h>
|
||||
|
||||
namespace isc {
|
||||
namespace yang {
|
||||
|
||||
/// @brief Missing key error.
|
||||
class MissingKey : public isc::Exception {
|
||||
public:
|
||||
MissingKey(const char* file, size_t line, const char* what) :
|
||||
isc::Exception(file, line, what)
|
||||
{}
|
||||
};
|
||||
|
||||
/// @brief JSON adaptor between canonical Kea and Yang models.
|
||||
///
|
||||
/// An adaptor slightly modifies a JSON configuration between canonical Kea
|
||||
/// what required or rendered by a Yang model, e.g. moving a parameter
|
||||
/// to/from a parent.
|
||||
/// The basic adaptor provides a set of tools.
|
||||
class Adaptor {
|
||||
public:
|
||||
|
||||
/// @brief Constructor.
|
||||
Adaptor();
|
||||
|
||||
/// @brief Destructor.
|
||||
virtual ~Adaptor();
|
||||
|
||||
/// @brief Get user context.
|
||||
///
|
||||
/// Get user-context and/or comment and return it with the comment
|
||||
/// if exists moved inside the user-context (without checking if
|
||||
/// there is already a comment as it should never be the case).
|
||||
///
|
||||
/// This behavior is used to handle comments. For historical purposes
|
||||
/// Kea allows to define comments in some scopes. Once the user-context
|
||||
/// has been introduced, the comment (as a separate text field)
|
||||
/// disappeared and was moved to comment key within user-context.
|
||||
/// Nevertheless, the old syntax is still supported.
|
||||
static isc::data::ConstElementPtr
|
||||
getContext(isc::data::ConstElementPtr parent);
|
||||
|
||||
/// @brief Moves a parameter from parent to a list of children.
|
||||
///
|
||||
/// Move a parameter from the parent to each item in a list.
|
||||
/// If the parameter exists in a child, it is skipped for this
|
||||
/// particular child, not overridden.
|
||||
///
|
||||
/// @param name The parameter name.
|
||||
/// @param parent The parent element.
|
||||
/// @param list The children list.
|
||||
static void fromParent(const std::string& name,
|
||||
isc::data::ConstElementPtr parent,
|
||||
isc::data::ConstElementPtr list);
|
||||
|
||||
/// @brief Moves a parameter to a parent.
|
||||
///
|
||||
/// Move a parameter from children to the parent. All children
|
||||
/// on the list must have the parameter specified and it has to have
|
||||
/// the same value.
|
||||
///
|
||||
/// @param name The parameter name.
|
||||
/// @param parent The parent element.
|
||||
/// @param list The children list.
|
||||
static void toParent(const std::string& name,
|
||||
isc::data::ElementPtr parent,
|
||||
isc::data::ConstElementPtr list);
|
||||
|
||||
/// @brief Modify a configuration in its JSON element format.
|
||||
///
|
||||
/// Smart merging tool, e.g. completing a from yang configuration.
|
||||
///
|
||||
/// A modification is a path and actions:
|
||||
/// - path item can be:
|
||||
/// * a string: current scope is a map, go down following the string
|
||||
/// as a key.
|
||||
/// * a number: current scope is a list, go down the number as an index.
|
||||
/// * special value -1: current scope is a list, apply to all items.
|
||||
/// * map { "<key>": <value> }: current scope is a list, go down to
|
||||
/// the item using the key / value pair.
|
||||
/// - an action can be: insert, replace or delete:
|
||||
/// * insert adds a value at a key:
|
||||
/// . in a map the key is the new entry key
|
||||
/// . in a list an integer key is the new element index
|
||||
/// . in a list a map key is the key / value pair the to-be-modified
|
||||
/// element contains
|
||||
/// * replace adds or replaces if it already exists a value at
|
||||
/// an entry key in a map.
|
||||
/// * delete removes a value designed by a key
|
||||
///
|
||||
/// For instance to add a control-socket entry in a configuration
|
||||
/// from a generic (vs Kea) model:
|
||||
/// @code
|
||||
/// path := [ ]
|
||||
/// actions := [ {
|
||||
/// "action": "insert",
|
||||
/// "key": "Dhcp4",
|
||||
/// "value":
|
||||
/// {
|
||||
/// "control-socket":
|
||||
/// {
|
||||
/// "socket-type": "unix",
|
||||
/// "socket-name": "/tmp/kea4-ctrl-socket"
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// @endcode
|
||||
///
|
||||
/// @param path The search list to follow down to the place to
|
||||
/// apply the action list.
|
||||
/// @param actions The action list
|
||||
/// @param config The configuration (JSON map) to modify.
|
||||
/// @note modify does not throw but returns on unexpected conditions.
|
||||
static void modify(isc::data::ConstElementPtr path,
|
||||
isc::data::ConstElementPtr actions,
|
||||
isc::data::ElementPtr config);
|
||||
|
||||
};
|
||||
|
||||
}; // end of namespace isc::yang
|
||||
}; // end of namespace isc
|
||||
|
||||
#endif // ISC_ADAPTOR_H
|
@@ -1,243 +0,0 @@
|
||||
module ietf-dhcpv4-options {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-dhcpv4-options";
|
||||
prefix "dhcpv4-options";
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
import ietf-dhcpv4-types {
|
||||
prefix dhcpv4-types;
|
||||
}
|
||||
|
||||
organization "DHC WG";
|
||||
contact
|
||||
"piotr.strzyzewski@polsl.pl";
|
||||
description "This model defines a YANG data model that can be
|
||||
used to configure DHCPv4 options.";
|
||||
|
||||
revision 2018-07-14 {
|
||||
description "Initial revision";
|
||||
reference "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Features
|
||||
*/
|
||||
|
||||
// features for server options
|
||||
feature router-op {
|
||||
description "Support for Router Option";
|
||||
}
|
||||
feature time-server-op {
|
||||
description "Support for Time Server Option";
|
||||
}
|
||||
feature domain-server-op {
|
||||
description "Support for Domain Server Option";
|
||||
}
|
||||
feature log-server-op {
|
||||
description "Support for Log Server Option";
|
||||
}
|
||||
feature hostname-op {
|
||||
description "Support for Hostname Option";
|
||||
}
|
||||
feature domain-name-op {
|
||||
description "Support for Domain Name Option";
|
||||
}
|
||||
feature broadcast-op {
|
||||
description "Support for Broadcast Address Option";
|
||||
}
|
||||
feature ntp-server-op {
|
||||
description "Support for NTP Servers Option";
|
||||
}
|
||||
feature server-name-op {
|
||||
description "Support for Server-Name Option";
|
||||
}
|
||||
feature bootfile-name-op {
|
||||
description "Support for Bootfile-Name Option";
|
||||
}
|
||||
|
||||
/*
|
||||
* Groupings
|
||||
*/
|
||||
|
||||
grouping server-option-definitions {
|
||||
description "Contains definitions for options configured on the
|
||||
DHCPv4 server which will be supplied to clients.";
|
||||
|
||||
container router-option {
|
||||
// if-feature router-op
|
||||
// presence "Enable this option";
|
||||
description "Router (3) Router addresses";
|
||||
reference "RFC2132: DHCP Options and BOOTP Vendor Extensions";
|
||||
list router {
|
||||
key router-id;
|
||||
description "Router info";
|
||||
leaf router-id {
|
||||
type uint8;
|
||||
mandatory true;
|
||||
description "Router list entry ID";
|
||||
}
|
||||
leaf router-addr {
|
||||
type inet:ipv4-address;
|
||||
mandatory true;
|
||||
description "Router address";
|
||||
}
|
||||
}
|
||||
}
|
||||
container time-server-option {
|
||||
// if-feature time-server-op
|
||||
// presence "Enable this option";
|
||||
description "Time Server (4) Timeserver addresses";
|
||||
reference "RFC2132: DHCP Options and BOOTP Vendor Extensions";
|
||||
list time-server {
|
||||
key time-server-id;
|
||||
description "Time Server info";
|
||||
leaf time-server-id {
|
||||
type uint8;
|
||||
mandatory true;
|
||||
description "Time Server list entry ID";
|
||||
}
|
||||
leaf time-server-addr {
|
||||
type inet:ipv4-address;
|
||||
mandatory true;
|
||||
description "Time Server address";
|
||||
}
|
||||
}
|
||||
}
|
||||
container domain-server-option {
|
||||
// if-feature domain-server-op
|
||||
// presence "Enable this option";
|
||||
description "Domain Server (6) DNS Server addresses";
|
||||
reference "RFC2132: DHCP Options and BOOTP Vendor Extensions";
|
||||
list domain-server {
|
||||
key domain-server-id;
|
||||
description "DNS Server info";
|
||||
leaf domain-server-id {
|
||||
type uint8;
|
||||
mandatory true;
|
||||
description "DNS Server list entry ID";
|
||||
}
|
||||
leaf domain-server-addr {
|
||||
type inet:ipv4-address;
|
||||
mandatory true;
|
||||
description "DNS Server address";
|
||||
}
|
||||
}
|
||||
}
|
||||
container log-server-option {
|
||||
// if-feature log-server-op
|
||||
// presence "Enable this option";
|
||||
description "Log Server (7) Logging Server addresses";
|
||||
reference "RFC2132: DHCP Options and BOOTP Vendor Extensions";
|
||||
list log-server {
|
||||
key log-server-id;
|
||||
description "Logging Server info";
|
||||
leaf log-server-id {
|
||||
type uint8;
|
||||
mandatory true;
|
||||
description "Logging Server list entry ID";
|
||||
}
|
||||
leaf log-server-addr {
|
||||
type inet:ipv4-address;
|
||||
mandatory true;
|
||||
description "Logging Server address";
|
||||
}
|
||||
}
|
||||
}
|
||||
container hostname-option {
|
||||
// if-feature hostname-op;
|
||||
// presence "Enable this option";
|
||||
description "Hostname (12) Hostname string";
|
||||
reference "RFC2132: DHCP Options and BOOTP Vendor Extensions";
|
||||
leaf hostname {
|
||||
type string;
|
||||
description "Hostname";
|
||||
}
|
||||
}
|
||||
container domain-name-option {
|
||||
// if-feature domain-name-op;
|
||||
// presence "Enable this option";
|
||||
description "Domain Name (15) The DNS domain name of the client";
|
||||
reference "RFC2132: DHCP Options and BOOTP Vendor Extensions";
|
||||
leaf domain-name {
|
||||
type string;
|
||||
description "Domain Name";
|
||||
}
|
||||
}
|
||||
container broadcast-option {
|
||||
// if-feature broadcast-op
|
||||
// presence "Enable this option";
|
||||
description "Broadcast Address (28) Broadcast Address";
|
||||
reference "RFC2132: DHCP Options and BOOTP Vendor Extensions";
|
||||
leaf broadcast-addr {
|
||||
type inet:ipv4-address;
|
||||
description "Broadcast address";
|
||||
}
|
||||
}
|
||||
container ntp-server-option {
|
||||
// if-feature ntp-server-op
|
||||
// presence "Enable this option";
|
||||
description "NTP Servers (42) NTP Server addresses";
|
||||
reference "RFC2132: DHCP Options and BOOTP Vendor Extensions";
|
||||
list ntp-server {
|
||||
key ntp-server-id;
|
||||
description "NTP Server info";
|
||||
leaf ntp-server-id {
|
||||
type uint8;
|
||||
mandatory true;
|
||||
description "NTP Server list entry ID";
|
||||
}
|
||||
leaf ntp-server-addr {
|
||||
type inet:ipv4-address;
|
||||
mandatory true;
|
||||
description "NTP Server address";
|
||||
}
|
||||
}
|
||||
}
|
||||
container server-name-option {
|
||||
// if-feature server-name-op;
|
||||
// presence "Enable this option";
|
||||
description "Server-Name (66) TFTP Server Name";
|
||||
reference "RFC2132: DHCP Options and BOOTP Vendor Extensions";
|
||||
leaf server-name {
|
||||
type string;
|
||||
description "TFTP Server Name";
|
||||
}
|
||||
}
|
||||
container bootfile-name-option {
|
||||
// if-feature bootfile-name-op;
|
||||
// presence "Enable this option";
|
||||
description "Bootfile-Name (67) Boot File Name";
|
||||
reference "RFC2132: DHCP Options and BOOTP Vendor Extensions";
|
||||
leaf bootfile-name {
|
||||
type string;
|
||||
description "Boot File Name";
|
||||
}
|
||||
}
|
||||
container domain-search-option {
|
||||
// if-feature domain-search-op;
|
||||
// presence "Enable this option";
|
||||
description "Domain Search (119) DNS domain search list";
|
||||
reference "RFC3397: Dynamic Host Configuration Protocol
|
||||
(DHCP) Domain Search Option";
|
||||
list domain-search {
|
||||
key domain-search-id;
|
||||
description "Domain Search info";
|
||||
leaf domain-search-id {
|
||||
type uint8;
|
||||
mandatory true;
|
||||
description "Domain Search entry ID";
|
||||
}
|
||||
leaf domain-search-entry {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Domain Search list entry";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,64 +0,0 @@
|
||||
module ietf-dhcpv4-types {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-dhcpv4-types";
|
||||
prefix "dhcpv4-types";
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
|
||||
organization "DHC WG";
|
||||
contact
|
||||
"piotr.strzyzewski@polsl.pl";
|
||||
description "This model defines a YANG data model that can be
|
||||
used to define some commonly used DHCPv4 types";
|
||||
|
||||
revision 2018-07-14 {
|
||||
description "Initial revision";
|
||||
reference "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Grouping
|
||||
*/
|
||||
grouping vendor-infor {
|
||||
description "Vendor information.";
|
||||
container vendor-info {
|
||||
description "";
|
||||
leaf ent-num {
|
||||
type uint32;
|
||||
description "enterprise number";
|
||||
}
|
||||
leaf-list data {
|
||||
type string;
|
||||
description "specific vendor info";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping portset-para {
|
||||
description "portset parameters";
|
||||
container port-parameter {
|
||||
description "port parameter";
|
||||
leaf offset {
|
||||
type uint8;
|
||||
mandatory true;
|
||||
description "offset in a port set";
|
||||
}
|
||||
leaf psid-len {
|
||||
type uint8;
|
||||
mandatory true;
|
||||
description "length of a psid";
|
||||
}
|
||||
leaf psid {
|
||||
type uint16;
|
||||
mandatory true;
|
||||
description "psid value";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
87
src/lib/yang/models/kea-ctrl-agent.yang
Normal file
87
src/lib/yang/models/kea-ctrl-agent.yang
Normal file
@@ -0,0 +1,87 @@
|
||||
module kea-ctrl-agent {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:kea-ctrl-agent";
|
||||
prefix "kea-ctrl-agent";
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
import kea-types {
|
||||
prefix kea;
|
||||
}
|
||||
import kea-logging {
|
||||
prefix logging;
|
||||
}
|
||||
|
||||
organization "Internet Systems Consortium";
|
||||
contact "kea-dev@lists.isc.org";
|
||||
description "This model defines a YANG data model that can be
|
||||
used to configure and manage a Kea control agent.";
|
||||
|
||||
revision 2018-08-20 {
|
||||
description "Initial revision";
|
||||
reference "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Data Nodes
|
||||
*/
|
||||
|
||||
container config {
|
||||
// config true;
|
||||
description "Contains control agent configuration.";
|
||||
|
||||
leaf http-host {
|
||||
type inet:ip-address;
|
||||
default "127.0.0.1";
|
||||
description "IP address to which HTTP service will be bound.";
|
||||
}
|
||||
|
||||
leaf http-port {
|
||||
type uint16;
|
||||
default 8000;
|
||||
description "Port to which HTTP service will be bound.";
|
||||
}
|
||||
|
||||
container control-sockets {
|
||||
description "Control sockets.";
|
||||
list socket {
|
||||
key server-type;
|
||||
description "List of server control socket.";
|
||||
leaf server-type {
|
||||
type enumeration {
|
||||
enum "dhcp4" {
|
||||
description "kea-dhcp4 server";
|
||||
}
|
||||
enum "dhcp6" {
|
||||
description "kea-dhcp6 server";
|
||||
}
|
||||
enum "d2" {
|
||||
description "kea-dhcp-ddns server";
|
||||
}
|
||||
}
|
||||
mandatory true;
|
||||
description "Server type.";
|
||||
}
|
||||
container control-socket {
|
||||
description "Control socket information.";
|
||||
uses kea:control-socket;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uses kea:hooks-libraries;
|
||||
|
||||
leaf user-context {
|
||||
type kea:user-context;
|
||||
description "Control agent user context.";
|
||||
}
|
||||
}
|
||||
|
||||
container logging {
|
||||
// config true;
|
||||
description "Logging";
|
||||
|
||||
uses logging:configuration;
|
||||
}
|
||||
}
|
185
src/lib/yang/models/kea-dhcp-ddns.yang
Normal file
185
src/lib/yang/models/kea-dhcp-ddns.yang
Normal file
@@ -0,0 +1,185 @@
|
||||
module kea-dhcp-ddns {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:kea-dhcp-ddns";
|
||||
prefix "kea-dhcp-ddns";
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
import kea-types {
|
||||
prefix kea;
|
||||
}
|
||||
import kea-logging {
|
||||
prefix logging;
|
||||
}
|
||||
|
||||
organization "Internet Systems Consortium";
|
||||
contact "kea-dev@lists.isc.org";
|
||||
description "This model defines a YANG data model that can be
|
||||
used to configure and manage a Kea DHCP-DDNS server.";
|
||||
|
||||
revision 2018-08-20 {
|
||||
description "Initial revision";
|
||||
reference "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Groupings
|
||||
*/
|
||||
|
||||
grouping managed-domains {
|
||||
description "Contains parameters for forward or reverse DDNS managed
|
||||
domains.";
|
||||
|
||||
container ddns-domains {
|
||||
description "DDNS domains.";
|
||||
list ddns-domain {
|
||||
key name;
|
||||
description "List of DDNS domains.";
|
||||
leaf name {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "DDNS domain name.";
|
||||
}
|
||||
leaf key-name {
|
||||
type string;
|
||||
description "TSIG key to use. Blank means no TSIG.";
|
||||
}
|
||||
container dns-servers {
|
||||
description "DNS servers.";
|
||||
list server {
|
||||
key ip-address;
|
||||
description "List of DNS servers.";
|
||||
leaf hostname {
|
||||
type string;
|
||||
description "DNS server hostname.";
|
||||
}
|
||||
leaf ip-address {
|
||||
type inet:ip-address;
|
||||
mandatory true;
|
||||
description "DNS server IP address.";
|
||||
}
|
||||
leaf port {
|
||||
type uint16;
|
||||
default 53;
|
||||
description "DNS server port.";
|
||||
}
|
||||
leaf user-context {
|
||||
type kea:user-context;
|
||||
description "DNS server user context.";
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf user-context {
|
||||
type kea:user-context;
|
||||
description "DDNS domain user context.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Data Nodes
|
||||
*/
|
||||
|
||||
container config {
|
||||
// config true;
|
||||
description "Contains DHCP-DDNS server configuration.";
|
||||
|
||||
leaf ip-address {
|
||||
type inet:ip-address;
|
||||
default "127.0.0.1";
|
||||
description "IP address on which the server listens for requests.";
|
||||
}
|
||||
|
||||
leaf port {
|
||||
type uint16;
|
||||
default 53001;
|
||||
description "Port on which the server listens for requests.";
|
||||
}
|
||||
|
||||
leaf dns-server-timeout {
|
||||
type uint32;
|
||||
units "milliseconds";
|
||||
description "Maximum amount of time that the server will wait for
|
||||
a response from a DNS server to a single DNS update message.";
|
||||
}
|
||||
|
||||
leaf ncr-protocol {
|
||||
type enumeration {
|
||||
enum "UDP" {
|
||||
description "UDP transport";
|
||||
}
|
||||
enum "TCP" {
|
||||
description "TCP transport";
|
||||
}
|
||||
}
|
||||
default "UDP";
|
||||
description "Protocol to use when sending requests to the server.";
|
||||
}
|
||||
|
||||
leaf ncr-format {
|
||||
type enumeration {
|
||||
enum "JSON" {
|
||||
description "JSON format";
|
||||
}
|
||||
}
|
||||
default "JSON";
|
||||
description "Packet format to use when sending requests to the server.";
|
||||
}
|
||||
|
||||
container forward-ddns {
|
||||
description "Forward DNS zones.";
|
||||
uses managed-domains;
|
||||
}
|
||||
|
||||
container reverse-ddns {
|
||||
description "Reverse DNS zones.";
|
||||
uses managed-domains;
|
||||
}
|
||||
|
||||
container tsig-keys {
|
||||
description "Keys to use with TSIG.";
|
||||
list key {
|
||||
key name;
|
||||
description "List of TSIG keys.";
|
||||
leaf name {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Key name.";
|
||||
}
|
||||
leaf algorithm {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Hashing algorithm to use with the key.";
|
||||
}
|
||||
leaf digest-bits {
|
||||
type uint16;
|
||||
units "bits";
|
||||
default 0;
|
||||
description "Minimum truncated length. 0 means no truncation.";
|
||||
}
|
||||
leaf secret {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Shared secret for the key.";
|
||||
}
|
||||
leaf user-context {
|
||||
type kea:user-context;
|
||||
description "Key user context.";
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf user-context {
|
||||
type kea:user-context;
|
||||
description "DHCP-DDNS server user context.";
|
||||
}
|
||||
}
|
||||
|
||||
container logging {
|
||||
// config true;
|
||||
description "Logging";
|
||||
|
||||
uses logging:configuration;
|
||||
}
|
||||
}
|
826
src/lib/yang/models/kea-dhcp-types.yang
Normal file
826
src/lib/yang/models/kea-dhcp-types.yang
Normal file
@@ -0,0 +1,826 @@
|
||||
module kea-dhcp-types {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:kea-dhcp-types";
|
||||
prefix "kea-dhcp-types";
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
import kea-types {
|
||||
prefix kea;
|
||||
}
|
||||
|
||||
organization "Internet Systems Consortium";
|
||||
contact "kea-dev@lists.isc.org";
|
||||
description "This file defines some commonly used Kea DHCP types and
|
||||
groupings.";
|
||||
revision 2018-08-20 {
|
||||
description "Initial revision";
|
||||
reference "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Typedef
|
||||
*/
|
||||
typedef host-reservation-mode {
|
||||
type enumeration {
|
||||
enum "disabled" {
|
||||
description "Host reservation support is disabled.";
|
||||
}
|
||||
enum "out-of-pool" {
|
||||
description "Allows only out of pool host reservations.";
|
||||
}
|
||||
enum "all" {
|
||||
description "Allows both in pool and out of pool host reservations.";
|
||||
}
|
||||
enum "global" {
|
||||
description "Allows only global host reservations.";
|
||||
}
|
||||
}
|
||||
default "all";
|
||||
description "Host reservation mode.";
|
||||
}
|
||||
|
||||
typedef lease-state {
|
||||
type enumeration {
|
||||
enum "default" {
|
||||
description "Active/default";
|
||||
}
|
||||
enum "declined" {
|
||||
description "Declined";
|
||||
}
|
||||
enum "expired-reclaimed" {
|
||||
description "Expired-reclaimed";
|
||||
}
|
||||
}
|
||||
default "default";
|
||||
description "Defines state of the lease.";
|
||||
}
|
||||
|
||||
/*
|
||||
* Grouping
|
||||
*/
|
||||
grouping valid-lifetime {
|
||||
description "Valid lifetime grouping.";
|
||||
leaf valid-lifetime {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
description "Valid lifetime entry.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping renew-timer {
|
||||
description "Renew timer grouping.";
|
||||
leaf renew-timer {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
description "Renew timer entry.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping rebind-timer {
|
||||
description "Rebind timer grouping.";
|
||||
leaf rebind-timer {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
description "Rebind timer entry.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping database {
|
||||
description "Database grouping.";
|
||||
leaf database-type {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Database type (e.g. mysql).";
|
||||
}
|
||||
leaf user {
|
||||
type string;
|
||||
description "Database user name.";
|
||||
}
|
||||
leaf password {
|
||||
type string;
|
||||
description "Database user password.";
|
||||
}
|
||||
leaf host {
|
||||
type string;
|
||||
description "Database host.";
|
||||
}
|
||||
leaf name {
|
||||
type string;
|
||||
description "Database name.";
|
||||
}
|
||||
leaf persist {
|
||||
type boolean;
|
||||
default true;
|
||||
description "Write lease to disk file. This parameter applies only to
|
||||
memfile backend.";
|
||||
}
|
||||
leaf port {
|
||||
type uint16;
|
||||
description "Database port.";
|
||||
}
|
||||
leaf lfc-interval {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
default 3600;
|
||||
description "Interval between two lease file cleanups.";
|
||||
}
|
||||
leaf readonly {
|
||||
type boolean;
|
||||
default false;
|
||||
description "If set to true, the database will be connected in
|
||||
read-only mode. This does not make sense for lease
|
||||
databases, only for host reservations and possibly
|
||||
for upcoming config backend.";
|
||||
}
|
||||
leaf connect-timeout {
|
||||
type uint32;
|
||||
units "milliseconds";
|
||||
description "Database connection timeout.";
|
||||
}
|
||||
leaf contact-points {
|
||||
type string;
|
||||
description "Cassandra database contact points, a coma separated list of
|
||||
IP addresses.";
|
||||
}
|
||||
leaf keyspace {
|
||||
type string;
|
||||
description "Cassandra database keyspace (this is Cassandra's equivalent
|
||||
of a database name).";
|
||||
}
|
||||
leaf max-reconnect-tries {
|
||||
type uint32;
|
||||
default 0;
|
||||
description "Maximum of recovery attempts before exit.";
|
||||
}
|
||||
leaf reconnect-wait-time {
|
||||
type uint32;
|
||||
units "milliseconds";
|
||||
default 0;
|
||||
description "Waiting delay between two recovery attempts.";
|
||||
}
|
||||
leaf request-timeout {
|
||||
type uint32;
|
||||
units "milliseconds";
|
||||
description "Timeout waiting for a response.";
|
||||
}
|
||||
leaf tcp-keepalive {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
default 0;
|
||||
description "TCP keepalive for the database connection.";
|
||||
}
|
||||
leaf tcp-nodelay {
|
||||
type boolean;
|
||||
default true;
|
||||
description "TCP nodelay for the database connection.";
|
||||
}
|
||||
uses kea:user-context {
|
||||
refine user-context {
|
||||
description "Database user context. Arbitrary JSON data can be
|
||||
stored here.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping databases {
|
||||
description "Databases grouping.";
|
||||
container lease-database {
|
||||
presence "Have lease database.";
|
||||
description "Lease database.";
|
||||
uses database;
|
||||
}
|
||||
container hosts-databases {
|
||||
description "Hosts databases.";
|
||||
list hosts-database {
|
||||
key database-type;
|
||||
description "List of databases.";
|
||||
uses database;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping expired-leases-processing {
|
||||
description "Expired leases processing grouping.";
|
||||
container expired-leases-processing {
|
||||
description "Expired leases processing setup.";
|
||||
leaf reclaim-timer-wait-time {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
default 10;
|
||||
description "Interval between reclamation cycles.";
|
||||
}
|
||||
leaf flush-reclaimed-timer-wait-time {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
default 25;
|
||||
description "Interval between reclaimed leases collection.";
|
||||
}
|
||||
leaf hold-reclaimed-time {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
default 3600;
|
||||
description "Hold timer for re-assignment.";
|
||||
}
|
||||
leaf max-reclaim-leases {
|
||||
type uint32;
|
||||
default 100;
|
||||
description "Maximum number of reclaimed leases per cycle.";
|
||||
}
|
||||
leaf max-reclaim-time {
|
||||
type uint32;
|
||||
units "milliseconds";
|
||||
default 250;
|
||||
description "Maximum duration of a reclamation cycle.";
|
||||
}
|
||||
leaf unwarned-reclaim-cycles {
|
||||
type uint32;
|
||||
default 5;
|
||||
description "Maximum numbers of uncomplete cycles before warning.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping control-socket {
|
||||
description "Control socket grouping.";
|
||||
container control-socket {
|
||||
presence "Have control socket.";
|
||||
description "Control socket container.";
|
||||
uses kea:control-socket;
|
||||
}
|
||||
}
|
||||
|
||||
grouping dhcp-ddns {
|
||||
description "DHCP-DDNS grouping.";
|
||||
container dhcp-ddns {
|
||||
description "DHCP-DDNS client setup.";
|
||||
leaf enable-updates {
|
||||
type boolean;
|
||||
default false;
|
||||
description "Enable DHCP-DDNS updates.";
|
||||
}
|
||||
leaf qualifying-suffix {
|
||||
type string;
|
||||
description "DHCP-DDNS qualifying suffix.";
|
||||
}
|
||||
leaf server-ip {
|
||||
type inet:ip-address;
|
||||
default "127.0.0.1";
|
||||
description "DHCP-DDNS server IP address.";
|
||||
}
|
||||
leaf server-port {
|
||||
type uint16;
|
||||
default 53001;
|
||||
description "DHCP-DDNS server port.";
|
||||
}
|
||||
leaf sender-ip {
|
||||
type inet:ip-address;
|
||||
description "DHCP-DDNS sender IP address.";
|
||||
}
|
||||
leaf sender-port {
|
||||
type uint16;
|
||||
description "DHCP-DDNS sender port.";
|
||||
}
|
||||
leaf max-queue-size {
|
||||
type uint32;
|
||||
default 1024;
|
||||
description "Maximum DHCP-DDNS queue size.";
|
||||
}
|
||||
leaf ncr-protocol {
|
||||
type enumeration {
|
||||
enum "UDP" {
|
||||
description "UDP transport";
|
||||
}
|
||||
enum "TCP" {
|
||||
description "TCP transport";
|
||||
}
|
||||
}
|
||||
default "UDP";
|
||||
description "Protocol to use for DHCP-DDNS communication.
|
||||
Currently only UDP is supported.";
|
||||
}
|
||||
leaf ncr-format {
|
||||
type enumeration {
|
||||
enum "JSON" {
|
||||
description "JSON format";
|
||||
}
|
||||
}
|
||||
default "JSON";
|
||||
description "Packet format to use for DHCP-DDNS.";
|
||||
}
|
||||
leaf always-include-fqdn {
|
||||
type boolean;
|
||||
description "???";
|
||||
}
|
||||
leaf override-no-update {
|
||||
type boolean;
|
||||
default false;
|
||||
description "Ignore client request and send update.";
|
||||
}
|
||||
leaf override-client-update {
|
||||
type boolean;
|
||||
default false;
|
||||
description "Ignore client delegation.";
|
||||
}
|
||||
leaf replace-client-name {
|
||||
type enumeration {
|
||||
enum "when-present" {
|
||||
description "When the client sent a name.";
|
||||
}
|
||||
enum "never" {
|
||||
description "Never replace or generate a name.";
|
||||
}
|
||||
enum "always" {
|
||||
description "Always replace or generate a name.";
|
||||
}
|
||||
enum "when-not-present" {
|
||||
description "When the client did not send a name.";
|
||||
}
|
||||
}
|
||||
default "never";
|
||||
description "Replace the name provided by the client.";
|
||||
}
|
||||
leaf generated-prefix {
|
||||
type string;
|
||||
default "myhost";
|
||||
description "DHCP-DDNS generated prefix.";
|
||||
}
|
||||
leaf hostname-char-set {
|
||||
type string;
|
||||
description "A regex defining invalid characters. If detected, those
|
||||
will be replaced by hostname-char-replacement.";
|
||||
}
|
||||
leaf hostname-char-replacement {
|
||||
type string;
|
||||
description "Replacement for invalid charaters. See
|
||||
hostname-char-set.";
|
||||
}
|
||||
uses kea:user-context {
|
||||
refine user-context {
|
||||
description "DHCP-DDNS user context. Arbitrary JSON data can
|
||||
be stored here.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping sanity-checks {
|
||||
description "Sanity checks grouping.";
|
||||
container sanity-checks {
|
||||
description "Sanity checks container.";
|
||||
leaf lease-checks {
|
||||
type enumeration {
|
||||
enum "none" {
|
||||
description "No checks.";
|
||||
}
|
||||
enum "warn" {
|
||||
description "When a check fails print a warning and accept the
|
||||
lease.";
|
||||
}
|
||||
enum "fix" {
|
||||
description "When a check fails try to fix it and accept the
|
||||
lease.";
|
||||
}
|
||||
enum "fix-del" {
|
||||
description "When a check fails try to fix it and reject the
|
||||
lease if still bad.";
|
||||
}
|
||||
enum "del" {
|
||||
description "When a check fails reject the lease.";
|
||||
}
|
||||
}
|
||||
default "warn";
|
||||
description "Lease checks: verify subnet-id consistency on memfile
|
||||
loading.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping client-class {
|
||||
description "Client class grouping.";
|
||||
leaf client-class {
|
||||
type string;
|
||||
description "Client class entry.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping pool-client-class {
|
||||
description "Client class grouping for a pool.";
|
||||
uses client-class {
|
||||
refine client-class {
|
||||
description "Pool client class guard (only clients belonging
|
||||
to this class will be allowed in this pool).";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping subnet-client-class {
|
||||
description "Client class grouping for a subnet.";
|
||||
uses client-class {
|
||||
refine client-class {
|
||||
description "Subnet client class guard (only clients belonging to this
|
||||
class will be allowed in this subnet).";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping network-client-class {
|
||||
description "Client class grouping for a shared network.";
|
||||
uses client-class {
|
||||
refine client-class {
|
||||
description "Shared network client class guard (only clients
|
||||
belonging to this class will be allowed in this
|
||||
shared network).";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping require-client-classes {
|
||||
description "Require client classes grouping.";
|
||||
leaf-list require-client-classes {
|
||||
type string;
|
||||
description "List of client classes.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping pool-require-client-classes {
|
||||
description "Require client classes grouping for a pool.";
|
||||
uses require-client-classes {
|
||||
refine require-client-classes {
|
||||
description "Pool require client classes.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping subnet-require-client-classes {
|
||||
description "Require client classes grouping for a subnet.";
|
||||
uses require-client-classes {
|
||||
refine require-client-classes {
|
||||
description "Subnet require client classes.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping network-require-client-classes {
|
||||
description "Require client classes grouping for a shared network.";
|
||||
uses require-client-classes {
|
||||
refine require-client-classes {
|
||||
description "Shared network require client classes.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping interface {
|
||||
description "Interface grouping.";
|
||||
leaf interface {
|
||||
type string;
|
||||
description "Interface entry.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping subnet-interface {
|
||||
description "Interface grouping for a subnet.";
|
||||
uses interface {
|
||||
refine interface {
|
||||
description "Name of the network interface this subnet is directly
|
||||
accessible with (optional).";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping network-interface {
|
||||
description "Interface grouping for a shared network.";
|
||||
uses interface {
|
||||
refine interface {
|
||||
description "Specifies the network interface this shared network is
|
||||
directly accessible with. (optional)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// To move to DHCPv6.
|
||||
grouping interface-id {
|
||||
description "Interface ID grouping.";
|
||||
leaf interface-id {
|
||||
type string;
|
||||
description "Interface ID entry.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping subnet-interface-id {
|
||||
description "Interface ID grouping for a subnet.";
|
||||
uses interface-id {
|
||||
refine interface-id {
|
||||
description "Subnet interface-id option.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping network-interface-id {
|
||||
description "Interface ID grouping for a shared network.";
|
||||
uses interface-id {
|
||||
refine interface-id {
|
||||
description "Shared network interface-id option.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping subnet-id {
|
||||
description "Subnet ID grouping.";
|
||||
leaf id {
|
||||
type uint32 {
|
||||
range 1..max;
|
||||
}
|
||||
mandatory true;
|
||||
description "Subnet ID, a unique identifier used to locate or reference
|
||||
a subnet.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping host-identifier {
|
||||
description "Host identifier grouping.";
|
||||
leaf identifier {
|
||||
type string;
|
||||
description "Host identifier.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping host-hostname {
|
||||
description "Host DNS name grouping.";
|
||||
leaf hostname {
|
||||
type string;
|
||||
description "Host DNS name.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping host-client-classes {
|
||||
description "Host client classes grouping.";
|
||||
leaf-list client-classes {
|
||||
type string;
|
||||
description "Host client classes (if host identifier matches, a
|
||||
client's packet will be added to the classes liste
|
||||
here.)";
|
||||
}
|
||||
}
|
||||
|
||||
grouping host-subnet-id {
|
||||
description "Host subnet ID grouping.";
|
||||
leaf subnet-id {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Host subnet ID.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping reservation-mode {
|
||||
description "Reservation mode grouping.";
|
||||
leaf reservation-mode {
|
||||
type host-reservation-mode;
|
||||
description "Reservation mode entry.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping subnet-reservation-mode {
|
||||
description "Reservation mode grouping for a subnet.";
|
||||
uses reservation-mode {
|
||||
refine reservation-mode {
|
||||
description "Subnet host reservation mode.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping network-reservation-mode {
|
||||
description "Reservation mode grouping for a shared network.";
|
||||
uses reservation-mode {
|
||||
refine reservation-mode {
|
||||
description "Shared network host reservation mode.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping interfaces-re-detect {
|
||||
description "Interfaces re-detect grouping.";
|
||||
leaf re-detect {
|
||||
type boolean;
|
||||
default false;
|
||||
description "Re-detect interfaces at each reconfiguration.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping class-name {
|
||||
description "Client class name grouping.";
|
||||
leaf name {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Name of the client class.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping class-test {
|
||||
description "Client class test grouping.";
|
||||
leaf test {
|
||||
type string;
|
||||
description "Defines an expression that evaluates every incoming
|
||||
packet.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping class-only-if-required {
|
||||
description "Client class only-if-required grouping.";
|
||||
leaf only-if-required {
|
||||
type boolean;
|
||||
default false;
|
||||
description "Client class only if required flag.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping option-def-name {
|
||||
description "Option definition name grouping.";
|
||||
leaf name {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Name of the new option being defined.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping option-def-type {
|
||||
description "Option definition type grouping.";
|
||||
leaf type {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Type of the new option being defined (such as
|
||||
string, record or uint8).";
|
||||
}
|
||||
}
|
||||
|
||||
grouping option-def-record-types {
|
||||
description "Option definition record types grouping.";
|
||||
leaf record-types {
|
||||
type string;
|
||||
description "Option definition record types.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping option-def-encapsulate {
|
||||
description "Option definition encapsulate grouping.";
|
||||
leaf encapsulate {
|
||||
type string;
|
||||
description "Defines option space this new option encapsulates.
|
||||
Usually empty.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping option-data-name {
|
||||
description "Option data name grouping.";
|
||||
leaf name {
|
||||
type string;
|
||||
description "Option name.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping option-data-data {
|
||||
description "Option data data grouping.";
|
||||
leaf data {
|
||||
type string;
|
||||
description "Option data.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping option-data-csv-format {
|
||||
description "Option data csv-format grouping.";
|
||||
leaf csv-format {
|
||||
type boolean;
|
||||
default true;
|
||||
description "If true, the option is specified as comma separated
|
||||
values. If false, it is expected as a hex string.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping option-data-always-send {
|
||||
description "Option data always-send grouping.";
|
||||
leaf always-send {
|
||||
type boolean;
|
||||
default false;
|
||||
description "Defines whether to always send the option,
|
||||
regardless if the client requested it or not.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping option-def-array {
|
||||
description "Option data array grouping.";
|
||||
leaf array {
|
||||
type boolean;
|
||||
default false;
|
||||
description "Option definition array flag.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping decline-probation-period {
|
||||
description "Decline probation period grouping.";
|
||||
leaf decline-probation-period {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
default 86400;
|
||||
description "Decline probabation period.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping network-name {
|
||||
description "Shared network name grouping.";
|
||||
leaf name {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Shared network name.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping dhcp4o6-port {
|
||||
description "DHCPv4-over-DHCPv6 port grouping.";
|
||||
leaf dhcp4o6-port {
|
||||
type uint16;
|
||||
description "DHCPv4-over-DHCPv6 interserver port.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping pool-user-context {
|
||||
description "User context grouping for a pool.";
|
||||
uses kea:user-context {
|
||||
refine user-context {
|
||||
description "Pool user context. Arbitrary JSON data can be
|
||||
stored here.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping host-user-context {
|
||||
description "User context grouping for a host reservation.";
|
||||
uses kea:user-context {
|
||||
refine user-context {
|
||||
description "Host user context. Arbitrary JSON data can be
|
||||
stored here.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping subnet-user-context {
|
||||
description "User context grouping for a subnet.";
|
||||
uses kea:user-context {
|
||||
refine user-context {
|
||||
description "Subnet user context. Arbitrary JSON data can be
|
||||
stored here.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping network-user-context {
|
||||
description "User context grouping for a shared network.";
|
||||
uses kea:user-context {
|
||||
refine user-context {
|
||||
description "Shared network user context. Arbitrary JSON data can be
|
||||
stored here.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping interfaces-user-context {
|
||||
description "User context grouping for interfaces.";
|
||||
uses kea:user-context {
|
||||
refine user-context {
|
||||
description "Interfaces user context. Arbitrary JSON data can
|
||||
be stored here.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping class-user-context {
|
||||
description "User context grouping for a client class.";
|
||||
uses kea:user-context {
|
||||
refine user-context {
|
||||
description "Client class user context. Arbitrary JSON data can
|
||||
be stored here.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping option-def-user-context {
|
||||
description "User context grouping for an option definition.";
|
||||
uses kea:user-context {
|
||||
refine user-context {
|
||||
description "Option definition user context. Arbitrary JSON data
|
||||
can be stored here.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping option-data-user-context {
|
||||
description "User context grouping for an option data.";
|
||||
uses kea:user-context {
|
||||
refine user-context {
|
||||
description "Option user context. Arbitrary JSON data can be
|
||||
stored here.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
526
src/lib/yang/models/kea-dhcp4-server.yang
Normal file
526
src/lib/yang/models/kea-dhcp4-server.yang
Normal file
@@ -0,0 +1,526 @@
|
||||
module kea-dhcp4-server {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:kea-dhcp4-server";
|
||||
prefix "kea-dhcp4-server";
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
import kea-types {
|
||||
prefix kea;
|
||||
}
|
||||
import kea-dhcp-types {
|
||||
prefix dhcp;
|
||||
}
|
||||
import kea-logging {
|
||||
prefix logging;
|
||||
}
|
||||
|
||||
organization "Internet Systems Consortium";
|
||||
contact "kea-dev@lists.isc.org";
|
||||
description "This model defines a YANG data model that can be
|
||||
used to configure and manage a Kea DHCPv4 server.";
|
||||
|
||||
revision 2018-08-20 {
|
||||
description "Initial revision";
|
||||
reference "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Typedefs
|
||||
*/
|
||||
typedef host-identifier-type {
|
||||
type enumeration {
|
||||
enum "duid" {
|
||||
description "DUID";
|
||||
}
|
||||
enum "hw-address" {
|
||||
description "Hardware address";
|
||||
}
|
||||
enum "circuit-id" {
|
||||
description "Circuit-id option";
|
||||
}
|
||||
enum "client-id" {
|
||||
description "Client identifier";
|
||||
}
|
||||
enum "flex-id" {
|
||||
description "Flexible identifier";
|
||||
}
|
||||
}
|
||||
description "Host identifier type.";
|
||||
}
|
||||
|
||||
/*
|
||||
* Groupings
|
||||
*/
|
||||
grouping match-client-id {
|
||||
description "Match client ID grouping.";
|
||||
leaf match-client-id {
|
||||
type boolean;
|
||||
default true;
|
||||
description "Use client-id for lease lookups. If set to false, client-id
|
||||
will be ignored.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping next-server {
|
||||
description "Next server address grouping.";
|
||||
leaf next-server {
|
||||
type inet:ipv4-address;
|
||||
description "Next server IPv4 address. If set, this value will be set
|
||||
in siaddr field.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping server-hostname {
|
||||
description "Server hostname grouping.";
|
||||
leaf server-hostname {
|
||||
type string;
|
||||
description "Server hostname (up to 64 bytes).";
|
||||
}
|
||||
}
|
||||
|
||||
grouping boot-file-name {
|
||||
description "Boot file name grouping.";
|
||||
leaf boot-file-name {
|
||||
type string;
|
||||
description "Boot file name (up to 128 bytes).";
|
||||
}
|
||||
}
|
||||
|
||||
grouping relay {
|
||||
description "Relay grouping.";
|
||||
leaf-list ip-addresses {
|
||||
type inet:ipv4-address;
|
||||
description "IPv4 addresses.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping subnet4-list {
|
||||
description "Subnet4 list grouping.";
|
||||
list subnet4 {
|
||||
key id;
|
||||
ordered-by user;
|
||||
description "List of IPv4 subnets.";
|
||||
uses dhcp:valid-lifetime;
|
||||
uses dhcp:renew-timer;
|
||||
uses dhcp:rebind-timer;
|
||||
uses option-data-list;
|
||||
container pools {
|
||||
description "List of pools.";
|
||||
list pool {
|
||||
key "start-address end-address";
|
||||
ordered-by user;
|
||||
description "Pool entry.";
|
||||
leaf prefix {
|
||||
type inet:ipv4-prefix;
|
||||
description "Defines a pool of dynamic IPv4 addresses to be managed
|
||||
by the server.";
|
||||
}
|
||||
leaf start-address {
|
||||
type inet:ipv4-address;
|
||||
mandatory true;
|
||||
description "First IPv4 address in a pool.";
|
||||
}
|
||||
leaf end-address {
|
||||
type inet:ipv4-address;
|
||||
mandatory true;
|
||||
description "Last IPv4 address in a pool.";
|
||||
}
|
||||
uses option-data-list;
|
||||
uses dhcp:pool-client-class;
|
||||
uses dhcp:pool-require-client-classes;
|
||||
uses dhcp:pool-user-context;
|
||||
}
|
||||
}
|
||||
leaf subnet {
|
||||
type inet:ipv4-prefix;
|
||||
mandatory true;
|
||||
description "IPv4 subnet prefix.";
|
||||
}
|
||||
uses dhcp:subnet-interface;
|
||||
uses dhcp:subnet-interface-id;
|
||||
uses dhcp:subnet-id;
|
||||
uses dhcp:subnet-client-class;
|
||||
uses dhcp:subnet-require-client-classes;
|
||||
container reservations {
|
||||
description "A container with host reservations specific to
|
||||
this IPv4 subnet.";
|
||||
list host {
|
||||
key "identifier-type identifier";
|
||||
description "Host reservation entry.";
|
||||
leaf identifier-type {
|
||||
type host-identifier-type;
|
||||
description "Host identifier type.";
|
||||
}
|
||||
uses dhcp:host-identifier;
|
||||
leaf ip-address {
|
||||
type inet:ipv4-address;
|
||||
description "Host reserved IPv4 address.";
|
||||
}
|
||||
uses dhcp:host-hostname;
|
||||
uses dhcp:host-client-classes;
|
||||
uses option-data-list;
|
||||
uses next-server;
|
||||
uses server-hostname;
|
||||
uses boot-file-name;
|
||||
uses dhcp:host-user-context;
|
||||
}
|
||||
}
|
||||
uses dhcp:subnet-reservation-mode;
|
||||
container relay {
|
||||
description "Optional information about relay agent.";
|
||||
uses relay;
|
||||
}
|
||||
uses match-client-id;
|
||||
uses next-server;
|
||||
uses server-hostname;
|
||||
uses boot-file-name;
|
||||
leaf subnet-4o6-interface {
|
||||
type string;
|
||||
description "Subnet DHCPv4-over-DHCPv6 interface.";
|
||||
}
|
||||
leaf subnet-4o6-interface-id {
|
||||
type string;
|
||||
description "Subnet DHCPv4-over-DHCPv6 interface-id option.";
|
||||
}
|
||||
leaf subnet-4o6-subnet {
|
||||
type inet:ipv6-prefix;
|
||||
description "Subnet DHCPv4-over-DHCPv6 IPv6 prefix.";
|
||||
}
|
||||
uses dhcp:subnet-user-context;
|
||||
}
|
||||
}
|
||||
|
||||
grouping client-class {
|
||||
description "Client class grouping.";
|
||||
uses dhcp:class-name;
|
||||
uses dhcp:class-test;
|
||||
uses dhcp:class-only-if-required;
|
||||
uses option-def-list;
|
||||
uses option-data-list;
|
||||
uses next-server;
|
||||
uses server-hostname;
|
||||
uses boot-file-name;
|
||||
uses dhcp:class-user-context;
|
||||
}
|
||||
|
||||
grouping option-def-list {
|
||||
description "Option definition list grouping.";
|
||||
container option-def-list {
|
||||
description "List with custom option definitions.";
|
||||
list option-def {
|
||||
key "code space";
|
||||
description "Option definition entry.";
|
||||
leaf code {
|
||||
type uint8;
|
||||
mandatory true;
|
||||
description "Option code to be used by the new option definition.";
|
||||
}
|
||||
leaf space {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Option space for the new option (typically dhcp4).";
|
||||
}
|
||||
uses dhcp:option-def-name;
|
||||
uses dhcp:option-def-type;
|
||||
uses dhcp:option-def-record-types;
|
||||
uses dhcp:option-def-encapsulate;
|
||||
uses dhcp:option-def-array;
|
||||
uses dhcp:option-def-user-context;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping option-data-list {
|
||||
description "Option data list grouping.";
|
||||
container option-data-list {
|
||||
description "Option data list.";
|
||||
list option-data {
|
||||
key "code space";
|
||||
description "Option data entry.";
|
||||
leaf code {
|
||||
type uint8;
|
||||
mandatory true;
|
||||
description "Option code.";
|
||||
}
|
||||
leaf space {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Option space.";
|
||||
}
|
||||
uses dhcp:option-data-name;
|
||||
uses dhcp:option-data-data;
|
||||
uses dhcp:option-data-csv-format;
|
||||
uses dhcp:option-data-always-send;
|
||||
uses dhcp:option-data-user-context;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Data Nodes
|
||||
*/
|
||||
|
||||
container config {
|
||||
// config true;
|
||||
description "Contains DHCPv4 server configuration.";
|
||||
|
||||
uses dhcp:valid-lifetime;
|
||||
uses dhcp:renew-timer;
|
||||
uses dhcp:rebind-timer;
|
||||
uses dhcp:decline-probation-period;
|
||||
|
||||
container subnet4 {
|
||||
description "Global list of IPv4 subnets.";
|
||||
uses subnet4-list;
|
||||
}
|
||||
|
||||
container shared-networks {
|
||||
description "Defines a list of IPv4 shared networks.";
|
||||
list shared-network {
|
||||
key name;
|
||||
description "List of IPv4 shared networks.";
|
||||
uses dhcp:network-name;
|
||||
container subnet4 {
|
||||
description "List of IPv4 subnets that belong to this shared
|
||||
network.";
|
||||
uses subnet4-list;
|
||||
}
|
||||
uses dhcp:network-interface;
|
||||
uses dhcp:renew-timer;
|
||||
uses dhcp:rebind-timer;
|
||||
uses option-data-list;
|
||||
uses match-client-id;
|
||||
uses next-server;
|
||||
uses server-hostname;
|
||||
uses boot-file-name;
|
||||
container relay {
|
||||
description "Optional information about relay agent.";
|
||||
uses relay;
|
||||
}
|
||||
uses dhcp:network-reservation-mode;
|
||||
uses dhcp:network-client-class;
|
||||
uses dhcp:network-require-client-classes;
|
||||
uses dhcp:valid-lifetime;
|
||||
uses dhcp:network-user-context;
|
||||
}
|
||||
}
|
||||
|
||||
container interfaces-config {
|
||||
description "Network interfaces configuration.";
|
||||
leaf-list interfaces {
|
||||
type string;
|
||||
description "Name of the interface (e.g. eth0) or name/address
|
||||
(e.g. eth0/192.168.1.1) or * (use all interfaces).";
|
||||
}
|
||||
leaf dhcp-socket-type {
|
||||
type enumeration {
|
||||
enum "raw" {
|
||||
description "DHCP service uses RAW sockets.";
|
||||
}
|
||||
enum "udp" {
|
||||
description "DHCP service uses UDP sockets.";
|
||||
}
|
||||
}
|
||||
default "raw";
|
||||
description "Type of sockets to use.";
|
||||
}
|
||||
leaf outbound-interface {
|
||||
type enumeration {
|
||||
enum "same-as-inbound" {
|
||||
description "Send the response on the interface where the query
|
||||
was received.";
|
||||
}
|
||||
enum "use-routing" {
|
||||
description "Use kernel routing.";
|
||||
}
|
||||
}
|
||||
default "same-as-inbound";
|
||||
description "Control the interface used to send a response.";
|
||||
}
|
||||
uses dhcp:interfaces-re-detect;
|
||||
uses dhcp:interfaces-user-context;
|
||||
}
|
||||
|
||||
uses dhcp:databases;
|
||||
|
||||
leaf-list host-reservation-identifiers {
|
||||
type host-identifier-type;
|
||||
description "Host reservation identifiers.";
|
||||
}
|
||||
|
||||
container client-classes {
|
||||
description "Client classes.";
|
||||
list client-class {
|
||||
key name;
|
||||
ordered-by user;
|
||||
description "List of client classes.";
|
||||
uses client-class;
|
||||
}
|
||||
}
|
||||
|
||||
uses option-def-list;
|
||||
uses option-data-list;
|
||||
uses kea:hooks-libraries;
|
||||
uses dhcp:expired-leases-processing;
|
||||
uses dhcp:dhcp4o6-port;
|
||||
uses dhcp:control-socket;
|
||||
uses dhcp:dhcp-ddns;
|
||||
|
||||
leaf echo-client-id {
|
||||
type boolean;
|
||||
default true;
|
||||
description "Send client-id back when the client sent it. This
|
||||
is conformant with RFC6842, but some older, buggy
|
||||
clients have problems with it.";
|
||||
}
|
||||
|
||||
uses match-client-id;
|
||||
uses next-server;
|
||||
uses server-hostname;
|
||||
uses boot-file-name;
|
||||
uses kea:user-context {
|
||||
refine user-context {
|
||||
description "DHCPv4 server user context. Arbitrary JSON data can
|
||||
be stored here.";
|
||||
}
|
||||
}
|
||||
uses dhcp:sanity-checks;
|
||||
}
|
||||
|
||||
container logging {
|
||||
// config true;
|
||||
description "Logging";
|
||||
|
||||
uses logging:configuration;
|
||||
}
|
||||
|
||||
/*
|
||||
* State data
|
||||
*/
|
||||
container state {
|
||||
config false;
|
||||
description "State of Kea DHCPv4 server.";
|
||||
|
||||
container leases {
|
||||
description "Kea DHCPv4 leases.";
|
||||
list lease {
|
||||
key ip-address;
|
||||
description "List of Kea DHCPv4 leases.";
|
||||
leaf ip-address {
|
||||
type inet:ipv4-address;
|
||||
mandatory true;
|
||||
description "Lease IP address.";
|
||||
}
|
||||
leaf hw-address {
|
||||
type binary;
|
||||
mandatory true;
|
||||
description "Lease hardware address.";
|
||||
}
|
||||
leaf client-id {
|
||||
type binary;
|
||||
description "Lease client-id.";
|
||||
}
|
||||
uses dhcp:valid-lifetime {
|
||||
refine valid-lifetime {
|
||||
mandatory true;
|
||||
}
|
||||
}
|
||||
leaf cltt {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
mandatory true;
|
||||
description "Lease client last transmission time.";
|
||||
}
|
||||
leaf subnet-id {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Lease subnet ID.";
|
||||
}
|
||||
leaf fqdn-fwd {
|
||||
type boolean;
|
||||
default false;
|
||||
description "Lease FQDN forward flag.";
|
||||
}
|
||||
leaf fqdn-rev {
|
||||
type boolean;
|
||||
default false;
|
||||
description "Lease FQDN reverse lag.";
|
||||
}
|
||||
leaf hostname {
|
||||
type string;
|
||||
default "";
|
||||
description "Lease hostname.";
|
||||
}
|
||||
leaf state {
|
||||
type dhcp:lease-state;
|
||||
default "default";
|
||||
description "Lease state.";
|
||||
}
|
||||
leaf user-context {
|
||||
type kea:user-context;
|
||||
description "Lease user context.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container lease-stats {
|
||||
description "Lease statistics.";
|
||||
list subnet {
|
||||
key subnet-id;
|
||||
description "List of IPv4 subnets.";
|
||||
leaf subnet-id {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Subnet ID.";
|
||||
}
|
||||
leaf total-addresses {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Total addresses counter.";
|
||||
}
|
||||
leaf assigned-addresses {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Assigned addresses counter.";
|
||||
}
|
||||
leaf declined-addresses {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Declined addresses counter.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container hosts {
|
||||
description "Kea DHCPv4 hosts.";
|
||||
list host {
|
||||
key "subnet-id identifier-type identifier";
|
||||
description "List of Kea DHCPv4 hosts.";
|
||||
leaf identifier-type {
|
||||
type host-identifier-type;
|
||||
mandatory true;
|
||||
description "Host identifier type.";
|
||||
}
|
||||
uses dhcp:host-identifier;
|
||||
uses dhcp:host-subnet-id;
|
||||
leaf ip-address {
|
||||
type inet:ipv4-address;
|
||||
description "Host reserved IP address.";
|
||||
}
|
||||
uses dhcp:host-hostname;
|
||||
uses dhcp:host-client-classes;
|
||||
uses option-data-list;
|
||||
uses next-server;
|
||||
uses server-hostname;
|
||||
uses boot-file-name;
|
||||
uses dhcp:host-user-context;
|
||||
leaf auth-key {
|
||||
type string;
|
||||
description "Host authentication key (unused in DHCPv4).";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
594
src/lib/yang/models/kea-dhcp6-server.yang
Normal file
594
src/lib/yang/models/kea-dhcp6-server.yang
Normal file
@@ -0,0 +1,594 @@
|
||||
module kea-dhcp6-server {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:kea-dhcp6-server";
|
||||
prefix "kea-dhcp6-server";
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
import kea-types {
|
||||
prefix kea;
|
||||
}
|
||||
import kea-dhcp-types {
|
||||
prefix dhcp;
|
||||
}
|
||||
import kea-logging {
|
||||
prefix logging;
|
||||
}
|
||||
|
||||
|
||||
organization "Internet Systems Consortium";
|
||||
contact "kea-dev@lists.isc.org";
|
||||
description "This model defines a YANG data model that can be
|
||||
used to configure and manage a Kea DHCPv6 server.";
|
||||
|
||||
revision 2018-08-20 {
|
||||
description "Initial revision";
|
||||
reference "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Typedefs
|
||||
*/
|
||||
typedef host-identifier-type {
|
||||
type enumeration {
|
||||
enum "duid" {
|
||||
description "DUID";
|
||||
}
|
||||
enum "hw-address" {
|
||||
description "Hardware address";
|
||||
}
|
||||
enum "flex-id" {
|
||||
description "Flexible identifier";
|
||||
}
|
||||
}
|
||||
description "Host identifier type.";
|
||||
}
|
||||
|
||||
/*
|
||||
* Groupings
|
||||
*/
|
||||
grouping preferred-lifetime {
|
||||
description "Preferred lifetime grouping.";
|
||||
leaf preferred-lifetime {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
description "Preferred lifetime.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping relay {
|
||||
description "Relay grouping.";
|
||||
leaf-list ip-addresses {
|
||||
type inet:ipv6-address;
|
||||
description "IPv6 addresses.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping rapid-commit {
|
||||
description "Rapid commit grouping.";
|
||||
leaf rapid-commit {
|
||||
type boolean;
|
||||
default false;
|
||||
description "Rapid commit entry.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping subnet6-list {
|
||||
description "Subnet6 list grouping.";
|
||||
list subnet6 {
|
||||
key id;
|
||||
ordered-by user;
|
||||
description "List of IPv6 subnets.";
|
||||
uses preferred-lifetime;
|
||||
uses dhcp:valid-lifetime;
|
||||
uses dhcp:renew-timer;
|
||||
uses dhcp:rebind-timer;
|
||||
uses option-data-list;
|
||||
container pools {
|
||||
description "List of pools.";
|
||||
list pool {
|
||||
key "start-address end-address";
|
||||
ordered-by user;
|
||||
description "Pool entry.";
|
||||
leaf prefix {
|
||||
type inet:ipv6-prefix;
|
||||
description "Pool prefix.";
|
||||
}
|
||||
leaf start-address {
|
||||
type inet:ipv6-address;
|
||||
mandatory true;
|
||||
description "First IPv6 address in a pool.";
|
||||
}
|
||||
leaf end-address {
|
||||
type inet:ipv6-address;
|
||||
mandatory true;
|
||||
description "Last IPv6 address in a pool.";
|
||||
}
|
||||
uses option-data-list;
|
||||
uses dhcp:pool-client-class;
|
||||
uses dhcp:pool-require-client-classes;
|
||||
uses dhcp:pool-user-context;
|
||||
}
|
||||
}
|
||||
container pd-pools {
|
||||
description "List of prefix delegation pools.";
|
||||
list pd-pool {
|
||||
key prefix;
|
||||
ordered-by user;
|
||||
description "Prefix delegation pool entry.";
|
||||
leaf prefix {
|
||||
type inet:ipv6-prefix;
|
||||
mandatory true;
|
||||
description "IPv6 pool prefix.";
|
||||
}
|
||||
leaf delegated-len {
|
||||
type uint8;
|
||||
description "Prefix pool delegated length.";
|
||||
}
|
||||
uses option-data-list;
|
||||
uses dhcp:client-class {
|
||||
refine client-class {
|
||||
description "Prefix pool client class guard. (only
|
||||
clients belonging to this class will be
|
||||
allowed in this pool).";
|
||||
}
|
||||
}
|
||||
uses dhcp:require-client-classes {
|
||||
refine require-client-classes {
|
||||
description "Prefix pool require client classes.";
|
||||
}
|
||||
}
|
||||
leaf excluded-prefix {
|
||||
type inet:ipv6-prefix;
|
||||
description "Prefix pool excluded prefix.";
|
||||
}
|
||||
uses kea:user-context {
|
||||
refine user-context {
|
||||
description "Prefix pool user context. Arbitrary JSON data
|
||||
can be stored here.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf subnet {
|
||||
type inet:ipv6-prefix;
|
||||
mandatory true;
|
||||
description "IPv6 subnet prefix.";
|
||||
}
|
||||
uses dhcp:subnet-interface;
|
||||
uses dhcp:subnet-interface-id;
|
||||
uses dhcp:subnet-id;
|
||||
uses rapid-commit {
|
||||
refine rapid-commit {
|
||||
description "Subnet rapid commit flag.";
|
||||
}
|
||||
}
|
||||
uses dhcp:subnet-client-class;
|
||||
uses dhcp:require-client-classes;
|
||||
container reservations {
|
||||
description "A container with host reservations specific to
|
||||
this IPv6 subnet.";
|
||||
list host {
|
||||
key "identifier-type identifier";
|
||||
description "Host reservation entry.";
|
||||
leaf identifier-type {
|
||||
type host-identifier-type;
|
||||
mandatory true;
|
||||
description "Host identifier type.";
|
||||
}
|
||||
uses dhcp:host-identifier;
|
||||
leaf-list ip-addresses {
|
||||
type inet:ipv6-address;
|
||||
description "Host reserved IP addresses.";
|
||||
}
|
||||
leaf-list prefixes {
|
||||
type inet:ipv6-prefix;
|
||||
description "Host reserved IP prefixes.";
|
||||
}
|
||||
uses dhcp:host-hostname;
|
||||
uses dhcp:host-client-classes;
|
||||
uses option-data-list;
|
||||
uses dhcp:host-user-context;
|
||||
}
|
||||
}
|
||||
uses dhcp:subnet-reservation-mode;
|
||||
container relay {
|
||||
description "Optional information about relay agent.";
|
||||
uses relay;
|
||||
}
|
||||
uses dhcp:subnet-user-context;
|
||||
}
|
||||
}
|
||||
|
||||
grouping client-class {
|
||||
description "Client class grouping.";
|
||||
uses dhcp:class-name;
|
||||
uses dhcp:class-test;
|
||||
uses dhcp:class-only-if-required;
|
||||
uses option-data-list;
|
||||
uses dhcp:class-user-context;
|
||||
}
|
||||
|
||||
grouping option-def-list {
|
||||
description "Option definition list grouping.";
|
||||
container option-def-list {
|
||||
description "Option definition list.";
|
||||
list option-def {
|
||||
key "code space";
|
||||
description "Option definition entry.";
|
||||
leaf code {
|
||||
type uint16;
|
||||
mandatory true;
|
||||
description "Option code to be used by the new option definition.";
|
||||
}
|
||||
leaf space {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Option space for the new option (typically dhcp6).";
|
||||
}
|
||||
uses dhcp:option-def-name;
|
||||
uses dhcp:option-def-type;
|
||||
uses dhcp:option-def-record-types;
|
||||
uses dhcp:option-def-encapsulate;
|
||||
uses dhcp:option-def-array;
|
||||
uses dhcp:option-def-user-context;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grouping option-data-list {
|
||||
description "Option data list grouping.";
|
||||
container option-data-list {
|
||||
description "Option data list.";
|
||||
list option-data {
|
||||
key "code space";
|
||||
description "Option data entry.";
|
||||
leaf code {
|
||||
type uint16;
|
||||
mandatory true;
|
||||
description "Option code.";
|
||||
}
|
||||
leaf space {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Option space.";
|
||||
}
|
||||
uses dhcp:option-data-name;
|
||||
uses dhcp:option-data-data;
|
||||
uses dhcp:option-data-csv-format;
|
||||
uses dhcp:option-data-always-send;
|
||||
uses dhcp:option-data-user-context;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Data Nodes
|
||||
*/
|
||||
|
||||
container config {
|
||||
// config true;
|
||||
description "Contains DHCPv6 server configuration.";
|
||||
|
||||
uses preferred-lifetime;
|
||||
uses dhcp:valid-lifetime;
|
||||
uses dhcp:renew-timer;
|
||||
uses dhcp:rebind-timer;
|
||||
uses dhcp:decline-probation-period;
|
||||
|
||||
container subnet6 {
|
||||
description "Global subnet6 list.";
|
||||
uses subnet6-list;
|
||||
}
|
||||
|
||||
container shared-networks {
|
||||
description "Defines a list of IPv6 shared networks.";
|
||||
list shared-network {
|
||||
key name;
|
||||
uses dhcp:network-name;
|
||||
description "List of IPv4 shared networks.";
|
||||
container subnet6 {
|
||||
description "List of IPv6 subnets that belong to this shared
|
||||
network.";
|
||||
uses subnet6-list;
|
||||
}
|
||||
uses dhcp:network-interface;
|
||||
uses dhcp:network-interface-id;
|
||||
uses dhcp:renew-timer;
|
||||
uses dhcp:rebind-timer;
|
||||
uses option-data-list;
|
||||
container relay {
|
||||
description "Optional information about relay agent.";
|
||||
uses relay;
|
||||
}
|
||||
uses dhcp:network-reservation-mode;
|
||||
uses dhcp:network-client-class;
|
||||
uses dhcp:require-client-classes;
|
||||
uses preferred-lifetime;
|
||||
uses rapid-commit {
|
||||
refine rapid-commit {
|
||||
description "Shared network rapid commit flag.";
|
||||
}
|
||||
}
|
||||
uses dhcp:valid-lifetime;
|
||||
uses dhcp:network-user-context;
|
||||
}
|
||||
}
|
||||
|
||||
container interfaces-config {
|
||||
description "Network interfaces configuration.";
|
||||
leaf-list interfaces {
|
||||
type string;
|
||||
description "Name of the interface (e.g. eth0) or name/address
|
||||
(e.g. eth0/2001:db8::1) or * (use all interfaces).";
|
||||
}
|
||||
uses dhcp:interfaces-re-detect;
|
||||
uses dhcp:interfaces-user-context;
|
||||
}
|
||||
|
||||
uses dhcp:databases;
|
||||
|
||||
leaf-list relay-supplied-options {
|
||||
type string;
|
||||
description "Relay supplied options.";
|
||||
}
|
||||
|
||||
leaf-list mac-sources {
|
||||
type string;
|
||||
description "MAC address sources.";
|
||||
}
|
||||
|
||||
leaf-list host-reservation-identifiers {
|
||||
type host-identifier-type;
|
||||
description "Host reservation identifiers.";
|
||||
}
|
||||
|
||||
container client-classes {
|
||||
description "Client classes.";
|
||||
list client-class {
|
||||
key name;
|
||||
ordered-by user;
|
||||
description "List of client classes.";
|
||||
uses client-class;
|
||||
}
|
||||
}
|
||||
|
||||
uses option-def-list;
|
||||
uses option-data-list;
|
||||
uses kea:hooks-libraries;
|
||||
uses dhcp:expired-leases-processing;
|
||||
|
||||
container server-id {
|
||||
description "Server DUID.";
|
||||
leaf type {
|
||||
type enumeration {
|
||||
enum "LLT" {
|
||||
description "Link-layer address and timestamp.";
|
||||
}
|
||||
enum "EN" {
|
||||
description "Enterprise number.";
|
||||
}
|
||||
enum "LL" {
|
||||
description "Link-layer address.";
|
||||
}
|
||||
}
|
||||
description "Server DIOD type.";
|
||||
}
|
||||
leaf identifier {
|
||||
type string;
|
||||
description "Server DUID identifier.";
|
||||
}
|
||||
leaf time {
|
||||
type uint32;
|
||||
description "Server DUID time.";
|
||||
}
|
||||
leaf htype {
|
||||
type uint16;
|
||||
description "Server DUID hardware type.";
|
||||
}
|
||||
leaf enterprise-id {
|
||||
type uint32;
|
||||
description "Server DUID enterprise ID.";
|
||||
}
|
||||
leaf persist {
|
||||
type boolean;
|
||||
default true;
|
||||
description "Server DUID persist flag.";
|
||||
}
|
||||
leaf user-context {
|
||||
type kea:user-context;
|
||||
description "Server DUID user context.";
|
||||
}
|
||||
}
|
||||
|
||||
uses dhcp:dhcp4o6-port;
|
||||
uses dhcp:control-socket;
|
||||
uses dhcp:dhcp-ddns;
|
||||
uses kea:user-context {
|
||||
refine user-context {
|
||||
description "DHCPv6 server user context. Arbitrary JSON data can
|
||||
be stored here.";
|
||||
}
|
||||
}
|
||||
uses dhcp:sanity-checks;
|
||||
}
|
||||
|
||||
container logging {
|
||||
// config true;
|
||||
description "Logging";
|
||||
|
||||
uses logging:configuration;
|
||||
}
|
||||
|
||||
/*
|
||||
* State data
|
||||
*/
|
||||
container state {
|
||||
config false;
|
||||
description "State of Kea DHCPv6 server.";
|
||||
|
||||
container leases {
|
||||
description "Kea DHCPv6 leases.";
|
||||
list lease {
|
||||
key ip-address;
|
||||
description "List of Kea DHCPv6 leases.";
|
||||
leaf ip-address {
|
||||
type inet:ipv6-address;
|
||||
mandatory true;
|
||||
description "Lease IP address.";
|
||||
}
|
||||
leaf duid {
|
||||
type binary;
|
||||
mandatory true;
|
||||
description "Lease DUID.";
|
||||
}
|
||||
uses dhcp:valid-lifetime {
|
||||
refine valid-lifetime {
|
||||
mandatory true;
|
||||
}
|
||||
}
|
||||
leaf cltt {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
mandatory true;
|
||||
description "Lease client last transmission time.";
|
||||
}
|
||||
leaf subnet-id {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Lease subnet ID.";
|
||||
}
|
||||
leaf preferred-lifetime {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
mandatory true;
|
||||
description "Lease preferred lifetime.";
|
||||
}
|
||||
leaf lease-type {
|
||||
type enumeration {
|
||||
enum "IA_NA" {
|
||||
description "Identity association for non-temporary addresses.";
|
||||
}
|
||||
enum "IA_TA" {
|
||||
description "Identity association for temporary addresses.";
|
||||
}
|
||||
enum "IA_PD" {
|
||||
description "Identity association for prefix delegation.";
|
||||
}
|
||||
}
|
||||
mandatory true;
|
||||
description "Lease IA type.";
|
||||
}
|
||||
leaf iaid {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Lease IA ID.";
|
||||
}
|
||||
leaf prefix-length {
|
||||
type uint8 {
|
||||
range 0..128;
|
||||
}
|
||||
description "Lease prefix length.";
|
||||
}
|
||||
leaf fqdn-fwd {
|
||||
type boolean;
|
||||
default false;
|
||||
description "Lease FQDN forward flag.";
|
||||
}
|
||||
leaf fqdn-rev {
|
||||
type boolean;
|
||||
default false;
|
||||
description "Lease FQDN reverse lag.";
|
||||
}
|
||||
leaf hostname {
|
||||
type string;
|
||||
default "";
|
||||
description "Lease hostname.";
|
||||
}
|
||||
leaf state {
|
||||
type dhcp:lease-state;
|
||||
default "default";
|
||||
description "Lease state.";
|
||||
}
|
||||
leaf user-context {
|
||||
type kea:user-context;
|
||||
description "Lease user context.";
|
||||
}
|
||||
leaf hw-address {
|
||||
type string;
|
||||
description "Lease hardware address.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container lease-stats {
|
||||
description "Lease statistics.";
|
||||
list subnet {
|
||||
key subnet-id;
|
||||
description "List of IPv6 subnets.";
|
||||
leaf subnet-id {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Subnet ID.";
|
||||
}
|
||||
leaf total-nas {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Total non-temporary addresses counter.";
|
||||
}
|
||||
leaf assigned-nas {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Assigned non-temporary counter.";
|
||||
}
|
||||
leaf declined-nas {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Declined non-temporary addresses counter.";
|
||||
}
|
||||
leaf total-pds {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Total delegated prefixes counter.";
|
||||
}
|
||||
leaf assigned-pds {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Assigned delegated prefixe counter.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container hosts {
|
||||
description "Kea DHCPv6 hosts.";
|
||||
list host {
|
||||
key "subnet-id identifier-type identifier";
|
||||
description "List of Kea DHCPv6 hosts.";
|
||||
leaf identifier-type {
|
||||
type host-identifier-type;
|
||||
mandatory true;
|
||||
description "Host identifier type.";
|
||||
}
|
||||
uses dhcp:host-identifier;
|
||||
uses dhcp:host-subnet-id;
|
||||
leaf-list ip-addresses {
|
||||
type inet:ipv6-address;
|
||||
description "Host reserved IP addresses.";
|
||||
}
|
||||
leaf-list prefixes {
|
||||
type inet:ipv6-prefix;
|
||||
description "Host reserved prefixes.";
|
||||
}
|
||||
uses dhcp:host-hostname;
|
||||
uses dhcp:host-client-classes;
|
||||
uses option-data-list;
|
||||
uses dhcp:host-user-context;
|
||||
leaf auth-key {
|
||||
type string;
|
||||
description "Host authentication key.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,578 +0,0 @@
|
||||
module kea-dhcpv4-server {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:kea-dhcpv4-server";
|
||||
prefix "dhcpv4-server";
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
import ietf-dhcpv4-options {
|
||||
prefix dhcpv4-options;
|
||||
}
|
||||
import ietf-dhcpv4-types {
|
||||
prefix dhcpv4-types;
|
||||
}
|
||||
import ietf-interfaces {
|
||||
prefix if;
|
||||
}
|
||||
|
||||
organization "DHC WG";
|
||||
contact
|
||||
"piotr.strzyzewski@polsl.pl";
|
||||
description "This model defines a YANG data model that can be
|
||||
used to configure and manage Kea-dhcp4, a DHCPv4 server from ISC.";
|
||||
|
||||
revision 2018-07-14 {
|
||||
description "Initial revision; mostly based on DHCPv6 version";
|
||||
reference "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Typedef
|
||||
*/
|
||||
typedef threshold {
|
||||
type union {
|
||||
type uint16 {
|
||||
range 0..100;
|
||||
}
|
||||
type enumeration {
|
||||
enum "disabled" {
|
||||
description "No threshold";
|
||||
}
|
||||
}
|
||||
}
|
||||
description "Threshold value in percent";
|
||||
}
|
||||
|
||||
/*
|
||||
* Data Nodes
|
||||
*/
|
||||
container server {
|
||||
presence "Enables the server";
|
||||
description "DHCPv4 server portion";
|
||||
|
||||
/*
|
||||
* Configuration data
|
||||
*/
|
||||
container server-config {
|
||||
description "This container contains the configuration data
|
||||
of a server.";
|
||||
container serv-attributes {
|
||||
description
|
||||
"This container contains basic attributes of a DHCPv4 server
|
||||
such as IPv4 address, server name and so on. Some optional
|
||||
functions that can be provided by the server is also included.";
|
||||
leaf name {
|
||||
type string;
|
||||
description "server's name";
|
||||
}
|
||||
leaf description {
|
||||
type string;
|
||||
description "description of the server.";
|
||||
}
|
||||
leaf-list ipv4-address {
|
||||
type inet:ipv4-address;
|
||||
description "server's IPv4 address.";
|
||||
}
|
||||
leaf-list interfaces-config {
|
||||
// Note - this should probably be references to
|
||||
// entries in the ietf-interfaces model
|
||||
type if:interface-ref;
|
||||
description "A leaf list to denote which one or more interfaces
|
||||
the server should listen on. The default value is to listen
|
||||
on all the interfaces. This node is also used to set a unicast
|
||||
address for the server to listen with a specific interface.
|
||||
For example, if someone want the server to listen on a unicast
|
||||
address with a specific interface, she/he can use the format
|
||||
like 'eth0/192.0.2.1'.";
|
||||
}
|
||||
uses dhcpv4-types:vendor-infor;
|
||||
}
|
||||
|
||||
container option-sets {
|
||||
description "DHCPv4 employs various options to carry additional
|
||||
information and parameters in DHCP messages. This container defines
|
||||
all the possible options that need to be configured at the server
|
||||
side.";
|
||||
list option-set {
|
||||
key option-set-id;
|
||||
description "A server may allow different option sets to be
|
||||
configured for different conditions (i.e. different networks,
|
||||
clients and etc). This 'option-set' list enables various sets of
|
||||
options being defined and configured in a single server. Different
|
||||
sets are distinguished by the key called 'option-set-id'. All the
|
||||
possible options discussed above are defined in the list and each
|
||||
option is corresponding to a container. Since all the options in
|
||||
the list are optional, each container in this list has a 'presence'
|
||||
statement to indicate whether this option (container) will be
|
||||
included in the current option set or not. In addition, each container
|
||||
also has a 'if-feature' statement to indicate whether the server
|
||||
supports this option (container).";
|
||||
leaf option-set-id {
|
||||
type uint32;
|
||||
description "option set id";
|
||||
}
|
||||
uses dhcpv4-options:server-option-definitions;
|
||||
}
|
||||
}
|
||||
|
||||
container network-ranges {
|
||||
description "This model supports a hierarchy
|
||||
to achieve dynamic configuration. That is to say we could configure the
|
||||
server at different levels through this model. The top level is a global
|
||||
level which is defined as the container 'network-ranges'. The following
|
||||
levels are defined as sub-containers under it. The 'network-ranges'
|
||||
contains the parameters (e.g. option-sets) that would be allocated to
|
||||
all the clients served by this server.";
|
||||
|
||||
leaf option-set-id {
|
||||
type leafref {
|
||||
path "/server/server-config/option-sets/option-set/option-set-id";
|
||||
}
|
||||
description
|
||||
"The ID field of relevant global option-set to be provisioned to
|
||||
clients.";
|
||||
}
|
||||
list network-range {
|
||||
key network-range-id;
|
||||
description
|
||||
"Under the 'network-ranges' container, a 'network-range' list
|
||||
is defined to configure the server at a network level which is also
|
||||
considered as the second level. Different network are identified by the
|
||||
key 'network-range-id'. This is because a server may have different
|
||||
configuration parameters (e.g. option sets) for different networks.";
|
||||
leaf network-range-id {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "equivalent to subnet id";
|
||||
}
|
||||
leaf network-description {
|
||||
type string;
|
||||
description "description of the subnet";
|
||||
}
|
||||
leaf network-prefix {
|
||||
type inet:ipv4-prefix;
|
||||
mandatory true;
|
||||
description "subnet prefix";
|
||||
}
|
||||
leaf option-set-id {
|
||||
type leafref {
|
||||
path "/server/server-config/option-sets/option-set/option-set-id";
|
||||
}
|
||||
description "The ID field of relevant option-set to be provisioned to
|
||||
clients of this network-range.";
|
||||
}
|
||||
|
||||
container address-pools {
|
||||
description
|
||||
"A container that describes the DHCPv4 server's
|
||||
address pools.";
|
||||
list address-pool {
|
||||
key pool-id;
|
||||
description "A DHCPv4 server can be configured with
|
||||
several address pools. This list defines such address pools
|
||||
which are distinguished by the key called 'pool-id'.";
|
||||
leaf pool-id {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "pool id";
|
||||
}
|
||||
leaf pool-prefix {
|
||||
type inet:ipv4-prefix;
|
||||
mandatory true;
|
||||
description "pool prefix";
|
||||
}
|
||||
leaf start-address {
|
||||
type inet:ipv4-address-no-zone;
|
||||
mandatory true;
|
||||
description "start address";
|
||||
}
|
||||
leaf end-address {
|
||||
type inet:ipv4-address-no-zone;
|
||||
mandatory true;
|
||||
description "end address";
|
||||
}
|
||||
leaf renew-time {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
description "renew time";
|
||||
}
|
||||
leaf rebind-time {
|
||||
type uint32;
|
||||
units "seconds";
|
||||
description "rebind time";
|
||||
}
|
||||
// leaf rapid-commit {
|
||||
// type boolean;
|
||||
// mandatory false;
|
||||
// description "A boolean value specifies whether the pool
|
||||
// supports client-server exchanges involving two messages.";
|
||||
// }
|
||||
leaf client-class {
|
||||
type string;
|
||||
description
|
||||
"If this leaf is specified, this pool will only serve
|
||||
the clients belonging to this class.";
|
||||
}
|
||||
leaf max-address-count {
|
||||
type threshold;
|
||||
description "maximum count of addresses that can
|
||||
be allocated in this pool. This value may be
|
||||
less than count of total addresses.";
|
||||
}
|
||||
leaf option-set-id {
|
||||
type leafref {
|
||||
path "/server/server-config/option-sets/option-set/option-set-id";
|
||||
}
|
||||
description "The ID field of relevant option-set to be
|
||||
provisioned to clients of this address-pool.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container host-reservations {
|
||||
description
|
||||
"This container allows the server to make reservations at host level.";
|
||||
list host-reservation {
|
||||
key cli-id;
|
||||
description "This list allows the server to reserve addresses,
|
||||
prefixes, hostname and options for different clients.";
|
||||
leaf cli-id {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "client id";
|
||||
}
|
||||
|
||||
choice client-identifier {
|
||||
description "When making reservations, the server needs to choose a
|
||||
identifier to identify the client. Currently 'Client ID' and
|
||||
'hardware address' are supported.";
|
||||
case client-id {
|
||||
description "Client ID";
|
||||
leaf client-ident {
|
||||
type string;
|
||||
description "Client ID";
|
||||
}
|
||||
}
|
||||
case hw-address {
|
||||
description "hardware address";
|
||||
leaf hardware-address {
|
||||
type yang:mac-address;
|
||||
description "MAC address of client";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leaf-list reserv-addr {
|
||||
type inet:ipv4-address-no-zone;
|
||||
description "reserved addr";
|
||||
}
|
||||
|
||||
leaf hostname {
|
||||
type string;
|
||||
description "reserved hostname";
|
||||
}
|
||||
|
||||
leaf option-set-id {
|
||||
type leafref {
|
||||
path "/server/server-config/option-sets/option-set/option-set-id";
|
||||
}
|
||||
description "The ID field of relevant option-set to be provisioned
|
||||
in the host reservation.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
container relay-opaque-paras {
|
||||
description "This container contains some opaque values in Relay Agent
|
||||
options that need to be configured on the server side only for value
|
||||
match. Such Relay Agent options include Interface-Id option,
|
||||
Remote-Id option and Subscriber-Id option.";
|
||||
list relays {
|
||||
key relay-name;
|
||||
description "relay agents";
|
||||
leaf relay-name {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "relay agent name";
|
||||
}
|
||||
list interface-info {
|
||||
key if-name;
|
||||
description "interface info";
|
||||
leaf if-name {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "interface name";
|
||||
}
|
||||
leaf interface-id {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "interface id";
|
||||
}
|
||||
}
|
||||
list subscribers {
|
||||
key subscriber;
|
||||
description "subscribers";
|
||||
leaf subscriber {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "subscriber";
|
||||
}
|
||||
leaf subscriber-id {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "subscriber id";
|
||||
}
|
||||
}
|
||||
list remote-host {
|
||||
key ent-num;
|
||||
description "remote host";
|
||||
leaf ent-num {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "enterprise number";
|
||||
}
|
||||
leaf remote-id {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "remote id";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* State data
|
||||
*/
|
||||
container server-state {
|
||||
config "false";
|
||||
description "states of server";
|
||||
container network-ranges {
|
||||
description "This model supports a hierarchy to achieve dynamic configuration.
|
||||
That is to say we could configure the server at different levels through
|
||||
this model. The top level is a global level which is defined as the container
|
||||
'network-ranges'. The following levels are defined as sub-containers under it.
|
||||
The 'network-ranges' contains the parameters (e.g. option-sets) that would be
|
||||
allocated to all the clients served by this server.";
|
||||
list network-range {
|
||||
key network-range-id;
|
||||
description "The ID field of relevant option-set to be provisioned
|
||||
to clients of this network-range.";
|
||||
leaf network-range-id {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "equivalent to subnet id";
|
||||
}
|
||||
container address-pools {
|
||||
description "A container that describes the DHCPv4 server's address pools";
|
||||
list address-pool {
|
||||
key pool-id;
|
||||
description "A DHCPv4 server can be configured with
|
||||
several address pools. This list defines such address pools
|
||||
which are distinguished by the key called 'pool-id'.";
|
||||
leaf pool-id {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "pool id";
|
||||
}
|
||||
leaf total-address-count {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "count of total addresses in the pool";
|
||||
}
|
||||
leaf allocated-address-conut {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "count of allocated addresses in the pool";
|
||||
}
|
||||
}
|
||||
list binding-info {
|
||||
key cli-id;
|
||||
description "A list that records a binding information for each DHCPv4
|
||||
client that has already been allocated IPv4 addresses.";
|
||||
leaf cli-id {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "client id";
|
||||
}
|
||||
list cli-hw {
|
||||
key hw-address;
|
||||
description "client host id";
|
||||
leaf hw-address {
|
||||
type yang:mac-address;
|
||||
mandatory true;
|
||||
description "HW address";
|
||||
}
|
||||
leaf-list cli-addr {
|
||||
type inet:ipv4-address;
|
||||
description "client addr";
|
||||
}
|
||||
leaf pool-id {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "pool id";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container host-reservations {
|
||||
description "This container provides host reservations in the host level.";
|
||||
list binding-info {
|
||||
key cli-id;
|
||||
description
|
||||
"A list records a binding information for each DHCPv4
|
||||
client that has already been alloated IPv4 addresses or prefixes
|
||||
by host reservations.";
|
||||
leaf cli-id {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "client id";
|
||||
}
|
||||
list cli-hw {
|
||||
key hw-address;
|
||||
description "client host id";
|
||||
leaf hw-address {
|
||||
type yang:mac-address;
|
||||
mandatory true;
|
||||
description "HW address";
|
||||
}
|
||||
leaf-list cli-addr {
|
||||
type inet:ipv4-address;
|
||||
description "client addr";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
container packet-stats {
|
||||
description "A container presents the packet statistics related to
|
||||
the DHCPv4 server.";
|
||||
leaf request-count {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "request counter";
|
||||
}
|
||||
leaf renew-count {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "renew counter";
|
||||
}
|
||||
leaf rebind-count {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "rebind counter";
|
||||
}
|
||||
leaf decline-count {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "decline count";
|
||||
}
|
||||
leaf release-count {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "release counter";
|
||||
}
|
||||
leaf info-req-count {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "information request counter";
|
||||
}
|
||||
leaf advertise-count {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "advertise counter";
|
||||
}
|
||||
leaf confirm-count {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "confirm counter";
|
||||
}
|
||||
leaf reconfigure-count {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "reconfigure counter";
|
||||
}
|
||||
leaf relay-forward-count {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "relay forward counter";
|
||||
}
|
||||
leaf relay-reply-count {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "relay reply counter";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Notifications
|
||||
*/
|
||||
|
||||
notification notifications {
|
||||
description "dhcpv4 server notification module";
|
||||
container dhcpv4-server-event {
|
||||
description "dhcpv4 server event";
|
||||
container address-pool-running-out {
|
||||
description "Raised when the address pool is going to
|
||||
run out. A threshold for utilization ratio of the pool has
|
||||
been defined in the server feature so that it will notify the
|
||||
administrator when the utilization ratio reaches the
|
||||
threshold, and such threshold is a settable parameter.";
|
||||
leaf total-address-count {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Count of total addresses in the pool.";
|
||||
}
|
||||
leaf max-address-count {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Maximum count of addresses that can be allocated
|
||||
in the pool. This value may be less than count of total
|
||||
addresses.";
|
||||
}
|
||||
leaf allocated-address-conut {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
description "Count of allocated addresses in the pool.";
|
||||
}
|
||||
leaf serv-name {
|
||||
type string;
|
||||
description "server name";
|
||||
}
|
||||
leaf pool-name {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "pool name";
|
||||
}
|
||||
}
|
||||
container invalid-client-detected {
|
||||
description "Raised when the server has found a client which
|
||||
can be regarded as a potential attacker. Some description
|
||||
could also be included.";
|
||||
leaf hw {
|
||||
type yang:mac-address;
|
||||
description "HW address";
|
||||
}
|
||||
leaf description {
|
||||
type string;
|
||||
description "description of the event";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
108
src/lib/yang/models/kea-logging.yang
Normal file
108
src/lib/yang/models/kea-logging.yang
Normal file
@@ -0,0 +1,108 @@
|
||||
module kea-logging {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:kea-logging";
|
||||
prefix "kea-logging";
|
||||
|
||||
import kea-types {
|
||||
prefix kea;
|
||||
}
|
||||
|
||||
organization "Internet Systems Consortium";
|
||||
contact "kea-dev@lists.isc.org";
|
||||
description "This model defines a YANG data model that can be
|
||||
used to configure and manage logging of a Kea server.";
|
||||
|
||||
revision 2018-08-20 {
|
||||
description "Initial revision";
|
||||
reference "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Groupings
|
||||
*/
|
||||
|
||||
grouping configuration {
|
||||
description "Contains parameters for logging configuration.";
|
||||
|
||||
container loggers {
|
||||
description "Loggers.";
|
||||
list logger {
|
||||
key name;
|
||||
description "List of loggers.";
|
||||
leaf name {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Name of the logger.";
|
||||
}
|
||||
container output-options {
|
||||
description "Output options.";
|
||||
list option {
|
||||
key output;
|
||||
description "List of output options.";
|
||||
leaf output {
|
||||
type string;
|
||||
description "Type of output. Special values are stdout (standard
|
||||
output), stderr (standard error), syslog (syslog using default
|
||||
name), syslog:name (syslog using specified name). Any other
|
||||
value is interpreted as a filename.";
|
||||
}
|
||||
leaf flush {
|
||||
type boolean;
|
||||
default true;
|
||||
description "When true flush buffers after each message.";
|
||||
}
|
||||
leaf maxsize {
|
||||
type uint32;
|
||||
default 10240000;
|
||||
description "Maximum size of output file before rotation.
|
||||
Values below 204800 including 0 disable rotation.";
|
||||
}
|
||||
leaf maxver {
|
||||
type uint32 {
|
||||
range 1..max;
|
||||
}
|
||||
default 1;
|
||||
description "Maximum version to keep a rotated output file.";
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf debuglevel {
|
||||
type uint8 {
|
||||
range 0..99;
|
||||
}
|
||||
description "What level of debug messages should be printed.";
|
||||
}
|
||||
leaf severity {
|
||||
type enumeration {
|
||||
enum "FATAL" {
|
||||
description "Condition is so serious that the server cannot
|
||||
continue executing";
|
||||
}
|
||||
enum "ERROR" {
|
||||
description "Error condition. The server will continue
|
||||
executing, but the results may not be as expected.";
|
||||
}
|
||||
enum "WARN" {
|
||||
description "Out of the ordinary condition. However, the server
|
||||
will continue executing normally.";
|
||||
}
|
||||
enum "INFO" {
|
||||
description "Information message marking some event.";
|
||||
}
|
||||
enum "DEBUG" {
|
||||
description "For debugging purposes.";
|
||||
}
|
||||
enum "NONE" {
|
||||
description "All messages are inhibited.";
|
||||
}
|
||||
}
|
||||
description "Category of messages logged.";
|
||||
}
|
||||
leaf user-context {
|
||||
type kea:user-context;
|
||||
description "Logger user context.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
75
src/lib/yang/models/kea-types.yang
Normal file
75
src/lib/yang/models/kea-types.yang
Normal file
@@ -0,0 +1,75 @@
|
||||
module kea-types {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:kea-types";
|
||||
prefix "kea-types";
|
||||
|
||||
organization "Internet Systems Consortium";
|
||||
contact "kea-dev@lists.isc.org";
|
||||
description "This file defines some commonly used Kea types and groupings.";
|
||||
|
||||
revision 2018-08-20 {
|
||||
description "Initial revision";
|
||||
reference "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Typedef
|
||||
*/
|
||||
typedef user-context {
|
||||
type string;
|
||||
description "User context (JSON map).";
|
||||
}
|
||||
|
||||
/*
|
||||
* Grouping
|
||||
*/
|
||||
grouping user-context {
|
||||
description "User context grouping.";
|
||||
leaf user-context {
|
||||
type user-context;
|
||||
description "User context entry.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping control-socket {
|
||||
description "Control socket.";
|
||||
leaf socket-name {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Path to the UNIX socket.";
|
||||
}
|
||||
leaf socket-type {
|
||||
type enumeration {
|
||||
enum "unix" {
|
||||
description "Unix socket type.";
|
||||
}
|
||||
}
|
||||
mandatory true;
|
||||
description "Socket type.";
|
||||
}
|
||||
leaf user-context {
|
||||
type user-context;
|
||||
description "Control socket user context.";
|
||||
}
|
||||
}
|
||||
|
||||
grouping hooks-libraries {
|
||||
description "Hooks libraries grouping.";
|
||||
container hooks-libraries {
|
||||
description "Hook libraries.";
|
||||
list hook-library {
|
||||
key library;
|
||||
description "List of hook library.";
|
||||
leaf library {
|
||||
type string;
|
||||
mandatory true;
|
||||
description "Path to the DSO.";
|
||||
}
|
||||
leaf parameters {
|
||||
type string;
|
||||
description "Parameters (JSON value).";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
26
src/lib/yang/sysrepo_error.h
Normal file
26
src/lib/yang/sysrepo_error.h
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (C) 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/.
|
||||
|
||||
#ifndef ISC_SYSREPO_ERROR_H
|
||||
#define ISC_SYSREPO_ERROR_H 1
|
||||
|
||||
#include <exceptions/exceptions.h>
|
||||
|
||||
namespace isc {
|
||||
namespace yang {
|
||||
|
||||
/// @brief Sysrepo error.
|
||||
class SysrepoError : public isc::Exception {
|
||||
public:
|
||||
SysrepoError(const char* file, size_t line, const char* what) :
|
||||
isc::Exception(file, line, what)
|
||||
{}
|
||||
};
|
||||
|
||||
}; // end of namespace isc::yang
|
||||
}; // end of namespace isc
|
||||
|
||||
#endif // ISC_SYSREPO_ERROR_H
|
40
src/lib/yang/tests/Makefile.am
Normal file
40
src/lib/yang/tests/Makefile.am
Normal file
@@ -0,0 +1,40 @@
|
||||
AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
|
||||
AM_CPPFLAGS += $(BOOST_INCLUDES) $(SYSREPO_CPPFLAGS)
|
||||
AM_CPPFLAGS += -DCFG_EXAMPLES=\"$(abs_top_srcdir)/doc/examples\"
|
||||
AM_CXXFLAGS = $(KEA_CXXFLAGS)
|
||||
|
||||
if USE_STATIC_LINK
|
||||
AM_LDFLAGS = -static
|
||||
endif
|
||||
|
||||
CLEANFILES = *.gcno *.gcda
|
||||
|
||||
TESTS_ENVIRONMENT = \
|
||||
$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
|
||||
|
||||
EXTRA_DIST = keatest-module.yang
|
||||
|
||||
TESTS =
|
||||
if HAVE_GTEST
|
||||
TESTS += run_unittests
|
||||
run_unittests_SOURCES = adaptor_unittests.cc
|
||||
run_unittests_SOURCES += translator_unittests.cc
|
||||
run_unittests_SOURCES += run_unittests.cc
|
||||
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
|
||||
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
|
||||
|
||||
run_unittests_LDADD = $(top_builddir)/src/lib/yang/libkea-yang.la
|
||||
run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libkea-testutils.la
|
||||
run_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la
|
||||
run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
|
||||
run_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la
|
||||
run_unittests_LDADD += $(top_builddir)/src/lib/util/threads/libkea-threads.la
|
||||
run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
|
||||
run_unittests_LDADD += $(top_builddir)/src/lib/util/libkea-util.la
|
||||
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la
|
||||
run_unittests_LDADD += $(LOG4CPLUS_LIBS) $(BOOST_LIBS)
|
||||
run_unittests_LDADD += $(SYSREPO_LIBS) $(GTEST_LDADD)
|
||||
|
||||
endif
|
||||
|
||||
noinst_PROGRAMS = $(TESTS)
|
394
src/lib/yang/tests/adaptor_unittests.cc
Normal file
394
src/lib/yang/tests/adaptor_unittests.cc
Normal file
@@ -0,0 +1,394 @@
|
||||
// Copyright (C) 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 <yang/adaptor.h>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace isc;
|
||||
using namespace isc::data;
|
||||
using namespace isc::yang;
|
||||
|
||||
namespace {
|
||||
|
||||
// Test that get context works as expected i.e. moves a comment into
|
||||
// the user context creating it if not exists.
|
||||
TEST(AdaptorTest, getContext) {
|
||||
// Empty.
|
||||
string config = "{\n"
|
||||
"}\n";
|
||||
ConstElementPtr json = Element::fromJSON(config);
|
||||
ConstElementPtr context;
|
||||
ASSERT_NO_THROW(context = Adaptor::getContext(json));
|
||||
EXPECT_FALSE(context);
|
||||
|
||||
// No relevant.
|
||||
config = "{\n"
|
||||
" \"foo\": 1\n"
|
||||
"}\n";
|
||||
json = Element::fromJSON(config);
|
||||
ASSERT_NO_THROW(context = Adaptor::getContext(json));
|
||||
EXPECT_FALSE(context);
|
||||
|
||||
// User context.
|
||||
config = "{\n"
|
||||
" \"foo\": 1,\n"
|
||||
" \"user-context\": { \"bar\": 2 }\n"
|
||||
"}\n";
|
||||
json = Element::fromJSON(config);
|
||||
ASSERT_NO_THROW(context = Adaptor::getContext(json));
|
||||
ASSERT_TRUE(context);
|
||||
EXPECT_EQ("{ \"bar\": 2 }", context->str());
|
||||
|
||||
// Comment.
|
||||
config = "{\n"
|
||||
" \"foo\": 1,\n"
|
||||
" \"comment\": \"a comment\"\n"
|
||||
"}\n";
|
||||
json = Element::fromJSON(config);
|
||||
ASSERT_NO_THROW(context = Adaptor::getContext(json));
|
||||
ASSERT_TRUE(context);
|
||||
EXPECT_EQ("{ \"comment\": \"a comment\" }", context->str());
|
||||
|
||||
// User context and comment.
|
||||
config = "{\n"
|
||||
" \"foo\": 1,\n"
|
||||
" \"user-context\": { \"bar\": 2 },\n"
|
||||
" \"comment\": \"a comment\"\n"
|
||||
"}\n";
|
||||
json = Element::fromJSON(config);
|
||||
ASSERT_NO_THROW(context = Adaptor::getContext(json));
|
||||
ASSERT_TRUE(context);
|
||||
EXPECT_EQ("{ \"bar\": 2, \"comment\": \"a comment\" }", context->str());
|
||||
|
||||
// User context with conflicting comment and comment.
|
||||
config = "{\n"
|
||||
" \"foo\": 1,\n"
|
||||
" \"user-context\": {\n"
|
||||
" \"bar\": 2,\n"
|
||||
" \"comment\": \"conflicting\"\n"
|
||||
" },\n"
|
||||
" \"comment\": \"a comment\"\n"
|
||||
"}\n";
|
||||
json = Element::fromJSON(config);
|
||||
ASSERT_NO_THROW(context = Adaptor::getContext(json));
|
||||
ASSERT_TRUE(context);
|
||||
EXPECT_EQ("{ \"bar\": 2, \"comment\": \"a comment\" }", context->str());
|
||||
}
|
||||
|
||||
// Test that fromParent works as expected i.e. moves parameters from the
|
||||
// parent to children and not overwrite them.
|
||||
TEST(AdaptorTest, fromParent) {
|
||||
string config = "{\n"
|
||||
" \"param1\": 123,\n"
|
||||
" \"param2\": \"foo\",\n"
|
||||
" \"list\": [\n"
|
||||
" {\n"
|
||||
" \"param1\": 234\n"
|
||||
" },{\n"
|
||||
" \"another\": \"entry\"\n"
|
||||
" }\n"
|
||||
" ]\n"
|
||||
"}\n";
|
||||
|
||||
ConstElementPtr json = Element::fromJSON(config);
|
||||
EXPECT_NO_THROW(Adaptor::fromParent("param1", json, json->get("list")));
|
||||
EXPECT_NO_THROW(Adaptor::fromParent("param2", json, json->get("list")));
|
||||
EXPECT_NO_THROW(Adaptor::fromParent("param3", json, json->get("list")));
|
||||
|
||||
string expected = "{\n"
|
||||
" \"param1\": 123,\n"
|
||||
" \"param2\": \"foo\",\n"
|
||||
" \"list\": [\n"
|
||||
" {\n"
|
||||
" \"param1\": 234,\n"
|
||||
" \"param2\": \"foo\"\n"
|
||||
" },{\n"
|
||||
" \"another\": \"entry\",\n"
|
||||
" \"param1\": 123,\n"
|
||||
" \"param2\": \"foo\"\n"
|
||||
" }\n"
|
||||
" ]\n"
|
||||
"}\n";
|
||||
EXPECT_TRUE(json->equals(*Element::fromJSON(expected)));
|
||||
}
|
||||
|
||||
// Test that toParent works as expected i.e. moves parameters from children
|
||||
// to the parent throwing when a value differs between two children.
|
||||
TEST(AdaptorTest, toParent) {
|
||||
string config = "{\n"
|
||||
" \"list\": [\n"
|
||||
" {\n"
|
||||
" \"param2\": \"foo\",\n"
|
||||
" \"param3\": 234,\n"
|
||||
" \"param4\": true\n"
|
||||
" },{\n"
|
||||
" \"another\": \"entry\",\n"
|
||||
" \"param2\": \"foo\",\n"
|
||||
" \"param3\": 123,\n"
|
||||
" \"param5\": false\n"
|
||||
" }\n"
|
||||
" ]\n"
|
||||
"}\n";
|
||||
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
EXPECT_NO_THROW(Adaptor::toParent("param1", json, json->get("list")));
|
||||
EXPECT_TRUE(json->equals(*Element::fromJSON(config)));
|
||||
|
||||
string expected = "{\n"
|
||||
" \"param2\": \"foo\",\n"
|
||||
" \"list\": [\n"
|
||||
" {\n"
|
||||
" \"param3\": 234,\n"
|
||||
" \"param4\": true\n"
|
||||
" },{\n"
|
||||
" \"another\": \"entry\",\n"
|
||||
" \"param3\": 123,\n"
|
||||
" \"param5\": false\n"
|
||||
" }\n"
|
||||
" ]\n"
|
||||
"}\n";
|
||||
|
||||
EXPECT_NO_THROW(Adaptor::toParent("param2",json, json->get("list")));
|
||||
EXPECT_TRUE(json->equals(*Element::fromJSON(expected)));
|
||||
|
||||
// param[345] have different values so it should throw.
|
||||
EXPECT_THROW(Adaptor::toParent("param3",json, json->get("list")),
|
||||
BadValue);
|
||||
EXPECT_THROW(Adaptor::toParent("param4",json, json->get("list")),
|
||||
BadValue);
|
||||
EXPECT_THROW(Adaptor::toParent("param5",json, json->get("list")),
|
||||
BadValue);
|
||||
// And not modify the value.
|
||||
EXPECT_TRUE(json->equals(*Element::fromJSON(expected)));
|
||||
}
|
||||
|
||||
// Test for modify (maps & insert).
|
||||
TEST(AdaptorTest, modifyMapInsert) {
|
||||
string config = "{\n"
|
||||
" \"foo\": {\n"
|
||||
" \"bar\": {\n"
|
||||
"}}}\n";
|
||||
ElementPtr json;
|
||||
ASSERT_NO_THROW(json = Element::fromJSON(config));
|
||||
string spath = "[ \"foo\", \"bar\" ]";
|
||||
ConstElementPtr path;
|
||||
ASSERT_NO_THROW(path = Element::fromJSON(spath));
|
||||
string sactions = "[\n"
|
||||
"{\n"
|
||||
" \"action\": \"insert\",\n"
|
||||
" \"key\": \"test\",\n"
|
||||
" \"value\": 1234\n"
|
||||
"}]\n";
|
||||
ConstElementPtr actions;
|
||||
ASSERT_NO_THROW(actions = Element::fromJSON(sactions));
|
||||
string result = "{\n"
|
||||
" \"foo\": {\n"
|
||||
" \"bar\": {\n"
|
||||
" \"test\": 1234\n"
|
||||
"}}}\n";
|
||||
ConstElementPtr expected;
|
||||
ASSERT_NO_THROW(expected = Element::fromJSON(result));
|
||||
ASSERT_NO_THROW(Adaptor::modify(path, actions, json));
|
||||
EXPECT_TRUE(expected->equals(*json));
|
||||
}
|
||||
|
||||
// Test for modify (maps & replace).
|
||||
TEST(AdaptorTest, modifyMapReplace) {
|
||||
string config = "{\n"
|
||||
" \"foo\": {\n"
|
||||
" \"bar\": {\n"
|
||||
" \"test1\": 1234,\n"
|
||||
" \"test2\": 1234\n"
|
||||
"}}}\n";
|
||||
ElementPtr json;
|
||||
ASSERT_NO_THROW(json = Element::fromJSON(config));
|
||||
string spath = "[ \"foo\", \"bar\" ]";
|
||||
ConstElementPtr path;
|
||||
ASSERT_NO_THROW(path = Element::fromJSON(spath));
|
||||
string sactions = "[\n"
|
||||
"{\n"
|
||||
" \"action\": \"insert\",\n"
|
||||
" \"key\": \"test1\",\n"
|
||||
" \"value\": 5678\n"
|
||||
"},{\n"
|
||||
" \"action\": \"replace\",\n"
|
||||
" \"key\": \"test2\",\n"
|
||||
" \"value\": 5678\n"
|
||||
"}]\n";
|
||||
ConstElementPtr actions;
|
||||
ASSERT_NO_THROW(actions = Element::fromJSON(sactions));
|
||||
string result = "{\n"
|
||||
" \"foo\": {\n"
|
||||
" \"bar\": {\n"
|
||||
" \"test1\": 1234,\n"
|
||||
" \"test2\": 5678\n"
|
||||
"}}}\n";
|
||||
ConstElementPtr expected;
|
||||
ASSERT_NO_THROW(expected = Element::fromJSON(result));
|
||||
ASSERT_NO_THROW(Adaptor::modify(path, actions, json));
|
||||
EXPECT_TRUE(expected->equals(*json));
|
||||
}
|
||||
|
||||
// Test for modify (maps & delete).
|
||||
TEST(AdaptorTest, modifyMapDelete) {
|
||||
string config = "{\n"
|
||||
" \"foo\": {\n"
|
||||
" \"bar\": {\n"
|
||||
" \"test\": 1234\n"
|
||||
"}}}\n";
|
||||
ElementPtr json;
|
||||
ASSERT_NO_THROW(json = Element::fromJSON(config));
|
||||
string spath = "[ \"foo\", \"bar\" ]";
|
||||
ConstElementPtr path;
|
||||
ASSERT_NO_THROW(path = Element::fromJSON(spath));
|
||||
string sactions = "[\n"
|
||||
"{\n"
|
||||
" \"action\": \"delete\",\n"
|
||||
" \"key\": \"test\"\n"
|
||||
"}]\n";
|
||||
ConstElementPtr actions;
|
||||
ASSERT_NO_THROW(actions = Element::fromJSON(sactions));
|
||||
string result = "{\n"
|
||||
" \"foo\": {\n"
|
||||
" \"bar\": {\n"
|
||||
"}}}\n";
|
||||
ConstElementPtr expected;
|
||||
ASSERT_NO_THROW(expected = Element::fromJSON(result));
|
||||
ASSERT_NO_THROW(Adaptor::modify(path, actions, json));
|
||||
EXPECT_TRUE(expected->equals(*json));
|
||||
}
|
||||
|
||||
// Test for modify (lists & insert).
|
||||
TEST(AdaptorTest, modifyListInsert) {
|
||||
string config = "[\n"
|
||||
"[{\n"
|
||||
" \"foo\": \"bar\"\n"
|
||||
"}]]\n";
|
||||
ElementPtr json;
|
||||
ASSERT_NO_THROW(json = Element::fromJSON(config));
|
||||
string spath = "[ 0, { \"key\": \"foo\", \"value\": \"bar\" }]";
|
||||
ConstElementPtr path;
|
||||
ASSERT_NO_THROW(path = Element::fromJSON(spath));
|
||||
string sactions = "[\n"
|
||||
"{\n"
|
||||
" \"action\": \"insert\",\n"
|
||||
" \"key\": \"test\",\n"
|
||||
" \"value\": 1234\n"
|
||||
"}]\n";
|
||||
ConstElementPtr actions;
|
||||
ASSERT_NO_THROW(actions = Element::fromJSON(sactions));
|
||||
string result = "[\n"
|
||||
"[{\n"
|
||||
" \"foo\": \"bar\",\n"
|
||||
" \"test\": 1234\n"
|
||||
"}]]\n";
|
||||
ConstElementPtr expected;
|
||||
ASSERT_NO_THROW(expected = Element::fromJSON(result));
|
||||
ASSERT_NO_THROW(Adaptor::modify(path, actions, json));
|
||||
EXPECT_TRUE(expected->equals(*json));
|
||||
}
|
||||
|
||||
// Test for modify (list all & insert).
|
||||
TEST(AdaptorTest, modifyListAllInsert) {
|
||||
string config = "[\n"
|
||||
"{},\n"
|
||||
"{},\n"
|
||||
"{ \"test\": 1234 },\n"
|
||||
"]\n";
|
||||
ElementPtr json;
|
||||
ASSERT_NO_THROW(json = Element::fromJSON(config));
|
||||
string spath = "[ -1 ]";
|
||||
ConstElementPtr path;
|
||||
ASSERT_NO_THROW(path = Element::fromJSON(spath));
|
||||
string sactions = "[\n"
|
||||
"{\n"
|
||||
" \"action\": \"insert\",\n"
|
||||
" \"key\": \"test\",\n"
|
||||
" \"value\": 5678\n"
|
||||
"}]\n";
|
||||
ConstElementPtr actions;
|
||||
ASSERT_NO_THROW(actions = Element::fromJSON(sactions));
|
||||
string result = "[\n"
|
||||
"{ \"test\": 5678 },\n"
|
||||
"{ \"test\": 5678 },\n"
|
||||
"{ \"test\": 1234 }\n"
|
||||
"]\n";
|
||||
ConstElementPtr expected;
|
||||
ASSERT_NO_THROW(expected = Element::fromJSON(result));
|
||||
ASSERT_NO_THROW(Adaptor::modify(path, actions, json));
|
||||
EXPECT_TRUE(expected->equals(*json));
|
||||
}
|
||||
|
||||
TEST(AdaptorTest, modifyListDelete) {
|
||||
string config = "[[\n"
|
||||
"{\n"
|
||||
" \"foo\": \"bar\"\n"
|
||||
"},{\n"
|
||||
"},[\n"
|
||||
"0, 1, 2, 3\n"
|
||||
"]]]\n";
|
||||
ElementPtr json;
|
||||
ASSERT_NO_THROW(json = Element::fromJSON(config));
|
||||
string spath = "[ 0 ]";
|
||||
ConstElementPtr path;
|
||||
ASSERT_NO_THROW(path = Element::fromJSON(spath));
|
||||
// Put the positional first as it applies after previous actions...
|
||||
string sactions = "[\n"
|
||||
"{\n"
|
||||
" \"action\": \"delete\",\n"
|
||||
" \"key\": 2\n"
|
||||
"},{\n"
|
||||
" \"action\": \"delete\",\n"
|
||||
" \"key\": { \"key\": \"foo\", \"value\": \"bar\" }\n"
|
||||
"}]\n";
|
||||
ConstElementPtr actions;
|
||||
ASSERT_NO_THROW(actions = Element::fromJSON(sactions));
|
||||
string result = "[[{}]]\n";
|
||||
ConstElementPtr expected;
|
||||
ASSERT_NO_THROW(expected = Element::fromJSON(result));
|
||||
ASSERT_NO_THROW(Adaptor::modify(path, actions, json));
|
||||
EXPECT_TRUE(expected->equals(*json));
|
||||
}
|
||||
|
||||
TEST(AdaptorTest, modifyListAllDelete) {
|
||||
string config = "[[\n"
|
||||
"{\n"
|
||||
" \"foo\": \"bar\"\n"
|
||||
"},{\n"
|
||||
"},[\n"
|
||||
"0, 1, 2, 3\n"
|
||||
"]]]\n";
|
||||
ElementPtr json;
|
||||
ASSERT_NO_THROW(json = Element::fromJSON(config));
|
||||
// The main change from the previous unit test is key 0 -> -1 so
|
||||
// modify() applies the delete to all elements vs only the first one.
|
||||
string spath = "[ -1 ]";
|
||||
ConstElementPtr path;
|
||||
ASSERT_NO_THROW(path = Element::fromJSON(spath));
|
||||
// Put the positional first as it applies after previous actions...
|
||||
string sactions = "[\n"
|
||||
"{\n"
|
||||
" \"action\": \"delete\",\n"
|
||||
" \"key\": 2\n"
|
||||
"},{\n"
|
||||
" \"action\": \"delete\",\n"
|
||||
" \"key\": { \"key\": \"foo\", \"value\": \"bar\" }\n"
|
||||
"}]\n";
|
||||
ConstElementPtr actions;
|
||||
ASSERT_NO_THROW(actions = Element::fromJSON(sactions));
|
||||
string result = "[[{}]]\n";
|
||||
ConstElementPtr expected;
|
||||
ASSERT_NO_THROW(expected = Element::fromJSON(result));
|
||||
ASSERT_NO_THROW(Adaptor::modify(path, actions, json));
|
||||
EXPECT_TRUE(expected->equals(*json));
|
||||
}
|
||||
|
||||
}; // end of anonymous namespace
|
605
src/lib/yang/tests/keatest-module.yang
Normal file
605
src/lib/yang/tests/keatest-module.yang
Normal file
@@ -0,0 +1,605 @@
|
||||
module keatest-module {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:keatest-module";
|
||||
prefix tm;
|
||||
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
|
||||
organization "Sysrepo and ISC";
|
||||
description
|
||||
"ISC imported an example module from Sysrepo tests and adapted it
|
||||
to kea testing regime.";
|
||||
contact
|
||||
"kea-dev@lists.isc.org";
|
||||
|
||||
container container {
|
||||
config true;
|
||||
list list {
|
||||
leaf leaf {
|
||||
type string;
|
||||
}
|
||||
leaf key1 {
|
||||
type string;
|
||||
}
|
||||
leaf key2 {
|
||||
type string;
|
||||
}
|
||||
key "key1 key2";
|
||||
}
|
||||
}
|
||||
|
||||
typedef threshold-power-dBm {
|
||||
type union {
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
type enumeration {
|
||||
enum off {
|
||||
description "No threshold configured";
|
||||
}
|
||||
}
|
||||
}
|
||||
description "Power in dBm";
|
||||
}
|
||||
|
||||
container main {
|
||||
leaf enum {
|
||||
type enumeration {
|
||||
enum "yes" {
|
||||
value 1;
|
||||
}
|
||||
enum "no" {
|
||||
value 2;
|
||||
}
|
||||
enum "maybe" {
|
||||
value 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf options {
|
||||
type bits {
|
||||
bit strict;
|
||||
bit recursive;
|
||||
bit logging;
|
||||
}
|
||||
}
|
||||
leaf raw {
|
||||
type binary;
|
||||
}
|
||||
leaf dec64 {
|
||||
type decimal64{
|
||||
fraction-digits 2;
|
||||
}
|
||||
}
|
||||
leaf i8 {
|
||||
type int8;
|
||||
}
|
||||
leaf i16 {
|
||||
type int16;
|
||||
}
|
||||
leaf i32 {
|
||||
type int32;
|
||||
}
|
||||
leaf i64 {
|
||||
type int64;
|
||||
}
|
||||
leaf ui8 {
|
||||
type uint8;
|
||||
}
|
||||
leaf ui16 {
|
||||
type uint16;
|
||||
}
|
||||
leaf ui32 {
|
||||
type uint32;
|
||||
}
|
||||
leaf ui64 {
|
||||
type uint64;
|
||||
}
|
||||
leaf empty {
|
||||
type empty;
|
||||
}
|
||||
leaf boolean {
|
||||
type boolean;
|
||||
}
|
||||
leaf string {
|
||||
type string;
|
||||
}
|
||||
leaf id_ref {
|
||||
type identityref{
|
||||
base base_id;
|
||||
}
|
||||
}
|
||||
leaf-list numbers {
|
||||
type uint8;
|
||||
}
|
||||
leaf instance_id {
|
||||
type instance-identifier;
|
||||
}
|
||||
anyxml xml-data;
|
||||
anydata any-data;
|
||||
}
|
||||
|
||||
identity base_id;
|
||||
|
||||
identity id_1 {
|
||||
base base_id;
|
||||
}
|
||||
|
||||
identity id_2 {
|
||||
base base_id;
|
||||
}
|
||||
|
||||
list list {
|
||||
key "key";
|
||||
leaf key {
|
||||
type string;
|
||||
}
|
||||
leaf id_ref {
|
||||
type identityref{
|
||||
base base_id;
|
||||
}
|
||||
}
|
||||
leaf instance_id {
|
||||
type instance-identifier;
|
||||
}
|
||||
leaf union {
|
||||
type union{
|
||||
type uint8;
|
||||
type enumeration {
|
||||
enum "infinity";
|
||||
}
|
||||
}
|
||||
}
|
||||
container wireless{
|
||||
presence "wireless is enabled";
|
||||
leaf vendor_name{
|
||||
type string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container transfer {
|
||||
choice how {
|
||||
default interval;
|
||||
case interval {
|
||||
leaf interval {
|
||||
type uint16;
|
||||
default 30;
|
||||
units minutes;
|
||||
}
|
||||
}
|
||||
case daily {
|
||||
leaf daily {
|
||||
type empty;
|
||||
}
|
||||
leaf time-of-day {
|
||||
type string;
|
||||
units 24-hour-clock;
|
||||
default 1am;
|
||||
}
|
||||
}
|
||||
case manual {
|
||||
leaf manual {
|
||||
type empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container location {
|
||||
presence true;
|
||||
leaf name {
|
||||
type string;
|
||||
}
|
||||
|
||||
leaf longitude {
|
||||
type string;
|
||||
mandatory true;
|
||||
}
|
||||
|
||||
leaf latitude {
|
||||
type string;
|
||||
mandatory true;
|
||||
}
|
||||
}
|
||||
|
||||
leaf hexnumber{
|
||||
type string {
|
||||
length "0..4";
|
||||
pattern "[0-9a-fA-F]*";
|
||||
}
|
||||
}
|
||||
|
||||
container interface {
|
||||
leaf ifType {
|
||||
type enumeration {
|
||||
enum ethernet;
|
||||
enum atm;
|
||||
}
|
||||
}
|
||||
leaf ifMTU {
|
||||
type uint32;
|
||||
}
|
||||
must "ifType != 'ethernet' or " +
|
||||
"(ifType = 'ethernet' and ifMTU = 1500)" {
|
||||
error-message "An ethernet MTU must be 1500";
|
||||
}
|
||||
must "ifType != 'atm' or " +
|
||||
"(ifType = 'atm' and ifMTU <= 17966 and ifMTU >= 64)" {
|
||||
error-message "An atm MTU must be 64 .. 17966";
|
||||
}
|
||||
}
|
||||
|
||||
list user {
|
||||
description "This is a list of users in the system.";
|
||||
ordered-by user;
|
||||
config true;
|
||||
|
||||
key "name";
|
||||
|
||||
leaf name {
|
||||
type string;
|
||||
}
|
||||
leaf type {
|
||||
type string;
|
||||
}
|
||||
leaf full-name {
|
||||
type string;
|
||||
}
|
||||
}
|
||||
|
||||
leaf-list ordered-numbers {
|
||||
ordered-by user;
|
||||
type uint8;
|
||||
}
|
||||
|
||||
list with_def {
|
||||
config true;
|
||||
key "name";
|
||||
leaf name {
|
||||
type string;
|
||||
}
|
||||
leaf num {
|
||||
type int8;
|
||||
default 0;
|
||||
}
|
||||
}
|
||||
|
||||
rpc activate-software-image {
|
||||
input {
|
||||
leaf image-name {
|
||||
type string;
|
||||
must ". != /top-level-default";
|
||||
}
|
||||
leaf location {
|
||||
type string;
|
||||
default "/";
|
||||
must ". != 'invalid location'";
|
||||
}
|
||||
}
|
||||
output {
|
||||
leaf status {
|
||||
type string;
|
||||
must ". != 'invalid status'";
|
||||
}
|
||||
leaf version {
|
||||
type string;
|
||||
}
|
||||
leaf location {
|
||||
type string;
|
||||
default "/";
|
||||
}
|
||||
container init-log {
|
||||
list log-msg {
|
||||
key "msg time";
|
||||
leaf msg {
|
||||
type string;
|
||||
}
|
||||
leaf time {
|
||||
type uint32;
|
||||
}
|
||||
leaf msg-type {
|
||||
type enumeration {
|
||||
enum "error" {
|
||||
value 1;
|
||||
}
|
||||
enum "warning" {
|
||||
value 2;
|
||||
}
|
||||
enum "debug" {
|
||||
value 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leaf top-level-default {
|
||||
type string;
|
||||
default "default value";
|
||||
}
|
||||
|
||||
container university {
|
||||
container students {
|
||||
list student {
|
||||
ordered-by user;
|
||||
config true;
|
||||
|
||||
key "name";
|
||||
|
||||
leaf name {
|
||||
type string;
|
||||
}
|
||||
|
||||
leaf age {
|
||||
type uint8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container classes {
|
||||
list class {
|
||||
config true;
|
||||
|
||||
key "title";
|
||||
|
||||
leaf title {
|
||||
type string;
|
||||
}
|
||||
|
||||
list student {
|
||||
key "name";
|
||||
|
||||
leaf name {
|
||||
type leafref {
|
||||
path "../../../../students/student/name";
|
||||
}
|
||||
}
|
||||
leaf age {
|
||||
type leafref {
|
||||
path "../../../../students/student[name = current()/../name]/age";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container leafref-chain {
|
||||
leaf A {
|
||||
type leafref {
|
||||
path "../B";
|
||||
}
|
||||
}
|
||||
|
||||
leaf B {
|
||||
type leafref {
|
||||
path "../C";
|
||||
}
|
||||
}
|
||||
|
||||
leaf C {
|
||||
type leafref {
|
||||
path "../D";
|
||||
}
|
||||
}
|
||||
|
||||
leaf D {
|
||||
type string;
|
||||
}
|
||||
}
|
||||
|
||||
grouping link {
|
||||
container source {
|
||||
leaf address {
|
||||
type inet:ipv4-address;
|
||||
}
|
||||
leaf interface {
|
||||
type string;
|
||||
}
|
||||
}
|
||||
container destination {
|
||||
leaf address {
|
||||
type inet:ipv4-address;
|
||||
}
|
||||
leaf interface {
|
||||
type string;
|
||||
}
|
||||
}
|
||||
leaf MTU {
|
||||
type uint16;
|
||||
default 1500;
|
||||
}
|
||||
}
|
||||
|
||||
notification link-discovered {
|
||||
uses link;
|
||||
}
|
||||
|
||||
notification link-removed {
|
||||
uses link;
|
||||
}
|
||||
|
||||
container kernel-modules {
|
||||
list kernel-module {
|
||||
key "name";
|
||||
|
||||
leaf name {
|
||||
type string;
|
||||
}
|
||||
|
||||
leaf location {
|
||||
type string;
|
||||
default "/lib/modules";
|
||||
}
|
||||
|
||||
leaf loaded {
|
||||
type boolean;
|
||||
}
|
||||
|
||||
action load {
|
||||
input {
|
||||
leaf params {
|
||||
mandatory "true";
|
||||
type string;
|
||||
}
|
||||
leaf force {
|
||||
type boolean;
|
||||
default "false";
|
||||
when "../../loaded = 'false'";
|
||||
}
|
||||
leaf dry-run {
|
||||
type boolean;
|
||||
default false;
|
||||
}
|
||||
}
|
||||
output {
|
||||
leaf return-code {
|
||||
type uint8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action unload { }
|
||||
|
||||
action get-dependencies {
|
||||
output {
|
||||
leaf-list dependency {
|
||||
type string;
|
||||
}
|
||||
leaf location {
|
||||
type leafref {
|
||||
path "/kernel-modules/kernel-module[name = current()/../../name]/location";
|
||||
}
|
||||
}
|
||||
leaf location2 {
|
||||
type leafref {
|
||||
path "../../location";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
typedef uniontpdf {
|
||||
type union {
|
||||
type string {
|
||||
pattern "disabled";
|
||||
}
|
||||
type uint8 {
|
||||
range "1..100";
|
||||
}
|
||||
}
|
||||
default "disabled";
|
||||
}
|
||||
|
||||
typedef enumtpdf {
|
||||
type enumeration {
|
||||
enum "a" {
|
||||
value 1;
|
||||
}
|
||||
enum "b" {
|
||||
value 2;
|
||||
}
|
||||
enum "c" {
|
||||
value 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef multiplunions {
|
||||
type union {
|
||||
type uniontpdf;
|
||||
type enumtpdf;
|
||||
type union {
|
||||
type boolean;
|
||||
type decimal64 {
|
||||
fraction-digits 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef leafreftpdf {
|
||||
type leafref {
|
||||
path "/list/key";
|
||||
}
|
||||
}
|
||||
|
||||
typedef inttpdf {
|
||||
type uint8 {
|
||||
range "1..100";
|
||||
}
|
||||
}
|
||||
|
||||
container tpdfs {
|
||||
leaf unival {
|
||||
type uniontpdf;
|
||||
}
|
||||
|
||||
leaf leafrefval {
|
||||
type leafreftpdf;
|
||||
}
|
||||
|
||||
leaf intval {
|
||||
type inttpdf;
|
||||
}
|
||||
|
||||
leaf undecided {
|
||||
type multiplunions;
|
||||
}
|
||||
}
|
||||
|
||||
leaf dec64-in-union {
|
||||
type threshold-power-dBm;
|
||||
}
|
||||
|
||||
container presence-container {
|
||||
presence "presence-container";
|
||||
|
||||
leaf topleaf1 {
|
||||
type int8;
|
||||
}
|
||||
|
||||
leaf topleaf2 {
|
||||
type int8;
|
||||
}
|
||||
|
||||
container child1 {
|
||||
leaf child1-leaf {
|
||||
type int8;
|
||||
}
|
||||
|
||||
container grandchild1 {
|
||||
leaf grandchild1-leaf {
|
||||
type int8;
|
||||
default 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container child2 {
|
||||
leaf child2-leaf {
|
||||
type int8;
|
||||
}
|
||||
|
||||
container grandchild2 {
|
||||
leaf grandchild2-leaf1 {
|
||||
type int8;
|
||||
}
|
||||
leaf grandchild2-leaf2 {
|
||||
type int8;
|
||||
}
|
||||
leaf grandchild2-leaf3 {
|
||||
type int8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
src/lib/yang/tests/run_unittests.cc
Normal file
20
src/lib/yang/tests/run_unittests.cc
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright (C) 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 <gtest/gtest.h>
|
||||
#include <util/unittests/run_all.h>
|
||||
#include <log/logger_support.h>
|
||||
|
||||
int
|
||||
main(int argc, char* argv[]) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
isc::log::initLogger();
|
||||
|
||||
return (isc::util::unittests::run_all());
|
||||
}
|
731
src/lib/yang/tests/translator_unittests.cc
Normal file
731
src/lib/yang/tests/translator_unittests.cc
Normal file
@@ -0,0 +1,731 @@
|
||||
// Copyright (C) 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 <yang/translator.h>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace isc;
|
||||
using namespace isc::data;
|
||||
using namespace isc::yang;
|
||||
|
||||
namespace {
|
||||
|
||||
const std::string TEST_MODULE="keatest-module";
|
||||
|
||||
|
||||
/// @brief checks if specified schema is installed and available in sysrepo
|
||||
///
|
||||
/// @name name of the schema to be checked (without .yang)
|
||||
/// @verbose print installed schemas?
|
||||
/// @return true if installed, false otherwise.
|
||||
bool schemaInstalled(const std::string& name, bool verbose = false) {
|
||||
// Get a connection.
|
||||
S_Connection conn(new Connection("translator unittests"));
|
||||
// Get a session.
|
||||
S_Session sess(new Session(conn, SR_DS_CANDIDATE));
|
||||
|
||||
S_Yang_Schemas schemas = sess->list_schemas();
|
||||
|
||||
size_t schema_cnt = schemas->schema_cnt();
|
||||
|
||||
if (verbose) {
|
||||
cout << "There are " << schema_cnt << " YANG schema(s) installed:" << endl;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (int i = 0; i < schema_cnt; i++) {
|
||||
string installed_name(schemas->schema(i)->module_name());
|
||||
if (installed_name == name) {
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
std::cout << "Schema " << i << ": " << installed_name << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return (found);
|
||||
}
|
||||
|
||||
// This test verifies if the test schema is installed and accessible.
|
||||
TEST(TranslatorBasicTest, environmentCheck1) {
|
||||
|
||||
EXPECT_TRUE(schemaInstalled(TEST_MODULE))
|
||||
<< "\nERROR: Module used in unit-tests " << TEST_MODULE
|
||||
<< " is not installed. The environment is not suitable for\n"
|
||||
<< "ERROR: running unit-tests. Please locate " << TEST_MODULE <<".yang "
|
||||
<< "and issue the following command:\n"
|
||||
<< "ERROR: sysrepoctl --install --yang=" << TEST_MODULE << ".yang\n"
|
||||
<< "ERROR:\n"
|
||||
<< "ERROR: Following tests will most likely fail.\n";
|
||||
}
|
||||
|
||||
// Test constructor.
|
||||
TEST(TranslatorBasicTest, constructor) {
|
||||
// Get a connection.
|
||||
S_Connection conn(new Connection("translator unittests"));
|
||||
// Get a session.
|
||||
S_Session sess(new Session(conn, SR_DS_CANDIDATE));
|
||||
// Get a translator object.
|
||||
boost::scoped_ptr<TranslatorBasic> t_obj;
|
||||
EXPECT_NO_THROW(t_obj.reset(new TranslatorBasic(sess)));
|
||||
}
|
||||
|
||||
// Test basic yang value to JSON using the static method.
|
||||
TEST(TranslatorBasicTest, valueFrom) {
|
||||
S_Val s_val;
|
||||
ConstElementPtr elem;
|
||||
|
||||
// Null.
|
||||
EXPECT_THROW(TranslatorBasic::value(s_val), BadValue);
|
||||
|
||||
// No easy and direct way to build a container or a list...
|
||||
|
||||
// String.
|
||||
string str("foo");
|
||||
s_val.reset(new Val(str.c_str(), SR_STRING_T));
|
||||
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::string, elem->getType());
|
||||
EXPECT_EQ(str, elem->stringValue());
|
||||
elem.reset();
|
||||
|
||||
// Bool.
|
||||
s_val.reset(new Val(false, SR_BOOL_T));
|
||||
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::boolean, elem->getType());
|
||||
EXPECT_FALSE(elem->boolValue());
|
||||
elem.reset();
|
||||
|
||||
// Unsigned 8 bit integer.
|
||||
uint8_t u8(123);
|
||||
s_val.reset(new Val(u8, SR_UINT8_T));
|
||||
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::integer, elem->getType());
|
||||
EXPECT_EQ(u8, elem->intValue());
|
||||
elem.reset();
|
||||
|
||||
// Unsigned 16 bit integer.
|
||||
uint16_t u16(12345);
|
||||
s_val.reset(new Val(u16, SR_UINT16_T));
|
||||
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::integer, elem->getType());
|
||||
EXPECT_EQ(u16, elem->intValue());
|
||||
elem.reset();
|
||||
|
||||
// Unsigned 32 bit integer.
|
||||
uint32_t u32(123456789);
|
||||
s_val.reset(new Val(u32, SR_UINT32_T));
|
||||
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::integer, elem->getType());
|
||||
EXPECT_EQ(u32, elem->intValue());
|
||||
elem.reset();
|
||||
|
||||
// Signed 8 bit integer.
|
||||
int8_t s8(-123);
|
||||
s_val.reset(new Val(s8, SR_INT8_T));
|
||||
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::integer, elem->getType());
|
||||
EXPECT_EQ(s8, elem->intValue());
|
||||
elem.reset();
|
||||
|
||||
// Signed 16 bit integer.
|
||||
int16_t s16(-12345);
|
||||
s_val.reset(new Val(s16, SR_INT16_T));
|
||||
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::integer, elem->getType());
|
||||
EXPECT_EQ(s16, elem->intValue());
|
||||
elem.reset();
|
||||
|
||||
// Signed 32 bit integer.
|
||||
int32_t s32(-123456789);
|
||||
s_val.reset(new Val(s32, SR_INT32_T));
|
||||
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::integer, elem->getType());
|
||||
EXPECT_EQ(s32, elem->intValue());
|
||||
elem.reset();
|
||||
|
||||
// Identity reference.
|
||||
s_val.reset(new Val(str.c_str(), SR_IDENTITYREF_T));
|
||||
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::string, elem->getType());
|
||||
EXPECT_EQ(str, elem->stringValue());
|
||||
elem.reset();
|
||||
|
||||
// Enumeration item.
|
||||
s_val.reset(new Val(str.c_str(), SR_ENUM_T));
|
||||
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::string, elem->getType());
|
||||
EXPECT_EQ(str, elem->stringValue());
|
||||
elem.reset();
|
||||
|
||||
// Binary.
|
||||
string binary("Zm9vYmFy");
|
||||
s_val.reset(new Val(binary.c_str(), SR_BINARY_T));
|
||||
EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::string, elem->getType());
|
||||
EXPECT_EQ("foobar", elem->stringValue());
|
||||
elem.reset();
|
||||
|
||||
// Unknown / unsupported.
|
||||
double d64(.1234);
|
||||
s_val.reset(new Val(d64));
|
||||
EXPECT_THROW(TranslatorBasic::value(s_val), NotImplemented);
|
||||
}
|
||||
|
||||
// Test basic yang value to JSON using sysrepo test models.
|
||||
TEST(TranslatorBasicTest, getItem) {
|
||||
// Get a translator object to play with.
|
||||
S_Connection conn(new Connection("translator unittests"));
|
||||
S_Session sess(new Session(conn, SR_DS_CANDIDATE));
|
||||
boost::scoped_ptr<TranslatorBasic> t_obj;
|
||||
ASSERT_NO_THROW(t_obj.reset(new TranslatorBasic(sess)));
|
||||
|
||||
// Container.
|
||||
string xpath = "/keatest-module:container/list";
|
||||
S_Val s_val;
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
ConstElementPtr elem;
|
||||
EXPECT_NO_THROW(elem = t_obj->getItem("/keatest-module:container"));
|
||||
EXPECT_FALSE(elem);
|
||||
elem.reset();
|
||||
|
||||
// List.
|
||||
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::list, elem->getType());
|
||||
EXPECT_EQ(0, elem->size());
|
||||
elem.reset();
|
||||
|
||||
// String.
|
||||
xpath = "/keatest-module:main/string";
|
||||
s_val.reset(new Val("str", SR_STRING_T));
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::string, elem->getType());
|
||||
EXPECT_EQ("str", elem->stringValue());
|
||||
elem.reset();
|
||||
|
||||
// Bool.
|
||||
xpath = "/keatest-module:main/boolean";
|
||||
s_val.reset(new Val(true, SR_BOOL_T));
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::boolean, elem->getType());
|
||||
EXPECT_TRUE(elem->boolValue());
|
||||
elem.reset();
|
||||
|
||||
// Unsigned 8 bit integer.
|
||||
xpath = "/keatest-module:main/ui8";
|
||||
uint8_t u8(8);
|
||||
s_val.reset(new Val(u8, SR_UINT8_T));
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::integer, elem->getType());
|
||||
EXPECT_EQ(8, elem->intValue());
|
||||
elem.reset();
|
||||
|
||||
// Unsigned 16 bit integer.
|
||||
xpath = "/keatest-module:main/ui16";
|
||||
uint16_t u16(16);
|
||||
s_val.reset(new Val(u16, SR_UINT16_T));
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::integer, elem->getType());
|
||||
EXPECT_EQ(16, elem->intValue());
|
||||
elem.reset();
|
||||
|
||||
// Unsigned 32 bit integer.
|
||||
xpath = "/keatest-module:main/ui32";
|
||||
uint32_t u32(32);
|
||||
s_val.reset(new Val(u32, SR_UINT32_T));
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::integer, elem->getType());
|
||||
EXPECT_EQ(32, elem->intValue());
|
||||
elem.reset();
|
||||
|
||||
// Signed 8 bit integer.
|
||||
xpath = "/keatest-module:main/i8";
|
||||
int8_t s8(8);
|
||||
s_val.reset(new Val(s8, SR_INT8_T));
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::integer, elem->getType());
|
||||
EXPECT_EQ(8, elem->intValue());
|
||||
elem.reset();
|
||||
|
||||
// Signed 16 bit integer.
|
||||
xpath = "/keatest-module:main/i16";
|
||||
int16_t s16(16);
|
||||
s_val.reset(new Val(s16, SR_INT16_T));
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::integer, elem->getType());
|
||||
EXPECT_EQ(16, elem->intValue());
|
||||
elem.reset();
|
||||
|
||||
// Signed 32 bit integer.
|
||||
xpath = "/keatest-module:main/i32";
|
||||
int32_t s32(32);
|
||||
s_val.reset(new Val(s32, SR_INT32_T));
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::integer, elem->getType());
|
||||
EXPECT_EQ(32, elem->intValue());
|
||||
elem.reset();
|
||||
|
||||
// Identity reference.
|
||||
xpath = "/keatest-module:main/id_ref";
|
||||
s_val.reset(new Val("keatest-module:id_1", SR_IDENTITYREF_T));
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::string, elem->getType());
|
||||
EXPECT_EQ("keatest-module:id_1", elem->stringValue());
|
||||
elem.reset();
|
||||
|
||||
// Enumeration item.
|
||||
xpath = "/keatest-module:main/enum";
|
||||
s_val.reset(new Val("maybe", SR_ENUM_T));
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::string, elem->getType());
|
||||
EXPECT_EQ("maybe", elem->stringValue());
|
||||
elem.reset();
|
||||
|
||||
// Binary.
|
||||
xpath = "/keatest-module:main/raw";
|
||||
s_val.reset(new Val("Zm9vYmFy", SR_BINARY_T));
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::string, elem->getType());
|
||||
EXPECT_EQ("foobar", elem->stringValue());
|
||||
elem.reset();
|
||||
|
||||
// Leaf-list: not yet exist.
|
||||
xpath = "/keatest-module:main/numbers";
|
||||
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
|
||||
EXPECT_FALSE(elem);
|
||||
elem.reset();
|
||||
|
||||
// No easy way to create it empty.
|
||||
|
||||
// Leaf-list: 1, 2 and 3.
|
||||
u8 = 1;
|
||||
s_val.reset(new Val(u8, SR_UINT8_T));
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
u8 = 2;
|
||||
s_val.reset(new Val(u8, SR_UINT8_T));
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
u8 = 3;
|
||||
s_val.reset(new Val(u8, SR_UINT8_T));
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
EXPECT_NO_THROW(elem = t_obj->getItems(xpath));
|
||||
ASSERT_TRUE(elem);
|
||||
ASSERT_EQ(Element::list, elem->getType());
|
||||
EXPECT_EQ(3, elem->size());
|
||||
EXPECT_EQ("[ 1, 2, 3 ]", elem->str());
|
||||
elem.reset();
|
||||
|
||||
// Unknown / unsupported.
|
||||
xpath = "/keatest-module:main/dec64";
|
||||
s_val.reset(new Val(9.85));
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
EXPECT_THROW(elem = t_obj->getItem(xpath), NotImplemented);
|
||||
elem.reset();
|
||||
|
||||
// Not found.
|
||||
xpath = "/keatest-module:main/no_such_string";
|
||||
EXPECT_NO_THROW(sess->delete_item(xpath.c_str()));
|
||||
EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
|
||||
EXPECT_FALSE(elem);
|
||||
elem.reset();
|
||||
|
||||
// Check error.
|
||||
xpath = "null";
|
||||
try {
|
||||
elem = t_obj->getItem(xpath);
|
||||
ADD_FAILURE() << "expected exception";
|
||||
} catch (const SysrepoError& ex) {
|
||||
EXPECT_EQ("sysrepo error getting item at 'null': Invalid argument",
|
||||
string(ex.what()));
|
||||
} catch (const std::exception& ex) {
|
||||
ADD_FAILURE() << "unexpected exception with: " << ex.what();
|
||||
}
|
||||
}
|
||||
|
||||
// Test JSON to basic yang value using the static method.
|
||||
TEST(TranslatorBasicTest, valueTo) {
|
||||
|
||||
// Null.
|
||||
ConstElementPtr elem;
|
||||
EXPECT_THROW(TranslatorBasic::value(elem, SR_STRING_T), BadValue);
|
||||
|
||||
// Container.
|
||||
elem = Element::createMap();
|
||||
EXPECT_THROW(TranslatorBasic::value(elem, SR_CONTAINER_T), NotImplemented);
|
||||
EXPECT_THROW(TranslatorBasic::value(elem, SR_CONTAINER_PRESENCE_T), NotImplemented);
|
||||
|
||||
// List.
|
||||
elem = Element::createList();
|
||||
S_Val s_val;
|
||||
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_LIST_T));
|
||||
EXPECT_FALSE(s_val);
|
||||
s_val.reset();
|
||||
|
||||
// String.
|
||||
string str("foo");
|
||||
elem = Element::create(str);
|
||||
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_STRING_T));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_STRING_T, s_val->type());
|
||||
EXPECT_EQ(str, string(s_val->data()->get_string()));
|
||||
s_val.reset();
|
||||
|
||||
// Bool.
|
||||
elem = Element::create(false);
|
||||
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_BOOL_T));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_BOOL_T, s_val->type());
|
||||
EXPECT_FALSE(s_val->data()->get_bool());
|
||||
s_val.reset();
|
||||
|
||||
// Unsigned 8 bit integer.
|
||||
elem = Element::create(123);
|
||||
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_UINT8_T));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_UINT8_T, s_val->type());
|
||||
EXPECT_EQ(123, s_val->data()->get_uint8());
|
||||
elem.reset();
|
||||
|
||||
// Unsigned 16 bit integer.
|
||||
elem = Element::create(12345);
|
||||
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_UINT16_T));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_UINT16_T, s_val->type());
|
||||
EXPECT_EQ(12345, s_val->data()->get_uint16());
|
||||
elem.reset();
|
||||
|
||||
// Unsigned 32 bit integer.
|
||||
elem = Element::create(123456789);
|
||||
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_UINT32_T));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_UINT32_T, s_val->type());
|
||||
EXPECT_EQ(123456789, s_val->data()->get_uint32());
|
||||
elem.reset();
|
||||
|
||||
// Signed 8 bit integer.
|
||||
elem = Element::create(-123);
|
||||
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_INT8_T));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_INT8_T, s_val->type());
|
||||
EXPECT_EQ(-123, s_val->data()->get_int8());
|
||||
elem.reset();
|
||||
|
||||
// Signed 16 bit integer.
|
||||
elem = Element::create(-12345);
|
||||
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_INT16_T));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_INT16_T, s_val->type());
|
||||
EXPECT_EQ(-12345, s_val->data()->get_int16());
|
||||
elem.reset();
|
||||
|
||||
// Signed 32 bit integer.
|
||||
elem = Element::create(-123456789);
|
||||
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_INT32_T));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_INT32_T, s_val->type());
|
||||
EXPECT_EQ(-123456789, s_val->data()->get_int32());
|
||||
elem.reset();
|
||||
|
||||
// Identity reference.
|
||||
elem = Element::create(str);
|
||||
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_IDENTITYREF_T));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_IDENTITYREF_T, s_val->type());
|
||||
EXPECT_EQ(str, string(s_val->data()->get_identityref()));
|
||||
s_val.reset();
|
||||
|
||||
// Enumeration item.
|
||||
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_ENUM_T));
|
||||
ASSERT_TRUE(s_val);
|
||||
EXPECT_EQ(str, string(s_val->data()->get_enum()));
|
||||
s_val.reset();
|
||||
|
||||
// Binary.
|
||||
elem = Element::create(string("foobar"));
|
||||
EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_BINARY_T));
|
||||
ASSERT_TRUE(s_val);
|
||||
EXPECT_EQ("Zm9vYmFy", string(s_val->data()->get_binary()));
|
||||
s_val.reset();
|
||||
|
||||
// Unknown / unsupported.
|
||||
elem = Element::create(.1234);
|
||||
EXPECT_THROW(TranslatorBasic::value(elem, SR_DECIMAL64_T), NotImplemented);
|
||||
}
|
||||
|
||||
// Test JSON to basic yang value using sysrepo test models.
|
||||
TEST(TranslatorBasicTest, setItem) {
|
||||
// Get a translator object to play with.
|
||||
S_Connection conn(new Connection("translator unittests"));
|
||||
S_Session sess(new Session(conn, SR_DS_CANDIDATE));
|
||||
boost::scoped_ptr<TranslatorBasic> t_obj;
|
||||
ASSERT_NO_THROW(t_obj.reset(new TranslatorBasic(sess)));
|
||||
|
||||
// Container.
|
||||
string xpath = "/keatest-module:container";
|
||||
ConstElementPtr elem = Element::createMap();
|
||||
EXPECT_THROW(t_obj->setItem(xpath, elem, SR_CONTAINER_T), NotImplemented);
|
||||
EXPECT_THROW(t_obj->setItem(xpath, elem, SR_CONTAINER_PRESENCE_T),
|
||||
NotImplemented);
|
||||
|
||||
// List.
|
||||
xpath = "/keatest-module:container/list";
|
||||
elem = Element::createList();
|
||||
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_LIST_T));
|
||||
S_Val s_val;
|
||||
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_LIST_T, s_val->type());
|
||||
s_val.reset();
|
||||
|
||||
// String.
|
||||
xpath = "/keatest-module:main/string";
|
||||
elem = Element::create(string("str"));
|
||||
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_STRING_T));
|
||||
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_STRING_T, s_val->type());
|
||||
EXPECT_EQ("str", string(s_val->data()->get_string()));
|
||||
s_val.reset();
|
||||
|
||||
// Bool.
|
||||
xpath = "/keatest-module:main/boolean";
|
||||
elem = Element::create(true);
|
||||
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_BOOL_T));
|
||||
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_BOOL_T, s_val->type());
|
||||
EXPECT_TRUE(s_val->data()->get_bool());
|
||||
s_val.reset();
|
||||
|
||||
// Unsigned 8 bit integer.
|
||||
xpath = "/keatest-module:main/ui8";
|
||||
elem = Element::create(8);
|
||||
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT8_T));
|
||||
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_UINT8_T, s_val->type());
|
||||
EXPECT_EQ(8, s_val->data()->get_uint8());
|
||||
s_val.reset();
|
||||
|
||||
// Unsigned 16 bit integer.
|
||||
xpath = "/keatest-module:main/ui16";
|
||||
elem = Element::create(16);
|
||||
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT16_T));
|
||||
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_UINT16_T, s_val->type());
|
||||
EXPECT_EQ(16, s_val->data()->get_uint16());
|
||||
s_val.reset();
|
||||
|
||||
// Unsigned 32 bit integer.
|
||||
xpath = "/keatest-module:main/ui32";
|
||||
elem = Element::create(32);
|
||||
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT32_T));
|
||||
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_UINT32_T, s_val->type());
|
||||
EXPECT_EQ(32, s_val->data()->get_uint32());
|
||||
s_val.reset();
|
||||
|
||||
// Signed 8 bit integer.
|
||||
xpath = "/keatest-module:main/i8";
|
||||
elem = Element::create(8);
|
||||
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_INT8_T));
|
||||
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_INT8_T, s_val->type());
|
||||
EXPECT_EQ(8, s_val->data()->get_int8());
|
||||
s_val.reset();
|
||||
|
||||
// Signed 16 bit integer.
|
||||
xpath = "/keatest-module:main/i16";
|
||||
elem = Element::create(16);
|
||||
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_INT16_T));
|
||||
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_INT16_T, s_val->type());
|
||||
EXPECT_EQ(16, s_val->data()->get_int16());
|
||||
s_val.reset();
|
||||
|
||||
// Signed 32 bit integer.
|
||||
xpath = "/keatest-module:main/i32";
|
||||
elem = Element::create(32);
|
||||
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_INT32_T));
|
||||
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_INT32_T, s_val->type());
|
||||
EXPECT_EQ(32, s_val->data()->get_int32());
|
||||
s_val.reset();
|
||||
|
||||
// Identity reference.
|
||||
xpath = "/keatest-module:main/id_ref";
|
||||
elem = Element::create(string("keatest-module:id_1"));
|
||||
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_IDENTITYREF_T));
|
||||
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_IDENTITYREF_T, s_val->type());
|
||||
EXPECT_EQ("keatest-module:id_1", string(s_val->data()->get_identityref()));
|
||||
s_val.reset();
|
||||
|
||||
// Enumeration item.
|
||||
xpath = "/keatest-module:main/enum";
|
||||
elem = Element::create(string("maybe"));
|
||||
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_ENUM_T));
|
||||
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_ENUM_T, s_val->type());
|
||||
EXPECT_EQ("maybe", string(s_val->data()->get_enum()));
|
||||
s_val.reset();
|
||||
|
||||
// Binary.
|
||||
xpath = "/keatest-module:main/raw";
|
||||
elem = Element::create(string("foobar"));
|
||||
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_BINARY_T));
|
||||
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
|
||||
ASSERT_TRUE(s_val);
|
||||
ASSERT_EQ(SR_BINARY_T, s_val->type());
|
||||
EXPECT_EQ("Zm9vYmFy", string(s_val->data()->get_binary()));
|
||||
s_val.reset();
|
||||
|
||||
// Leaf-list.
|
||||
xpath = "/keatest-module:main/numbers";
|
||||
S_Vals s_vals;
|
||||
EXPECT_NO_THROW(s_vals = sess->get_items(xpath.c_str()));
|
||||
EXPECT_FALSE(s_vals);
|
||||
s_vals.reset();
|
||||
|
||||
// Fill it.
|
||||
elem = Element::create(1);
|
||||
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT8_T));
|
||||
elem = Element::create(2);
|
||||
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT8_T));
|
||||
elem = Element::create(3);
|
||||
EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT8_T));
|
||||
EXPECT_NO_THROW(s_vals = sess->get_items(xpath.c_str()));
|
||||
ASSERT_TRUE(s_vals);
|
||||
EXPECT_EQ(3, s_vals->val_cnt());
|
||||
s_vals.reset();
|
||||
|
||||
// Clean it.
|
||||
EXPECT_NO_THROW(t_obj->delItem(xpath));
|
||||
EXPECT_NO_THROW(s_vals = sess->get_items(xpath.c_str()));
|
||||
EXPECT_FALSE(s_vals);
|
||||
s_vals.reset();
|
||||
|
||||
// Unknown / unsupported.
|
||||
xpath = "/keatest-module:main/dec64";
|
||||
elem = Element::create(9.85);
|
||||
EXPECT_THROW(t_obj->setItem(xpath, elem, SR_DECIMAL64_T), NotImplemented);
|
||||
|
||||
// Bad xpath.
|
||||
xpath = "/keatest-module:main/no_such_string";
|
||||
elem = Element::create(string("str"));
|
||||
try {
|
||||
t_obj->setItem(xpath, elem, SR_STRING_T);
|
||||
ADD_FAILURE() << "expected exception";
|
||||
} catch (const SysrepoError& ex) {
|
||||
string expected = "sysrepo error setting item '\"str\"' at '" +
|
||||
xpath + "': Request contains unknown element";
|
||||
EXPECT_EQ(expected, string(ex.what()));
|
||||
} catch (const std::exception& ex) {
|
||||
ADD_FAILURE() << "unexpected exception with: " << ex.what();
|
||||
}
|
||||
|
||||
// Bad type.
|
||||
xpath = "/keatest-module:main/string";
|
||||
elem = Element::create(true);
|
||||
try {
|
||||
t_obj->setItem(xpath, elem, SR_BOOL_T);
|
||||
ADD_FAILURE() << "expected exception";
|
||||
} catch (const SysrepoError& ex) {
|
||||
string expected = "sysrepo error setting item 'true' at '" +
|
||||
xpath + "': Invalid argument";
|
||||
EXPECT_EQ(expected, string(ex.what()));
|
||||
} catch (const std::exception& ex) {
|
||||
ADD_FAILURE() << "unexpected exception with: " << ex.what();
|
||||
}
|
||||
|
||||
// Delete (twice).
|
||||
xpath = "/keatest-module:main/string";
|
||||
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
|
||||
EXPECT_TRUE(s_val);
|
||||
s_val.reset();
|
||||
EXPECT_NO_THROW(t_obj->delItem(xpath));
|
||||
EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
|
||||
EXPECT_FALSE(s_val);
|
||||
EXPECT_NO_THROW(t_obj->delItem(xpath));
|
||||
}
|
||||
|
||||
// Test yang list iteration.
|
||||
TEST(TranslatorBasicTest, list) {
|
||||
// Get a translator object to play with.
|
||||
S_Connection conn(new Connection("translator unittests"));
|
||||
S_Session sess(new Session(conn, SR_DS_CANDIDATE));
|
||||
boost::scoped_ptr<TranslatorBasic> t_obj;
|
||||
ASSERT_NO_THROW(t_obj.reset(new TranslatorBasic(sess)));
|
||||
|
||||
// Empty list.
|
||||
S_Iter_Value iter;
|
||||
EXPECT_NO_THROW(iter = t_obj->getIter("/keatest-module:container/list"));
|
||||
ASSERT_TRUE(iter);
|
||||
string xpath;
|
||||
EXPECT_NO_THROW(xpath = t_obj->getNext(iter));
|
||||
EXPECT_TRUE(xpath.empty());
|
||||
|
||||
// Retried with a filled list.
|
||||
xpath = "/keatest-module:container/list[key1='key1'][key2='key2']/leaf";
|
||||
S_Val s_val(new Val("Leaf value"));
|
||||
EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
|
||||
EXPECT_NO_THROW(iter = t_obj->getIter("/keatest-module:container/list"));
|
||||
ASSERT_TRUE(iter);
|
||||
EXPECT_NO_THROW(xpath = t_obj->getNext(iter));
|
||||
EXPECT_EQ("/keatest-module:container/list[key1='key1'][key2='key2']", xpath);
|
||||
EXPECT_NO_THROW(xpath = t_obj->getNext(iter));
|
||||
EXPECT_TRUE(xpath.empty());
|
||||
|
||||
// Not found: same than empty because sr_get_items_iter() translates
|
||||
// SR_ERR_NOT_FOUND by SR_ERR_OK...
|
||||
}
|
||||
|
||||
}; // end of anonymous namespace
|
295
src/lib/yang/translator.cc
Normal file
295
src/lib/yang/translator.cc
Normal file
@@ -0,0 +1,295 @@
|
||||
// Copyright (C) 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 <yang/translator.h>
|
||||
#include <util/encode/base64.h>
|
||||
#include <cstring>
|
||||
|
||||
using namespace std;
|
||||
using namespace isc::data;
|
||||
using namespace isc::util::encode;
|
||||
|
||||
namespace {
|
||||
|
||||
string encode64(const string& input) {
|
||||
vector<uint8_t> binary;
|
||||
binary.resize(input.size());
|
||||
memmove(&binary[0], input.c_str(), binary.size());
|
||||
return (encodeBase64(binary));
|
||||
}
|
||||
|
||||
string decode64(const string& input) {
|
||||
vector<uint8_t> binary;
|
||||
decodeBase64(input, binary);
|
||||
string result;
|
||||
result.resize(binary.size());
|
||||
memmove(&result[0], &binary[0], result.size());
|
||||
return (result);
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
namespace isc {
|
||||
namespace yang {
|
||||
|
||||
TranslatorBasic::TranslatorBasic(S_Session session) : session_(session) {
|
||||
}
|
||||
|
||||
TranslatorBasic::~TranslatorBasic() {
|
||||
}
|
||||
|
||||
ElementPtr
|
||||
TranslatorBasic::value(S_Val s_val) {
|
||||
if (!s_val) {
|
||||
isc_throw(BadValue, "value called with null");
|
||||
}
|
||||
switch (s_val->type()) {
|
||||
case SR_CONTAINER_T:
|
||||
case SR_CONTAINER_PRESENCE_T:
|
||||
// Internal node.
|
||||
return (ElementPtr());
|
||||
|
||||
case SR_LIST_T:
|
||||
return (Element::createList());
|
||||
|
||||
case SR_STRING_T:
|
||||
return (Element::create(string(s_val->data()->get_string())));
|
||||
|
||||
case SR_BOOL_T:
|
||||
return (Element::create(s_val->data()->get_bool() ? true : false));
|
||||
|
||||
case SR_UINT8_T:
|
||||
return (Element::create(static_cast<long long>(s_val->data()->get_uint8())));
|
||||
|
||||
case SR_UINT16_T:
|
||||
return (Element::create(static_cast<long long>(s_val->data()->get_uint16())));
|
||||
|
||||
case SR_UINT32_T:
|
||||
return (Element::create(static_cast<long long>(s_val->data()->get_uint32())));
|
||||
|
||||
case SR_INT8_T:
|
||||
return (Element::create(static_cast<long long>(s_val->data()->get_int8())));
|
||||
|
||||
case SR_INT16_T:
|
||||
return (Element::create(static_cast<long long>(s_val->data()->get_int16())));
|
||||
|
||||
case SR_INT32_T:
|
||||
return (Element::create(static_cast<long long>(s_val->data()->get_int32())));
|
||||
|
||||
case SR_IDENTITYREF_T:
|
||||
return (Element::create(string(s_val->data()->get_identityref())));
|
||||
|
||||
case SR_ENUM_T:
|
||||
return (Element::create(string(s_val->data()->get_enum())));
|
||||
|
||||
case SR_BINARY_T:
|
||||
return (Element::create(decode64(s_val->data()->get_binary())));
|
||||
|
||||
default:
|
||||
isc_throw(NotImplemented,
|
||||
"value called with unupported type: " << s_val->type());
|
||||
}
|
||||
}
|
||||
|
||||
ElementPtr
|
||||
TranslatorBasic::getItem(const string& xpath) {
|
||||
S_Val s_val;
|
||||
try {
|
||||
s_val = session_->get_item(xpath.c_str());
|
||||
} catch (const sysrepo_exception& ex) {
|
||||
isc_throw(SysrepoError, "sysrepo error getting item at '" << xpath
|
||||
<< "': " << ex.what());
|
||||
}
|
||||
if (!s_val) {
|
||||
return (ElementPtr());
|
||||
}
|
||||
return (value(s_val));
|
||||
}
|
||||
|
||||
ElementPtr
|
||||
TranslatorBasic::getItems(const string& xpath) {
|
||||
S_Vals s_vals;
|
||||
try {
|
||||
s_vals = session_->get_items(xpath.c_str());
|
||||
if (!s_vals) {
|
||||
return (ElementPtr());
|
||||
}
|
||||
ElementPtr result = Element::createList();
|
||||
for (size_t i = 0; i < s_vals->val_cnt(); ++i) {
|
||||
S_Val s_val = s_vals->val(i);
|
||||
result->add(value(s_val));
|
||||
}
|
||||
return (result);
|
||||
} catch (const sysrepo_exception& ex) {
|
||||
isc_throw(SysrepoError,
|
||||
"sysrepo error getting item at '" << xpath
|
||||
<< "': " << ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
S_Val
|
||||
TranslatorBasic::value(ConstElementPtr elem, sr_type_t type) {
|
||||
if (!elem) {
|
||||
isc_throw(BadValue, "value called with null");
|
||||
}
|
||||
S_Val s_val;
|
||||
switch (type) {
|
||||
case SR_CONTAINER_T:
|
||||
case SR_CONTAINER_PRESENCE_T:
|
||||
isc_throw(NotImplemented, "value called for a container");
|
||||
|
||||
case SR_LIST_T:
|
||||
if (elem->getType() != Element::list) {
|
||||
isc_throw(BadValue, "value for a list called with not a list: "
|
||||
<< elem->str());
|
||||
}
|
||||
// Return null.
|
||||
break;
|
||||
|
||||
case SR_STRING_T:
|
||||
case SR_IDENTITYREF_T:
|
||||
case SR_ENUM_T:
|
||||
if (elem->getType() != Element::string) {
|
||||
isc_throw(BadValue,
|
||||
"value for a string called with not a string: "
|
||||
<< elem->str());
|
||||
}
|
||||
s_val.reset(new Val(elem->stringValue().c_str(), type));
|
||||
break;
|
||||
|
||||
case SR_BOOL_T:
|
||||
if (elem->getType() != Element::boolean) {
|
||||
isc_throw(BadValue,
|
||||
"value for a boolean called with not a boolean: "
|
||||
<< elem->str());
|
||||
}
|
||||
s_val.reset(new Val(elem->boolValue(), type));
|
||||
break;
|
||||
|
||||
case SR_UINT8_T:
|
||||
if (elem->getType() != Element::integer) {
|
||||
isc_throw(BadValue,
|
||||
"value for an integer called with not an integer: "
|
||||
<< elem->str());
|
||||
}
|
||||
s_val.reset(new Val(static_cast<uint8_t>(elem->intValue()), type));
|
||||
break;
|
||||
|
||||
case SR_UINT16_T:
|
||||
if (elem->getType() != Element::integer) {
|
||||
isc_throw(BadValue,
|
||||
"value for an integer called with not an integer: "
|
||||
<< elem->str());
|
||||
}
|
||||
s_val.reset(new Val(static_cast<uint16_t>(elem->intValue()), type));
|
||||
break;
|
||||
|
||||
case SR_UINT32_T:
|
||||
if (elem->getType() != Element::integer) {
|
||||
isc_throw(BadValue,
|
||||
"value for an integer called with not an integer: "
|
||||
<< elem->str());
|
||||
}
|
||||
s_val.reset(new Val(static_cast<uint32_t>(elem->intValue()), type));
|
||||
break;
|
||||
|
||||
case SR_INT8_T:
|
||||
if (elem->getType() != Element::integer) {
|
||||
isc_throw(BadValue,
|
||||
"value for an integer called with not an integer: "
|
||||
<< elem->str());
|
||||
}
|
||||
s_val.reset(new Val(static_cast<int8_t>(elem->intValue()), type));
|
||||
break;
|
||||
|
||||
case SR_INT16_T:
|
||||
if (elem->getType() != Element::integer) {
|
||||
isc_throw(BadValue,
|
||||
"value for an integer called with not an integer: "
|
||||
<< elem->str());
|
||||
}
|
||||
s_val.reset(new Val(static_cast<int16_t>(elem->intValue()), type));
|
||||
break;
|
||||
|
||||
case SR_INT32_T:
|
||||
if (elem->getType() != Element::integer) {
|
||||
isc_throw(BadValue,
|
||||
"value for an integer called with not an integer: "
|
||||
<< elem->str());
|
||||
}
|
||||
s_val.reset(new Val(static_cast<int32_t>(elem->intValue()), type));
|
||||
break;
|
||||
|
||||
case SR_BINARY_T:
|
||||
if (elem->getType() != Element::string) {
|
||||
isc_throw(BadValue,
|
||||
"value for a base64 called with not a string: "
|
||||
<< elem->str());
|
||||
}
|
||||
s_val.reset(new Val(encode64(elem->stringValue()).c_str(), type));
|
||||
break;
|
||||
|
||||
default:
|
||||
isc_throw(NotImplemented,
|
||||
"value called with unupported type: " << type);
|
||||
}
|
||||
|
||||
return (s_val);
|
||||
}
|
||||
|
||||
void
|
||||
TranslatorBasic::setItem(const string& xpath, ConstElementPtr elem,
|
||||
sr_type_t type) {
|
||||
S_Val s_val = value(elem, type);
|
||||
if (!s_val && (type != SR_LIST_T)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
session_->set_item(xpath.c_str(), s_val);
|
||||
} catch (const sysrepo_exception& ex) {
|
||||
isc_throw(SysrepoError,
|
||||
"sysrepo error setting item '" << elem->str()
|
||||
<< "' at '" << xpath << "': " << ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TranslatorBasic::delItem(const std::string& xpath) {
|
||||
try {
|
||||
session_->delete_item(xpath.c_str());
|
||||
} catch (const sysrepo_exception& ex) {
|
||||
isc_throw(SysrepoError,
|
||||
"sysrepo error deleting item at '"
|
||||
<< xpath << "': " << ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
S_Iter_Value
|
||||
TranslatorBasic::getIter(const std::string& xpath) {
|
||||
return (session_->get_items_iter(xpath.c_str()));
|
||||
}
|
||||
|
||||
string
|
||||
TranslatorBasic::getNext(S_Iter_Value iter) {
|
||||
if (!iter) {
|
||||
isc_throw(BadValue, "getNext called with null");
|
||||
}
|
||||
S_Val s_val;
|
||||
try {
|
||||
s_val = session_->get_item_next(iter);
|
||||
} catch (const sysrepo_exception&) {
|
||||
// Should not happen according to the doc but still happen?
|
||||
return ("");
|
||||
}
|
||||
if (!s_val) {
|
||||
return ("");
|
||||
}
|
||||
return (s_val->xpath());
|
||||
}
|
||||
|
||||
}; // end of namespace isc::yang
|
||||
}; // end of namespace isc
|
100
src/lib/yang/translator.h
Normal file
100
src/lib/yang/translator.h
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright (C) 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/.
|
||||
|
||||
#ifndef ISC_TRANSLATOR_H
|
||||
#define ISC_TRANSLATOR_H 1
|
||||
|
||||
#include <cc/data.h>
|
||||
#include <yang/sysrepo_error.h>
|
||||
|
||||
#include <sysrepo-cpp/Session.h>
|
||||
|
||||
namespace isc {
|
||||
namespace yang {
|
||||
|
||||
/// @brief Between Yang and JSON translator class for basic values.
|
||||
class TranslatorBasic {
|
||||
public:
|
||||
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// @param session Sysrepo session.
|
||||
TranslatorBasic(S_Session session);
|
||||
|
||||
/// @brief Destructor.
|
||||
virtual ~TranslatorBasic();
|
||||
|
||||
/// @brief Translate basic value from Yang to JSON.
|
||||
///
|
||||
/// @note Please don't use this outside tests.
|
||||
///
|
||||
/// @param s_val The value.
|
||||
/// @return The Element representing the sysrepo value.
|
||||
/// @throw NotImplemented when the value type is not supported.
|
||||
static isc::data::ElementPtr value(S_Val s_val);
|
||||
|
||||
/// @brief Get and translate basic value from Yang to JSON.
|
||||
///
|
||||
/// @note Should be const as it is read only...
|
||||
///
|
||||
/// @param xpath The xpath of the basic value.
|
||||
/// @return The Element representing the item at xpath or null
|
||||
/// when not found.
|
||||
/// @throw SysrepoError when sysrepo raises an error.
|
||||
/// @throw NotImplemented when the value type is not supported.
|
||||
isc::data::ElementPtr getItem(const std::string& xpath);
|
||||
|
||||
/// @brief Get and translate a list of basic values from Yang to JSON.
|
||||
///
|
||||
/// @param xpath The xpath of the list of basic values.
|
||||
/// @return The ListElement representing the leaf-list at xpath or
|
||||
/// null when not found.
|
||||
isc::data::ElementPtr getItems(const std::string& xpath);
|
||||
|
||||
/// @brief Translate basic value from JSON to Yang.
|
||||
///
|
||||
/// @note Please don't use this outside tests.
|
||||
///
|
||||
/// @param elem The JSON element.
|
||||
/// @param type The sysrepo type.
|
||||
static S_Val value(isc::data::ConstElementPtr elem, sr_type_t type);
|
||||
|
||||
/// @brief Translate and set basic value from JSON to Yang.
|
||||
///
|
||||
/// @param xpath The xpath of the basic value.
|
||||
/// @param elem The JSON element.
|
||||
/// @param type The sysrepo type.
|
||||
void setItem(const std::string& xpath, isc::data::ConstElementPtr elem,
|
||||
sr_type_t type);
|
||||
|
||||
/// @brief Delete basic value from Yang.
|
||||
///
|
||||
/// @param xpath The xpath of the basic value.
|
||||
void delItem(const std::string& xpath);
|
||||
|
||||
/// List iterator methods keeping the session private.
|
||||
|
||||
/// @brief Get iterator over a Yang list.
|
||||
///
|
||||
/// @param xpath The xpath of the list.
|
||||
/// @return An S_Iter_Value pointer. Null is the list does not exist.
|
||||
S_Iter_Value getIter(const std::string& xpath);
|
||||
|
||||
/// @brief Get xpath of the next Yang list item.
|
||||
///
|
||||
/// @param iter The iterator pointing to the previous element
|
||||
/// @return The xpath of the next element. Empty string when at the end of the list.
|
||||
std::string getNext(S_Iter_Value iter);
|
||||
|
||||
protected:
|
||||
/// @brief The sysrepo session.
|
||||
S_Session session_;
|
||||
};
|
||||
|
||||
}; // end of namespace isc::yang
|
||||
}; // end of namespace isc
|
||||
|
||||
#endif // ISC_TRANSLATOR_H
|
102
src/lib/yang/yang.dox
Normal file
102
src/lib/yang/yang.dox
Normal file
@@ -0,0 +1,102 @@
|
||||
// Copyright (C) 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/.
|
||||
|
||||
/**
|
||||
@page libyang libkea-yang - Kea Yang Utilities Library
|
||||
|
||||
The libkea-yang library was developed to handle base YANG operations,
|
||||
such are retrieving YANG schema and configuration and translating
|
||||
data between YANG syntax and JSON that is understandable by Kea.
|
||||
|
||||
@section yangTranslator Translator between Yang and JSON
|
||||
|
||||
An essential concept is the idea of translator. It is a primitive that is able
|
||||
to convert certain data structure between YANG and JSON. It is envisaged
|
||||
that more complex translators will use other translators to handle more
|
||||
complex data structures. For details, see @ref isc::yang::TranslatorBasic.
|
||||
|
||||
Note that although the initial focus is on translation from YANG to JSON (so
|
||||
Kea can retrieve its configuration), the opposite translation direction -
|
||||
from JSON to YANG - is also very useful, for at least two reasons. First,
|
||||
in many cases we can use it in tests to check that conversion back and forth
|
||||
doesn't lose anything: yang = toYang(toJson(yang)). Second, YANG models
|
||||
cover two major types of data: configuration and run-time state. While
|
||||
we're initially focusing on getting the configuration, the run-time state
|
||||
is something that Kea is expected to provide. Kea uses JSON internally in many
|
||||
places and that data will have to be exported in YANG format.
|
||||
|
||||
All translators take a Session pointer (a structure provided by Sysrepo that
|
||||
is responsible for maintaining a connection) in constructors and derive from
|
||||
the basic / base class and recursively of translators for embedded parts.
|
||||
|
||||
@c isc::yang::TranslatorBasic provides some methods:
|
||||
- getItem() gets and translates basic value from Yang to JSON
|
||||
- getItems() gets and translates a leaf-list from Yang to JSON
|
||||
(for a list please use an iterator)
|
||||
- setItem() translates and sets a basic value from JSON to Yang
|
||||
- delItem() deletes a value
|
||||
- getIter() gets an iterator over a Yang list
|
||||
- getNext() returns the xpath of the next item
|
||||
|
||||
@section yangTranslatorPool Pool translator
|
||||
|
||||
@c isc::yang::TranslatorPool is the standard example of a translator
|
||||
for a structured value. Its constructor takes a model name: the code
|
||||
implements some variants to accommodate the model with shared code
|
||||
moved into a common private routine.
|
||||
|
||||
@c isc::yang::TranslatorPools deals with a list of pools. The getPools
|
||||
method iterates over the list in both ways. Look at examples in unit
|
||||
tests to understand how can be filled.
|
||||
|
||||
Note pools show two shortcomings in IETF models:
|
||||
- option sets make to track changes nearly impossible: the only easy
|
||||
code is to translate the whole configuration.
|
||||
- prefix and start - end forms of pool ranges are both mandatory.
|
||||
|
||||
@section yangTranslatorSubnet Subnet translator
|
||||
|
||||
The new thing here is the use of adaptors to move timers from subnets
|
||||
to pools and back.
|
||||
|
||||
@section yangAdaptor Adapting JSON configuration
|
||||
|
||||
Adaptors are tools which adapts JSON complete or partial configuration
|
||||
before translation to Yang to ease this translation or after translation
|
||||
from Yang to follow the Kea syntax, for instance by adding static
|
||||
components which are not in the model.
|
||||
|
||||
Methods provided by adaptors are class methods (i.e. declared static).
|
||||
Specific adaptors are derived from the isc::yang::Adaptor base class.
|
||||
|
||||
@page unitTestsSysrepo Running unit-tests with Sysrepo
|
||||
|
||||
To run YANG/NETCONF/Sysrepo tests you obviously need to compile Kea with
|
||||
Sysrepo support:
|
||||
|
||||
@verbatim
|
||||
./configure --with-sysrepo
|
||||
@endverbatim
|
||||
|
||||
For details, see Section 20 "YANG/NETCONF support" in the Kea User's Guide.
|
||||
|
||||
You also need to install YANG schemas, so the unit-tests are able to
|
||||
retrieve, add, update and generally interact with the sysrepo information.
|
||||
There are several production Kea models (src/lib/yang/models) and one test
|
||||
specific model (src/lib/yang/tests/keatest-module.yang).
|
||||
|
||||
To install the test module, issue the following command:
|
||||
|
||||
@verbatim
|
||||
sudo sysrepoctl --install --yang=src/lib/yang/tests/keatest-module.yang
|
||||
@endverbatim
|
||||
|
||||
To verify that you have the schemas installed, do this:
|
||||
@verbatim
|
||||
sysrepoctl -l
|
||||
@endverbatim
|
||||
Make sure that keatest-module is on the list.
|
||||
*/
|
@@ -765,8 +765,521 @@ CREATE TABLE logs (
|
||||
CREATE INDEX timestamp_index ON logs (timestamp);
|
||||
|
||||
#add auth key for reconfiguration
|
||||
ALTER TABLE hosts
|
||||
ADD COLUMN auth_key VARCHAR(16) NULL;
|
||||
ALTER TABLE hosts
|
||||
ADD COLUMN auth_key VARCHAR(16) NULL;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `modification`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS modification (
|
||||
id TINYINT(3) NOT NULL,
|
||||
modification_type VARCHAR(32) NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO modification(id, modification_type)
|
||||
VALUES(0, "create");
|
||||
|
||||
INSERT INTO modification(id, modification_type)
|
||||
VALUES(1, "update");
|
||||
|
||||
INSERT INTO modification(id, modification_type)
|
||||
VALUES(2, "delete");
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp4_server`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_server (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
tag VARCHAR(256) NOT NULL,
|
||||
description TEXT,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY dhcp4_server_tag_UNIQUE (tag),
|
||||
KEY key_dhcp4_server_modification_ts (modification_ts)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp4_audit`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_audit (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
object_type VARCHAR(256) NOT NULL,
|
||||
object_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_type TINYINT(1) NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
log_message TEXT,
|
||||
PRIMARY KEY (id),
|
||||
KEY key_dhcp4_audit_by_modification_ts (modification_ts),
|
||||
KEY fk_dhcp4_audit_modification_type (modification_type),
|
||||
CONSTRAINT fk_dhcp4_audit_modification_type FOREIGN KEY (modification_type)
|
||||
REFERENCES modification (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp4_global_parameter`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_global_parameter (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
value LONGTEXT NOT NULL,
|
||||
modification_ts timestamp NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY key_dhcp4_global_parameter_modification_ts (modification_ts),
|
||||
KEY key_dhcp4_global_parameter_name (name)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp4_global_parameter_server`
|
||||
-- M-to-M cross-reference between global parameters and
|
||||
-- servers
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_global_parameter_server (
|
||||
parameter_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (parameter_id, server_id),
|
||||
KEY fk_dhcp4_global_parameter_server_server_id (server_id),
|
||||
KEY key_dhcp4_global_parameter_server (modification_ts),
|
||||
CONSTRAINT fk_dhcp4_global_parameter_server_parameter_id FOREIGN KEY (parameter_id)
|
||||
REFERENCES dhcp4_global_parameter (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp4_global_parameter_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp4_server (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp4_option_def`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_option_def (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
code TINYINT(3) UNSIGNED NOT NULL,
|
||||
space VARCHAR(128) NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
array TINYINT(1) NOT NULL,
|
||||
encapsulate VARCHAR(128) NOT NULL,
|
||||
record_types VARCHAR(512) DEFAULT NULL,
|
||||
user_context LONGTEXT,
|
||||
PRIMARY KEY (id),
|
||||
KEY key_dhcp4_option_def_modification_ts (modification_ts),
|
||||
KEY key_dhcp4_option_def_code_space (code, space)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp4_option_def_server`
|
||||
-- M-to-M cross-reference between option definitions and
|
||||
-- servers
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_option_def_server (
|
||||
option_def_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (option_def_id, server_id),
|
||||
KEY fk_dhcp4_option_def_server_server_id_idx (server_id),
|
||||
KEY key_dhcp4_option_def_server_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp4_option_def_server_option_def_id FOREIGN KEY (option_def_id)
|
||||
REFERENCES dhcp4_option_def (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp4_option_def_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp4_server (id) ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp4_shared_network`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_shared_network (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
client_class VARCHAR(128) DEFAULT NULL,
|
||||
interface VARCHAR(128) DEFAULT NULL,
|
||||
match_client_id TINYINT(1) NOT NULL DEFAULT '1',
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
rebind_timer INT(10) DEFAULT NULL,
|
||||
relay LONGTEXT,
|
||||
renew_timer INT(10) DEFAULT NULL,
|
||||
require_client_classes LONGTEXT DEFAULT NULL,
|
||||
reservation_mode TINYINT(3) NOT NULL DEFAULT '3',
|
||||
server_hostname VARCHAR(512) DEFAULT NULL,
|
||||
user_context LONGTEXT,
|
||||
valid_lifetime INT(10) DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY name_UNIQUE (name),
|
||||
KEY key_dhcp4_shared_network_modification_ts (modification_ts)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp4_shared_network_server`
|
||||
-- M-to-M cross-reference between shared networks and
|
||||
-- servers
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_shared_network_server (
|
||||
shared_network_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (shared_network_id, server_id),
|
||||
KEY key_dhcp4_shared_network_server_modification_ts (modification_ts),
|
||||
KEY fk_dhcp4_shared_network_server_server_id (server_id),
|
||||
CONSTRAINT fk_dhcp4_shared_network_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp4_server (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp4_shared_network_server_shared_network_id FOREIGN KEY (shared_network_id)
|
||||
REFERENCES dhcp4_shared_network (id) ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp4_subnet`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_subnet (
|
||||
subnet_id INT(10) UNSIGNED NOT NULL,
|
||||
subnet_prefix VARCHAR(32) NOT NULL,
|
||||
4o6_interface VARCHAR(128) DEFAULT NULL,
|
||||
4o6_interface_id VARCHAR(128) DEFAULT NULL,
|
||||
4o6_subnet VARCHAR(64) DEFAULT NULL,
|
||||
boot_file_name VARCHAR(512) DEFAULT NULL,
|
||||
client_class VARCHAR(128) DEFAULT NULL,
|
||||
interface VARCHAR(128) DEFAULT NULL,
|
||||
match_client_id TINYINT(1) NOT NULL DEFAULT '1',
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
next_server INT(10) DEFAULT NULL,
|
||||
rebind_timer INT(10) DEFAULT NULL,
|
||||
relay LONGTEXT,
|
||||
renew_timer INT(10) DEFAULT NULL,
|
||||
require_client_classes LONGTEXT DEFAULT NULL,
|
||||
reservation_mode TINYINT(3) NOT NULL DEFAULT '3',
|
||||
server_hostname VARCHAR(512) DEFAULT NULL,
|
||||
shared_network_name VARCHAR(128) DEFAULT NULL,
|
||||
user_context LONGTEXT,
|
||||
valid_lifetime INT(10) DEFAULT NULL,
|
||||
PRIMARY KEY (subnet_id),
|
||||
UNIQUE KEY subnet4_subnet_prefix (subnet_prefix),
|
||||
KEY fk_dhcp4_subnet_shared_network (shared_network_name),
|
||||
KEY key_dhcp4_subnet_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp4_subnet_shared_network FOREIGN KEY (shared_network_name)
|
||||
REFERENCES dhcp4_shared_network (name)
|
||||
ON DELETE SET NULL ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp4_pool`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_pool (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
start_address INT(10) NOT NULL,
|
||||
end_address INT(10) NOT NULL,
|
||||
subnet_id INT(10) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY key_dhcp4_pool_modification_ts (modification_ts),
|
||||
KEY fk_dhcp4_pool_subnet_id (subnet_id),
|
||||
CONSTRAINT fk_dhcp4_pool_subnet_id FOREIGN KEY (subnet_id)
|
||||
REFERENCES dhcp4_subnet (subnet_id)
|
||||
ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp4_subnet_server`
|
||||
-- M-to-M cross-reference between subnets and servers
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_subnet_server (
|
||||
subnet_id INT(10) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (subnet_id,server_id),
|
||||
KEY fk_dhcp4_subnet_server_server_id_idx (server_id),
|
||||
KEY key_dhcp4_subnet_server_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp4_subnet_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp4_server (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp4_subnet_server_subnet_id FOREIGN KEY (subnet_id)
|
||||
REFERENCES dhcp4_subnet (subnet_id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
|
||||
# Modify the primary key to BINGINT as other tables have.
|
||||
ALTER TABLE dhcp4_options MODIFY option_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;
|
||||
|
||||
# Add conifguration backend specific columns.
|
||||
ALTER TABLE dhcp4_options
|
||||
ADD COLUMN shared_network_name VARCHAR(128) DEFAULT NULL,
|
||||
ADD COLUMN pool_id BIGINT(20) UNSIGNED DEFAULT NULL,
|
||||
ADD COLUMN modification_ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp4_options_server`
|
||||
-- M-to-M cross-reference between options and servers
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_options_server (
|
||||
option_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (option_id, server_id),
|
||||
KEY fk_dhcp4_options_server_server_id (server_id),
|
||||
KEY key_dhcp4_options_server_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp4_options_server_option_id FOREIGN KEY (option_id)
|
||||
REFERENCES dhcp4_options (option_id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp4_options_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp4_server (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp6_server`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_server (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
tag VARCHAR(256) NOT NULL,
|
||||
description TEXT,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY dhcp6_server_tag_UNIQUE (tag),
|
||||
KEY key_dhcp6_server_modification_ts (modification_ts)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp6_audit`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_audit (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
object_type VARCHAR(256) NOT NULL,
|
||||
object_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_type TINYINT(1) NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
log_message TEXT,
|
||||
PRIMARY KEY (id),
|
||||
KEY key_dhcp6_audit_modification_ts (modification_ts),
|
||||
KEY fk_dhcp6_audit_modification_type (modification_type),
|
||||
CONSTRAINT fk_dhcp6_audit_modification_type FOREIGN KEY (modification_type)
|
||||
REFERENCES modification (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp6_global_parameter`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_global_parameter (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
value LONGTEXT NOT NULL,
|
||||
modification_ts timestamp NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY key_dhcp6_global_parameter_modification_ts (modification_ts),
|
||||
KEY key_dhcp6_global_parameter_name (name)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp6_global_parameter_server`
|
||||
-- M-to-M cross-reference between global parameters and
|
||||
-- servers
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_global_parameter_server (
|
||||
parameter_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (parameter_id, server_id),
|
||||
KEY fk_dhcp6_global_parameter_server_server_id (server_id),
|
||||
KEY key_dhcp6_global_parameter_server (modification_ts),
|
||||
CONSTRAINT fk_dhcp6_global_parameter_server_parameter_id FOREIGN KEY (parameter_id)
|
||||
REFERENCES dhcp6_global_parameter (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp6_global_parameter_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp6_server (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp6_option_def`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_option_def (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
code TINYINT(3) UNSIGNED NOT NULL,
|
||||
space VARCHAR(128) NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
array TINYINT(1) NOT NULL,
|
||||
encapsulate VARCHAR(128) NOT NULL,
|
||||
record_types VARCHAR(512) DEFAULT NULL,
|
||||
user_context LONGTEXT,
|
||||
PRIMARY KEY (id),
|
||||
KEY key_dhcp6_option_def_modification_ts (modification_ts),
|
||||
KEY key_dhcp6_option_def_code_space (code, space)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp6_option_def_server`
|
||||
-- M-to-M cross-reference between option definitions and
|
||||
-- servers
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_option_def_server (
|
||||
option_def_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (option_def_id, server_id),
|
||||
KEY fk_dhcp6_option_def_server_server_id_idx (server_id),
|
||||
KEY key_dhcp6_option_def_server_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp6_option_def_server_option_def_id FOREIGN KEY (option_def_id)
|
||||
REFERENCES dhcp6_option_def (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp6_option_def_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp6_server (id) ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp6_shared_network`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE dhcp6_shared_network (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
client_class VARCHAR(128) DEFAULT NULL,
|
||||
interface VARCHAR(128) DEFAULT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
preferred_lifetime INT(10) DEFAULT NULL,
|
||||
rapid_commit TINYINT(1) NOT NULL DEFAULT '1',
|
||||
rebind_timer INT(10) DEFAULT NULL,
|
||||
relay LONGTEXT DEFAULT NULL,
|
||||
renew_timer INT(10) DEFAULT NULL,
|
||||
require_client_classes LONGTEXT,
|
||||
reservation_mode TINYINT(3) NOT NULL DEFAULT '3',
|
||||
server_hostname VARCHAR(512) DEFAULT NULL,
|
||||
user_context LONGTEXT,
|
||||
valid_lifetime INT(10) DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY name_UNIQUE (name),
|
||||
KEY key_dhcp6_shared_network_modification_ts (modification_ts)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp6_shared_network_server`
|
||||
-- M-to-M cross-reference between shared networks and
|
||||
-- servers
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_shared_network_server (
|
||||
shared_network_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
KEY key_dhcp6_shared_network_server_modification_ts (modification_ts),
|
||||
KEY fk_dhcp6_shared_network_server_server_id_idx (server_id),
|
||||
KEY fk_dhcp6_shared_network_server_shared_network_id (shared_network_id),
|
||||
CONSTRAINT fk_dhcp6_shared_network_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp6_server (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp6_shared_network_server_shared_network_id FOREIGN KEY (shared_network_id)
|
||||
REFERENCES dhcp6_shared_network (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp6_subnet`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE dhcp6_subnet (
|
||||
subnet_id INT(10) UNSIGNED NOT NULL,
|
||||
subnet_prefix VARCHAR(64) NOT NULL,
|
||||
client_class VARCHAR(128) DEFAULT NULL,
|
||||
interface VARCHAR(128) DEFAULT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
preferred_lifetime INT(10) DEFAULT NULL,
|
||||
rapid_commit TINYINT(1) NOT NULL DEFAULT '1',
|
||||
rebind_timer INT(10) DEFAULT NULL,
|
||||
relay LONGTEXT DEFAULT NULL,
|
||||
renew_timer INT(10) DEFAULT NULL,
|
||||
require_client_classes LONGTEXT,
|
||||
reservation_mode TINYINT(3) NOT NULL DEFAULT '3',
|
||||
shared_network_name VARCHAR(128) DEFAULT NULL,
|
||||
user_context LONGTEXT,
|
||||
valid_lifetime INT(10) DEFAULT NULL,
|
||||
PRIMARY KEY (subnet_id),
|
||||
UNIQUE KEY subnet_prefix_UNIQUE (subnet_prefix),
|
||||
KEY subnet6_subnet_prefix (subnet_prefix),
|
||||
KEY fk_dhcp6_subnet_shared_network (shared_network_name),
|
||||
KEY key_dhcp6_subnet_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp6_subnet_shared_network FOREIGN KEY (shared_network_name)
|
||||
REFERENCES dhcp6_shared_network (name)
|
||||
ON DELETE SET NULL ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp6_subnet_server`
|
||||
-- M-to-M cross-reference between subnets and servers
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE dhcp6_subnet_server (
|
||||
subnet_id INT(10) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (subnet_id, server_id),
|
||||
KEY fk_dhcp6_subnet_server_server_id (server_id),
|
||||
KEY key_dhcp6_subnet_server_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp6_subnet_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp6_server (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp6_subnet_server_subnet_id FOREIGN KEY (subnet_id)
|
||||
REFERENCES dhcp6_subnet (subnet_id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp6_pd_pool`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_pd_pool (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
prefix VARCHAR(45) NOT NULL,
|
||||
prefix_length TINYINT(3) NOT NULL,
|
||||
delegated_prefix_length TINYINT(3) NOT NULL,
|
||||
dhcp6_subnet_id INT(10) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY fk_dhcp6_pd_pool_subnet_id (dhcp6_subnet_id),
|
||||
KEY key_dhcp6_pd_pool_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp6_pd_pool_subnet_id FOREIGN KEY (dhcp6_subnet_id)
|
||||
REFERENCES dhcp6_subnet (subnet_id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp6_pool`
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_pool (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
start_address VARCHAR(45) NOT NULL,
|
||||
end_address VARCHAR(45) NOT NULL,
|
||||
dhcp6_subnet_id INT(10) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY fk_dhcp6_pool_subnet_id (dhcp6_subnet_id),
|
||||
KEY key_dhcp6_pool_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp6_pool_subnet_id FOREIGN KEY (dhcp6_subnet_id)
|
||||
REFERENCES dhcp6_subnet (subnet_id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Modify the primary key to BINGINT as other tables have.
|
||||
ALTER TABLE dhcp6_options MODIFY option_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;
|
||||
|
||||
# Add conifguration backend specific columns.
|
||||
ALTER TABLE dhcp6_options
|
||||
ADD COLUMN shared_network_name VARCHAR(128) DEFAULT NULL,
|
||||
ADD COLUMN pool_id BIGINT(20) UNSIGNED DEFAULT NULL,
|
||||
ADD COLUMN pd_pool_id BIGINT(20) UNSIGNED DEFAULT NULL,
|
||||
ADD COLUMN modification_ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `dhcp6_options_server`
|
||||
-- M-to-M cross-reference between options and servers
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_options_server (
|
||||
option_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (option_id, server_id),
|
||||
KEY fk_dhcp6_options_server_server_id_idx (server_id),
|
||||
KEY key_dhcp6_options_server_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp6_options_server_option_id FOREIGN KEY (option_id)
|
||||
REFERENCES dhcp6_options (option_id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp6_options_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp6_server (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Update the schema version number
|
||||
UPDATE schema_version
|
||||
|
@@ -32,3 +32,29 @@ DROP TRIGGER IF EXISTS lease6_stat_update;
|
||||
DROP TRIGGER IF EXISTS lease6_stat_delete;
|
||||
DROP TABLE IF EXISTS lease6_stat;
|
||||
DROP TABLE IF EXISTS logs;
|
||||
DROP TABLE IF EXISTS dhcp4_audit;
|
||||
DROP TABLE IF EXISTS dhcp4_global_parameter;
|
||||
DROP TABLE IF EXISTS dhcp4_global_parameter_server;
|
||||
DROP TABLE IF EXISTS dhcp4_option_def;
|
||||
DROP TABLE IF EXISTS dhcp4_option_def_server;
|
||||
DROP TABLE IF EXISTS dhcp4_options_server;
|
||||
DROP TABLE IF EXISTS dhcp4_pool;
|
||||
DROP TABLE IF EXISTS dhcp4_server;
|
||||
DROP TABLE IF EXISTS dhcp4_shared_network;
|
||||
DROP TABLE IF EXISTS dhcp4_shared_network_server;
|
||||
DROP TABLE IF EXISTS dhcp4_subnet;
|
||||
DROP TABLE IF EXISTS dhcp4_subnet_server;
|
||||
DROP TABLE IF EXISTS dhcp6_audit;
|
||||
DROP TABLE IF EXISTS dhcp6_global_parameter;
|
||||
DROP TABLE IF EXISTS dhcp6_global_parameter_server;
|
||||
DROP TABLE IF EXISTS dhcp6_option_def;
|
||||
DROP TABLE IF EXISTS dhcp6_option_def_server;
|
||||
DROP TABLE IF EXISTS dhcp6_options_server;
|
||||
DROP TABLE IF EXISTS dhcp6_pd_pool;
|
||||
DROP TABLE IF EXISTS dhcp6_pool;
|
||||
DROP TABLE IF EXISTS dhcp6_server;
|
||||
DROP TABLE IF EXISTS dhcp6_shared_network;
|
||||
DROP TABLE IF EXISTS dhcp6_shared_network_server;
|
||||
DROP TABLE IF EXISTS dhcp6_subnet;
|
||||
DROP TABLE IF EXISTS dhcp6_subnet_server;
|
||||
DROP TABLE IF EXISTS modification;
|
||||
|
@@ -112,6 +112,485 @@ UPDATE dhcp4_options SET dhcp4_subnet_id = NULL WHERE dhcp4_subnet_id = 0;
|
||||
UPDATE hosts SET dhcp6_subnet_id = NULL WHERE dhcp6_subnet_id = 0;
|
||||
UPDATE dhcp6_options SET dhcp6_subnet_id = NULL WHERE dhcp6_subnet_id = 0;
|
||||
|
||||
# Create table modification
|
||||
CREATE TABLE IF NOT EXISTS modification (
|
||||
id TINYINT(3) NOT NULL,
|
||||
modification_type VARCHAR(32) NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO modification(id, modification_type)
|
||||
VALUES(0, "create");
|
||||
|
||||
INSERT INTO modification(id, modification_type)
|
||||
VALUES(1, "update");
|
||||
|
||||
INSERT INTO modification(id, modification_type)
|
||||
VALUES(2, "delete");
|
||||
|
||||
# Create table dhcp4_server
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_server (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
tag VARCHAR(256) NOT NULL,
|
||||
description TEXT,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY dhcp4_server_tag_UNIQUE (tag),
|
||||
KEY key_dhcp4_server_modification_ts (modification_ts)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp4_audit
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_audit (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
object_type VARCHAR(256) NOT NULL,
|
||||
object_id BIGINT(2) UNSIGNED NOT NULL,
|
||||
modification_type TINYINT(1) NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
log_message TEXT,
|
||||
PRIMARY KEY (id),
|
||||
KEY key_dhcp4_audit_by_modification_ts (modification_ts),
|
||||
KEY fk_dhcp4_audit_modification_type (modification_type),
|
||||
CONSTRAINT fk_dhcp4_audit_modification_type FOREIGN KEY (modification_type)
|
||||
REFERENCES modification (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp4_global_parameter
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_global_parameter (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
value LONGTEXT NOT NULL,
|
||||
modification_ts timestamp NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY key_dhcp4_global_parameter_modification_ts (modification_ts),
|
||||
KEY key_dhcp4_global_parameter_name (name)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp4_global_parameter_server
|
||||
# M-to-M cross-reference between global parameters and servers
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_global_parameter_server (
|
||||
parameter_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (parameter_id, server_id),
|
||||
KEY fk_dhcp4_global_parameter_server_server_id (server_id),
|
||||
KEY key_dhcp4_global_parameter_server (modification_ts),
|
||||
CONSTRAINT fk_dhcp4_global_parameter_server_parameter_id FOREIGN KEY (parameter_id)
|
||||
REFERENCES dhcp4_global_parameter (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp4_global_parameter_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp4_server (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp4_option_def
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_option_def (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
code TINYINT(3) UNSIGNED NOT NULL,
|
||||
space VARCHAR(128) NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
array TINYINT(1) NOT NULL,
|
||||
encapsulate VARCHAR(128) NOT NULL,
|
||||
record_types VARCHAR(512) DEFAULT NULL,
|
||||
user_context LONGTEXT,
|
||||
PRIMARY KEY (id),
|
||||
KEY key_dhcp4_option_def_modification_ts (modification_ts),
|
||||
KEY key_dhcp4_option_def_code_space (code, space)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp4_option_def_server
|
||||
# M-to-M cross-reference between option definitions and servers
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_option_def_server (
|
||||
option_def_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (option_def_id, server_id),
|
||||
KEY fk_dhcp4_option_def_server_server_id_idx (server_id),
|
||||
KEY key_dhcp4_option_def_server_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp4_option_def_server_option_def_id FOREIGN KEY (option_def_id)
|
||||
REFERENCES dhcp4_option_def (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp4_option_def_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp4_server (id) ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp4_shared_network
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_shared_network (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
client_class VARCHAR(128) DEFAULT NULL,
|
||||
interface VARCHAR(128) DEFAULT NULL,
|
||||
match_client_id TINYINT(1) NOT NULL DEFAULT '1',
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
rebind_timer INT(10) DEFAULT NULL,
|
||||
relay LONGTEXT,
|
||||
renew_timer INT(10) DEFAULT NULL,
|
||||
require_client_classes LONGTEXT DEFAULT NULL,
|
||||
reservation_mode TINYINT(3) NOT NULL DEFAULT '3',
|
||||
server_hostname VARCHAR(512) DEFAULT NULL,
|
||||
user_context LONGTEXT,
|
||||
valid_lifetime INT(10) DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY name_UNIQUE (name),
|
||||
KEY key_dhcp4_shared_network_modification_ts (modification_ts)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp4_shared_network_server
|
||||
# M-to-M cross-reference between shared networks and servers
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_shared_network_server (
|
||||
shared_network_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (shared_network_id, server_id),
|
||||
KEY key_dhcp4_shared_network_server_modification_ts (modification_ts),
|
||||
KEY fk_dhcp4_shared_network_server_server_id (server_id),
|
||||
CONSTRAINT fk_dhcp4_shared_network_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp4_server (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp4_shared_network_server_shared_network_id FOREIGN KEY (shared_network_id)
|
||||
REFERENCES dhcp4_shared_network (id) ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp4_subnet
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_subnet (
|
||||
subnet_id INT(10) UNSIGNED NOT NULL,
|
||||
subnet_prefix VARCHAR(32) NOT NULL,
|
||||
4o6_interface VARCHAR(128) DEFAULT NULL,
|
||||
4o6_interface_id VARCHAR(128) DEFAULT NULL,
|
||||
4o6_subnet VARCHAR(64) DEFAULT NULL,
|
||||
boot_file_name VARCHAR(512) DEFAULT NULL,
|
||||
client_class VARCHAR(128) DEFAULT NULL,
|
||||
interface VARCHAR(128) DEFAULT NULL,
|
||||
match_client_id TINYINT(1) NOT NULL DEFAULT '1',
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
next_server INT(10) DEFAULT NULL,
|
||||
rebind_timer INT(10) DEFAULT NULL,
|
||||
relay LONGTEXT,
|
||||
renew_timer INT(10) DEFAULT NULL,
|
||||
require_client_classes LONGTEXT DEFAULT NULL,
|
||||
reservation_mode TINYINT(3) NOT NULL DEFAULT '3',
|
||||
server_hostname VARCHAR(512) DEFAULT NULL,
|
||||
shared_network_name VARCHAR(128) DEFAULT NULL,
|
||||
user_context LONGTEXT,
|
||||
valid_lifetime INT(10) DEFAULT NULL,
|
||||
PRIMARY KEY (subnet_id),
|
||||
UNIQUE KEY subnet4_subnet_prefix (subnet_prefix),
|
||||
KEY fk_dhcp4_subnet_shared_network (shared_network_name),
|
||||
KEY key_dhcp4_subnet_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp4_subnet_shared_network FOREIGN KEY (shared_network_name)
|
||||
REFERENCES dhcp4_shared_network (name)
|
||||
ON DELETE SET NULL ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp4_pool
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_pool (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
start_address INT(10) NOT NULL,
|
||||
end_address INT(10) NOT NULL,
|
||||
subnet_id INT(10) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY key_dhcp4_pool_modification_ts (modification_ts),
|
||||
KEY fk_dhcp4_pool_subnet_id (subnet_id),
|
||||
CONSTRAINT fk_dhcp4_pool_subnet_id FOREIGN KEY (subnet_id)
|
||||
REFERENCES dhcp4_subnet (subnet_id)
|
||||
ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp4_subnet_server
|
||||
# M-to-M cross-reference between subnets and servers
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_subnet_server (
|
||||
subnet_id INT(10) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (subnet_id,server_id),
|
||||
KEY fk_dhcp4_subnet_server_server_id_idx (server_id),
|
||||
KEY key_dhcp4_subnet_server_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp4_subnet_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp4_server (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp4_subnet_server_subnet_id FOREIGN KEY (subnet_id)
|
||||
REFERENCES dhcp4_subnet (subnet_id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
|
||||
# Modify the primary key to BINGINT as other tables have.
|
||||
#
|
||||
ALTER TABLE dhcp4_options MODIFY option_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;
|
||||
|
||||
# Add conifguration backend specific columns.
|
||||
ALTER TABLE dhcp4_options
|
||||
ADD COLUMN shared_network_name VARCHAR(128) DEFAULT NULL,
|
||||
ADD COLUMN pool_id BIGINT(20) UNSIGNED DEFAULT NULL,
|
||||
ADD COLUMN modification_ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||
|
||||
# Create table dhcp4_options_server
|
||||
# M-to-M cross-reference between options and servers
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp4_options_server (
|
||||
option_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (option_id, server_id),
|
||||
KEY fk_dhcp4_options_server_server_id (server_id),
|
||||
KEY key_dhcp4_options_server_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp4_options_server_option_id FOREIGN KEY (option_id)
|
||||
REFERENCES dhcp4_options (option_id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp4_options_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp4_server (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp6_server
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_server (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
tag VARCHAR(256) NOT NULL,
|
||||
description TEXT,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY dhcp6_server_tag_UNIQUE (tag),
|
||||
KEY key_dhcp6_server_modification_ts (modification_ts)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp6_audit
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_audit (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
object_type VARCHAR(256) NOT NULL,
|
||||
object_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_type TINYINT(1) NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
log_message TEXT,
|
||||
PRIMARY KEY (id),
|
||||
KEY key_dhcp6_audit_modification_ts (modification_ts),
|
||||
KEY fk_dhcp6_audit_modification_type (modification_type),
|
||||
CONSTRAINT fk_dhcp6_audit_modification_type FOREIGN KEY (modification_type)
|
||||
REFERENCES modification (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp6_global_parameter
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_global_parameter (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
value LONGTEXT NOT NULL,
|
||||
modification_ts timestamp NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY key_dhcp6_global_parameter_modification_ts (modification_ts),
|
||||
KEY key_dhcp6_global_parameter_name (name)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp6_global_parameter_server
|
||||
# M-to-M cross-reference between global parameters and servers
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_global_parameter_server (
|
||||
parameter_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (parameter_id, server_id),
|
||||
KEY fk_dhcp6_global_parameter_server_server_id (server_id),
|
||||
KEY key_dhcp6_global_parameter_server (modification_ts),
|
||||
CONSTRAINT fk_dhcp6_global_parameter_server_parameter_id FOREIGN KEY (parameter_id)
|
||||
REFERENCES dhcp6_global_parameter (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp6_global_parameter_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp6_server (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp6_option_def
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_option_def (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
code TINYINT(3) UNSIGNED NOT NULL,
|
||||
space VARCHAR(128) NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
array TINYINT(1) NOT NULL,
|
||||
encapsulate VARCHAR(128) NOT NULL,
|
||||
record_types VARCHAR(512) DEFAULT NULL,
|
||||
user_context LONGTEXT,
|
||||
PRIMARY KEY (id),
|
||||
KEY key_dhcp6_option_def_modification_ts (modification_ts),
|
||||
KEY key_dhcp6_option_def_code_space (code, space)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp6_option_def_server
|
||||
# M-to-M cross-reference between option definitions and servers
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_option_def_server (
|
||||
option_def_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (option_def_id, server_id),
|
||||
KEY fk_dhcp6_option_def_server_server_id_idx (server_id),
|
||||
KEY key_dhcp6_option_def_server_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp6_option_def_server_option_def_id FOREIGN KEY (option_def_id)
|
||||
REFERENCES dhcp6_option_def (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp6_option_def_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp6_server (id) ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp6_shared_network
|
||||
#
|
||||
CREATE TABLE dhcp6_shared_network (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
client_class VARCHAR(128) DEFAULT NULL,
|
||||
interface VARCHAR(128) DEFAULT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
preferred_lifetime INT(10) DEFAULT NULL,
|
||||
rapid_commit TINYINT(1) NOT NULL DEFAULT '1',
|
||||
rebind_timer INT(10) DEFAULT NULL,
|
||||
relay LONGTEXT DEFAULT NULL,
|
||||
renew_timer INT(10) DEFAULT NULL,
|
||||
require_client_classes LONGTEXT,
|
||||
reservation_mode TINYINT(3) NOT NULL DEFAULT '3',
|
||||
server_hostname VARCHAR(512) DEFAULT NULL,
|
||||
user_context LONGTEXT,
|
||||
valid_lifetime INT(10) DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY name_UNIQUE (name),
|
||||
KEY key_dhcp6_shared_network_modification_ts (modification_ts)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp6_shared_network_server
|
||||
# M-to-M cross-reference between shared networks and servers
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_shared_network_server (
|
||||
shared_network_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
KEY key_dhcp6_shared_network_server_modification_ts (modification_ts),
|
||||
KEY fk_dhcp6_shared_network_server_server_id_idx (server_id),
|
||||
KEY fk_dhcp6_shared_network_server_shared_network_id (shared_network_id),
|
||||
CONSTRAINT fk_dhcp6_shared_network_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp6_server (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp6_shared_network_server_shared_network_id FOREIGN KEY (shared_network_id)
|
||||
REFERENCES dhcp6_shared_network (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp6_subnet
|
||||
#
|
||||
CREATE TABLE dhcp6_subnet (
|
||||
subnet_id int(10) UNSIGNED NOT NULL,
|
||||
subnet_prefix VARCHAR(64) NOT NULL,
|
||||
client_class VARCHAR(128) DEFAULT NULL,
|
||||
interface VARCHAR(128) DEFAULT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
preferred_lifetime INT(10) DEFAULT NULL,
|
||||
rapid_commit TINYINT(1) NOT NULL DEFAULT '1',
|
||||
rebind_timer INT(10) DEFAULT NULL,
|
||||
relay LONGTEXT DEFAULT NULL,
|
||||
renew_timer INT(10) DEFAULT NULL,
|
||||
require_client_classes LONGTEXT,
|
||||
reservation_mode TINYINT(3) NOT NULL DEFAULT '3',
|
||||
shared_network_name VARCHAR(128) DEFAULT NULL,
|
||||
user_context LONGTEXT,
|
||||
valid_lifetime INT(10) DEFAULT NULL,
|
||||
PRIMARY KEY (subnet_id),
|
||||
UNIQUE KEY subnet6_subnet_prefix (subnet_prefix),
|
||||
KEY fk_dhcp6_subnet_shared_network (shared_network_name),
|
||||
KEY key_dhcp6_subnet_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp6_subnet_shared_network FOREIGN KEY (shared_network_name)
|
||||
REFERENCES dhcp6_shared_network (name)
|
||||
ON DELETE SET NULL ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp6_subnet_server
|
||||
# M-to-M cross-reference between subnets and servers
|
||||
#
|
||||
CREATE TABLE dhcp6_subnet_server (
|
||||
subnet_id INT(10) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (subnet_id, server_id),
|
||||
KEY fk_dhcp6_subnet_server_server_id (server_id),
|
||||
KEY key_dhcp6_subnet_server_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp6_subnet_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp6_server (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp6_subnet_server_subnet_id FOREIGN KEY (subnet_id)
|
||||
REFERENCES dhcp6_subnet (subnet_id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp6_pd_pool
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_pd_pool (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
prefix VARCHAR(45) NOT NULL,
|
||||
prefix_length TINYINT(3) NOT NULL,
|
||||
delegated_prefix_length TINYINT(3) NOT NULL,
|
||||
dhcp6_subnet_id INT(10) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY fk_dhcp6_pd_pool_subnet_id (dhcp6_subnet_id),
|
||||
KEY key_dhcp6_pd_pool_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp6_pd_pool_subnet_id FOREIGN KEY (dhcp6_subnet_id)
|
||||
REFERENCES dhcp6_subnet (subnet_id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Create table dhcp6_pool
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_pool (
|
||||
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
start_address VARCHAR(45) NOT NULL,
|
||||
end_address VARCHAR(45) NOT NULL,
|
||||
dhcp6_subnet_id INT(10) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY fk_dhcp6_pool_subnet_id (dhcp6_subnet_id),
|
||||
KEY key_dhcp6_pool_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp6_pool_subnet_id FOREIGN KEY (dhcp6_subnet_id)
|
||||
REFERENCES dhcp6_subnet (subnet_id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Modify the primary key to BINGINT as other tables have.
|
||||
ALTER TABLE dhcp6_options MODIFY option_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;
|
||||
|
||||
# Add conifguration backend specific columns.
|
||||
ALTER TABLE dhcp6_options
|
||||
ADD COLUMN shared_network_name VARCHAR(128) DEFAULT NULL,
|
||||
ADD COLUMN pool_id BIGINT(20) UNSIGNED DEFAULT NULL,
|
||||
ADD COLUMN pd_pool_id BIGINT(20) UNSIGNED DEFAULT NULL,
|
||||
ADD COLUMN modification_ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||
|
||||
# Create table dhcp6_options_server
|
||||
# M-to-M cross-reference between options and servers
|
||||
#
|
||||
CREATE TABLE IF NOT EXISTS dhcp6_options_server (
|
||||
option_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
server_id BIGINT(20) UNSIGNED NOT NULL,
|
||||
modification_ts TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (option_id, server_id),
|
||||
KEY fk_dhcp6_options_server_server_id_idx (server_id),
|
||||
KEY key_dhcp6_options_server_modification_ts (modification_ts),
|
||||
CONSTRAINT fk_dhcp6_options_server_option_id FOREIGN KEY (option_id)
|
||||
REFERENCES dhcp6_options (option_id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||
CONSTRAINT fk_dhcp6_options_server_server_id FOREIGN KEY (server_id)
|
||||
REFERENCES dhcp6_server (id)
|
||||
ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Update the schema version number
|
||||
UPDATE schema_version
|
||||
SET version = '7', minor = '0';
|
||||
|
Reference in New Issue
Block a user