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

[3399] Kea configuration backend for DHCPv4

parent ab261756
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
#include <asiolink/asiolink.h>
#include <dhcp/iface_mgr.h>
#include <dhcpsrv/dhcp_config_parser.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcp4/json_config_parser.h>
#include <dhcp4/ctrl_dhcp4_srv.h>
#include <dhcp4/dhcp4_log.h>
#include <dhcp4/spec_config.h>
#include <log/logger_level.h>
#include <log/logger_name.h>
#include <log/logger_manager.h>
#include <log/logger_specification.h>
#include <log/logger_support.h>
#include <log/output_option.h>
#include <exceptions/exceptions.h>
#include <util/buffer.h>
#include <cassert>
#include <iostream>
#include <string>
#include <vector>
using namespace isc::asiolink;
using namespace isc::cc;
using namespace isc::config;
using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::log;
using namespace isc::util;
using namespace std;
namespace isc {
namespace dhcp {
void
ControlledDhcpv4Srv::init(const std::string& file_name) {
// This is a configuration backend implementation that reads the
// configuration from a JSON file.
isc::data::ConstElementPtr json;
isc::data::ConstElementPtr dhcp4;
isc::data::ConstElementPtr result;
// Basic sanity check: file name must not be empty.
try {
if (file_name.empty()) {
// Basic sanity check: file name must not be empty.
isc_throw(BadValue, "JSON configuration file not specified. Please "
"use -c command line option.");
}
// Read contents of the file and parse it as JSON
json = Element::fromJSONFile(file_name, true);
if (!json) {
LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL)
.arg("Config file " + file_name + " missing or empty.");
isc_throw(BadValue, "Unable to process JSON configuration file:"
+ file_name);
}
// Get Dhcp4 component from the config
dhcp4 = json->get("Dhcp4");
if (!dhcp4) {
LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL)
.arg("Config file " + file_name + " does not include 'Dhcp4' entry.");
isc_throw(BadValue, "Unable to process JSON configuration file:"
+ file_name);
}
// Use parsed JSON structures to configure the server
result = processCommand("config-reload", dhcp4);
} catch (const std::exception& ex) {
LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL).arg(ex.what());
isc_throw(BadValue, "Unable to process JSON configuration file:"
+ file_name);
}
if (!result) {
// Undetermined status of the configuration. This should never happen,
// but as the configureDhcp4Server returns a pointer, it is theoretically
// possible that it will return NULL.
LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL)
.arg("Configuration failed: Undefined result of configureDhcp4Server"
"() function after attempting to read " + file_name);
return;
}
// Now check is the returned result is successful (rcode=0) or not
ConstElementPtr comment; /// see @ref isc::config::parseAnswer
int rcode;
comment = parseAnswer(rcode, result);
if (rcode != 0) {
string reason = "";
if (comment) {
reason = string(" (") + comment->stringValue() + string(")");
}
LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL).arg(reason);
isc_throw(BadValue, "Failed to apply configuration:" << reason);
}
// We don't need to call openActiveSockets() or startD2() as these
// methods are called in processConfig() which is called by
// processCommand("reload-config", ...)
}
void ControlledDhcpv4Srv::cleanup() {
// Nothing to do here. No need to disconnect from anything.
}
/// This is a logger initialization for JSON file backend.
/// For now, it's just setting log messages to be printed on stdout.
/// @todo: Implement this properly (see #3427)
void Daemon::loggerInit(const char*, bool verbose, bool ) {
setenv("B10_LOCKFILE_DIR_FROM_BUILD", "/tmp", 1);
setenv("B10_LOGGER_ROOT", "kea", 0);
setenv("B10_LOGGER_SEVERITY", (verbose ? "DEBUG":"INFO"), 0);
setenv("B10_LOGGER_DBGLEVEL", "99", 0);
setenv("B10_LOGGER_DESTINATION", "stdout", 0);
isc::log::initLogger();
}
};
};
......@@ -16,7 +16,7 @@
#include <config/ccsession.h>
#include <dhcp/dhcp4.h>
#include <dhcp6/ctrl_dhcp4_srv.h>
#include <dhcp4/ctrl_dhcp4_srv.h>
#include <dhcpsrv/cfgmgr.h>
#include <boost/scoped_ptr.hpp>
......@@ -73,7 +73,7 @@ const char* JSONFileBackendTest::TEST_FILE = "test-config.json";
TEST_F(JSONFileBackendTest, jsonFile) {
// Prepare configuration file.
string config = "{ \"interfaces\": [ \"*\" ],"
string config = "{ \"Dhcp4\": { \"interfaces\": [ \"*\" ],"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet4\": [ { "
......@@ -89,7 +89,8 @@ TEST_F(JSONFileBackendTest, jsonFile) {
" \"pool\": [ \"192.0.4.101 - 192.0.4.150\" ],"
" \"subnet\": \"192.0.4.0/24\" "
" } ],"
"\"valid-lifetime\": 4000 }";
"\"valid-lifetime\": 4000 }"
"}";
writeFile(TEST_FILE, config);
......@@ -138,7 +139,7 @@ TEST_F(JSONFileBackendTest, jsonFile) {
const PoolCollection& pools3 = subnets->at(2)->getPools(Lease::TYPE_V4);
EXPECT_EQ("192.0.4.101", pools3.at(0)->getFirstAddress().toText());
EXPECT_EQ("192.0.4.150", pools3.at(0)->getLastAddress().toText());
EXPECT_EQ(Lease::TYPE_NA, pools3.at(0)->getType());
EXPECT_EQ(Lease::TYPE_V4, pools3.at(0)->getType());
}
// This test checks if configuration can be read from a JSON file.
......@@ -181,11 +182,11 @@ TEST_F(JSONFileBackendTest, comments) {
EXPECT_EQ(22, subnets->at(0)->get().second);
// Check pools in the first subnet.
const PoolCollection& pools1 = subnets->at(0)->getPools(Lease::TYPE_NA);
const PoolCollection& pools1 = subnets->at(0)->getPools(Lease::TYPE_V4);
ASSERT_EQ(1, pools1.size());
EXPECT_EQ("192.0.2.0", pools1.at(0)->getFirstAddress().toText());
EXPECT_EQ("192.0.2.255", pools1.at(0)->getLastAddress().toText());
EXPECT_EQ(Lease::TYPE_NA, pools1.at(0)->getType());
EXPECT_EQ(Lease::TYPE_V4, pools1.at(0)->getType());
}
// This test checks if configuration detects failure when trying:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment