2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-31 05:55:28 +00:00

[#101,!202] Interrim commit - v4 fetch and merge functional

Server fetches config, populates external SrvConfig and invokes
merge. libdhcpsrv still lacks merging of globals,opt defs,options,
and shared networks.

src/bin/dhcp4/json_config_parser.*
    configureDhcp4Server() - restored call to databaseConfigFetch()
    databaseConfigFetch(const SrvConfigPtr& srv_cfg) - completed
    implementation, now fetches external config and invokes merge

    addGlobalsToConfig()
    handleExplicitGlobal()
    handleImplicitGlobal() - new functions for populating external
    config globals with backend globals

src/bin/dhcp4/tests
    config_backend_unittest.cc - new file that tests config fetch and merge

src/lib/cc/stamped_value.*
    StampedValue::toElement(Element::types elem_type) - new method for
    creating Elements from StampedValues

src/lib/cc/tests/stamped_value_unittest.cc
    TEST(StampedValueTest, toElement) - new test

src/lib/dhcpsrv/testutils/test_config_backend.h
    TestConfigBackend() - fixed host_ assignment
This commit is contained in:
Thomas Markwalder
2019-01-24 10:16:19 -05:00
parent 71c92cab57
commit dc74694de3
9 changed files with 726 additions and 33 deletions

View File

@@ -8,6 +8,8 @@
#include <cc/command_interpreter.h>
#include <database/dbaccess_parser.h>
#include <database/backend_selector.h>
#include <database/server_selector.h>
#include <dhcp4/dhcp4_log.h>
#include <dhcp4/dhcp4_srv.h>
#include <dhcp4/json_config_parser.h>
@@ -54,6 +56,7 @@ using namespace isc::asiolink;
using namespace isc::hooks;
using namespace isc::process;
using namespace isc::config;
using namespace isc::db;
namespace {
@@ -291,6 +294,7 @@ void configureCommandChannel() {
}
}
isc::data::ConstElementPtr
configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
bool check_only) {
@@ -618,10 +622,8 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
CfgMgr::instance().getStagingCfg()->getHooksConfig();
libraries.loadLibraries();
#ifdef CONFIG_BACKEND // Disabled until we restart CB work
// If there are config backends, fetch and merge into staging config
databaseConfigFetch(srv_cfg, mutable_cfg);
#endif
databaseConfigFetch(srv_cfg);
}
catch (const isc::Exception& ex) {
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(ex.what());
@@ -654,6 +656,62 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
return (answer);
}
void databaseConfigFetch(const SrvConfigPtr& srv_cfg) {
ConfigBackendDHCPv4Mgr& mgr = ConfigBackendDHCPv4Mgr::instance();
// Close any existing CB databasess, then open all in srv_cfg (if any)
if (!databaseConfigConnect(srv_cfg)) {
// There are no CB databases so we're done
return;
}
// For now we find data based on first backend that has it.
BackendSelector backend_selector(BackendSelector::Type::UNSPEC);
// Use the server_tag if set, otherwise use ALL.
std::string server_tag = srv_cfg->getServerTag();
ServerSelector& server_selector = (server_tag.empty()? ServerSelector::ALL()
: ServerSelector::ONE(server_tag));
// 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.
data::StampedValueCollection globals;
globals = mgr.getPool()->getAllGlobalParameters4(backend_selector, server_selector);
addGlobalsToConfig(external_cfg, globals);
// Now we fetch the option definitions and add them.
OptionDefContainer option_defs = mgr.getPool()->getAllOptionDefs4(backend_selector,
server_selector);
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.
OptionContainer options = mgr.getPool()->getAllOptions4(backend_selector, server_selector);
for (auto option = options.begin(); option != options.end(); ++option) {
external_cfg->getCfgOption()->add((*option), (*option).space_name_);
}
// Now fetch the shared networks.
SharedNetwork4Collection networks = mgr.getPool()->getAllSharedNetworks4(backend_selector,
server_selector);
for (auto network = networks.begin(); network != networks.end(); ++network) {
external_cfg->getCfgSharedNetworks4()->add((*network));
}
// Next we fetch subnets.
Subnet4Collection subnets = mgr.getPool()->getAllSubnets4(backend_selector, server_selector);
for (auto subnet = subnets.begin(); subnet != subnets.end(); ++subnet) {
external_cfg->getCfgSubnets4()->add((*subnet));
}
// Now we merge the fecthed configuration into the staging configuration.
// Probably a good place for a log message
CfgMgr::instance().mergeIntoStagingCfg(external_cfg->getSequence());
}
bool databaseConfigConnect(const SrvConfigPtr& srv_cfg) {
// We need to get rid of any existing backends. These would be any
// opened by previous configuration cycle.
@@ -678,25 +736,72 @@ bool databaseConfigConnect(const SrvConfigPtr& srv_cfg) {
return (true);
}
void databaseConfigFetch(const SrvConfigPtr& srv_cfg, ElementPtr /* mutable_cfg */) {
// Close any existing CB databasess, then open all in srv_cfg (if any)
if (!databaseConfigConnect(srv_cfg)) {
// There are no CB databases so we're done
return;
void addGlobalsToConfig(SrvConfigPtr external_cfg, data::StampedValueCollection& cb_globals) {
const auto& index = cb_globals.get<StampedValueNameIndexTag>();
for (auto cb_global = index.begin(); cb_global != index.end(); ++cb_global) {
// If the global is an explicit member of SrvConfig handle it that way.
if (handleExplicitGlobal(external_cfg, (*cb_global))) {
continue;
}
// Otherwise it must be added to the implicitly configured globals
if (handleImplicitGlobal(external_cfg, (*cb_global))) {
continue;
}
isc_throw (DhcpConfigError, "Config backend supplied unsupported global: " <<
(*cb_global)->getName() << " = " << (*cb_global)->getValue());
}
// @todo Fetching and merging the configuration falls under #99
// ConfigBackendDHCPv4Mgr& mgr = ConfigBackendDHCPv4Mgr::instance();
// Next we have to fetch the pieces we care about it and merge them
// probably in this order?
// globals
// option defs
// options
// shared networks
// subnets
}
bool handleExplicitGlobal(SrvConfigPtr external_cfg, const data::StampedValuePtr& cb_global) {
bool was_handled = true;
try {
const std::string& name = cb_global->getName();
if (name == "decline-probation-period") {
external_cfg->setDeclinePeriod(cb_global->getSignedIntegerValue());
}
else if (name == "echo-client-id") {
external_cfg->setEchoClientId(cb_global->getValue() == "true" ? true : false);
} else {
was_handled = false;
}
} catch(const std::exception& ex) {
isc_throw (BadValue, "Invalid value:" << cb_global->getValue()
<< " explict global:" << cb_global->getName());
}
return (was_handled);
}
bool handleImplicitGlobal(SrvConfigPtr external_cfg, const data::StampedValuePtr& cb_global) {
// @todo One day we convert it based on the type stored in StampedValue, but
// that day is not today. For now, if we find it in the global defaults use
// the element type there.
for (auto global_default : SimpleParser4::GLOBAL4_DEFAULTS) {
if (global_default.name_ == cb_global->getName()) {
ElementPtr element = cb_global->toElement(global_default.type_);
external_cfg->addConfiguredGlobal(cb_global->getName(), element);
return (true);
}
}
// We didn't find it in the default list, so is it an optional implicit?
const std::string& name = cb_global->getName();
if ((name == "renew-timer") ||
(name == "rebind-timer")) {
ElementPtr element = cb_global->toElement(Element::integer);
external_cfg->addConfiguredGlobal(cb_global->getName(), element);
return (true);
}
return (false);
}
}; // end of isc::dhcp namespace
}; // end of isc namespace