Commit f5fe96c6 authored by Thomas Markwalder's avatar Thomas Markwalder

[#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_pa...
parent 62ad7da5
......@@ -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
// 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
......
This diff is collapsed.
......@@ -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_) {
......
// 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",
......
// 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.
......
This diff is collapsed.
This diff is collapsed.
......@@ -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);
......
// 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());
......
// 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
......
// 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".
......
// 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.
......
// 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"