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

[3770_rebase] Implemented logic checks for DHCPv6

parent 7433650c
......@@ -153,6 +153,9 @@ main(int argc, char* argv[]) {
}
ControlledDhcpv4Srv server(0);
ConstElementPtr answer;
// Now we pass the Dhcp4 configuration to the server, but
// tell it to check the configuration only (check_only = true)
answer = configureDhcp4Server(server, dhcp4, true);
int status_code = 0;
......
......@@ -612,7 +612,9 @@ void configureCommandChannel() {
}
isc::data::ConstElementPtr
configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set,
bool check_only) {
if (!config_set) {
ConstElementPtr answer = isc::config::createAnswer(1,
string("Can't parse NULL config"));
......@@ -807,9 +809,6 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
<< " (" << config_pair.second->getPosition() << ")");
}
// Setup the command channel.
configureCommandChannel();
// Apply global options in the staging config.
Dhcp6ConfigParser global_parser;
global_parser.parse(srv_config, mutable_cfg);
......@@ -830,6 +829,15 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
rollback = true;
}
if (check_only) {
rollback = true;
if (!answer) {
answer = isc::config::createAnswer(0,
"Configuration seems sane. Control-socket, hook-libraries, and D2 "
"configuration were sanity checked, but not applied.");
}
}
// So far so good, there was no parsing error so let's commit the
// configuration. This will add created subnets and option values into
// the server's configuration.
......@@ -837,6 +845,9 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
if (!rollback) {
try {
// Setup the command channel.
configureCommandChannel();
// No need to commit interface names as this is handled by the
// CfgMgr::commit() function.
......
......@@ -24,6 +24,10 @@ class Dhcpv6Srv;
/// extra parameter is a reference to DHCPv6 server component. It is currently
/// not used and CfgMgr::instance() is accessed instead.
///
/// Test-only mode is supported. If check_only flag is set to true, the
/// configuration is parsed, but the actual change is not applied. The goal is
/// to have the ability to test configuration.
///
/// This method does not throw. It catches all exceptions and returns them as
/// reconfiguration statuses. It may return the following response codes:
/// 0 - configuration successful
......@@ -36,7 +40,8 @@ class Dhcpv6Srv;
/// @return answer that contains result of the reconfiguration.
/// @throw Dhcp6ConfigError if trying to create a parser for NULL config.
isc::data::ConstElementPtr
configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set);
configureDhcp6Server(Dhcpv6Srv& server, isc::data::ConstElementPtr config_set,
bool check_only = false);
}; // end of isc::dhcp namespace
}; // end of isc namespace
......
......@@ -9,6 +9,7 @@
#include <dhcp6/ctrl_dhcp6_srv.h>
#include <dhcp6/dhcp6_log.h>
#include <dhcp6/parser_context.h>
#include <dhcp6/json_config_parser.h>
#include <dhcpsrv/cfgmgr.h>
#include <log/logger_support.h>
#include <log/logger_manager.h>
......@@ -128,6 +129,13 @@ main(int argc, char* argv[]) {
if (check_mode) {
try {
// We need to initialize logging, in case any error messages are to be printed.
// This is just a test, so we don't care about lockfile.
setenv("KEA_LOCKFILE_DIR", "none", 0);
CfgMgr::instance().setDefaultLoggerName(DHCP6_ROOT_LOGGER_NAME);
Daemon::loggerInit(DHCP6_ROOT_LOGGER_NAME, verbose_mode);
// Check the syntax first.
Parser6Context parser;
ConstElementPtr json;
json = parser.parseFile(config_file, Parser6Context::PARSER_DHCP6);
......@@ -138,6 +146,30 @@ main(int argc, char* argv[]) {
if (verbose_mode) {
cerr << "Syntax check OK" << endl;
}
// Check the logic next.
ConstElementPtr dhcp6 = json->get("Dhcp6");
if (!dhcp6) {
cerr << "Missing mandatory Dhcp6 element" << endl;
return (EXIT_FAILURE);
}
ControlledDhcpv6Srv server(0);
ConstElementPtr answer;
// Now we pass the Dhcp6 configuration to the server, but
// tell it to check the configuration only (check_only = true)
answer = configureDhcp6Server(server, dhcp6, true);
int status_code = 0;
answer = isc::config::parseAnswer(status_code, answer);
if (status_code == 0) {
return (EXIT_SUCCESS);
} else {
cerr << "Error encountered: " << answer->stringValue() << endl;
return (EXIT_FAILURE);
}
return (EXIT_SUCCESS);
} catch (const std::exception& ex) {
cerr << "Syntax check failed with " << ex.what() << endl;
......
......@@ -60,6 +60,9 @@ CONFIG="{
}
}"
# Invalid configuration (syntax error) to check that Kea can check syntax.
# This config has following errors:
# - it should be interfaces-config/interfaces, not interfaces
# - it should be subnet6/pools, no subnet6/pool
CONFIG_BAD_SYNTAX="{
\"Dhcp6\":
{
......@@ -135,6 +138,41 @@ CONFIG_INVALID="{
}
}"
# This config has bad pool values. The pool it out of scope for the subnet
# it is defined in. Syntactically the config is correct, though.
CONFIG_BAD_VALUES="{
\"Dhcp6\":
{ \"interfaces-config\": {
\"interfaces\": [ ]
},
\"server-id\": {
\"type\": \"LLT\",
\"persist\": false
},
\"preferred-lifetime\": 3000,
\"valid-lifetime\": 4000,
\"renew-timer\": 1000,
\"rebind-timer\": 2000,
\"lease-database\":
{
\"type\": \"memfile\",
\"name\": \"$LEASE_FILE\",
\"persist\": false,
\"lfc-interval\": 0
},
\"subnet6\": [
{
\"subnet\": \"2001:db8::/64\",
\"pools\": [ { \"pool\": \"3000::-3000::ffff\" } ]
} ],
\"dhcp-ddns\": {
\"enable-updates\": true,
\"qualifying-suffix\": \"\"
}
}
}"
# Set the location of the executable.
bin="kea-dhcp6"
bin_path=@abs_top_builddir@/src/bin/dhcp6
......@@ -142,10 +180,18 @@ bin_path=@abs_top_builddir@/src/bin/dhcp6
# Import common test library.
. @abs_top_builddir@/src/lib/testutils/dhcp_test_lib.sh
# This test verifies that syntax check works properly.
# This test verifies that syntax checking works properly. This function
# requires 3 parameters:
# testname
# config - string with a content of the config (will be written to a file)
# exp_code - expected exit code returned by kea (0 - success, 1 - failure)
syntax_check_test() {
local TESTNAME="${1}"
local CONFIG="${2}"
local EXP_CODE="${3}"
# Log the start of the test and print test name.
test_start "dhcpv6_srv.syntax_check"
test_start $TESTNAME
# Remove dangling Kea instances and remove log files.
cleanup
# Create correct configuration file.
......@@ -154,22 +200,12 @@ syntax_check_test() {
printf "Running command %s.\n" "\"${bin_path}/${bin} -t -c ${CFG_FILE}\""
${bin_path}/${bin} -t -c ${CFG_FILE}
exit_code=$?
if [ ${exit_code} -ne 0 ]; then
printf "ERROR: expected exit code 0, got ${exit_code}\n"
if [ ${exit_code} -ne $EXP_CODE ]; then
printf "ERROR: expected exit code $EXP_CODE, got ${exit_code}\n"
clean_exit 1
fi
# Create incorrect configuration file.
create_config "${CONFIG_BAD_SYNTAX}"
# Check it
printf "Running command %s.\n" "\"${bin_path}/${bin} -t -c ${CFG_FILE}\""
printf "A syntax error should be detected\n"
${bin_path}/${bin} -t -c ${CFG_FILE}
if [ $? -eq 0 ]; then
printf "ERROR: expected exit code not 0, got 0\n"
clean_exit 1
fi
# All ok
clean_exit 0
test_finish 0
}
# This test verifies that DHCPv6 can be reconfigured with a SIGHUP signal.
......@@ -451,4 +487,6 @@ shutdown_test "dhcpv6.sigint_test" 2
version_test "dhcpv6.version"
logger_vars_test "dhcpv6.variables"
lfc_timer_test
syntax_check_test
syntax_check_test "dhcpv6.syntax_check_success" "${CONFIG}" 0
syntax_check_test "dhcpv6.syntax_check_bad_syntax" "${CONFIG_BAD_SYNTAX}" 1
syntax_check_test "dhcpv6.syntax_check_bad_values" "${CONFIG_BAD_VALUES}" 1
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