}
isc::data::ConstElementPtr
-configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
+configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set,
+ bool check_only) {
if (!config_set) {
ConstElementPtr answer = isc::config::createAnswer(1,
string("Can't parse NULL config"));
<< " (" << config_pair.second->getPosition() << ")");
}
- // Setup the command channel.
- configureCommandChannel();
-
// Apply global options in the staging config.
Dhcp4ConfigParser global_parser;
global_parser.parse(srv_cfg, mutable_cfg);
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.
// This operation should be exception safe but let's make sure.
if (!rollback) {
try {
+
+ // Setup the command channel.
+ configureCommandChannel();
+
// No need to commit interface names as this is handled by the
// CfgMgr::commit() function.
/// extra parameter is a reference to DHCPv4 server component. It is currently
/// not used and CfgMgr::instance() is accessed instead.
///
+/// Test-only mode added. 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
/// values in to server's configuration)
///
/// @param config_set a new configuration (JSON) for DHCPv4 server
+/// @param check_only whether this configuration is for testing only
/// @return answer that contains result of reconfiguration
isc::data::ConstElementPtr
configureDhcp4Server(Dhcpv4Srv&,
- isc::data::ConstElementPtr config_set);
+ isc::data::ConstElementPtr config_set,
+ bool check_only = false);
}; // end of isc::dhcp namespace
}; // end of isc namespace
#include <dhcp4/ctrl_dhcp4_srv.h>
#include <dhcp4/dhcp4_log.h>
#include <dhcp4/parser_context.h>
+#include <dhcp4/json_config_parser.h>
+#include <cc/command_interpreter.h>
#include <dhcpsrv/cfgmgr.h>
#include <log/logger_support.h>
#include <log/logger_manager.h>
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(DHCP4_ROOT_LOGGER_NAME);
+ Daemon::loggerInit(DHCP4_ROOT_LOGGER_NAME, verbose_mode);
+
+ // Check the syntax first.
Parser4Context parser;
ConstElementPtr json;
json = parser.parseFile(config_file, Parser4Context::PARSER_DHCP4);
if (verbose_mode) {
cerr << "Syntax check OK" << endl;
}
- return (EXIT_SUCCESS);
+
+ // Check the logic next.
+ ConstElementPtr dhcp4 = json->get("Dhcp4");
+ if (!dhcp4) {
+ cerr << "Missing mandatory Dhcp4 element" << endl;
+ return (EXIT_FAILURE);
+ }
+ ControlledDhcpv4Srv server(0);
+ ConstElementPtr answer;
+ answer = configureDhcp4Server(server, dhcp4, 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);
+ }
} catch (const std::exception& ex) {
- cerr << "Syntax check failed with " << ex.what() << endl;
+ cerr << "Syntax check failed with: " << ex.what() << endl;
}
return (EXIT_FAILURE);
}
-# Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2014-2017 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
}
}"
# 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 subnet4/pools, no subnet4/pool
CONFIG_BAD_SYNTAX="{
\"Dhcp4\":
{
]
}
}"
+
+# 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="{
+ \"Dhcp4\":
+ {
+ \"interfaces-config\": {
+ \"interfaces\": [ ]
+ },
+ \"valid-lifetime\": 4000,
+ \"renew-timer\": 1000,
+ \"rebind-timer\": 2000,
+ \"lease-database\":
+ {
+ \"type\": \"memfile\",
+ \"persist\": false
+ },
+ \"subnet4\": [
+ {
+ \"subnet\": \"10.0.0.0/8\",
+ \"pools\": [ { \"pool\": \"192.168.0.10-192.168.0.100\" } ]
+ } ]
+ },
+
+ \"Logging\":
+ {
+ \"loggers\": [
+ {
+ \"name\": \"kea-dhcp4\",
+ \"output_options\": [
+ {
+ \"output\": \"$LOG_FILE\"
+ }
+ ],
+ \"severity\": \"INFO\"
+ }
+ ]
+ }
+}"
+
# Invalid configuration (negative valid-lifetime) to check that Kea
# gracefully handles reconfiguration errors.
CONFIG_INVALID="{
# 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 "dhcpv4_srv.syntax_check"
+ test_start $TESTNAME
# Remove dangling Kea instances and remove log files.
cleanup
# Create correct configuration file.
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"
- 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"
+ if [ ${exit_code} -ne $EXP_CODE ]; then
+ printf "ERROR: expected exit code ${EXP_CODE}, got ${exit_code}\n"
clean_exit 1
fi
- # All ok
- clean_exit 0
+ test_finish 0
}
# This test verifies that DHCPv4 can be reconfigured with a SIGHUP signal.
version_test "dhcpv4.version"
logger_vars_test "dhcpv4.variables"
lfc_timer_test
-syntax_check_test
+syntax_check_test "dhcpv4.syntax_check_success" "${CONFIG}" 0
+syntax_check_test "dhcpv4.syntax_check_bad_syntax" "${CONFIG_BAD_SYNTAX}" 1
+syntax_check_test "dhcpv4.syntax_check_bad_values" "${CONFIG_BAD_VALUES}" 1