mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-28 20:47:48 +00:00
[#104,!290] kea-dhcpv6 now supports fetching config from backends
Infrastructure has been added to kea-dhcp6 such that it can now be configured to fetch full and then periodic updates from config backends. Merging the actual fetched content will be done under subsequent issues. src/bin/dhcp6 ctrl_dhcp6_srv.* - ControlledDhcpv6Srv::processConfig() - added logic to schedule CB update timer - ControlledDhcpv6Srv::cbFetchUpdates() - new callback function for CB updates dhcp6_lexer.ll dhcp6_parser.yy - Added config-fetch-wait-time dhcp6_messages.mes - New log messages dhcp6_srv.* - Dhcpv6Srv::cb_control_ - new member for config backend access - Dhcpv6Srv::inTestMode() - new function to test for unit test mode json_config_parser.cc - configureDhcp6Server() - invokes full fetch from config backend src/bin/dhcp6/tests config_backend_unittest.cc - new file/tests for config backend testing config_parser_unittest.cc - updated get_config_unittest.cc - rebuild tests kea_controller_unittest.cc - added CB control/timer tests src/lib/dhcpsrv/ dhcpsrv_messages.mes - added log message cb_ctl_dhcp6.* - new files that provide v6 impl of config backend controller doc/examples/kea6/all-keys-current.json - added config-fetch-wait-time
This commit is contained in:
parent
62ad7da5f7
commit
f5fe96c6ee
@ -699,7 +699,10 @@
|
||||
// Type of the database, e.g. "mysql", "postgresql", "cql".
|
||||
"type": "mysql"
|
||||
}
|
||||
]
|
||||
],
|
||||
// Intervals between attempts to fetch configuration updates
|
||||
// via the configuration backends used.
|
||||
"config-fetch-wait-time": 30
|
||||
},
|
||||
|
||||
// Server tag.
|
||||
|
@ -695,6 +695,34 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
|
||||
return (isc::config::createAnswer(1, err.str()));
|
||||
}
|
||||
|
||||
// Setup config backend polling, if configured for it.
|
||||
auto ctl_info = CfgMgr::instance().getStagingCfg()->getConfigControlInfo();
|
||||
if (ctl_info) {
|
||||
long fetch_time = static_cast<long>(ctl_info->getConfigFetchWaitTime());
|
||||
// Only schedule the CB fetch timer if the fetch wait time is greater
|
||||
// than 0.
|
||||
if (fetch_time > 0) {
|
||||
// When we run unit tests, we want to use milliseconds unit for the
|
||||
// specified interval. Otherwise, we use seconds. Note that using
|
||||
// milliseconds as a unit in unit tests prevents us from waiting 1
|
||||
// second on more before the timer goes off. Instead, we wait one
|
||||
// millisecond which significantly reduces the test time.
|
||||
if (!server_->inTestMode()) {
|
||||
fetch_time = 1000 * fetch_time;
|
||||
}
|
||||
|
||||
boost::shared_ptr<unsigned> failure_count(new unsigned(0));
|
||||
TimerMgr::instance()->
|
||||
registerTimer("Dhcp6CBFetchTimer",
|
||||
boost::bind(&ControlledDhcpv6Srv::cbFetchUpdates,
|
||||
server_, CfgMgr::instance().getStagingCfg(),
|
||||
failure_count),
|
||||
fetch_time,
|
||||
asiolink::IntervalTimer::ONE_SHOT);
|
||||
TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, we can commit runtime option definitions in libdhcp++. This is
|
||||
// exception free.
|
||||
LibDHCP::commitRuntimeOptionDefs();
|
||||
@ -962,5 +990,36 @@ ControlledDhcpv6Srv::dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
|
||||
return(true);
|
||||
}
|
||||
|
||||
void
|
||||
ControlledDhcpv6Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
|
||||
boost::shared_ptr<unsigned> failure_count) {
|
||||
try {
|
||||
// The true value indicates that the server should not reconnect
|
||||
// to the configuration backends and should take into account
|
||||
// audit entries stored in the database since last fetch.
|
||||
server_->getCBControl()->databaseConfigFetch(srv_cfg,
|
||||
CBControlDHCPv6::FetchMode::FETCH_UPDATE);
|
||||
(*failure_count) = 0;
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
LOG_ERROR(dhcp6_logger, DHCP6_CB_FETCH_UPDATES_FAIL)
|
||||
.arg(ex.what());
|
||||
|
||||
// We allow at most 10 consecutive failures after which we stop
|
||||
// making further attempts to fetch the configuration updates.
|
||||
// Let's return without re-scheduling the timer.
|
||||
if (++(*failure_count) > 10) {
|
||||
LOG_ERROR(dhcp6_logger, DHCP6_CB_FETCH_UPDATES_RETRIES_EXHAUSTED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Reschedule the timer to fetch new updates or re-try if
|
||||
// the previous attempt resulted in an error.
|
||||
if (TimerMgr::instance()->isTimerRegistered("Dhcp6CBFetchTimer")) {
|
||||
TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
|
||||
}
|
||||
}
|
||||
|
||||
}; // end of isc::dhcp namespace
|
||||
}; // end of isc namespace
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2012-2019 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -357,6 +357,20 @@ private:
|
||||
/// configured reconnect parameters
|
||||
bool dbLostCallback(db::ReconnectCtlPtr db_reconnect_ctl);
|
||||
|
||||
/// @brief Callback invoked periodically to fetch configuration updates
|
||||
/// from the Config Backends.
|
||||
///
|
||||
/// This method calls @c CBControlDHCPv6::databaseConfigFetch and then
|
||||
/// reschedules the timer.
|
||||
///
|
||||
/// @param srv_cfg Server configuration holding the database credentials
|
||||
/// and server tag.
|
||||
/// @param failure_count pointer to failure counter which causes this
|
||||
/// callback to stop scheduling the timer after 10 consecutive failures
|
||||
/// to fetch the updates.
|
||||
void cbFetchUpdates(const SrvConfigPtr& srv_cfg,
|
||||
boost::shared_ptr<unsigned> failure_count);
|
||||
|
||||
/// @brief Static pointer to the sole instance of the DHCP server.
|
||||
///
|
||||
/// This is required for config and command handlers to gain access to
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -531,6 +531,14 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
|
||||
}
|
||||
}
|
||||
|
||||
\"config-fetch-wait-time\" {
|
||||
switch(driver.ctx_) {
|
||||
case isc::dhcp::Parser6Context::CONFIG_CONTROL:
|
||||
return isc::dhcp::Dhcp6Parser::make_CONFIG_FETCH_WAIT_TIME(driver.loc_);
|
||||
default:
|
||||
return isc::dhcp::Dhcp6Parser::make_STRING("config-fetch-wait-time", driver.loc_);
|
||||
}
|
||||
}
|
||||
|
||||
\"readonly\" {
|
||||
switch(driver.ctx_) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// File created from ../../../src/bin/dhcp6/dhcp6_messages.mes on Fri Feb 08 2019 20:33
|
||||
// File created from ../../../src/bin/dhcp6/dhcp6_messages.mes on Tue Mar 26 2019 13:41
|
||||
|
||||
#include <cstddef>
|
||||
#include <log/message_types.h>
|
||||
@ -14,6 +14,8 @@ extern const isc::log::MessageID DHCP6_ALREADY_RUNNING = "DHCP6_ALREADY_RUNNING"
|
||||
extern const isc::log::MessageID DHCP6_BUFFER_RECEIVED = "DHCP6_BUFFER_RECEIVED";
|
||||
extern const isc::log::MessageID DHCP6_BUFFER_UNPACK = "DHCP6_BUFFER_UNPACK";
|
||||
extern const isc::log::MessageID DHCP6_BUFFER_WAIT_SIGNAL = "DHCP6_BUFFER_WAIT_SIGNAL";
|
||||
extern const isc::log::MessageID DHCP6_CB_FETCH_UPDATES_FAIL = "DHCP6_CB_FETCH_UPDATES_FAIL";
|
||||
extern const isc::log::MessageID DHCP6_CB_FETCH_UPDATES_RETRIES_EXHAUSTED = "DHCP6_CB_FETCH_UPDATES_RETRIES_EXHAUSTED";
|
||||
extern const isc::log::MessageID DHCP6_CLASS_ASSIGNED = "DHCP6_CLASS_ASSIGNED";
|
||||
extern const isc::log::MessageID DHCP6_CLASS_UNCONFIGURED = "DHCP6_CLASS_UNCONFIGURED";
|
||||
extern const isc::log::MessageID DHCP6_CLASS_UNDEFINED = "DHCP6_CLASS_UNDEFINED";
|
||||
@ -152,6 +154,8 @@ const char* values[] = {
|
||||
"DHCP6_BUFFER_RECEIVED", "received buffer from %1:%2 to %3:%4 over interface %5",
|
||||
"DHCP6_BUFFER_UNPACK", "parsing buffer received from %1 to %2 over interface %3",
|
||||
"DHCP6_BUFFER_WAIT_SIGNAL", "signal received while waiting for next packet, next waiting signal is %1",
|
||||
"DHCP6_CB_FETCH_UPDATES_FAIL", "error on attempt to fetch configuration updates from the configuration backend(s): %1",
|
||||
"DHCP6_CB_FETCH_UPDATES_RETRIES_EXHAUSTED", "maximum number of configuration fetch attempts: 10, has been exhausted without success",
|
||||
"DHCP6_CLASS_ASSIGNED", "%1: client packet has been assigned to the following class(es): %2",
|
||||
"DHCP6_CLASS_UNCONFIGURED", "%1: client packet belongs to an unconfigured class: %2",
|
||||
"DHCP6_CLASS_UNDEFINED", "required class %1 has no definition",
|
||||
|
@ -1,4 +1,4 @@
|
||||
// File created from ../../../src/bin/dhcp6/dhcp6_messages.mes on Fri Feb 08 2019 20:33
|
||||
// File created from ../../../src/bin/dhcp6/dhcp6_messages.mes on Tue Mar 26 2019 13:41
|
||||
|
||||
#ifndef DHCP6_MESSAGES_H
|
||||
#define DHCP6_MESSAGES_H
|
||||
@ -15,6 +15,8 @@ extern const isc::log::MessageID DHCP6_ALREADY_RUNNING;
|
||||
extern const isc::log::MessageID DHCP6_BUFFER_RECEIVED;
|
||||
extern const isc::log::MessageID DHCP6_BUFFER_UNPACK;
|
||||
extern const isc::log::MessageID DHCP6_BUFFER_WAIT_SIGNAL;
|
||||
extern const isc::log::MessageID DHCP6_CB_FETCH_UPDATES_FAIL;
|
||||
extern const isc::log::MessageID DHCP6_CB_FETCH_UPDATES_RETRIES_EXHAUSTED;
|
||||
extern const isc::log::MessageID DHCP6_CLASS_ASSIGNED;
|
||||
extern const isc::log::MessageID DHCP6_CLASS_UNCONFIGURED;
|
||||
extern const isc::log::MessageID DHCP6_CLASS_UNDEFINED;
|
||||
|
@ -74,6 +74,20 @@ has no definition.
|
||||
This debug message informs that a class was listed for required evaluation but
|
||||
its definition does not include a test expression to evaluate.
|
||||
|
||||
% DHCP6_CB_FETCH_UPDATES_FAIL error on attempt to fetch configuration updates from the configuration backend(s): %1
|
||||
This error message is issued when the server attempted to fetch
|
||||
configuration updates from the database and this attempt failed.
|
||||
The server will re-try according to the configured value of the
|
||||
config-fetch-wait-time parameter. The sole argument contains the
|
||||
reason for failure.
|
||||
|
||||
% DHCP6_CB_FETCH_UPDATES_RETRIES_EXHAUSTED maximum number of configuration fetch attempts: 10, has been exhausted without success
|
||||
This error indicates that the server has made a number of unsuccessful
|
||||
attempts to fetch configuration updates from a configuration backend.
|
||||
The server will continue to operate but won't make any further attempts
|
||||
to fetch configuration updates. The administrator must fix the configuration
|
||||
in the database and reload (or restart) the server.
|
||||
|
||||
% DHCP6_COMMAND_RECEIVED received command %1, arguments: %2
|
||||
A debug message listing the command (and possible arguments) received
|
||||
from the Kea control system by the IPv6 DHCP server.
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -53,6 +53,8 @@ using namespace std;
|
||||
DATA_DIRECTORY "data-directory"
|
||||
CONFIG_CONTROL "config-control"
|
||||
CONFIG_DATABASES "config-databases"
|
||||
CONFIG_FETCH_WAIT_TIME "config-fetch-wait-time"
|
||||
|
||||
INTERFACES_CONFIG "interfaces-config"
|
||||
INTERFACES "interfaces"
|
||||
RE_DETECT "re-detect"
|
||||
@ -2219,6 +2221,7 @@ config_control_params: config_control_param
|
||||
|
||||
// This defines a list of allowed parameters for each subnet.
|
||||
config_control_param: config_databases
|
||||
| config_fetch_wait_time
|
||||
;
|
||||
|
||||
config_databases: CONFIG_DATABASES {
|
||||
@ -2231,6 +2234,11 @@ config_databases: CONFIG_DATABASES {
|
||||
ctx.leave();
|
||||
};
|
||||
|
||||
config_fetch_wait_time: CONFIG_FETCH_WAIT_TIME COLON INTEGER {
|
||||
ElementPtr value(new IntElement($3, ctx.loc2pos(@3)));
|
||||
ctx.stack_.back()->set("config-fetch-wait-time", value);
|
||||
};
|
||||
|
||||
// --- logging entry -----------------------------------------
|
||||
|
||||
// This defines the top level "Logging" object. It parses
|
||||
|
@ -183,9 +183,8 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t server_port, uint16_t client_port)
|
||||
: io_service_(new IOService()), server_port_(server_port),
|
||||
client_port_(client_port), serverid_(), shutdown_(true),
|
||||
alloc_engine_(), name_change_reqs_(),
|
||||
network_state_(new NetworkState(NetworkState::DHCPv6))
|
||||
{
|
||||
|
||||
network_state_(new NetworkState(NetworkState::DHCPv6)),
|
||||
cb_control_(new CBControlDHCPv6()) {
|
||||
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_OPEN_SOCKET)
|
||||
.arg(server_port);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2011-2018 Internet Systems Consortium, Inc. ("ISC")
|
||||
// Copyright (C) 2011-2019 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -18,6 +18,7 @@
|
||||
#include <dhcp/pkt6.h>
|
||||
#include <dhcpsrv/alloc_engine.h>
|
||||
#include <dhcpsrv/callout_handle_store.h>
|
||||
#include <dhcpsrv/cb_ctl_dhcp6.h>
|
||||
#include <dhcpsrv/cfg_option.h>
|
||||
#include <dhcpsrv/d2_client_mgr.h>
|
||||
#include <dhcpsrv/network_state.h>
|
||||
@ -88,6 +89,14 @@ public:
|
||||
/// @brief Destructor. Used during DHCPv6 service shutdown.
|
||||
virtual ~Dhcpv6Srv();
|
||||
|
||||
/// @brief Checks if the server is running in unit test mode.
|
||||
///
|
||||
/// @return true if the server is running in unit test mode,
|
||||
/// false otherwise.
|
||||
bool inTestMode() const {
|
||||
return (server_port_ == 0);
|
||||
}
|
||||
|
||||
/// @brief Returns pointer to the IO service used by the server.
|
||||
asiolink::IOServicePtr& getIOService() {
|
||||
return (io_service_);
|
||||
@ -98,6 +107,15 @@ public:
|
||||
return (network_state_);
|
||||
}
|
||||
|
||||
/// @brief Returns an object which controls access to the configuration
|
||||
/// backends.
|
||||
///
|
||||
/// @return Pointer to the instance of the object which controls
|
||||
/// access to the configuration backends.
|
||||
CBControlDHCPv6Ptr getCBControl() const {
|
||||
return (cb_control_);
|
||||
}
|
||||
|
||||
/// @brief returns Kea version on stdout and exit.
|
||||
/// redeclaration/redefinition. @ref isc::process::Daemon::getVersion()
|
||||
static std::string getVersion(bool extended);
|
||||
@ -998,6 +1016,8 @@ protected:
|
||||
/// disabled subnet/network scopes.
|
||||
NetworkStatePtr network_state_;
|
||||
|
||||
/// @brief Controls access to the configuration backends.
|
||||
CBControlDHCPv6Ptr cb_control_;
|
||||
};
|
||||
|
||||
}; // namespace isc::dhcp
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <dhcp6/dhcp6_log.h>
|
||||
#include <dhcp6/dhcp6_srv.h>
|
||||
#include <dhcp/iface_mgr.h>
|
||||
#include <dhcpsrv/cb_ctl_dhcp4.h>
|
||||
#include <dhcpsrv/cfg_option.h>
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
#include <dhcpsrv/db_type.h>
|
||||
@ -419,6 +420,7 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
|
||||
if (!check_only) {
|
||||
TimerMgr::instance()->unregisterTimers();
|
||||
server.discardPackets();
|
||||
server.getCBControl()->reset();
|
||||
}
|
||||
|
||||
// Revert any runtime option definitions configured so far and not committed.
|
||||
@ -444,9 +446,10 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
|
||||
// the parsers. It is declared outside the loop so in case of error, the
|
||||
// name of the failing parser can be retrieved within the "catch" clause.
|
||||
ConfigPair config_pair;
|
||||
SrvConfigPtr srv_config;
|
||||
try {
|
||||
|
||||
SrvConfigPtr srv_config = CfgMgr::instance().getStagingCfg();
|
||||
// Get the staging configuration.
|
||||
srv_config = CfgMgr::instance().getStagingCfg();
|
||||
|
||||
// Preserve all scalar global parameters
|
||||
srv_config->extractConfiguredGlobals(config_set);
|
||||
@ -739,6 +742,10 @@ configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
|
||||
const HooksConfig& libraries =
|
||||
CfgMgr::instance().getStagingCfg()->getHooksConfig();
|
||||
libraries.loadLibraries();
|
||||
|
||||
// If there are config backends, fetch and merge into staging config
|
||||
server.getCBControl()->databaseConfigFetch(srv_config,
|
||||
CBControlDHCPv6::FetchMode::FETCH_ALL);
|
||||
}
|
||||
catch (const isc::Exception& ex) {
|
||||
LOG_ERROR(dhcp6_logger, DHCP6_PARSER_COMMIT_FAIL).arg(ex.what());
|
||||
|
@ -1,9 +1,8 @@
|
||||
// Generated 201903231444
|
||||
// A Bison parser, made by GNU Bison 3.3.2.
|
||||
// A Bison parser, made by GNU Bison 3.2.1.
|
||||
|
||||
// Locations for Bison parsers in C++
|
||||
|
||||
// Copyright (C) 2002-2015, 2018-2019 Free Software Foundation, Inc.
|
||||
// Copyright (C) 2002-2015, 2018 Free Software Foundation, Inc.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,5 +1,4 @@
|
||||
// Generated 201903231444
|
||||
// A Bison parser, made by GNU Bison 3.3.2.
|
||||
// A Bison parser, made by GNU Bison 3.2.1.
|
||||
|
||||
// Starting with Bison 3.2, this file is useless: the structure it
|
||||
// used to define is now defined in "location.hh".
|
||||
|
@ -1,5 +1,4 @@
|
||||
// Generated 201903231444
|
||||
// A Bison parser, made by GNU Bison 3.3.2.
|
||||
// A Bison parser, made by GNU Bison 3.2.1.
|
||||
|
||||
// Starting with Bison 3.2, this file is useless: the structure it
|
||||
// used to define is now defined with the parser itself.
|
||||
|
510
src/bin/dhcp6/tests/config_backend_unittest.cc
Normal file
510
src/bin/dhcp6/tests/config_backend_unittest.cc
Normal file
@ -0,0 +1,510 @@
|
||||
// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <database/backend_selector.h>
|
||||
#include <dhcp/tests/iface_mgr_test_config.h>
|
||||
#include <dhcp6/dhcp6_srv.h>
|
||||
#include <dhcp6/ctrl_dhcp6_srv.h>
|
||||
#include <dhcp6/json_config_parser.h>
|
||||
#include <dhcpsrv/subnet.h>
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
#include <dhcpsrv/cfg_subnets6.h>
|
||||
#include <dhcpsrv/testutils/generic_backend_unittest.h>
|
||||
#include <dhcpsrv/testutils/test_config_backend_dhcp6.h>
|
||||
|
||||
#include "dhcp6_test_utils.h"
|
||||
#include "get_config_unittest.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <limits.h>
|
||||
|
||||
using namespace isc::asiolink;
|
||||
using namespace isc::config;
|
||||
using namespace isc::data;
|
||||
using namespace isc::dhcp;
|
||||
using namespace isc::dhcp::test;
|
||||
using namespace isc::db;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
/// @brief Test fixture for testing external configuration merging
|
||||
class Dhcp6CBTest : public GenericBackendTest {
|
||||
protected:
|
||||
/// @brief Pre test set up
|
||||
/// Called prior to each test. It creates two configuration backends
|
||||
/// that differ by host name ("db1" and "db2"). It then registers
|
||||
/// a backend factory that will return them rather than create
|
||||
/// new instances. The backends need to pre-exist so they can be
|
||||
/// populated prior to calling server configure. It uses
|
||||
/// TestConfigBackend instances but with a type of "memfile" to pass
|
||||
/// parsing. Doing it all here allows us to use ASSERTs if we feel like
|
||||
/// it.
|
||||
virtual void SetUp() {
|
||||
DatabaseConnection::ParameterMap params;
|
||||
params[std::string("type")] = std::string("memfile");
|
||||
params[std::string("host")] = std::string("db1");
|
||||
db1_.reset(new TestConfigBackendDHCPv6(params));
|
||||
|
||||
params[std::string("host")] = std::string("db2");
|
||||
db2_.reset(new TestConfigBackendDHCPv6(params));
|
||||
|
||||
ConfigBackendDHCPv6Mgr::instance().registerBackendFactory("memfile",
|
||||
[this](const DatabaseConnection::ParameterMap& params)
|
||||
-> ConfigBackendDHCPv6Ptr {
|
||||
auto host = params.find("host");
|
||||
if (host != params.end()) {
|
||||
if (host->second == "db1") {
|
||||
return (db1_);
|
||||
} else if (host->second == "db2") {
|
||||
return (db2_);
|
||||
}
|
||||
}
|
||||
|
||||
// Apparently we're looking for one that does not prexist.
|
||||
return (TestConfigBackendDHCPv6Ptr(new TestConfigBackendDHCPv6(params)));
|
||||
});
|
||||
}
|
||||
|
||||
/// @brief Clean up after each test
|
||||
virtual void TearDown() {
|
||||
// Unregister the factory to be tidy.
|
||||
ConfigBackendDHCPv6Mgr::instance().unregisterBackendFactory("memfile");
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// Constructor
|
||||
Dhcp6CBTest()
|
||||
: rcode_(-1), db1_selector("db1"), db2_selector("db1") {
|
||||
// Open port 0 means to not do anything at all. We don't want to
|
||||
// deal with sockets here, just check if configuration handling
|
||||
// is sane.
|
||||
srv_.reset(new ControlledDhcpv6Srv(0));
|
||||
|
||||
// Create fresh context.
|
||||
resetConfiguration();
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
virtual ~Dhcp6CBTest() {
|
||||
resetConfiguration();
|
||||
};
|
||||
|
||||
/// @brief Reset configuration singletons.
|
||||
void resetConfiguration() {
|
||||
CfgMgr::instance().clear();
|
||||
ConfigBackendDHCPv6Mgr::destroy();
|
||||
}
|
||||
|
||||
/// @brief Convenience method for running configuration
|
||||
///
|
||||
/// This method does not throw, but signals errors using gtest macros.
|
||||
///
|
||||
/// @param config text to be parsed as JSON
|
||||
/// @param expected_code expected code (see cc/command_interpreter.h)
|
||||
/// @param exp_error expected text error (check skipped if empty)
|
||||
void configure(std::string config, int expected_code,
|
||||
std::string exp_error = "") {
|
||||
ConstElementPtr json;
|
||||
try {
|
||||
json = parseDHCP6(config, true);
|
||||
} catch(const std::exception& ex) {
|
||||
ADD_FAILURE() << "parseDHCP6 failed: " << ex.what();
|
||||
}
|
||||
|
||||
ConstElementPtr status;
|
||||
ASSERT_NO_THROW(status = configureDhcp6Server(*srv_, json));
|
||||
ASSERT_TRUE(status);
|
||||
|
||||
int rcode;
|
||||
ConstElementPtr comment = parseAnswer(rcode, status);
|
||||
ASSERT_EQ(expected_code, rcode) << " comment: "
|
||||
<< comment->stringValue();
|
||||
|
||||
string text;
|
||||
ASSERT_NO_THROW(text = comment->stringValue());
|
||||
|
||||
if (expected_code != rcode) {
|
||||
std::cout << "Reported status: " << text << std::endl;
|
||||
}
|
||||
|
||||
if ((rcode != 0)) {
|
||||
if (!exp_error.empty()) {
|
||||
ASSERT_EQ(exp_error, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boost::scoped_ptr<Dhcpv6Srv> srv_; ///< DHCP6 server under test
|
||||
int rcode_; ///< Return code from element parsing
|
||||
ConstElementPtr comment_; ///< Reason for parse fail
|
||||
|
||||
BackendSelector db1_selector; ///< BackendSelector by host for first config backend
|
||||
BackendSelector db2_selector; ///< BackendSelector by host for second config backend
|
||||
|
||||
TestConfigBackendDHCPv6Ptr db1_; ///< First configuration backend instance
|
||||
TestConfigBackendDHCPv6Ptr db2_; ///< Second configuration backend instance
|
||||
};
|
||||
|
||||
// This test verifies that externally configured globals are
|
||||
// merged correctly into staging configuration.
|
||||
TEST_F(Dhcp6CBTest, mergeGlobals) {
|
||||
string base_config =
|
||||
"{ \n"
|
||||
" \"interfaces-config\": { \n"
|
||||
" \"interfaces\": [\"*\" ] \n"
|
||||
" }, \n"
|
||||
" \"echo-client-id\": false, \n"
|
||||
" \"decline-probation-period\": 7000, \n"
|
||||
" \"valid-lifetime\": 1000, \n"
|
||||
" \"rebind-timer\": 800, \n"
|
||||
" \"server-hostname\": \"overwrite.me.com\", \n"
|
||||
" \"config-control\": { \n"
|
||||
" \"config-databases\": [ { \n"
|
||||
" \"type\": \"memfile\", \n"
|
||||
" \"host\": \"db1\" \n"
|
||||
" },{ \n"
|
||||
" \"type\": \"memfile\", \n"
|
||||
" \"host\": \"db2\" \n"
|
||||
" } \n"
|
||||
" ] \n"
|
||||
" } \n"
|
||||
"} \n";
|
||||
|
||||
extractConfig(base_config);
|
||||
|
||||
// Make some globals:
|
||||
StampedValuePtr server_hostname(new StampedValue("server-hostname", "isc.example.org"));
|
||||
StampedValuePtr decline_period(new StampedValue("decline-probation-period", Element::create(86400)));
|
||||
StampedValuePtr calc_tee_times(new StampedValue("calculate-tee-times", Element::create(bool(false))));
|
||||
StampedValuePtr t2_percent(new StampedValue("t2-percent", Element::create(0.75)));
|
||||
StampedValuePtr renew_timer(new StampedValue("renew-timer", Element::create(500)));
|
||||
|
||||
// Let's add all of the globals to the second backend. This will verify
|
||||
// we find them there.
|
||||
db2_->createUpdateGlobalParameter6(ServerSelector::ALL(), server_hostname);
|
||||
db2_->createUpdateGlobalParameter6(ServerSelector::ALL(), decline_period);
|
||||
db2_->createUpdateGlobalParameter6(ServerSelector::ALL(), calc_tee_times);
|
||||
db2_->createUpdateGlobalParameter6(ServerSelector::ALL(), t2_percent);
|
||||
db2_->createUpdateGlobalParameter6(ServerSelector::ALL(), renew_timer);
|
||||
|
||||
// Should parse and merge without error.
|
||||
ASSERT_NO_FATAL_FAILURE(configure(base_config, CONTROL_RESULT_SUCCESS, ""));
|
||||
|
||||
// Verify the composite staging is correct. (Remember that
|
||||
// CfgMgr::instance().commit() hasn't been called)
|
||||
SrvConfigPtr staging_cfg = CfgMgr::instance().getStagingCfg();
|
||||
|
||||
// echo-client-id is set explicitly in the original config, meanwhile
|
||||
// the backend config does not set it, so the explicit value wins.
|
||||
EXPECT_FALSE(staging_cfg->getEchoClientId());
|
||||
|
||||
// decline-probation-period is an explicit member that should come
|
||||
// from the backend.
|
||||
EXPECT_EQ(86400, staging_cfg->getDeclinePeriod());
|
||||
|
||||
// Verify that the implicit globals from JSON are there.
|
||||
ASSERT_NO_FATAL_FAILURE(checkConfiguredGlobal(staging_cfg, "valid-lifetime",
|
||||
Element::create(1000)));
|
||||
ASSERT_NO_FATAL_FAILURE(checkConfiguredGlobal(staging_cfg, "rebind-timer",
|
||||
Element::create(800)));
|
||||
|
||||
// Verify that the implicit globals from the backend are there.
|
||||
ASSERT_NO_FATAL_FAILURE(checkConfiguredGlobal(staging_cfg, server_hostname));
|
||||
ASSERT_NO_FATAL_FAILURE(checkConfiguredGlobal(staging_cfg, calc_tee_times));
|
||||
ASSERT_NO_FATAL_FAILURE(checkConfiguredGlobal(staging_cfg, t2_percent));
|
||||
ASSERT_NO_FATAL_FAILURE(checkConfiguredGlobal(staging_cfg, renew_timer));
|
||||
}
|
||||
|
||||
#if 0
|
||||
// This test verifies that externally configured option definitions
|
||||
// merged correctly into staging configuration.
|
||||
TEST_F(Dhcp6CBTest, mergeOptionDefs) {
|
||||
string base_config =
|
||||
"{ \n"
|
||||
" \"option-def\": [ { \n"
|
||||
" \"name\": \"one\", \n"
|
||||
" \"code\": 1, \n"
|
||||
" \"type\": \"ipv6-address\", \n"
|
||||
" \"space\": \"isc\" \n"
|
||||
" }, \n"
|
||||
" { \n"
|
||||
" \"name\": \"two\", \n"
|
||||
" \"code\": 2, \n"
|
||||
" \"type\": \"string\", \n"
|
||||
" \"space\": \"isc\" \n"
|
||||
" } \n"
|
||||
" ], \n"
|
||||
" \"config-control\": { \n"
|
||||
" \"config-databases\": [ { \n"
|
||||
" \"type\": \"memfile\", \n"
|
||||
" \"host\": \"db1\" \n"
|
||||
" },{ \n"
|
||||
" \"type\": \"memfile\", \n"
|
||||
" \"host\": \"db2\" \n"
|
||||
" } \n"
|
||||
" ] \n"
|
||||
" } \n"
|
||||
"} \n";
|
||||
|
||||
extractConfig(base_config);
|
||||
|
||||
// Create option one replacement and add it to first backend.
|
||||
OptionDefinitionPtr def;
|
||||
def.reset(new OptionDefinition("one", 101, "uint16"));
|
||||
def->setOptionSpaceName("isc");
|
||||
db1_->createUpdateOptionDef6(ServerSelector::ALL(), def);
|
||||
|
||||
// Create option three and add it to first backend.
|
||||
def.reset(new OptionDefinition("three", 3, "string"));
|
||||
def->setOptionSpaceName("isc");
|
||||
db1_->createUpdateOptionDef6(ServerSelector::ALL(), def);
|
||||
|
||||
// Create option four and add it to second backend.
|
||||
def.reset(new OptionDefinition("four", 4, "string"));
|
||||
def->setOptionSpaceName("isc");
|
||||
db2_->createUpdateOptionDef6(ServerSelector::ALL(), def);
|
||||
|
||||
// Should parse and merge without error.
|
||||
ASSERT_NO_FATAL_FAILURE(configure(base_config, CONTROL_RESULT_SUCCESS, ""));
|
||||
|
||||
// Verify the composite staging is correct.
|
||||
SrvConfigPtr staging_cfg = CfgMgr::instance().getStagingCfg();
|
||||
ConstCfgOptionDefPtr option_defs = staging_cfg->getCfgOptionDef();
|
||||
|
||||
// Definition "one" from first backend should be there.
|
||||
OptionDefinitionPtr found_def = option_defs->get("isc", "one");
|
||||
ASSERT_TRUE(found_def);
|
||||
EXPECT_EQ(101, found_def->getCode());
|
||||
EXPECT_EQ(OptionDataType::OPT_UINT16_TYPE, found_def->getType());
|
||||
|
||||
// Definition "two" from JSON config should be there.
|
||||
found_def = option_defs->get("isc", "two");
|
||||
ASSERT_TRUE(found_def);
|
||||
EXPECT_EQ(2, found_def->getCode());
|
||||
|
||||
// Definition "three" from first backend should be there.
|
||||
found_def = option_defs->get("isc", "three");
|
||||
ASSERT_TRUE(found_def);
|
||||
EXPECT_EQ(3, found_def->getCode());
|
||||
|
||||
// Definition "four" from first backend should not be there.
|
||||
found_def = option_defs->get("isc", "four");
|
||||
ASSERT_FALSE(found_def);
|
||||
}
|
||||
|
||||
// This test verifies that externally configured options
|
||||
// merged correctly into staging configuration.
|
||||
TEST_F(Dhcp6CBTest, mergeOptions) {
|
||||
string base_config =
|
||||
"{ \n"
|
||||
" \"option-data\": [ { \n"
|
||||
" \"name\": \"dhcp-message\", \n"
|
||||
" \"data\": \"0A0B0C0D\", \n"
|
||||
" \"csv-format\": false \n"
|
||||
" },{ \n"
|
||||
" \"name\": \"host-name\", \n"
|
||||
" \"data\": \"old.example.com\", \n"
|
||||
" \"csv-format\": true \n"
|
||||
" } \n"
|
||||
" ], \n"
|
||||
" \"config-control\": { \n"
|
||||
" \"config-databases\": [ { \n"
|
||||
" \"type\": \"memfile\", \n"
|
||||
" \"host\": \"db1\" \n"
|
||||
" },{ \n"
|
||||
" \"type\": \"memfile\", \n"
|
||||
" \"host\": \"db2\" \n"
|
||||
" } \n"
|
||||
" ] \n"
|
||||
" } \n"
|
||||
"} \n";
|
||||
|
||||
extractConfig(base_config);
|
||||
|
||||
OptionDescriptorPtr opt;
|
||||
|
||||
// Add host-name to the first backend.
|
||||
opt.reset(new OptionDescriptor(
|
||||
createOption<OptionString>(Option::V6, DHO_HOST_NAME,
|
||||
true, false, "new.example.com")));
|
||||
opt->space_name_ = DHCP6_OPTION_SPACE;
|
||||
db1_->createUpdateOption6(ServerSelector::ALL(), opt);
|
||||
|
||||
// Add boot-file-name to the first backend.
|
||||
opt.reset(new OptionDescriptor(
|
||||
createOption<OptionString>(Option::V6, DHO_BOOT_FILE_NAME,
|
||||
true, false, "my-boot-file")));
|
||||
opt->space_name_ = DHCP6_OPTION_SPACE;
|
||||
db1_->createUpdateOption6(ServerSelector::ALL(), opt);
|
||||
|
||||
// Add boot-file-name to the second backend.
|
||||
opt.reset(new OptionDescriptor(
|
||||
createOption<OptionString>(Option::V6, DHO_BOOT_FILE_NAME,
|
||||
true, false, "your-boot-file")));
|
||||
opt->space_name_ = DHCP6_OPTION_SPACE;
|
||||
db2_->createUpdateOption6(ServerSelector::ALL(), opt);
|
||||
|
||||
// Should parse and merge without error.
|
||||
ASSERT_NO_FATAL_FAILURE(configure(base_config, CONTROL_RESULT_SUCCESS, ""));
|
||||
|
||||
// Verify the composite staging is correct.
|
||||
SrvConfigPtr staging_cfg = CfgMgr::instance().getStagingCfg();
|
||||
|
||||
// Option definition from JSON should be there.
|
||||
CfgOptionPtr options = staging_cfg->getCfgOption();
|
||||
|
||||
// dhcp-message should come from the original config.
|
||||
OptionDescriptor found_opt = options->get("dhcp6", DHO_DHCP_MESSAGE);
|
||||
ASSERT_TRUE(found_opt.option_);
|
||||
EXPECT_EQ("0x0A0B0C0D", found_opt.option_->toHexString());
|
||||
|
||||
// host-name should come from the first back end,
|
||||
// (overwriting the original).
|
||||
found_opt = options->get("dhcp6", DHO_HOST_NAME);
|
||||
ASSERT_TRUE(found_opt.option_);
|
||||
EXPECT_EQ("new.example.com", found_opt.option_->toString());
|
||||
|
||||
// booth-file-name should come from the first back end.
|
||||
found_opt = options->get("dhcp6", DHO_BOOT_FILE_NAME);
|
||||
ASSERT_TRUE(found_opt.option_);
|
||||
EXPECT_EQ("my-boot-file", found_opt.option_->toString());
|
||||
}
|
||||
|
||||
// This test verifies that externally configured shared-networks are
|
||||
// merged correctly into staging configuration.
|
||||
TEST_F(Dhcp6CBTest, mergeSharedNetworks) {
|
||||
string base_config =
|
||||
"{ \n"
|
||||
" \"interfaces-config\": { \n"
|
||||
" \"interfaces\": [\"*\" ] \n"
|
||||
" }, \n"
|
||||
" \"valid-lifetime\": 4000, \n"
|
||||
" \"config-control\": { \n"
|
||||
" \"config-databases\": [ { \n"
|
||||
" \"type\": \"memfile\", \n"
|
||||
" \"host\": \"db1\" \n"
|
||||
" },{ \n"
|
||||
" \"type\": \"memfile\", \n"
|
||||
" \"host\": \"db2\" \n"
|
||||
" } \n"
|
||||
" ] \n"
|
||||
" }, \n"
|
||||
" \"shared-networks\": [ { \n"
|
||||
" \"name\": \"two\" \n"
|
||||
" }] \n"
|
||||
"} \n";
|
||||
|
||||
extractConfig(base_config);
|
||||
|
||||
// Make a few networks
|
||||
SharedNetwork6Ptr network1(new SharedNetwork6("one"));
|
||||
SharedNetwork6Ptr network3(new SharedNetwork6("three"));
|
||||
|
||||
// Add network1 to db1 and network3 to db2
|
||||
db1_->createUpdateSharedNetwork6(ServerSelector::ALL(), network1);
|
||||
db2_->createUpdateSharedNetwork6(ServerSelector::ALL(), network3);
|
||||
|
||||
// Should parse and merge without error.
|
||||
ASSERT_NO_FATAL_FAILURE(configure(base_config, CONTROL_RESULT_SUCCESS, ""));
|
||||
|
||||
// Verify the composite staging is correct. (Remember that
|
||||
// CfgMgr::instance().commit() hasn't been called)
|
||||
SrvConfigPtr staging_cfg = CfgMgr::instance().getStagingCfg();
|
||||
|
||||
CfgSharedNetworks4Ptr networks = staging_cfg->getCfgSharedNetworks4();
|
||||
SharedNetwork6Ptr staged_network;
|
||||
|
||||
// SharedNetwork One should have been added from db1 config
|
||||
staged_network = networks->getByName("one");
|
||||
ASSERT_TRUE(staged_network);
|
||||
|
||||
// Subnet2 should have come from the json config
|
||||
staged_network = networks->getByName("two");
|
||||
ASSERT_TRUE(staged_network);
|
||||
|
||||
// Subnet3, which is in db2 should not have been merged.
|
||||
// We queried db1 first and the query returned data. In
|
||||
// other words, we iterate over the backends, asking for
|
||||
// data. We use the first data, we find.
|
||||
staged_network = networks->getByName("three");
|
||||
ASSERT_FALSE(staged_network);
|
||||
}
|
||||
|
||||
// This test verifies that externally configured subnets are
|
||||
// merged correctly into staging configuration.
|
||||
TEST_F(Dhcp6CBTest, mergeSubnets) {
|
||||
string base_config =
|
||||
"{ \n"
|
||||
" \"interfaces-config\": { \n"
|
||||
" \"interfaces\": [\"*\" ] \n"
|
||||
" }, \n"
|
||||
" \"valid-lifetime\": 4000, \n"
|
||||
" \"config-control\": { \n"
|
||||
" \"config-databases\": [ { \n"
|
||||
" \"type\": \"memfile\", \n"
|
||||
" \"host\": \"db1\" \n"
|
||||
" },{ \n"
|
||||
" \"type\": \"memfile\", \n"
|
||||
" \"host\": \"db2\" \n"
|
||||
" } \n"
|
||||
" ] \n"
|
||||
" }, \n"
|
||||
" \"subnet6\": [ \n"
|
||||
" { \n"
|
||||
" \"id\": 2,\n"
|
||||
" \"subnet\": \"192.0.3.0/24\" \n"
|
||||
" } ]\n"
|
||||
"} \n";
|
||||
|
||||
extractConfig(base_config);
|
||||
|
||||
// Make a few subnets
|
||||
Subnet6Ptr subnet1(new Subnet6(IOAddress("192.0.2.0"), 26, 1, 2, 3, SubnetID(1)));
|
||||
Subnet6Ptr subnet3(new Subnet6(IOAddress("192.0.4.0"), 26, 1, 2, 3, SubnetID(3)));
|
||||
|
||||
// Add subnet1 to db1 and subnet3 to db2
|
||||
db1_->createUpdateSubnet6(ServerSelector::ALL(), subnet1);
|
||||
db2_->createUpdateSubnet6(ServerSelector::ALL(), subnet3);
|
||||
|
||||
// Should parse and merge without error.
|
||||
configure(base_config, CONTROL_RESULT_SUCCESS, "");
|
||||
|
||||
// Verify the composite staging is correct. (Remember that
|
||||
// CfgMgr::instance().commit() hasn't been called)
|
||||
|
||||
SrvConfigPtr staging_cfg = CfgMgr::instance().getStagingCfg();
|
||||
|
||||
CfgSubnets6Ptr subnets = staging_cfg->getCfgSubnets6();
|
||||
Subnet6Ptr staged_subnet;
|
||||
|
||||
// Subnet1 should have been added from db1 config
|
||||
staged_subnet = subnets->getSubnet(1);
|
||||
ASSERT_TRUE(staged_subnet);
|
||||
|
||||
// Subnet2 should have come from the json config
|
||||
staged_subnet = subnets->getSubnet(2);
|
||||
ASSERT_TRUE(staged_subnet);
|
||||
|
||||
// Subnet3, which is in db2 should not have been merged, since it is
|
||||
// first found, first used?
|
||||
staged_subnet = subnets->getSubnet(3);
|
||||
ASSERT_FALSE(staged_subnet);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
@ -25,6 +25,7 @@
|
||||
#include <dhcpsrv/subnet.h>
|
||||
#include <dhcpsrv/subnet_selector.h>
|
||||
#include <dhcpsrv/testutils/config_result_check.h>
|
||||
#include <dhcpsrv/testutils/test_config_backend_dhcp6.h>
|
||||
#include <hooks/hooks_manager.h>
|
||||
#include <process/config_ctl_info.h>
|
||||
|
||||
@ -242,6 +243,7 @@ const char* PARSER_CONFIGS[] = {
|
||||
" \"rebind-timer\": 2000, \n"
|
||||
" \"renew-timer\": 1000, \n"
|
||||
" \"config-control\": { \n"
|
||||
" \"config-fetch-wait-time\": 10, \n"
|
||||
" \"config-databases\": [ { \n"
|
||||
" \"type\": \"mysql\", \n"
|
||||
" \"name\": \"keatest1\", \n"
|
||||
@ -6990,7 +6992,12 @@ TEST_F(Dhcp6ParserTest, globalReservations) {
|
||||
// This test verifies that configuration control info gets populated.
|
||||
TEST_F(Dhcp6ParserTest, configControlInfo) {
|
||||
string config = PARSER_CONFIGS[8];
|
||||
extractConfig(config);
|
||||
|
||||
// Should be able to register a backend factory for "mysql".
|
||||
ASSERT_TRUE(TestConfigBackendDHCPv6::
|
||||
registerBackendType(ConfigBackendDHCPv6Mgr::instance(),
|
||||
"mysql"));
|
||||
|
||||
configure(config, CONTROL_RESULT_SUCCESS, "");
|
||||
|
||||
// Make sure the config control info is there.
|
||||
@ -7009,6 +7016,10 @@ TEST_F(Dhcp6ParserTest, configControlInfo) {
|
||||
dblist.front().getAccessString());
|
||||
EXPECT_EQ("name=keatest2 password=keatest type=mysql user=keatest",
|
||||
dblist.back().getAccessString());
|
||||
|
||||
// Verify that the config-fetch-wait-time is correct.
|
||||
EXPECT_FALSE(info->getConfigFetchWaitTime().unspecified());
|
||||
EXPECT_EQ(10, info->getConfigFetchWaitTime().get());
|
||||
}
|
||||
|
||||
// Check whether it is possible to configure server-tag
|
||||
|
@ -1829,32 +1829,6 @@ const char* EXTRACTED_CONFIGS[] = {
|
||||
" }\n"
|
||||
" ],\n"
|
||||
" \"valid-lifetime\": 4000\n"
|
||||
" }\n",
|
||||
// CONFIGURATION 58
|
||||
"{\n"
|
||||
" \"config-control\": {\n"
|
||||
" \"config-databases\": [\n"
|
||||
" {\n"
|
||||
" \"name\": \"keatest1\",\n"
|
||||
" \"password\": \"keatest\",\n"
|
||||
" \"type\": \"mysql\",\n"
|
||||
" \"user\": \"keatest\"\n"
|
||||
" },\n"
|
||||
" {\n"
|
||||
" \"name\": \"keatest2\",\n"
|
||||
" \"password\": \"keatest\",\n"
|
||||
" \"type\": \"mysql\",\n"
|
||||
" \"user\": \"keatest\"\n"
|
||||
" }\n"
|
||||
" ]\n"
|
||||
" },\n"
|
||||
" \"interfaces-config\": {\n"
|
||||
" \"interfaces\": [ \"*\" ],\n"
|
||||
" \"re-detect\": false\n"
|
||||
" },\n"
|
||||
" \"rebind-timer\": 2000,\n"
|
||||
" \"renew-timer\": 1000,\n"
|
||||
" \"valid-lifetime\": 4000\n"
|
||||
" }\n"
|
||||
};
|
||||
|
||||
@ -7717,86 +7691,6 @@ const char* UNPARSED_CONFIGS[] = {
|
||||
" }\n"
|
||||
" ],\n"
|
||||
" \"valid-lifetime\": 4000\n"
|
||||
" }\n",
|
||||
// CONFIGURATION 58
|
||||
"{\n"
|
||||
" \"config-control\": {\n"
|
||||
" \"config-databases\": [\n"
|
||||
" {\n"
|
||||
" \"name\": \"keatest1\",\n"
|
||||
" \"password\": \"keatest\",\n"
|
||||
" \"type\": \"mysql\",\n"
|
||||
" \"user\": \"keatest\"\n"
|
||||
" },\n"
|
||||
" {\n"
|
||||
" \"name\": \"keatest2\",\n"
|
||||
" \"password\": \"keatest\",\n"
|
||||
" \"type\": \"mysql\",\n"
|
||||
" \"user\": \"keatest\"\n"
|
||||
" }\n"
|
||||
" ]\n"
|
||||
" },\n"
|
||||
" \"decline-probation-period\": 86400,\n"
|
||||
" \"dhcp-ddns\": {\n"
|
||||
" \"enable-updates\": false,\n"
|
||||
" \"generated-prefix\": \"myhost\",\n"
|
||||
" \"hostname-char-replacement\": \"\",\n"
|
||||
" \"hostname-char-set\": \"\",\n"
|
||||
" \"max-queue-size\": 1024,\n"
|
||||
" \"ncr-format\": \"JSON\",\n"
|
||||
" \"ncr-protocol\": \"UDP\",\n"
|
||||
" \"override-client-update\": false,\n"
|
||||
" \"override-no-update\": false,\n"
|
||||
" \"qualifying-suffix\": \"\",\n"
|
||||
" \"replace-client-name\": \"never\",\n"
|
||||
" \"sender-ip\": \"0.0.0.0\",\n"
|
||||
" \"sender-port\": 0,\n"
|
||||
" \"server-ip\": \"127.0.0.1\",\n"
|
||||
" \"server-port\": 53001\n"
|
||||
" },\n"
|
||||
" \"dhcp-queue-control\": {\n"
|
||||
" \"capacity\": 500,\n"
|
||||
" \"enable-queue\": false,\n"
|
||||
" \"queue-type\": \"kea-ring6\"\n"
|
||||
" },\n"
|
||||
" \"dhcp4o6-port\": 0,\n"
|
||||
" \"expired-leases-processing\": {\n"
|
||||
" \"flush-reclaimed-timer-wait-time\": 25,\n"
|
||||
" \"hold-reclaimed-time\": 3600,\n"
|
||||
" \"max-reclaim-leases\": 100,\n"
|
||||
" \"max-reclaim-time\": 250,\n"
|
||||
" \"reclaim-timer-wait-time\": 10,\n"
|
||||
" \"unwarned-reclaim-cycles\": 5\n"
|
||||
" },\n"
|
||||
" \"hooks-libraries\": [ ],\n"
|
||||
" \"host-reservation-identifiers\": [ \"hw-address\", \"duid\" ],\n"
|
||||
" \"interfaces-config\": {\n"
|
||||
" \"interfaces\": [ \"*\" ],\n"
|
||||
" \"re-detect\": false\n"
|
||||
" },\n"
|
||||
" \"lease-database\": {\n"
|
||||
" \"type\": \"memfile\"\n"
|
||||
" },\n"
|
||||
" \"mac-sources\": [ \"any\" ],\n"
|
||||
" \"option-data\": [ ],\n"
|
||||
" \"option-def\": [ ],\n"
|
||||
" \"rebind-timer\": 2000,\n"
|
||||
" \"relay-supplied-options\": [ \"65\" ],\n"
|
||||
" \"renew-timer\": 1000,\n"
|
||||
" \"sanity-checks\": {\n"
|
||||
" \"lease-checks\": \"warn\"\n"
|
||||
" },\n"
|
||||
" \"server-id\": {\n"
|
||||
" \"enterprise-id\": 0,\n"
|
||||
" \"htype\": 0,\n"
|
||||
" \"identifier\": \"\",\n"
|
||||
" \"persist\": true,\n"
|
||||
" \"time\": 0,\n"
|
||||
" \"type\": \"LLT\"\n"
|
||||
" },\n"
|
||||
" \"shared-networks\": [ ],\n"
|
||||
" \"subnet6\": [ ],\n"
|
||||
" \"valid-lifetime\": 4000\n"
|
||||
" }\n"
|
||||
};
|
||||
|
||||
|
@ -14,9 +14,11 @@
|
||||
#include <dhcp6/ctrl_dhcp6_srv.h>
|
||||
#include <dhcp6/parser_context.h>
|
||||
#include <dhcp6/tests/dhcp6_test_utils.h>
|
||||
#include <dhcpsrv/cb_ctl_dhcp4.h>
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
#include <dhcpsrv/lease.h>
|
||||
#include <dhcpsrv/lease_mgr_factory.h>
|
||||
#include <process/config_base.h>
|
||||
|
||||
#ifdef HAVE_MYSQL
|
||||
#include <mysql/testutils/mysql_schema.h>
|
||||
@ -25,9 +27,11 @@
|
||||
#include <log/logger_support.h>
|
||||
#include <util/stopwatch.h>
|
||||
|
||||
#include <boost/pointer_cast.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <functional>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
@ -51,10 +55,100 @@ using namespace isc::hooks;
|
||||
|
||||
namespace {
|
||||
|
||||
class NakedControlledDhcpv6Srv: public ControlledDhcpv6Srv {
|
||||
// "Naked" DHCPv6 server, exposes internal fields
|
||||
/// @brief Test implementation of the @c CBControlDHCPv6.
|
||||
///
|
||||
/// This implementation is installed on the test server instance. It
|
||||
/// overrides the implementation of the @c databaseConfigFetch function
|
||||
/// to verify arguments passed to this function and throw an exception
|
||||
/// when desired in the negative test scenarios. It doesn't do the
|
||||
/// actual configuration fetch as this is tested elswhere and would
|
||||
/// require setting up a database configuration backend.
|
||||
class TestCBControlDHCPv6 : public CBControlDHCPv6 {
|
||||
public:
|
||||
NakedControlledDhcpv6Srv():ControlledDhcpv6Srv(0) { }
|
||||
|
||||
/// @brief Constructor.
|
||||
TestCBControlDHCPv6()
|
||||
: CBControlDHCPv6(), db_config_fetch_calls_(0),
|
||||
enable_check_fetch_mode_(false), enable_throw_(false) {
|
||||
}
|
||||
|
||||
/// @brief Stub implementation of the "fetch" function.
|
||||
///
|
||||
/// It checks if the @c fetch_updates_only is set to true when it
|
||||
/// is a later than first invocation of the function. It also
|
||||
/// throws an exception when desired by a test, to verify that the
|
||||
/// server gracefully handles such exception.
|
||||
///
|
||||
/// @param fetch_mode value indicating if the method is called upon the
|
||||
/// server start up or it is called to fetch configuration updates.
|
||||
///
|
||||
/// @throw Unexpected when configured to do so.
|
||||
virtual void databaseConfigFetch(const process::ConfigPtr&,
|
||||
const FetchMode& fetch_mode) {
|
||||
++db_config_fetch_calls_;
|
||||
|
||||
if (enable_check_fetch_mode_) {
|
||||
if ((db_config_fetch_calls_ <= 1) && (fetch_mode == FetchMode::FETCH_UPDATE)) {
|
||||
ADD_FAILURE() << "databaseConfigFetch was called with the value "
|
||||
"of fetch_mode=FetchMode::FETCH_UPDATE upon the server configuration";
|
||||
|
||||
} else if ((db_config_fetch_calls_ > 1) && (fetch_mode == FetchMode::FETCH_ALL)) {
|
||||
ADD_FAILURE() << "databaseConfigFetch was called with the value "
|
||||
"of fetch_mode=FetchMode::FETCH_ALL during fetching the updates";
|
||||
}
|
||||
}
|
||||
|
||||
if (enable_throw_) {
|
||||
isc_throw(Unexpected, "testing if exceptions are corectly handled");
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Returns number of invocations of the @c databaseConfigFetch.
|
||||
size_t getDatabaseConfigFetchCalls() const {
|
||||
return (db_config_fetch_calls_);
|
||||
}
|
||||
|
||||
/// @brief Enables checking of the @c fetch_mode value.
|
||||
void enableCheckFetchMode() {
|
||||
enable_check_fetch_mode_ = true;
|
||||
}
|
||||
|
||||
/// @brief Enables the object to throw from @c databaseConfigFetch.
|
||||
void enableThrow() {
|
||||
enable_throw_ = true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Counter holding number of invocations of the @c databaseConfigFetch.
|
||||
size_t db_config_fetch_calls_;
|
||||
|
||||
/// @brief Boolean flag indicated if the value of the @c fetch_mode
|
||||
/// should be verified.
|
||||
bool enable_check_fetch_mode_;
|
||||
|
||||
/// @brief Boolean flag indicating if the @c databaseConfigFetch should
|
||||
/// throw.
|
||||
bool enable_throw_;
|
||||
};
|
||||
|
||||
/// @brief Shared pointer to the @c TestCBControlDHCPv6.
|
||||
typedef boost::shared_ptr<TestCBControlDHCPv6> TestCBControlDHCPv6Ptr;
|
||||
|
||||
/// @brief "Naked" DHCPv6 server.
|
||||
///
|
||||
/// Exposes internal fields and installs stub implementation of the
|
||||
/// @c CBControlDHCPv6 object.
|
||||
class NakedControlledDhcpv6Srv: public ControlledDhcpv6Srv {
|
||||
public:
|
||||
/// @brief Constructor.
|
||||
NakedControlledDhcpv6Srv()
|
||||
: ControlledDhcpv6Srv(0) {
|
||||
// We're replacing the @c CBControlDHCPv6 instance with our
|
||||
// stub implementation used in tests.
|
||||
cb_control_.reset(new TestCBControlDHCPv6());
|
||||
}
|
||||
|
||||
using ControlledDhcpv6Srv::signal_handler_;
|
||||
};
|
||||
|
||||
@ -85,15 +179,105 @@ public:
|
||||
///
|
||||
/// @param io_service Pointer to the IO service to be ran.
|
||||
/// @param timeout_ms Amount of time after which the method returns.
|
||||
void runTimersWithTimeout(const IOServicePtr& io_service, const long timeout_ms) {
|
||||
/// @param cond Pointer to the function which if returns true it
|
||||
/// stops the IO service and causes the function to return.
|
||||
void runTimersWithTimeout(const IOServicePtr& io_service, const long timeout_ms,
|
||||
std::function<bool()> cond = std::function<bool()>()) {
|
||||
IntervalTimer timer(*io_service);
|
||||
timer.setup([&io_service]() {
|
||||
bool stopped = false;
|
||||
timer.setup([&io_service, &stopped]() {
|
||||
io_service->stop();
|
||||
stopped = true;
|
||||
}, timeout_ms, IntervalTimer::ONE_SHOT);
|
||||
io_service->run();
|
||||
|
||||
// Run as long as the timeout hasn't occurred and the interrupting
|
||||
// condition is not specified or not met.
|
||||
while (!stopped && (!cond || !cond())) {
|
||||
io_service->run_one();
|
||||
}
|
||||
io_service->get_io_service().reset();
|
||||
}
|
||||
|
||||
/// @brief This test verifies that the timer used to fetch the configuration
|
||||
/// updates from the database works as expected.
|
||||
void testConfigBackendTimer(const int config_wait_fetch_time,
|
||||
const bool throw_during_fetch = false) {
|
||||
std::ostringstream config;
|
||||
config <<
|
||||
"{ \"Dhcp6\": {"
|
||||
"\"interfaces-config\": {"
|
||||
" \"interfaces\": [ ]"
|
||||
"},"
|
||||
"\"lease-database\": {"
|
||||
" \"type\": \"memfile\","
|
||||
" \"persist\": false"
|
||||
"},"
|
||||
"\"config-control\": {"
|
||||
" \"config-fetch-wait-time\": " << config_wait_fetch_time <<
|
||||
"},"
|
||||
"\"rebind-timer\": 2000, "
|
||||
"\"renew-timer\": 1000, \n"
|
||||
"\"subnet6\": [ ],"
|
||||
"\"valid-lifetime\": 4000 }"
|
||||
"}";
|
||||
writeFile(TEST_FILE, config.str());
|
||||
|
||||
// Create an instance of the server and initialize it.
|
||||
boost::scoped_ptr<NakedControlledDhcpv6Srv> srv;
|
||||
ASSERT_NO_THROW(srv.reset(new NakedControlledDhcpv6Srv()));
|
||||
ASSERT_NO_THROW(srv->init(TEST_FILE));
|
||||
|
||||
// Get the CBControlDHCPv6 object belonging to this server.
|
||||
auto cb_control = boost::dynamic_pointer_cast<TestCBControlDHCPv6>(srv->getCBControl());
|
||||
|
||||
// Verify that the parameter passed to the databaseConfigFetch has an
|
||||
// expected value.
|
||||
cb_control->enableCheckFetchMode();
|
||||
|
||||
// Instruct our stub implementation of the CBControlDHCPv6 to throw as a
|
||||
// result of fetch if desired.
|
||||
if (throw_during_fetch) {
|
||||
cb_control->enableThrow();
|
||||
}
|
||||
|
||||
// So far there should be exactly one attempt to fetch the configuration
|
||||
// from the backend. That's the attempt made upon startup.
|
||||
EXPECT_EQ(1, cb_control->getDatabaseConfigFetchCalls());
|
||||
|
||||
|
||||
if ((config_wait_fetch_time > 0) && (!throw_during_fetch)) {
|
||||
// If we're configured to run the timer, we expect that it was
|
||||
// invoked at least 3 times. This is sufficient to verify that
|
||||
// the timer was scheduled and that the timer continued to run
|
||||
// even when an exception occurred during fetch (that's why it
|
||||
// is 3 not 2).
|
||||
ASSERT_NO_THROW(runTimersWithTimeout(srv->getIOService(), 500,
|
||||
[cb_control]() {
|
||||
// Interrupt the timers poll if we have recorded at
|
||||
// least 3 attempts to fetch the updates.
|
||||
return (cb_control->getDatabaseConfigFetchCalls() >= 3);
|
||||
}));
|
||||
EXPECT_GE(cb_control->getDatabaseConfigFetchCalls(), 3);
|
||||
|
||||
} else {
|
||||
ASSERT_NO_THROW(runTimersWithTimeout(srv->getIOService(), 500));
|
||||
|
||||
if (throw_during_fetch) {
|
||||
// If we're simulating the failure condition the number
|
||||
// of consecutive failures should not exceed 10. Therefore
|
||||
// the number of recorded fetches should be 12. One at
|
||||
// startup, 10 failures and one that causes the timer
|
||||
// to stop.
|
||||
EXPECT_EQ(12, cb_control->getDatabaseConfigFetchCalls());
|
||||
|
||||
} else {
|
||||
// If the server is not configured to schedule the timer,
|
||||
// we should still have one fetch attempt recorded.
|
||||
EXPECT_EQ(1, cb_control->getDatabaseConfigFetchCalls());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char* TEST_FILE;
|
||||
static const char* TEST_INCLUDE;
|
||||
};
|
||||
@ -635,6 +819,29 @@ TEST_F(JSONFileBackendTest, defaultLeaseDbBackend) {
|
||||
EXPECT_NO_THROW(static_cast<void>(LeaseMgrFactory::instance()));
|
||||
}
|
||||
|
||||
|
||||
// This test verifies that the timer triggering configuration updates
|
||||
// is invoked according to the configured value of the
|
||||
// config-fetch-wait-time.
|
||||
TEST_F(JSONFileBackendTest, configBackendTimer) {
|
||||
testConfigBackendTimer(1);
|
||||
}
|
||||
|
||||
// This test verifies that the timer for triggering configuration updates
|
||||
// is not invoked when the value of the config-fetch-wait-time is set
|
||||
// to 0.
|
||||
TEST_F(JSONFileBackendTest, configBackendTimerDisabled) {
|
||||
testConfigBackendTimer(0);
|
||||
}
|
||||
|
||||
// This test verifies that the server will gracefully handle exceptions
|
||||
// thrown from the CBControlDHCPv6::databaseConfigFetch, i.e. will
|
||||
// reschedule the timer.
|
||||
TEST_F(JSONFileBackendTest, configBackendTimerWithThrow) {
|
||||
// The true value instructs the test to throw during the fetch.
|
||||
testConfigBackendTimer(1, true);
|
||||
}
|
||||
|
||||
// Starting tests which require MySQL backend availability. Those tests
|
||||
// will not be executed if Kea has been compiled without the
|
||||
// --with-mysql.
|
||||
|
@ -68,6 +68,7 @@ libkea_dhcpsrv_la_SOURCES += cache_host_data_source.h
|
||||
libkea_dhcpsrv_la_SOURCES += callout_handle_store.h
|
||||
libkea_dhcpsrv_la_SOURCES += cb_ctl_dhcp.h
|
||||
libkea_dhcpsrv_la_SOURCES += cb_ctl_dhcp4.cc cb_ctl_dhcp4.h
|
||||
libkea_dhcpsrv_la_SOURCES += cb_ctl_dhcp6.cc cb_ctl_dhcp6.h
|
||||
libkea_dhcpsrv_la_SOURCES += cfg_4o6.cc cfg_4o6.h
|
||||
libkea_dhcpsrv_la_SOURCES += cfg_consistency.cc cfg_consistency.h
|
||||
libkea_dhcpsrv_la_SOURCES += cfg_db_access.cc cfg_db_access.h
|
||||
|
85
src/lib/dhcpsrv/cb_ctl_dhcp6.cc
Normal file
85
src/lib/dhcpsrv/cb_ctl_dhcp6.cc
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <config.h>
|
||||
#include <dhcpsrv/cb_ctl_dhcp6.h>
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
#include <dhcpsrv/dhcpsrv_log.h>
|
||||
|
||||
using namespace isc::data;
|
||||
using namespace isc::process;
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
void
|
||||
CBControlDHCPv6::databaseConfigApply(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const boost::posix_time::ptime& lb_modification_time,
|
||||
const db::AuditEntryCollection& audit_entries) {
|
||||
// Create the external config into which we'll fetch backend config data.
|
||||
SrvConfigPtr external_cfg = CfgMgr::instance().createExternalCfg();
|
||||
|
||||
// First let's fetch the globals and add them to external config.
|
||||
if (fetchConfigElement(audit_entries, "dhcp6_global_parameter")) {
|
||||
data::StampedValueCollection globals;
|
||||
globals = getMgr().getPool()->getModifiedGlobalParameters6(backend_selector, server_selector,
|
||||
lb_modification_time);
|
||||
addGlobalsToConfig(external_cfg, globals);
|
||||
}
|
||||
|
||||
// Now we fetch the option definitions and add them.
|
||||
if (fetchConfigElement(audit_entries, "dhcp6_option_def")) {
|
||||
OptionDefContainer option_defs =
|
||||
getMgr().getPool()->getModifiedOptionDefs6(backend_selector, server_selector,
|
||||
lb_modification_time);
|
||||
for (auto option_def = option_defs.begin(); option_def != option_defs.end(); ++option_def) {
|
||||
external_cfg->getCfgOptionDef()->add((*option_def), (*option_def)->getOptionSpaceName());
|
||||
}
|
||||
}
|
||||
|
||||
// Next fetch the options. They are returned as a container of OptionDescriptors.
|
||||
if (fetchConfigElement(audit_entries, "dhcp6_options")) {
|
||||
OptionContainer options = getMgr().getPool()->getModifiedOptions6(backend_selector,
|
||||
server_selector,
|
||||
lb_modification_time);
|
||||
for (auto option = options.begin(); option != options.end(); ++option) {
|
||||
external_cfg->getCfgOption()->add((*option), (*option).space_name_);
|
||||
}
|
||||
}
|
||||
|
||||
// Now fetch the shared networks.
|
||||
if (fetchConfigElement(audit_entries, "dhcp6_shared_network")) {
|
||||
SharedNetwork6Collection networks =
|
||||
getMgr().getPool()->getModifiedSharedNetworks6(backend_selector, server_selector,
|
||||
lb_modification_time);
|
||||
for (auto network = networks.begin(); network != networks.end(); ++network) {
|
||||
external_cfg->getCfgSharedNetworks6()->add((*network));
|
||||
}
|
||||
}
|
||||
|
||||
// Next we fetch subnets.
|
||||
if (fetchConfigElement(audit_entries, "dhcp6_subnet")) {
|
||||
Subnet6Collection subnets = getMgr().getPool()->getModifiedSubnets6(backend_selector,
|
||||
server_selector,
|
||||
lb_modification_time);
|
||||
for (auto subnet = subnets.begin(); subnet != subnets.end(); ++subnet) {
|
||||
external_cfg->getCfgSubnets6()->add((*subnet));
|
||||
}
|
||||
}
|
||||
|
||||
if (audit_entries.empty()) {
|
||||
CfgMgr::instance().mergeIntoStagingCfg(external_cfg->getSequence());
|
||||
|
||||
} else {
|
||||
CfgMgr::instance().mergeIntoCurrentCfg(external_cfg->getSequence());
|
||||
}
|
||||
LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_CONFIG6_MERGED);
|
||||
}
|
||||
|
||||
|
||||
} // end of namespace isc::dhcp
|
||||
} // end of namespace isc
|
50
src/lib/dhcpsrv/cb_ctl_dhcp6.h
Normal file
50
src/lib/dhcpsrv/cb_ctl_dhcp6.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (C) 2019 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef CB_CTL_DHCP6_H
|
||||
#define CB_CTL_DHCP6_H
|
||||
|
||||
#include <dhcpsrv/cb_ctl_dhcp.h>
|
||||
#include <dhcpsrv/config_backend_dhcp6_mgr.h>
|
||||
#include <dhcpsrv/srv_config.h>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
/// @brief Implementation of the mechanisms to control the use of
|
||||
/// the Configuration Backends by the DHCPv6 server.
|
||||
///
|
||||
/// It implements fetching and merging DHCPv6 server configuration from
|
||||
/// the database into the staging or current configuration.
|
||||
///
|
||||
/// @tparam ConfigBackendMgrType Type of the Config Backend Manager used
|
||||
/// by the server implementing this class. For example, for the DHCPv6
|
||||
/// server it will be @c ConfigBackendDHCPv6Mgr.
|
||||
class CBControlDHCPv6 : public CBControlDHCP<ConfigBackendDHCPv6Mgr> {
|
||||
protected:
|
||||
|
||||
/// @brief DHCPv6 server specific method to fetch and apply back end
|
||||
/// configuration into the local configuration.
|
||||
///
|
||||
/// @param backend_selector Backend selector.
|
||||
/// @param server_selector Server selector.
|
||||
/// @param lb_modification_time Lower bound modification time for the
|
||||
/// configuration elements to be fetched.
|
||||
/// @param audit_entries Audit entries fetched from the database since
|
||||
/// the last configuration update. This collection is empty if there
|
||||
/// were no updates.
|
||||
virtual void databaseConfigApply(const db::BackendSelector& backend_selector,
|
||||
const db::ServerSelector& server_selector,
|
||||
const boost::posix_time::ptime& lb_modification_time,
|
||||
const db::AuditEntryCollection& audit_entries);
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<CBControlDHCPv6> CBControlDHCPv6Ptr;
|
||||
|
||||
} // end of namespace isc::dhcp
|
||||
} // end of namespace isc
|
||||
|
||||
#endif // CB_CTL_DHCP6_H
|
@ -1,4 +1,4 @@
|
||||
// File created from ../../../src/lib/dhcpsrv/dhcpsrv_messages.mes on Tue Mar 19 2019 10:19
|
||||
// File created from ../../../src/lib/dhcpsrv/dhcpsrv_messages.mes on Tue Mar 26 2019 13:08
|
||||
|
||||
#include <cstddef>
|
||||
#include <log/message_types.h>
|
||||
@ -14,6 +14,7 @@ extern const isc::log::MessageID DHCPSRV_CFGMGR_ALL_IFACES_ACTIVE = "DHCPSRV_CFG
|
||||
extern const isc::log::MessageID DHCPSRV_CFGMGR_CFG_DHCP_DDNS = "DHCPSRV_CFGMGR_CFG_DHCP_DDNS";
|
||||
extern const isc::log::MessageID DHCPSRV_CFGMGR_CLEAR_ACTIVE_IFACES = "DHCPSRV_CFGMGR_CLEAR_ACTIVE_IFACES";
|
||||
extern const isc::log::MessageID DHCPSRV_CFGMGR_CONFIG4_MERGED = "DHCPSRV_CFGMGR_CONFIG4_MERGED";
|
||||
extern const isc::log::MessageID DHCPSRV_CFGMGR_CONFIG6_MERGED = "DHCPSRV_CFGMGR_CONFIG6_MERGED";
|
||||
extern const isc::log::MessageID DHCPSRV_CFGMGR_CONFIGURE_SERVERID = "DHCPSRV_CFGMGR_CONFIGURE_SERVERID";
|
||||
extern const isc::log::MessageID DHCPSRV_CFGMGR_DEL_SUBNET4 = "DHCPSRV_CFGMGR_DEL_SUBNET4";
|
||||
extern const isc::log::MessageID DHCPSRV_CFGMGR_DEL_SUBNET6 = "DHCPSRV_CFGMGR_DEL_SUBNET6";
|
||||
@ -245,6 +246,7 @@ const char* values[] = {
|
||||
"DHCPSRV_CFGMGR_CFG_DHCP_DDNS", "Setting DHCP-DDNS configuration to: %1",
|
||||
"DHCPSRV_CFGMGR_CLEAR_ACTIVE_IFACES", "stop listening on all interfaces",
|
||||
"DHCPSRV_CFGMGR_CONFIG4_MERGED", "Configuration backend data has been merged.",
|
||||
"DHCPSRV_CFGMGR_CONFIG6_MERGED", "Configuration backend data has been merged.",
|
||||
"DHCPSRV_CFGMGR_CONFIGURE_SERVERID", "server configuration includes specification of a server identifier",
|
||||
"DHCPSRV_CFGMGR_DEL_SUBNET4", "IPv4 subnet %1 removed",
|
||||
"DHCPSRV_CFGMGR_DEL_SUBNET6", "IPv6 subnet %1 removed",
|
||||
|
@ -1,4 +1,4 @@
|
||||
// File created from ../../../src/lib/dhcpsrv/dhcpsrv_messages.mes on Tue Mar 19 2019 10:19
|
||||
// File created from ../../../src/lib/dhcpsrv/dhcpsrv_messages.mes on Tue Mar 26 2019 13:08
|
||||
|
||||
#ifndef DHCPSRV_MESSAGES_H
|
||||
#define DHCPSRV_MESSAGES_H
|
||||
@ -15,6 +15,7 @@ extern const isc::log::MessageID DHCPSRV_CFGMGR_ALL_IFACES_ACTIVE;
|
||||
extern const isc::log::MessageID DHCPSRV_CFGMGR_CFG_DHCP_DDNS;
|
||||
extern const isc::log::MessageID DHCPSRV_CFGMGR_CLEAR_ACTIVE_IFACES;
|
||||
extern const isc::log::MessageID DHCPSRV_CFGMGR_CONFIG4_MERGED;
|
||||
extern const isc::log::MessageID DHCPSRV_CFGMGR_CONFIG6_MERGED;
|
||||
extern const isc::log::MessageID DHCPSRV_CFGMGR_CONFIGURE_SERVERID;
|
||||
extern const isc::log::MessageID DHCPSRV_CFGMGR_DEL_SUBNET4;
|
||||
extern const isc::log::MessageID DHCPSRV_CFGMGR_DEL_SUBNET6;
|
||||
|
@ -36,6 +36,11 @@ This is an informational message emitted when the DHCPv4 server has
|
||||
successfully merged configuration data retrieved from its configuration
|
||||
backends into the current configuration.
|
||||
|
||||
% DHCPSRV_CFGMGR_CONFIG6_MERGED Configuration backend data has been merged.
|
||||
This is an informational message emitted when the DHCPv6 server has
|
||||
successfully merged configuration data retrieved from its configuration
|
||||
backends into the current configuration.
|
||||
|
||||
% DHCPSRV_CFGMGR_CONFIGURE_SERVERID server configuration includes specification of a server identifier
|
||||
This warning message is issued when the server specified configuration of
|
||||
a server identifier. If this new configuration overrides an existing
|
||||
|
Loading…
x
Reference in New Issue
Block a user