Commit a419556f authored by Thomas Markwalder's avatar Thomas Markwalder
Browse files

[4096] kea-dhcp4 now parses client class definitions list

src/bin/dhcp4/json_config_parser.cc
    - createGlobalDhcp4ConfigParser() - creates ClientClassDefListParser
    for "client-classes" element
    - configureDhcp4Server() - runs the ClientClassDefListParser against
    the "client-classes" element

src/bin/dhcp4/tests/config_parser_unittest.cc
    Added new tests for parsing client class definitions:
    TEST_F(Dhcp4ParserTest, clientClassDictionary)
    TEST_F(Dhcp4ParserTest, invalidClientClassDictionary)

src/bin/dhcp4/dhcp4.spec
    Added global "client-classes" element
parent 559c0a69
......@@ -270,7 +270,71 @@
}
]
},
{ "item_name": "client-classes",
"item_type": "list",
"item_optional": true,
"item_default": [],
"list_item_spec":
{
"item_name": "client-class",
"item_type": "map",
"item_optional": false,
"item_default": {},
"map_item_spec": [
{ "item_name": "name",
"item_type": "string",
"item_optional": false,
"item_default": ""
},
{ "item_name": "test",
"item_type": "string",
"item_optional": true,
"item_default": ""
},
{ "item_name": "option-data",
"item_type": "list",
"item_optional": true,
"item_default": [],
"list_item_spec":
{
"item_name": "single-option-data",
"item_type": "map",
"item_optional": false,
"item_default": {},
"map_item_spec": [
{
"item_name": "name",
"item_type": "string",
"item_optional": false,
"item_default": ""
},
{
"item_name": "code",
"item_type": "integer",
"item_optional": false,
"item_default": 0
},
{
"item_name": "data",
"item_type": "string",
"item_optional": false,
"item_default": ""
},
{ "item_name": "csv-format",
"item_type": "boolean",
"item_optional": false,
"item_default": false
},
{ "item_name": "space",
"item_type": "string",
"item_optional": false,
"item_default": "dhcp4"
} ]
}
}
]
}
},
{ "item_name": "subnet4",
"item_type": "list",
"item_optional": false,
......
......@@ -20,6 +20,7 @@
#include <dhcp/option_definition.h>
#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/parsers/client_class_def_parser.h>
#include <dhcp4/json_config_parser.h>
#include <dhcpsrv/option_space_container.h>
#include <dhcpsrv/parsers/dbaccess_parser.h>
......@@ -451,6 +452,8 @@ DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id,
parser = new ControlSocketParser(config_id);
} else if (config_id.compare("expired-leases-processing") == 0) {
parser = new ExpirationConfigParser();
} else if (config_id.compare("client-classes") == 0) {
parser = new ClientClassDefListParser(config_id, globalContext());
} else {
isc_throw(DhcpConfigError,
"unsupported global configuration parameter: "
......@@ -524,6 +527,7 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
ParserPtr option_parser;
ParserPtr iface_parser;
ParserPtr leases_parser;
ParserPtr client_classes_parser;
// Some of the parsers alter the state of the system in a way that can't
// easily be undone. (Or alter it in a way such that undoing the change has
......@@ -574,6 +578,8 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
// but defer the commit until everything else has committed.
hooks_parser = parser;
parser->build(config_pair.second);
} else if (config_pair.first == "client-classes") {
client_classes_parser = parser;
} else {
// Those parsers should be started before other
// parsers so we can call build straight away.
......@@ -595,6 +601,15 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
option_parser->commit();
}
// The class definitions parser is the next one to be run.
std::map<std::string, ConstElementPtr>::const_iterator cc_config =
values_map.find("client-classes");
if (cc_config != values_map.end()) {
config_pair.first = "client-classes";
client_classes_parser->build(cc_config->second);
client_classes_parser->commit();
}
// The subnet parser is the next one to be run.
std::map<std::string, ConstElementPtr>::const_iterator subnet_config =
values_map.find("subnet4");
......
......@@ -3898,4 +3898,78 @@ TEST_F(Dhcp4ParserTest, 4o6subnetInterfaceId) {
EXPECT_EQ(0, memcmp(&data[0], exp, data.size()));
}
// Verifies that simple list of valid classes parses and
// is staged for commit.
TEST_F(Dhcp4ParserTest, validClientClassDictionary) {
string config = "{ " + genIfaceConfig() + "," +
"\"valid-lifetime\": 4000, \n"
"\"rebind-timer\": 2000, \n"
"\"renew-timer\": 1000, \n"
"\"client-classes\" : [ \n"
" { \n"
" \"name\": \"one\" \n"
" }, \n"
" { \n"
" \"name\": \"two\" \n"
" }, \n"
" { \n"
" \"name\": \"three\" \n"
" } \n"
"], \n"
"\"subnet4\": [ { \n"
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ], \n"
" \"subnet\": \"192.0.2.0/24\" \n"
" } ] \n"
"} \n";
ConstElementPtr status;
ElementPtr json = Element::fromJSON(config);
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
ASSERT_TRUE(status);
checkResult(status, 0);
// We check staging config because CfgMgr::commit hasn't been executed.
ClientClassDictionaryPtr dictionary;
dictionary = CfgMgr::instance().getStagingCfg()->getClientClassDictionary();
ASSERT_TRUE(dictionary);
EXPECT_EQ(3, dictionary->getClasses()->size());
// Execute the commit
ASSERT_NO_THROW(CfgMgr::instance().commit());
// Verify that after commit, the current config has the correct dictionary
dictionary = CfgMgr::instance().getCurrentCfg()->getClientClassDictionary();
ASSERT_TRUE(dictionary);
EXPECT_EQ(3, dictionary->getClasses()->size());
}
// Verifies that an class list containing an invalid
// class definition causes a configuraiton error.
TEST_F(Dhcp4ParserTest, invalidClientClassDictionary) {
string config = "{ " + genIfaceConfig() + "," +
"\"valid-lifetime\": 4000, \n"
"\"rebind-timer\": 2000, \n"
"\"renew-timer\": 1000, \n"
"\"client-classes\" : [ \n"
" { \n"
" \"name\": \"one\", \n"
" \"bogus\": \"bad\" \n"
" } \n"
"], \n"
"\"subnet4\": [ { \n"
" \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ], \n"
" \"subnet\": \"192.0.2.0/24\" \n"
" } ] \n"
"} \n";
ConstElementPtr status;
ElementPtr json = Element::fromJSON(config);
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
ASSERT_TRUE(status);
checkResult(status, 1);
}
}
......@@ -150,7 +150,7 @@ typedef boost::shared_ptr<ClientClassDefParser> ClientClassDefParserPtr;
/// This parser iterates over all configuration entries that define
/// client classes and creates ClientClassDef instances for each.
/// If the parsing done in build() is successful, the collection of
/// created definitions is given to the @todo CfgMgr.
/// created definitions is given to the CfgMgr.
class ClientClassDefListParser : public DhcpConfigParser {
public:
/// @brief Constructor.
......
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