mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 14:05:33 +00:00
[5014_phase2] SimpleParser implemented, 4 parsers converted
- SimpleParser concept implemented - Converted 4 parsers (option data, option data list, option defintion, option definition list) - updated unit-tests - converted other parsers (HostReservationParser{4,6}, ClientClassDefParser) to use those new parsers - converted kea-dhcp{4,6} to use those new parsers Conflicts: src/bin/dhcp6/json_config_parser.cc src/lib/dhcpsrv/parsers/dhcp_parsers.cc
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
#include <dhcpsrv/parsers/host_reservation_parser.h>
|
||||
#include <dhcpsrv/parsers/host_reservations_list_parser.h>
|
||||
#include <dhcpsrv/parsers/ifaces_config_parser.h>
|
||||
#include <dhcpsrv/parsers/simple_parser.h>
|
||||
#include <dhcpsrv/timer_mgr.h>
|
||||
#include <config/command_mgr.h>
|
||||
#include <util/encode/hex.h>
|
||||
@@ -190,8 +191,7 @@ protected:
|
||||
parser = new Pools4ListParser(config_id, pools_);
|
||||
} else if (config_id.compare("relay") == 0) {
|
||||
parser = new RelayInfoParser(config_id, relay_info_, Option::V4);
|
||||
} else if (config_id.compare("option-data") == 0) {
|
||||
parser = new OptionDataListParser(config_id, options_, AF_INET);
|
||||
// option-data has been converted to SimpleParser already.
|
||||
} else if (config_id.compare("match-client-id") == 0) {
|
||||
parser = new BooleanParser(config_id, boolean_values_);
|
||||
} else if (config_id.compare("4o6-subnet") == 0) {
|
||||
@@ -424,10 +424,7 @@ DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id,
|
||||
parser = new IfacesConfigParser4();
|
||||
} else if (config_id.compare("subnet4") == 0) {
|
||||
parser = new Subnets4ListConfigParser(config_id);
|
||||
} else if (config_id.compare("option-data") == 0) {
|
||||
parser = new OptionDataListParser(config_id, CfgOptionPtr(), AF_INET);
|
||||
} else if (config_id.compare("option-def") == 0) {
|
||||
parser = new OptionDefListParser(config_id, globalContext());
|
||||
// option-data and option-def have been converted to SimpleParser already.
|
||||
} else if ((config_id.compare("version") == 0) ||
|
||||
(config_id.compare("next-server") == 0)) {
|
||||
parser = new StringParser(config_id,
|
||||
@@ -538,7 +535,6 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
|
||||
// Please do not change this order!
|
||||
ParserCollection independent_parsers;
|
||||
ParserPtr subnet_parser;
|
||||
ParserPtr option_parser;
|
||||
ParserPtr iface_parser;
|
||||
ParserPtr leases_parser;
|
||||
ParserPtr client_classes_parser;
|
||||
@@ -567,10 +563,43 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
|
||||
// the name of the failing parser can be retrieved in the "catch" clause.
|
||||
ConfigPair config_pair;
|
||||
try {
|
||||
|
||||
// This is a way to convert ConstElementPtr to ElementPtr.
|
||||
// We need a config that can be edited, because we will insert
|
||||
// default values and will insert derived values as well.
|
||||
std::map<std::string, ConstElementPtr> values;
|
||||
config_set->getValue(values);
|
||||
ElementPtr mutable_cfg(new MapElement());
|
||||
mutable_cfg->setValue(values);
|
||||
|
||||
// Set all default values if not specified by the user.
|
||||
SimpleParser::setAllDefaults(mutable_cfg, false);
|
||||
|
||||
// We need definitions first
|
||||
ConstElementPtr option_defs = mutable_cfg->get("option-def");
|
||||
if (option_defs) {
|
||||
OptionDefListParser parser(AF_INET);
|
||||
CfgOptionDefPtr cfg_option_def = CfgMgr::instance().getStagingCfg()->getCfgOptionDef();
|
||||
parser.parse(cfg_option_def, option_defs);
|
||||
}
|
||||
|
||||
// Make parsers grouping.
|
||||
const std::map<std::string, ConstElementPtr>& values_map =
|
||||
config_set->mapValue();
|
||||
mutable_cfg->mapValue();
|
||||
BOOST_FOREACH(config_pair, values_map) {
|
||||
|
||||
if (config_pair.first == "option-def") {
|
||||
// This is converted to SimpleParser and is handled already above.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (config_pair.first == "option-data") {
|
||||
OptionDataListParser parser(AF_INET);
|
||||
CfgOptionPtr cfg_option = CfgMgr::instance().getStagingCfg()->getCfgOption();
|
||||
parser.parse(cfg_option, config_pair.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
ParserPtr parser(createGlobalDhcp4ConfigParser(config_pair.first,
|
||||
config_pair.second));
|
||||
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PARSER_CREATED)
|
||||
@@ -579,8 +608,6 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
|
||||
subnet_parser = parser;
|
||||
} else if (config_pair.first == "lease-database") {
|
||||
leases_parser = parser;
|
||||
} else if (config_pair.first == "option-data") {
|
||||
option_parser = parser;
|
||||
} else if (config_pair.first == "interfaces-config") {
|
||||
// The interface parser is independent from any other
|
||||
// parser and can be run here before any other parsers.
|
||||
@@ -606,15 +633,6 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
|
||||
}
|
||||
}
|
||||
|
||||
// The option values parser is the next one to be run.
|
||||
std::map<std::string, ConstElementPtr>::const_iterator option_config =
|
||||
values_map.find("option-data");
|
||||
if (option_config != values_map.end()) {
|
||||
config_pair.first = "option-data";
|
||||
option_parser->build(option_config->second);
|
||||
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");
|
||||
|
@@ -203,7 +203,7 @@ const char* HOST_CONFIGS[] = {
|
||||
"\"valid-lifetime\": 600,"
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"vivso-suboptions\","
|
||||
" \"data\": 4491"
|
||||
" \"data\": \"4491\""
|
||||
"},"
|
||||
"{"
|
||||
" \"name\": \"tftp-servers\","
|
||||
@@ -221,7 +221,7 @@ const char* HOST_CONFIGS[] = {
|
||||
" \"ip-address\": \"10.0.0.7\","
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"vivso-suboptions\","
|
||||
" \"data\": 4491"
|
||||
" \"data\": \"4491\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"tftp-servers\","
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include <dhcpsrv/parsers/host_reservation_parser.h>
|
||||
#include <dhcpsrv/parsers/host_reservations_list_parser.h>
|
||||
#include <dhcpsrv/parsers/ifaces_config_parser.h>
|
||||
#include <dhcpsrv/parsers/simple_parser.h>
|
||||
#include <log/logger_support.h>
|
||||
#include <util/encode/hex.h>
|
||||
#include <util/strutil.h>
|
||||
@@ -184,10 +185,12 @@ public:
|
||||
uint32_values_));
|
||||
parser = code_parser;
|
||||
} else if (entry == "option-data") {
|
||||
OptionDataListParserPtr option_parser(new OptionDataListParser(entry,
|
||||
options_,
|
||||
AF_INET6));
|
||||
parser = option_parser;
|
||||
OptionDataListParser opts_parser(AF_INET6);
|
||||
opts_parser.parse(options_, param.second);
|
||||
|
||||
// OptionDataListParser is converted to SimpleParser already,
|
||||
// no need to go through build/commit phases.
|
||||
continue;
|
||||
} else if (entry == "user-context") {
|
||||
user_context_ = param.second;
|
||||
continue; // no parser to remember, simply store the value
|
||||
@@ -425,8 +428,7 @@ protected:
|
||||
parser = new RelayInfoParser(config_id, relay_info_, Option::V6);
|
||||
} else if (config_id.compare("pd-pools") == 0) {
|
||||
parser = new PdPoolListParser(config_id, pools_);
|
||||
} else if (config_id.compare("option-data") == 0) {
|
||||
parser = new OptionDataListParser(config_id, options_, AF_INET6);
|
||||
// option-data was here, but it is now converted to SimpleParser
|
||||
} else if (config_id.compare("rapid-commit") == 0) {
|
||||
parser = new BooleanParser(config_id, boolean_values_);
|
||||
} else {
|
||||
@@ -703,10 +705,8 @@ DhcpConfigParser* createGlobal6DhcpConfigParser(const std::string& config_id,
|
||||
parser = new IfacesConfigParser6();
|
||||
} else if (config_id.compare("subnet6") == 0) {
|
||||
parser = new Subnets6ListConfigParser(config_id);
|
||||
} else if (config_id.compare("option-data") == 0) {
|
||||
parser = new OptionDataListParser(config_id, CfgOptionPtr(), AF_INET6);
|
||||
} else if (config_id.compare("option-def") == 0) {
|
||||
parser = new OptionDefListParser(config_id, globalContext());
|
||||
// option-data and option-def are no longer needed here. They're now
|
||||
// converted to SimpleParser and are handled in configureDhcp6Server
|
||||
} else if (config_id.compare("version") == 0) {
|
||||
parser = new StringParser(config_id,
|
||||
globalContext()->string_values_);
|
||||
@@ -808,7 +808,6 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
|
||||
// Please do not change this order!
|
||||
ParserCollection independent_parsers;
|
||||
ParserPtr subnet_parser;
|
||||
ParserPtr option_parser;
|
||||
ParserPtr iface_parser;
|
||||
ParserPtr leases_parser;
|
||||
ParserPtr client_classes_parser;
|
||||
@@ -838,10 +837,42 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
|
||||
ConfigPair config_pair;
|
||||
try {
|
||||
|
||||
// This is a way to convert ConstElementPtr to ElementPtr.
|
||||
// We need a config that can be edited, because we will insert
|
||||
// default values and will insert derived values as well.
|
||||
std::map<std::string, ConstElementPtr> values;
|
||||
config_set->getValue(values);
|
||||
ElementPtr mutable_cfg(new MapElement());
|
||||
mutable_cfg->setValue(values);
|
||||
|
||||
SimpleParser::setAllDefaults(mutable_cfg, true);
|
||||
|
||||
// Make parsers grouping.
|
||||
const std::map<std::string, ConstElementPtr>& values_map =
|
||||
config_set->mapValue();
|
||||
mutable_cfg->mapValue();
|
||||
|
||||
// We need definitions first
|
||||
ConstElementPtr option_defs = mutable_cfg->get("option-def");
|
||||
if (option_defs) {
|
||||
OptionDefListParser parser(AF_INET6);
|
||||
CfgOptionDefPtr cfg_option_def = CfgMgr::instance().getStagingCfg()->getCfgOptionDef();
|
||||
parser.parse(cfg_option_def, option_defs);
|
||||
}
|
||||
|
||||
BOOST_FOREACH(config_pair, values_map) {
|
||||
|
||||
if (config_pair.first == "option-def") {
|
||||
// This is converted to SimpleParser and is handled already above.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (config_pair.first == "option-data") {
|
||||
OptionDataListParser parser(AF_INET6);
|
||||
CfgOptionPtr cfg_option = CfgMgr::instance().getStagingCfg()->getCfgOption();
|
||||
parser.parse(cfg_option, config_pair.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
ParserPtr parser(createGlobal6DhcpConfigParser(config_pair.first,
|
||||
config_pair.second));
|
||||
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PARSER_CREATED)
|
||||
@@ -850,9 +881,9 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
|
||||
subnet_parser = parser;
|
||||
} else if (config_pair.first == "lease-database") {
|
||||
leases_parser = parser;
|
||||
} else if (config_pair.first == "option-data") {
|
||||
} /* else if (config_pair.first == "option-data") {
|
||||
option_parser = parser;
|
||||
} else if (config_pair.first == "hooks-libraries") {
|
||||
} */ else if (config_pair.first == "hooks-libraries") {
|
||||
// Executing the commit will alter currently loaded hooks
|
||||
// libraries. Check if the supplied libraries are valid,
|
||||
// but defer the commit until after everything else has
|
||||
@@ -878,15 +909,6 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
|
||||
}
|
||||
}
|
||||
|
||||
// The option values parser is the next one to be run.
|
||||
std::map<std::string, ConstElementPtr>::const_iterator option_config =
|
||||
values_map.find("option-data");
|
||||
if (option_config != values_map.end()) {
|
||||
config_pair.first = "option-data";
|
||||
option_parser->build(option_config->second);
|
||||
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");
|
||||
|
@@ -2024,10 +2024,12 @@ TEST_F(Dhcpv6SrvTest, rsooOverride) {
|
||||
" \"option-def\": [ {"
|
||||
" \"name\": \"foo\","
|
||||
" \"code\": 120,"
|
||||
" \"csv-format\": false,"
|
||||
" \"type\": \"binary\""
|
||||
" } ],"
|
||||
" \"option-data\": [ {"
|
||||
" \"code\": 120,"
|
||||
" \"csv-format\": false,"
|
||||
" \"data\": \"05\""
|
||||
" } ],"
|
||||
" \"preferred-lifetime\": 3000,"
|
||||
|
@@ -229,7 +229,7 @@ const char* CONFIGS[] = {
|
||||
"\"renew-timer\": 1000, "
|
||||
"\"option-data\": [ {"
|
||||
" \"name\": \"vendor-opts\","
|
||||
" \"data\": 4491"
|
||||
" \"data\": \"4491\""
|
||||
"},"
|
||||
"{"
|
||||
" \"name\": \"tftp-servers\","
|
||||
@@ -247,7 +247,7 @@ const char* CONFIGS[] = {
|
||||
" \"ip-addresses\": [ \"2001:db8:1::2\" ],"
|
||||
" \"option-data\": [ {"
|
||||
" \"name\": \"vendor-opts\","
|
||||
" \"data\": 4491"
|
||||
" \"data\": \"4491\""
|
||||
" },"
|
||||
" {"
|
||||
" \"name\": \"tftp-servers\","
|
||||
|
@@ -32,6 +32,8 @@ EXTRA_DIST =
|
||||
EXTRA_DIST += parsers/client_class_def_parser.cc
|
||||
EXTRA_DIST += parsers/client_class_def_parser.h
|
||||
EXTRA_DIST += parsers/dhcp_config_parser.h
|
||||
EXTRA_DIST += parsers/simple_parser.cc
|
||||
EXTRA_DIST += parsers/simple_parser.h
|
||||
EXTRA_DIST += parsers/dbaccess_parser.cc
|
||||
EXTRA_DIST += parsers/dbaccess_parser.h
|
||||
EXTRA_DIST += parsers/dhcp_parsers.cc
|
||||
@@ -161,6 +163,8 @@ libkea_dhcpsrv_la_SOURCES += parsers/dbaccess_parser.cc
|
||||
libkea_dhcpsrv_la_SOURCES += parsers/dbaccess_parser.h
|
||||
libkea_dhcpsrv_la_SOURCES += parsers/dhcp_parsers.cc
|
||||
libkea_dhcpsrv_la_SOURCES += parsers/dhcp_parsers.h
|
||||
libkea_dhcpsrv_la_SOURCES += parsers/simple_parser.cc
|
||||
libkea_dhcpsrv_la_SOURCES += parsers/simple_parser.h
|
||||
libkea_dhcpsrv_la_SOURCES += parsers/duid_config_parser.cc
|
||||
libkea_dhcpsrv_la_SOURCES += parsers/duid_config_parser.h
|
||||
libkea_dhcpsrv_la_SOURCES += parsers/expiration_config_parser.cc
|
||||
|
@@ -91,12 +91,16 @@ ClientClassDefParser::build(ConstElementPtr class_def_cfg) {
|
||||
global_context_));
|
||||
parser = exp_parser;
|
||||
} else if (entry == "option-data") {
|
||||
OptionDataListParserPtr opts_parser;
|
||||
|
||||
uint16_t family = (global_context_->universe_ == Option::V4 ?
|
||||
AF_INET : AF_INET6);
|
||||
|
||||
opts_parser.reset(new OptionDataListParser(entry, options_, family));
|
||||
parser = opts_parser;
|
||||
OptionDataListParser opts_parser(family);
|
||||
opts_parser.parse(options_, param.second);
|
||||
|
||||
// OptionDataListParser is converted to SimpleParser already,
|
||||
// no need to go through build/commit phases.
|
||||
continue;
|
||||
} else if (entry == "next-server") {
|
||||
StringParserPtr str_parser(new StringParser(entry, string_values_));
|
||||
parser = str_parser;
|
||||
|
@@ -376,75 +376,30 @@ HooksLibrariesParser::getLibraries(isc::hooks::HookLibsCollection& libraries,
|
||||
}
|
||||
|
||||
// **************************** OptionDataParser *************************
|
||||
OptionDataParser::OptionDataParser(const std::string&, const CfgOptionPtr& cfg,
|
||||
const uint16_t address_family)
|
||||
: boolean_values_(new BooleanStorage()),
|
||||
string_values_(new StringStorage()), uint32_values_(new Uint32Storage()),
|
||||
option_descriptor_(false), cfg_(cfg),
|
||||
address_family_(address_family) {
|
||||
// If configuration not specified, then it is a global configuration
|
||||
// scope.
|
||||
if (!cfg_) {
|
||||
cfg_ = CfgMgr::instance().getStagingCfg()->getCfgOption();
|
||||
}
|
||||
OptionDataParser::OptionDataParser(const uint16_t address_family)
|
||||
: address_family_(address_family) {
|
||||
}
|
||||
|
||||
void
|
||||
OptionDataParser::build(ConstElementPtr option_data_entries) {
|
||||
BOOST_FOREACH(ConfigPair param, option_data_entries->mapValue()) {
|
||||
ParserPtr parser;
|
||||
if (param.first == "name" || param.first == "data" ||
|
||||
param.first == "space") {
|
||||
StringParserPtr name_parser(new StringParser(param.first,
|
||||
string_values_));
|
||||
parser = name_parser;
|
||||
} else if (param.first == "code") {
|
||||
Uint32ParserPtr code_parser(new Uint32Parser(param.first,
|
||||
uint32_values_));
|
||||
parser = code_parser;
|
||||
} else if (param.first == "csv-format") {
|
||||
BooleanParserPtr value_parser(new BooleanParser(param.first,
|
||||
boolean_values_));
|
||||
parser = value_parser;
|
||||
} else {
|
||||
isc_throw(DhcpConfigError,
|
||||
"option-data parameter not supported: " << param.first
|
||||
<< " (" << param.second->getPosition() << ")");
|
||||
}
|
||||
|
||||
parser->build(param.second);
|
||||
// Before we can create an option we need to get the data from
|
||||
// the child parsers. The only way to do it is to invoke commit
|
||||
// on them so as they store the values in appropriate storages
|
||||
// that this class provided to them. Note that this will not
|
||||
// modify values stored in the global storages so the configuration
|
||||
// will remain consistent even parsing fails somewhere further on.
|
||||
parser->commit();
|
||||
}
|
||||
std::pair<OptionDescriptor, std::string>
|
||||
OptionDataParser::parse(isc::data::ConstElementPtr single_option) {
|
||||
|
||||
// Try to create the option instance.
|
||||
createOption(option_data_entries);
|
||||
std::pair<OptionDescriptor, std::string> opt = createOption(single_option);
|
||||
|
||||
if (!option_descriptor_.option_) {
|
||||
if (!opt.first.option_) {
|
||||
isc_throw(isc::InvalidOperation,
|
||||
"parser logic error: no option has been configured and"
|
||||
" thus there is nothing to commit. Has build() been called?");
|
||||
}
|
||||
|
||||
cfg_->add(option_descriptor_.option_, option_descriptor_.persistent_,
|
||||
option_space_);
|
||||
}
|
||||
|
||||
void
|
||||
OptionDataParser::commit() {
|
||||
// Does nothing
|
||||
return (opt);
|
||||
}
|
||||
|
||||
OptionalValue<uint32_t>
|
||||
OptionDataParser::extractCode(ConstElementPtr parent) const {
|
||||
uint32_t code;
|
||||
try {
|
||||
code = uint32_values_->getParam("code");
|
||||
code = getInteger(parent, "code");
|
||||
|
||||
} catch (const exception&) {
|
||||
// The code parameter was not found. Return an unspecified
|
||||
@@ -454,14 +409,14 @@ OptionDataParser::extractCode(ConstElementPtr parent) const {
|
||||
|
||||
if (code == 0) {
|
||||
isc_throw(DhcpConfigError, "option code must not be zero "
|
||||
"(" << uint32_values_->getPosition("code", parent) << ")");
|
||||
"(" << getPosition("code", parent) << ")");
|
||||
|
||||
} else if (address_family_ == AF_INET &&
|
||||
code > std::numeric_limits<uint8_t>::max()) {
|
||||
isc_throw(DhcpConfigError, "invalid option code '" << code
|
||||
<< "', it must not be greater than '"
|
||||
<< static_cast<int>(std::numeric_limits<uint8_t>::max())
|
||||
<< "' (" << uint32_values_->getPosition("code", parent)
|
||||
<< "' (" << getPosition("code", parent)
|
||||
<< ")");
|
||||
|
||||
} else if (address_family_ == AF_INET6 &&
|
||||
@@ -469,7 +424,7 @@ OptionDataParser::extractCode(ConstElementPtr parent) const {
|
||||
isc_throw(DhcpConfigError, "invalid option code '" << code
|
||||
<< "', it must not exceed '"
|
||||
<< std::numeric_limits<uint16_t>::max()
|
||||
<< "' (" << uint32_values_->getPosition("code", parent)
|
||||
<< "' (" << getPosition("code", parent)
|
||||
<< ")");
|
||||
|
||||
}
|
||||
@@ -481,7 +436,7 @@ OptionalValue<std::string>
|
||||
OptionDataParser::extractName(ConstElementPtr parent) const {
|
||||
std::string name;
|
||||
try {
|
||||
name = string_values_->getParam("name");
|
||||
name = getString(parent, "name");
|
||||
|
||||
} catch (...) {
|
||||
return (OptionalValue<std::string>());
|
||||
@@ -490,17 +445,17 @@ OptionDataParser::extractName(ConstElementPtr parent) const {
|
||||
if (name.find(" ") != std::string::npos) {
|
||||
isc_throw(DhcpConfigError, "invalid option name '" << name
|
||||
<< "', space character is not allowed ("
|
||||
<< string_values_->getPosition("name", parent) << ")");
|
||||
<< getPosition("name", parent) << ")");
|
||||
}
|
||||
|
||||
return (OptionalValue<std::string>(name, OptionalValueState(true)));
|
||||
}
|
||||
|
||||
std::string
|
||||
OptionDataParser::extractData() const {
|
||||
OptionDataParser::extractData(ConstElementPtr parent) const {
|
||||
std::string data;
|
||||
try {
|
||||
data = string_values_->getParam("data");
|
||||
data = getString(parent, "data");
|
||||
|
||||
} catch (...) {
|
||||
// The "data" parameter was not found. Return an empty value.
|
||||
@@ -511,10 +466,10 @@ OptionDataParser::extractData() const {
|
||||
}
|
||||
|
||||
OptionalValue<bool>
|
||||
OptionDataParser::extractCSVFormat() const {
|
||||
OptionDataParser::extractCSVFormat(ConstElementPtr parent) const {
|
||||
bool csv_format = true;
|
||||
try {
|
||||
csv_format = boolean_values_->getParam("csv-format");
|
||||
csv_format = getBoolean(parent, "csv-format");
|
||||
|
||||
} catch (...) {
|
||||
return (OptionalValue<bool>(csv_format));
|
||||
@@ -524,11 +479,11 @@ OptionDataParser::extractCSVFormat() const {
|
||||
}
|
||||
|
||||
std::string
|
||||
OptionDataParser::extractSpace() const {
|
||||
OptionDataParser::extractSpace(ConstElementPtr parent) const {
|
||||
std::string space = address_family_ == AF_INET ?
|
||||
DHCP4_OPTION_SPACE : DHCP6_OPTION_SPACE;
|
||||
try {
|
||||
space = string_values_->getParam("space");
|
||||
space = getString(parent, "space");
|
||||
|
||||
} catch (...) {
|
||||
return (space);
|
||||
@@ -556,7 +511,7 @@ OptionDataParser::extractSpace() const {
|
||||
// should never get here. Therefore, it is ok to call getPosition for
|
||||
// the space parameter here as this parameter will always be specified.
|
||||
isc_throw(DhcpConfigError, ex.what() << " ("
|
||||
<< string_values_->getPosition("space") << ")");
|
||||
<< getPosition("space", parent) << ")");
|
||||
}
|
||||
|
||||
return (space);
|
||||
@@ -588,16 +543,16 @@ OptionDataParser::findOptionDefinition(const std::string& option_space,
|
||||
return (def);
|
||||
}
|
||||
|
||||
void
|
||||
std::pair<OptionDescriptor, std::string>
|
||||
OptionDataParser::createOption(ConstElementPtr option_data) {
|
||||
const Option::Universe universe = address_family_ == AF_INET ?
|
||||
Option::V4 : Option::V6;
|
||||
|
||||
OptionalValue<uint32_t> code_param = extractCode(option_data);
|
||||
OptionalValue<std::string> name_param = extractName(option_data);
|
||||
OptionalValue<bool> csv_format_param = extractCSVFormat();
|
||||
std::string data_param = extractData();
|
||||
std::string space_param = extractSpace();
|
||||
OptionalValue<bool> csv_format_param = extractCSVFormat(option_data);
|
||||
std::string data_param = extractData(option_data);
|
||||
std::string space_param = extractSpace(option_data);
|
||||
|
||||
// Require that option code or option name is specified.
|
||||
if (!code_param.isSpecified() && !name_param.isSpecified()) {
|
||||
@@ -622,7 +577,7 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
|
||||
<< space_param << "." << name_param
|
||||
<< "' having code '" << code_param
|
||||
<< "' does not exist ("
|
||||
<< string_values_->getPosition("name", option_data)
|
||||
<< getPosition("name", option_data)
|
||||
<< ")");
|
||||
|
||||
// If there is no option definition and the option code is not specified
|
||||
@@ -631,7 +586,7 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
|
||||
isc_throw(DhcpConfigError, "definition for the option '"
|
||||
<< space_param << "." << name_param
|
||||
<< "' does not exist ("
|
||||
<< string_values_->getPosition("name", option_data)
|
||||
<< getPosition("name", option_data)
|
||||
<< ")");
|
||||
}
|
||||
}
|
||||
@@ -664,12 +619,14 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
|
||||
isc_throw(DhcpConfigError, "option data is not a valid"
|
||||
<< " string of hexadecimal digits: " << data_param
|
||||
<< " ("
|
||||
<< string_values_->getPosition("data", option_data)
|
||||
<< getPosition("data", option_data)
|
||||
<< ")");
|
||||
}
|
||||
}
|
||||
|
||||
OptionPtr option;
|
||||
OptionDescriptor desc(false);
|
||||
|
||||
if (!def) {
|
||||
// @todo We have a limited set of option definitions initalized at
|
||||
// the moment. In the future we want to initialize option definitions
|
||||
@@ -678,13 +635,9 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
|
||||
// ok to create generic option if definition does not exist.
|
||||
OptionPtr option(new Option(universe, static_cast<uint16_t>(code_param),
|
||||
binary));
|
||||
// The created option is stored in option_descriptor_ class member
|
||||
// until the commit stage when it is inserted into the main storage.
|
||||
// If an option with the same code exists in main storage already the
|
||||
// old option is replaced.
|
||||
option_descriptor_.option_ = option;
|
||||
option_descriptor_.persistent_ = false;
|
||||
|
||||
desc.option_ = option;
|
||||
desc.persistent_ = false;
|
||||
} else {
|
||||
|
||||
// Option name is specified it should match the name in the definition.
|
||||
@@ -693,7 +646,7 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
|
||||
<< name_param << "' does not match the "
|
||||
<< "option definition: '" << space_param
|
||||
<< "." << def->getName() << "' ("
|
||||
<< string_values_->getPosition("name", option_data)
|
||||
<< getPosition("name", option_data)
|
||||
<< ")");
|
||||
}
|
||||
|
||||
@@ -704,144 +657,65 @@ OptionDataParser::createOption(ConstElementPtr option_data) {
|
||||
!csv_format_param.isSpecified() || csv_format_param ?
|
||||
def->optionFactory(universe, def->getCode(), data_tokens) :
|
||||
def->optionFactory(universe, def->getCode(), binary);
|
||||
OptionDescriptor desc(option, false);
|
||||
option_descriptor_.option_ = option;
|
||||
option_descriptor_.persistent_ = false;
|
||||
|
||||
desc.option_ = option;
|
||||
desc.persistent_ = false;
|
||||
} catch (const isc::Exception& ex) {
|
||||
isc_throw(DhcpConfigError, "option data does not match"
|
||||
<< " option definition (space: " << space_param
|
||||
<< ", code: " << def->getCode() << "): "
|
||||
<< ex.what() << " ("
|
||||
<< string_values_->getPosition("data", option_data)
|
||||
<< getPosition("data", option_data)
|
||||
<< ")");
|
||||
}
|
||||
}
|
||||
|
||||
// All went good, so we can set the option space name.
|
||||
option_space_ = space_param;
|
||||
return make_pair(desc, space_param);
|
||||
}
|
||||
|
||||
// **************************** OptionDataListParser *************************
|
||||
OptionDataListParser::OptionDataListParser(const std::string&,
|
||||
const CfgOptionPtr& cfg,
|
||||
OptionDataListParser::OptionDataListParser(//const std::string&,
|
||||
//const CfgOptionPtr& cfg,
|
||||
const uint16_t address_family)
|
||||
: cfg_(cfg), address_family_(address_family) {
|
||||
: address_family_(address_family) {
|
||||
}
|
||||
|
||||
void
|
||||
OptionDataListParser::build(ConstElementPtr option_data_list) {
|
||||
BOOST_FOREACH(ConstElementPtr option_value, option_data_list->listValue()) {
|
||||
boost::shared_ptr<OptionDataParser>
|
||||
parser(new OptionDataParser("option-data", cfg_, address_family_));
|
||||
|
||||
parser->build(option_value);
|
||||
parsers_.push_back(parser);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OptionDataListParser::commit() {
|
||||
BOOST_FOREACH(ParserPtr parser, parsers_) {
|
||||
parser->commit();
|
||||
}
|
||||
// Append suboptions to the top-level options
|
||||
if (cfg_) {
|
||||
cfg_->encapsulate();
|
||||
} else {
|
||||
CfgMgr::instance().getStagingCfg()->getCfgOption()->encapsulate();
|
||||
void OptionDataListParser::parse(const CfgOptionPtr& cfg,
|
||||
isc::data::ConstElementPtr option_data_list) {
|
||||
OptionDataParser option_parser(address_family_);
|
||||
BOOST_FOREACH(ConstElementPtr data, option_data_list->listValue()) {
|
||||
std::pair<OptionDescriptor, std::string> option =
|
||||
option_parser.parse(data);
|
||||
cfg->add(option.first.option_, option.first.persistent_, option.second);
|
||||
cfg->encapsulate();
|
||||
}
|
||||
}
|
||||
|
||||
// ******************************** OptionDefParser ****************************
|
||||
OptionDefParser::OptionDefParser(const std::string&,
|
||||
ParserContextPtr global_context)
|
||||
: boolean_values_(new BooleanStorage()),
|
||||
string_values_(new StringStorage()),
|
||||
uint32_values_(new Uint32Storage()),
|
||||
global_context_(global_context) {
|
||||
OptionDefParser::OptionDefParser(const uint16_t address_family)
|
||||
: address_family_(address_family) {
|
||||
}
|
||||
|
||||
void
|
||||
OptionDefParser::build(ConstElementPtr option_def) {
|
||||
// Parse the elements that make up the option definition.
|
||||
BOOST_FOREACH(ConfigPair param, option_def->mapValue()) {
|
||||
std::string entry(param.first);
|
||||
ParserPtr parser;
|
||||
if (entry == "name" || entry == "type" || entry == "record-types"
|
||||
|| entry == "space" || entry == "encapsulate") {
|
||||
StringParserPtr str_parser(new StringParser(entry,
|
||||
string_values_));
|
||||
parser = str_parser;
|
||||
} else if (entry == "code") {
|
||||
Uint32ParserPtr code_parser(new Uint32Parser(entry,
|
||||
uint32_values_));
|
||||
parser = code_parser;
|
||||
} else if (entry == "array") {
|
||||
BooleanParserPtr array_parser(new BooleanParser(entry,
|
||||
boolean_values_));
|
||||
parser = array_parser;
|
||||
} else {
|
||||
isc_throw(DhcpConfigError, "invalid parameter '" << entry
|
||||
<< "' (" << param.second->getPosition() << ")");
|
||||
}
|
||||
std::pair<isc::dhcp::OptionDefinitionPtr, std::string>
|
||||
OptionDefParser::parse(ConstElementPtr option_def) {
|
||||
|
||||
parser->build(param.second);
|
||||
parser->commit();
|
||||
}
|
||||
// Create an instance of option definition.
|
||||
createOptionDef(option_def);
|
||||
// Get mandatory parameters.
|
||||
std::string name = getString(option_def, "name");
|
||||
uint32_t code = getInteger(option_def, "code");
|
||||
std::string type = getString(option_def, "type");
|
||||
|
||||
try {
|
||||
CfgMgr::instance().getStagingCfg()->getCfgOptionDef()->
|
||||
add(option_definition_, option_space_name_);
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
// Append position if there is a failure.
|
||||
isc_throw(DhcpConfigError, ex.what() << " ("
|
||||
<< option_def->getPosition() << ")");
|
||||
}
|
||||
|
||||
// All definitions have been prepared. Put them as runtime options into
|
||||
// the libdhcp++.
|
||||
const OptionDefSpaceContainer& container =
|
||||
CfgMgr::instance().getStagingCfg()->getCfgOptionDef()->getContainer();
|
||||
LibDHCP::setRuntimeOptionDefs(container);
|
||||
}
|
||||
|
||||
void
|
||||
OptionDefParser::commit() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
void
|
||||
OptionDefParser::createOptionDef(ConstElementPtr option_def_element) {
|
||||
// Check if mandatory parameters have been specified.
|
||||
std::string name;
|
||||
uint32_t code;
|
||||
std::string type;
|
||||
try {
|
||||
name = string_values_->getParam("name");
|
||||
code = uint32_values_->getParam("code");
|
||||
type = string_values_->getParam("type");
|
||||
} catch (const std::exception& ex) {
|
||||
isc_throw(DhcpConfigError, ex.what() << " ("
|
||||
<< option_def_element->getPosition() << ")");
|
||||
}
|
||||
|
||||
bool array_type = boolean_values_->getOptionalParam("array", false);
|
||||
std::string record_types =
|
||||
string_values_->getOptionalParam("record-types", "");
|
||||
std::string space = string_values_->getOptionalParam("space",
|
||||
global_context_->universe_ == Option::V4 ? DHCP4_OPTION_SPACE :
|
||||
DHCP6_OPTION_SPACE);
|
||||
std::string encapsulates =
|
||||
string_values_->getOptionalParam("encapsulate", "");
|
||||
// Get optional parameters. Whoever called this parser, should have
|
||||
// called SimpleParser::setDefaults first.
|
||||
bool array_type = getBoolean(option_def, "array");
|
||||
std::string record_types = getString(option_def, "record-types");
|
||||
std::string space = getString(option_def, "space");
|
||||
std::string encapsulates = getString(option_def, "encapsulate");
|
||||
|
||||
if (!OptionSpace::validateName(space)) {
|
||||
isc_throw(DhcpConfigError, "invalid option space name '"
|
||||
<< space << "' ("
|
||||
<< string_values_->getPosition("space") << ")");
|
||||
<< getPosition("space", option_def) << ")");
|
||||
}
|
||||
|
||||
// Create option definition.
|
||||
@@ -854,14 +728,14 @@ OptionDefParser::createOptionDef(ConstElementPtr option_def_element) {
|
||||
isc_throw(DhcpConfigError, "option '" << space << "."
|
||||
<< "name" << "', comprising an array of data"
|
||||
<< " fields may not encapsulate any option space ("
|
||||
<< option_def_element->getPosition() << ")");
|
||||
<< option_def->getPosition() << ")");
|
||||
|
||||
} else if (encapsulates == space) {
|
||||
isc_throw(DhcpConfigError, "option must not encapsulate"
|
||||
<< " an option space it belongs to: '"
|
||||
<< space << "." << name << "' is set to"
|
||||
<< " encapsulate '" << space << "' ("
|
||||
<< option_def_element->getPosition() << ")");
|
||||
<< option_def->getPosition() << ")");
|
||||
|
||||
} else {
|
||||
def.reset(new OptionDefinition(name, code, type,
|
||||
@@ -888,7 +762,7 @@ OptionDefParser::createOptionDef(ConstElementPtr option_def_element) {
|
||||
isc_throw(DhcpConfigError, "invalid record type values"
|
||||
<< " specified for the option definition: "
|
||||
<< ex.what() << " ("
|
||||
<< string_values_->getPosition("record-types") << ")");
|
||||
<< getPosition("record-types", option_def) << ")");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -897,38 +771,43 @@ OptionDefParser::createOptionDef(ConstElementPtr option_def_element) {
|
||||
def->validate();
|
||||
} catch (const std::exception& ex) {
|
||||
isc_throw(DhcpConfigError, ex.what()
|
||||
<< " (" << option_def_element->getPosition() << ")");
|
||||
<< " (" << option_def->getPosition() << ")");
|
||||
}
|
||||
|
||||
// Option definition has been created successfully.
|
||||
option_space_name_ = space;
|
||||
option_definition_ = def;
|
||||
return make_pair(def, space);
|
||||
}
|
||||
|
||||
// ******************************** OptionDefListParser ************************
|
||||
OptionDefListParser::OptionDefListParser(const std::string&,
|
||||
ParserContextPtr global_context)
|
||||
: global_context_(global_context) {
|
||||
OptionDefListParser::OptionDefListParser(const uint16_t address_family)
|
||||
: address_family_(address_family) {
|
||||
}
|
||||
|
||||
void
|
||||
OptionDefListParser::build(ConstElementPtr option_def_list) {
|
||||
OptionDefListParser::parse(CfgOptionDefPtr storage, ConstElementPtr option_def_list) {
|
||||
if (!option_def_list) {
|
||||
isc_throw(DhcpConfigError, "parser error: a pointer to a list of"
|
||||
<< " option definitions is NULL ("
|
||||
<< option_def_list->getPosition() << ")");
|
||||
}
|
||||
|
||||
OptionDefParser parser(address_family_);
|
||||
BOOST_FOREACH(ConstElementPtr option_def, option_def_list->listValue()) {
|
||||
boost::shared_ptr<OptionDefParser>
|
||||
parser(new OptionDefParser("single-option-def", global_context_));
|
||||
parser->build(option_def);
|
||||
}
|
||||
}
|
||||
OptionDefinitionTuple def;
|
||||
|
||||
void
|
||||
OptionDefListParser::commit() {
|
||||
// Do nothing.
|
||||
def = parser.parse(option_def);
|
||||
try {
|
||||
storage->add(def.first, def.second);
|
||||
} catch (const std::exception& ex) {
|
||||
// Append position if there is a failure.
|
||||
isc_throw(DhcpConfigError, ex.what() << " ("
|
||||
<< option_def->getPosition() << ")");
|
||||
}
|
||||
}
|
||||
|
||||
// All definitions have been prepared. Put them as runtime options into
|
||||
// the libdhcp++.
|
||||
LibDHCP::setRuntimeOptionDefs(storage->getContainer());
|
||||
}
|
||||
|
||||
//****************************** RelayInfoParser ********************************
|
||||
@@ -1138,13 +1017,9 @@ PoolParser::build(ConstElementPtr pool_structure) {
|
||||
" address pools");
|
||||
}
|
||||
|
||||
OptionDataListParserPtr option_parser(new OptionDataListParser("option-data",
|
||||
options_,
|
||||
address_family_));
|
||||
option_parser->build(option_data);
|
||||
option_parser->commit();
|
||||
options_->copyTo(*pool->getCfgOption());;
|
||||
|
||||
CfgOptionPtr cfg = pool->getCfgOption();
|
||||
OptionDataListParser option_parser(address_family_);
|
||||
option_parser.parse(cfg, option_data);
|
||||
} catch (const std::exception& ex) {
|
||||
isc_throw(isc::dhcp::DhcpConfigError, ex.what()
|
||||
<< " (" << option_data->getPosition() << ")");
|
||||
@@ -1194,6 +1069,13 @@ SubnetConfigParser::build(ConstElementPtr subnet) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (param.first == "option-data") {
|
||||
uint16_t family = global_context_->universe_ == Option::V4 ? AF_INET : AF_INET6;
|
||||
OptionDataListParser opt_parser(family);
|
||||
opt_parser.parse(options_, param.second);
|
||||
continue;
|
||||
}
|
||||
|
||||
ParserPtr parser;
|
||||
// When unsupported parameter is specified, the function called
|
||||
// below will thrown an exception. We have to catch this exception
|
||||
|
@@ -15,7 +15,9 @@
|
||||
#include <dhcpsrv/cfg_iface.h>
|
||||
#include <dhcpsrv/cfg_option.h>
|
||||
#include <dhcpsrv/subnet.h>
|
||||
#include <dhcpsrv/cfg_option_def.h>
|
||||
#include <dhcpsrv/parsers/dhcp_config_parser.h>
|
||||
#include <dhcpsrv/parsers/simple_parser.h>
|
||||
#include <hooks/libinfo.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
#include <util/optional_value.h>
|
||||
@@ -534,39 +536,30 @@ private:
|
||||
/// an option the configuration will not be accepted. If parsing
|
||||
/// is successful then an instance of an option is created and
|
||||
/// added to the storage provided by the calling class.
|
||||
class OptionDataParser : public DhcpConfigParser {
|
||||
class OptionDataParser : public SimpleParser {
|
||||
public:
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// @param dummy first argument is ignored, all Parser constructors
|
||||
/// accept string as first argument.
|
||||
/// @param [out] cfg Pointer to the configuration object where parsed option
|
||||
/// should be stored or NULL if this is a global option.
|
||||
/// @param address_family Address family: @c AF_INET or @c AF_INET6.
|
||||
/// @throw isc::dhcp::DhcpConfigError if options or global_context are null.
|
||||
OptionDataParser(const std::string& dummy, const CfgOptionPtr& cfg,
|
||||
const uint16_t address_family);
|
||||
OptionDataParser(const uint16_t address_family);
|
||||
|
||||
/// @brief Parses the single option data.
|
||||
/// @brief Parses ElementPtr containing option definition
|
||||
///
|
||||
/// This method parses the data of a single option from the configuration.
|
||||
/// The option data includes option name, option code and data being
|
||||
/// carried by this option. Eventually it creates the instance of the
|
||||
/// option and adds it to the Configuration Manager.
|
||||
/// This method parses ElementPtr containing the option defintion,
|
||||
/// instantiates the option for it and then returns a pair
|
||||
/// of option descritor (that holds that new option) and
|
||||
/// a string that specifies the option space.
|
||||
///
|
||||
/// @param option_data_entries collection of entries that define value
|
||||
/// for a particular option.
|
||||
/// @throw DhcpConfigError if invalid parameter specified in
|
||||
/// the configuration.
|
||||
/// @throw isc::InvalidOperation if failed to set storage prior to
|
||||
/// calling build.
|
||||
virtual void build(isc::data::ConstElementPtr option_data_entries);
|
||||
|
||||
/// @brief Does nothing.
|
||||
virtual void commit();
|
||||
|
||||
/// @brief virtual destructor to ensure orderly destruction of derivations.
|
||||
virtual ~OptionDataParser(){};
|
||||
/// Note: ElementPtr is expected to contain all fields. If your
|
||||
/// ElementPtr does not have them, please use
|
||||
/// @ref SimpleParser::setOptionDefaults to fill the missing fields
|
||||
/// with default values.
|
||||
///
|
||||
/// @param single_option ElementPtr containing option defintion
|
||||
/// @return Option object wrapped in option description and an option
|
||||
/// space
|
||||
std::pair<OptionDescriptor, std::string>
|
||||
parse(isc::data::ConstElementPtr single_option);
|
||||
private:
|
||||
|
||||
/// @brief Finds an option definition within an option space
|
||||
@@ -594,22 +587,19 @@ private:
|
||||
/// options storage. If the option data parsed by \ref build function
|
||||
/// are invalid or insufficient this function emits an exception.
|
||||
///
|
||||
/// @warning this function does not check if options_ storage pointer
|
||||
/// is intitialized but this check is not needed here because it is done
|
||||
/// in the \ref build function.
|
||||
///
|
||||
/// @param option_data An element holding data for a single option being
|
||||
/// created.
|
||||
///
|
||||
/// @return created option descriptor
|
||||
///
|
||||
/// @throw DhcpConfigError if parameters provided in the configuration
|
||||
/// are invalid.
|
||||
void createOption(isc::data::ConstElementPtr option_data);
|
||||
std::pair<OptionDescriptor, std::string>
|
||||
createOption(isc::data::ConstElementPtr option_data);
|
||||
|
||||
/// @brief Retrieves parsed option code as an optional value.
|
||||
///
|
||||
/// @param parent A data element holding full option data configuration.
|
||||
/// It is used here to log a position if the element holding a code
|
||||
/// is not specified and its position is therefore unavailable.
|
||||
///
|
||||
/// @return Option code, possibly unspecified.
|
||||
/// @throw DhcpConfigError if option code is invalid.
|
||||
@@ -619,8 +609,6 @@ private:
|
||||
/// @brief Retrieves parsed option name as an optional value.
|
||||
///
|
||||
/// @param parent A data element holding full option data configuration.
|
||||
/// It is used here to log a position if the element holding a name
|
||||
/// is not specified and its position is therefore unavailable.
|
||||
///
|
||||
/// @return Option name, possibly unspecified.
|
||||
/// @throw DhcpConfigError if option name is invalid.
|
||||
@@ -630,13 +618,14 @@ private:
|
||||
/// @brief Retrieves csv-format parameter as an optional value.
|
||||
///
|
||||
/// @return Value of the csv-format parameter, possibly unspecified.
|
||||
util::OptionalValue<bool> extractCSVFormat() const;
|
||||
util::OptionalValue<bool> extractCSVFormat(data::ConstElementPtr parent) const;
|
||||
|
||||
/// @brief Retrieves option data as a string.
|
||||
///
|
||||
/// @param parent A data element holding full option data configuration.
|
||||
/// @return Option data as a string. It will return empty string if
|
||||
/// option data is unspecified.
|
||||
std::string extractData() const;
|
||||
std::string extractData(data::ConstElementPtr parent) const;
|
||||
|
||||
/// @brief Retrieves option space name.
|
||||
///
|
||||
@@ -644,27 +633,10 @@ private:
|
||||
/// 'dhcp4' or 'dhcp6' option space name is returned, depending on
|
||||
/// the universe specified in the parser context.
|
||||
///
|
||||
/// @param parent A data element holding full option data configuration.
|
||||
///
|
||||
/// @return Option space name.
|
||||
std::string extractSpace() const;
|
||||
|
||||
/// Storage for boolean values.
|
||||
BooleanStoragePtr boolean_values_;
|
||||
|
||||
/// Storage for string values (e.g. option name or data).
|
||||
StringStoragePtr string_values_;
|
||||
|
||||
/// Storage for uint32 values (e.g. option code).
|
||||
Uint32StoragePtr uint32_values_;
|
||||
|
||||
/// Option descriptor holds newly configured option.
|
||||
OptionDescriptor option_descriptor_;
|
||||
|
||||
/// Option space name where the option belongs to.
|
||||
std::string option_space_;
|
||||
|
||||
/// @brief Configuration holding option being parsed or NULL if the option
|
||||
/// is global.
|
||||
CfgOptionPtr cfg_;
|
||||
std::string extractSpace(data::ConstElementPtr parent) const;
|
||||
|
||||
/// @brief Address family: @c AF_INET or @c AF_INET6.
|
||||
uint16_t address_family_;
|
||||
@@ -680,97 +652,52 @@ typedef OptionDataParser *OptionDataParserFactory(const std::string&,
|
||||
/// data for a particular subnet and creates a collection of options.
|
||||
/// If parsing is successful, all these options are added to the Subnet
|
||||
/// object.
|
||||
class OptionDataListParser : public DhcpConfigParser {
|
||||
class OptionDataListParser : public SimpleParser {
|
||||
public:
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// @param dummy nominally would be param name, this is always ignored.
|
||||
/// @param [out] cfg Pointer to the configuration object where options
|
||||
/// should be stored or NULL if this is global option scope.
|
||||
/// @param address_family Address family: @c AF_INET or AF_INET6
|
||||
OptionDataListParser(const std::string& dummy, const CfgOptionPtr& cfg,
|
||||
const uint16_t address_family);
|
||||
OptionDataListParser(const uint16_t address_family);
|
||||
|
||||
/// @brief Parses entries that define options' data for a subnet.
|
||||
/// @brief Parses a list of options, instantiates them and stores in cfg
|
||||
///
|
||||
/// This method iterates over all entries that define option data
|
||||
/// for options within a single subnet and creates options' instances.
|
||||
/// This method expects to get a list of options in option_data_list,
|
||||
/// iterates over them, creates option objects, wraps them with
|
||||
/// option descriptor and stores in specified cfg.
|
||||
///
|
||||
/// @param option_data_list pointer to a list of options' data sets.
|
||||
/// @throw DhcpConfigError if option parsing failed.
|
||||
void build(isc::data::ConstElementPtr option_data_list);
|
||||
|
||||
/// @brief Commit all option values.
|
||||
///
|
||||
/// This function invokes commit for all option values
|
||||
/// and append suboptions to the top-level options.
|
||||
void commit();
|
||||
|
||||
/// @param cfg created options will be stored here
|
||||
/// @param option_data_list configuration that describes the options
|
||||
void parse(const CfgOptionPtr& cfg,
|
||||
isc::data::ConstElementPtr option_data_list);
|
||||
private:
|
||||
|
||||
/// Collection of parsers;
|
||||
ParserCollection parsers_;
|
||||
|
||||
/// @brief Pointer to a configuration where options are stored.
|
||||
CfgOptionPtr cfg_;
|
||||
|
||||
/// @brief Address family: @c AF_INET or @c AF_INET6
|
||||
uint16_t address_family_;
|
||||
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<OptionDataListParser> OptionDataListParserPtr;
|
||||
|
||||
typedef std::pair<isc::dhcp::OptionDefinitionPtr, std::string> OptionDefinitionTuple;
|
||||
|
||||
/// @brief Parser for a single option definition.
|
||||
///
|
||||
/// This parser creates an instance of a single option definition.
|
||||
class OptionDefParser : public DhcpConfigParser {
|
||||
class OptionDefParser : public SimpleParser {
|
||||
public:
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// @param dummy first argument is ignored, all Parser constructors
|
||||
/// accept string as first argument.
|
||||
/// @param global_context is a pointer to the global context which
|
||||
/// stores global scope parameters, options, option defintions.
|
||||
OptionDefParser(const std::string& dummy, ParserContextPtr global_context);
|
||||
/// @param address_family Address family: @c AF_INET or AF_INET6
|
||||
OptionDefParser(const uint16_t address_family);
|
||||
|
||||
/// @brief Parses an entry that describes single option definition.
|
||||
///
|
||||
/// @param option_def a configuration entry to be parsed.
|
||||
/// @return tuple (option definition, option space) of the parsed structure
|
||||
///
|
||||
/// @throw DhcpConfigError if parsing was unsuccessful.
|
||||
void build(isc::data::ConstElementPtr option_def);
|
||||
|
||||
/// @brief Stores the parsed option definition in a storage.
|
||||
void commit();
|
||||
OptionDefinitionTuple
|
||||
parse(isc::data::ConstElementPtr option_def);
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Create option definition from the parsed parameters.
|
||||
///
|
||||
/// @param option_def_element A data element holding the configuration
|
||||
/// for an option definition.
|
||||
void createOptionDef(isc::data::ConstElementPtr option_def_element);
|
||||
|
||||
/// Instance of option definition being created by this parser.
|
||||
OptionDefinitionPtr option_definition_;
|
||||
|
||||
/// Name of the space the option definition belongs to.
|
||||
std::string option_space_name_;
|
||||
|
||||
/// Storage for boolean values.
|
||||
BooleanStoragePtr boolean_values_;
|
||||
|
||||
/// Storage for string values.
|
||||
StringStoragePtr string_values_;
|
||||
|
||||
/// Storage for uint32 values.
|
||||
Uint32StoragePtr uint32_values_;
|
||||
|
||||
/// Parsing context which contains global values, options and option
|
||||
/// definitions.
|
||||
ParserContextPtr global_context_;
|
||||
/// @brief Address family: @c AF_INET or @c AF_INET6
|
||||
uint16_t address_family_;
|
||||
};
|
||||
|
||||
/// @brief Parser for a list of option definitions.
|
||||
@@ -779,7 +706,7 @@ private:
|
||||
/// option definitions and creates instances of these definitions.
|
||||
/// If the parsing is successful, the collection of created definitions
|
||||
/// is put into the provided storage.
|
||||
class OptionDefListParser : public DhcpConfigParser {
|
||||
class OptionDefListParser : public SimpleParser {
|
||||
public:
|
||||
/// @brief Constructor.
|
||||
///
|
||||
@@ -787,29 +714,24 @@ public:
|
||||
/// accept string as first argument.
|
||||
/// @param global_context is a pointer to the global context which
|
||||
/// stores global scope parameters, options, option defintions.
|
||||
OptionDefListParser(const std::string& dummy,
|
||||
ParserContextPtr global_context);
|
||||
OptionDefListParser(const uint16_t address_family);
|
||||
//const std::string& dummy,
|
||||
//ParserContextPtr global_context);
|
||||
|
||||
/// @brief Parse configuration entries.
|
||||
/// @brief Parses a list of option defintions, create them and store in cfg
|
||||
///
|
||||
/// This function parses configuration entries, creates instances
|
||||
/// of option definitions and tries to add them to the Configuration
|
||||
/// Manager.
|
||||
/// This method iterates over def_list, which is a JSON list of option defintions,
|
||||
/// then creates corresponding option defintions and store them in the
|
||||
/// configuration structure.
|
||||
///
|
||||
/// @param option_def_list pointer to an element that holds entries
|
||||
/// that define option definitions.
|
||||
/// @throw DhcpConfigError if configuration parsing fails.
|
||||
void build(isc::data::ConstElementPtr option_def_list);
|
||||
/// @param def_list JSON list describing option definitions
|
||||
/// @param cfg parsed option definitions will be stored here
|
||||
void parse(CfgOptionDefPtr cfg, isc::data::ConstElementPtr def_list);
|
||||
|
||||
/// @brief Commits option definitions.
|
||||
///
|
||||
/// Currently this function is no-op, because option definitions are
|
||||
/// added to the Configuration Manager in the @c build method.
|
||||
void commit();
|
||||
protected:
|
||||
|
||||
/// Parsing context which contains global values, options and option
|
||||
/// definitions.
|
||||
ParserContextPtr global_context_;
|
||||
/// @brief Address family: @c AF_INET or @c AF_INET6
|
||||
uint16_t address_family_;
|
||||
};
|
||||
|
||||
/// @brief a collection of pools
|
||||
|
@@ -196,8 +196,12 @@ HostReservationParser4::build(isc::data::ConstElementPtr reservation_data) {
|
||||
// surround it with try-catch.
|
||||
if (element.first == "option-data") {
|
||||
CfgOptionPtr cfg_option = host_->getCfgOption4();
|
||||
OptionDataListParser parser(element.first, cfg_option, AF_INET);
|
||||
parser.build(element.second);
|
||||
|
||||
// This parser is converted to SimpleParser already. It
|
||||
// parses the Element structure immediately, there's no need
|
||||
// to go through build/commit phases.
|
||||
OptionDataListParser parser(AF_INET);
|
||||
parser.parse(cfg_option, element.second);
|
||||
|
||||
// Everything else should be surrounded with try-catch to append
|
||||
// position.
|
||||
@@ -255,8 +259,12 @@ HostReservationParser6::build(isc::data::ConstElementPtr reservation_data) {
|
||||
// appended).
|
||||
if (element.first == "option-data") {
|
||||
CfgOptionPtr cfg_option = host_->getCfgOption6();
|
||||
OptionDataListParser parser(element.first, cfg_option, AF_INET6);
|
||||
parser.build(element.second);
|
||||
|
||||
// This parser is converted to SimpleParser already. It
|
||||
// parses the Element structure immediately, there's no need
|
||||
// to go through build/commit phases.
|
||||
OptionDataListParser parser(AF_INET6);
|
||||
parser.parse(cfg_option, element.second);
|
||||
|
||||
} else if (element.first == "ip-addresses" || element.first == "prefixes") {
|
||||
BOOST_FOREACH(ConstElementPtr prefix_element,
|
||||
|
253
src/lib/dhcpsrv/parsers/simple_parser.cc
Normal file
253
src/lib/dhcpsrv/parsers/simple_parser.cc
Normal file
@@ -0,0 +1,253 @@
|
||||
#include <dhcpsrv/parsers/simple_parser.h>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <cc/data.h>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
using namespace isc::data;
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
/// This table defines default values for option definitions in DHCPv4
|
||||
const SimpleDefaults OPTION4_DEF_DEFAULTS{
|
||||
{ "record-types", Element::string, ""},
|
||||
{ "space", Element::string, "dhcp4"},
|
||||
{ "array", Element::boolean, "false"},
|
||||
{ "encapsulate", Element::string, "" }
|
||||
};
|
||||
|
||||
/// This table defines default values for option definitions in DHCPv6
|
||||
const SimpleDefaults OPTION6_DEF_DEFAULTS{
|
||||
{ "record-types", Element::string, ""},
|
||||
{ "space", Element::string, "dhcp6"},
|
||||
{ "array", Element::boolean, "false"},
|
||||
{ "encapsulate", Element::string, "" }
|
||||
};
|
||||
|
||||
/// This table defines default values for options in DHCPv4
|
||||
const SimpleDefaults OPTION4_DEFAULTS({
|
||||
{ "space", Element::string, "dhcp4"},
|
||||
{ "csv-format", Element::boolean, "true"},
|
||||
{ "encapsulate", Element::string, "" }
|
||||
});
|
||||
|
||||
/// This table defines default values for options in DHCPv6
|
||||
const SimpleDefaults OPTION6_DEFAULTS({
|
||||
{ "space", Element::string, "dhcp6"},
|
||||
{ "csv-format", Element::boolean, "true"},
|
||||
{ "encapsulate", Element::string, "" }
|
||||
});
|
||||
|
||||
/// This table defines default values for both DHCPv4 and DHCPv6
|
||||
const SimpleDefaults GLOBAL_DEFAULTS = {
|
||||
{ "renew-timer", Element::integer, "900" },
|
||||
{ "rebind-timer", Element::integer, "1800" },
|
||||
{ "preferred-lifetime", Element::integer, "3600" },
|
||||
{ "valid-lifetime", Element::integer, "7200" }
|
||||
};
|
||||
|
||||
std::string
|
||||
SimpleParser::getString(isc::data::ConstElementPtr scope, const std::string& name) {
|
||||
ConstElementPtr x = scope->get(name);
|
||||
if (!x) {
|
||||
isc_throw(BadValue, "Element " << name << " not found");
|
||||
}
|
||||
if (x->getType() != Element::string) {
|
||||
isc_throw(BadValue, "Element " << name << " found, but is not a string");
|
||||
}
|
||||
|
||||
return (x->stringValue());
|
||||
}
|
||||
|
||||
int64_t
|
||||
SimpleParser::getInteger(isc::data::ConstElementPtr scope, const std::string& name) {
|
||||
ConstElementPtr x = scope->get(name);
|
||||
if (!x) {
|
||||
isc_throw(BadValue, "Element " << name << " not found");
|
||||
}
|
||||
if (x->getType() != Element::integer) {
|
||||
isc_throw(BadValue, "Element " << name << " found, but is not an integer");
|
||||
}
|
||||
|
||||
return (x->intValue());
|
||||
}
|
||||
|
||||
bool
|
||||
SimpleParser::getBoolean(isc::data::ConstElementPtr scope, const std::string& name) {
|
||||
ConstElementPtr x = scope->get(name);
|
||||
if (!x) {
|
||||
isc_throw(BadValue, "Element " << name << " not found");
|
||||
}
|
||||
if (x->getType() != Element::boolean) {
|
||||
isc_throw(BadValue, "Element " << name << " found, but is not a boolean");
|
||||
}
|
||||
|
||||
return (x->boolValue());
|
||||
}
|
||||
|
||||
const data::Element::Position&
|
||||
SimpleParser::getPosition(const std::string& name, const data::ConstElementPtr parent) const {
|
||||
if (!parent) {
|
||||
return (data::Element::ZERO_POSITION());
|
||||
}
|
||||
ConstElementPtr elem = parent->get(name);
|
||||
if (!elem) {
|
||||
return (data::Element::ZERO_POSITION());
|
||||
}
|
||||
return (elem->getPosition());
|
||||
}
|
||||
|
||||
size_t SimpleParser::setDefaults(isc::data::ElementPtr scope,
|
||||
const SimpleDefaults& default_values) {
|
||||
size_t cnt = 0;
|
||||
|
||||
// This is the position representing a default value. As the values
|
||||
// we're inserting here are not present in whatever the config file
|
||||
// came from, we need to make sure it's clearly labeled as default.
|
||||
const Element::Position pos("<default-value>", 0, 0);
|
||||
|
||||
// Let's go over all parameters we have defaults for.
|
||||
BOOST_FOREACH(SimpleDefault def_value, default_values) {
|
||||
|
||||
// Try if such a parameter is there. If it is, let's
|
||||
// skip it, because user knows best *cough*.
|
||||
ConstElementPtr x = scope->get(string(def_value.name_));
|
||||
if (x) {
|
||||
// There is such a value already, skip it.
|
||||
continue;
|
||||
}
|
||||
|
||||
// There isn't such a value defined, let's create the default
|
||||
// value...
|
||||
switch (def_value.type_) {
|
||||
case Element::string: {
|
||||
x.reset(new StringElement(def_value.value_, pos));
|
||||
break;
|
||||
}
|
||||
case Element::integer: {
|
||||
int int_value = boost::lexical_cast<int>(def_value.value_);
|
||||
x.reset(new IntElement(int_value, pos));
|
||||
break;
|
||||
}
|
||||
case Element::boolean: {
|
||||
bool bool_value;
|
||||
if (def_value.value_ == string("true")) {
|
||||
bool_value = true;
|
||||
} else if (def_value.value_ == string("false")) {
|
||||
bool_value = false;
|
||||
} else {
|
||||
isc_throw(BadValue, "Internal error. Boolean value specified as "
|
||||
<< def_value.value_ << ", expected true or false");
|
||||
}
|
||||
x.reset(new BoolElement(bool_value, pos));
|
||||
break;
|
||||
}
|
||||
case Element::real: {
|
||||
double dbl_value = boost::lexical_cast<double>(def_value.value_);
|
||||
x.reset(new DoubleElement(dbl_value, pos));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// No default values for null, list or map
|
||||
isc_throw(BadValue, "Internal error. Incorrect default value type.");
|
||||
}
|
||||
|
||||
// ... and insert it into the provided Element tree.
|
||||
scope->set(def_value.name_, x);
|
||||
cnt++;
|
||||
}
|
||||
|
||||
return (cnt);
|
||||
}
|
||||
|
||||
size_t SimpleParser::setGlobalDefaults(isc::data::ElementPtr global) {
|
||||
return (setDefaults(global, GLOBAL_DEFAULTS));
|
||||
}
|
||||
|
||||
size_t SimpleParser::setOptionDefaults(isc::data::ElementPtr option, bool v6) {
|
||||
return (setDefaults(option, v6?OPTION6_DEFAULTS : OPTION4_DEFAULTS));
|
||||
}
|
||||
|
||||
size_t SimpleParser::setOptionListDefaults(isc::data::ElementPtr option_list, bool v6) {
|
||||
size_t cnt = 0;
|
||||
BOOST_FOREACH(ElementPtr single_option, option_list->listValue()) {
|
||||
cnt += setOptionDefaults(single_option, v6);
|
||||
}
|
||||
return (cnt);
|
||||
}
|
||||
|
||||
size_t SimpleParser::setOptionDefDefaults(isc::data::ElementPtr option_def, bool v6) {
|
||||
return (setDefaults(option_def, v6? OPTION6_DEF_DEFAULTS : OPTION4_DEF_DEFAULTS));
|
||||
}
|
||||
|
||||
size_t SimpleParser::setOptionDefListDefaults(isc::data::ElementPtr option_def_list,
|
||||
bool v6) {
|
||||
size_t cnt = 0;
|
||||
BOOST_FOREACH(ElementPtr single_def, option_def_list->listValue()) {
|
||||
cnt += setOptionDefDefaults(single_def, v6);
|
||||
}
|
||||
return (cnt);
|
||||
}
|
||||
|
||||
|
||||
size_t SimpleParser::setAllDefaults(isc::data::ElementPtr global, bool v6) {
|
||||
size_t cnt = 0;
|
||||
|
||||
// Set global defaults first.
|
||||
//cnt = setGlobalDefaults(global);
|
||||
|
||||
// Now set option defintion defaults for each specified option definition
|
||||
ConstElementPtr option_defs = global->get("option-def");
|
||||
if (option_defs) {
|
||||
BOOST_FOREACH(ElementPtr single_def, option_defs->listValue()) {
|
||||
cnt += setOptionDefDefaults(single_def, v6);
|
||||
}
|
||||
}
|
||||
|
||||
ConstElementPtr options = global->get("option-data");
|
||||
if (options) {
|
||||
BOOST_FOREACH(ElementPtr single_option, options->listValue()) {
|
||||
cnt += setOptionDefaults(single_option, v6);
|
||||
}
|
||||
//setOptionListDefaults(options);
|
||||
}
|
||||
|
||||
return (cnt);
|
||||
}
|
||||
|
||||
size_t
|
||||
SimpleParser::deriveParams(isc::data::ConstElementPtr parent,
|
||||
isc::data::ElementPtr child,
|
||||
const ParamsList& params) {
|
||||
if ( (parent->getType() != Element::map) ||
|
||||
(child->getType() != Element::map)) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
size_t cnt = 0;
|
||||
BOOST_FOREACH(string param, params) {
|
||||
ConstElementPtr x = parent->get(param);
|
||||
if (!x) {
|
||||
// Parent doesn't define this parameter, so there's
|
||||
// nothing to derive from
|
||||
continue;
|
||||
}
|
||||
|
||||
if (child->get(param)) {
|
||||
// Child defines this parameter already. There's
|
||||
// nothing to do here.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Copy the parameters to the child scope.
|
||||
child->set(param, x);
|
||||
cnt++;
|
||||
}
|
||||
|
||||
return (cnt);
|
||||
}
|
||||
|
||||
}; // end of isc::dhcp namespace
|
||||
}; // end of isc namespace
|
189
src/lib/dhcpsrv/parsers/simple_parser.h
Normal file
189
src/lib/dhcpsrv/parsers/simple_parser.h
Normal file
@@ -0,0 +1,189 @@
|
||||
#ifndef SIMPLE_PARSER_H
|
||||
#define SIMPLE_PARSER_H
|
||||
|
||||
#include <cc/data.h>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
/// This array defines a single entry of default values
|
||||
struct SimpleDefault {
|
||||
SimpleDefault(const char* name, isc::data::Element::types type, const char* value)
|
||||
:name_(name), type_(type), value_(value) {}
|
||||
std::string name_;
|
||||
const isc::data::Element::types type_;
|
||||
const char* value_;
|
||||
};
|
||||
|
||||
/// This specifies all default values in a given scope (e.g. a subnet)
|
||||
typedef std::vector<SimpleDefault> SimpleDefaults;
|
||||
|
||||
/// This defines a list of all parameters that are derived (or inherited) between
|
||||
/// contexts
|
||||
typedef std::vector<std::string> ParamsList;
|
||||
|
||||
|
||||
/// @brief A simple parser
|
||||
///
|
||||
/// This class is intended to be a simpler replacement for @ref DhcpConfigParser.
|
||||
/// The simplification comes from several factors:
|
||||
/// - no build/commit nonsense. There's a single step:
|
||||
/// CfgStorage parse(ConstElementPtr json)
|
||||
/// that converts JSON configuration into an object and returns it.
|
||||
/// - almost no state kept. The only state kept in most cases is whether the
|
||||
/// parsing is done in v4 or v6 context. This greatly simplifies the
|
||||
/// parsers (no contexts, no child parsers list, no separate storage for
|
||||
/// uint32, strings etc. In fact, there's so little state kept, that this
|
||||
/// parser is mostly a collection of static methods.
|
||||
/// - no optional parameters (all are mandatory). This simplifies the parser,
|
||||
/// but introduces a new step before parsing where we insert the default
|
||||
/// values into client configuration before parsing. This is actually a good
|
||||
/// thing, because we now have a clear picture of the default parameters as
|
||||
/// they're defined in a single place (the DhcpConfigParser had the defaults
|
||||
/// spread out in multiple files in multiple directories).
|
||||
class SimpleParser {
|
||||
public:
|
||||
|
||||
/// @brief Derives (inherits) parameters from parent scope to a child
|
||||
///
|
||||
/// This method derives parameters from the parent scope to the child,
|
||||
/// if there are no values specified in the child scope. For example,
|
||||
/// this method can be used to derive timers from global scope (e.g. for
|
||||
/// the whole DHCPv6 server) to a subnet scope. This method checks
|
||||
/// if the child scope doesn't have more specific values defined. If
|
||||
/// it doesn't, then the value from parent scope is copied over.
|
||||
///
|
||||
/// @param parent scope to copy from (e.g. global)
|
||||
/// @param child scope to copy from (e.g. subnet)
|
||||
/// @param params names of the parameters to copy
|
||||
/// @return number of parameters copied
|
||||
static size_t deriveParams(isc::data::ConstElementPtr parent,
|
||||
isc::data::ElementPtr child,
|
||||
const ParamsList& params);
|
||||
|
||||
/// @brief Sets the default values
|
||||
///
|
||||
/// This method sets the default values for parameters that are not
|
||||
/// defined. The list of default values is specified by default_values.
|
||||
/// If not present, those will be inserted into the scope. If
|
||||
/// a parameter is already present, the default value will not
|
||||
/// be inserted.
|
||||
///
|
||||
/// @param scope default values will be inserted here
|
||||
/// @param default_values list of default values
|
||||
/// @return number of parameters inserted
|
||||
static size_t setDefaults(isc::data::ElementPtr scope,
|
||||
const SimpleDefaults& default_values);
|
||||
|
||||
/// @brief Sets global defaults
|
||||
///
|
||||
/// This method sets global defaults. Note it does not set the
|
||||
/// defaults for any scopes lower than global. See @ref setAllDefaults
|
||||
/// for that.
|
||||
///
|
||||
/// @param global scope to be filled in with defaults.
|
||||
/// @return number of default values added
|
||||
static size_t setGlobalDefaults(isc::data::ElementPtr global);
|
||||
|
||||
/// @brief Sets option defaults for a single option
|
||||
///
|
||||
/// This method sets default values for a single option.
|
||||
///
|
||||
/// @param option an option data to be filled in with defaults.
|
||||
/// @param v6 is it v6 (true) or v4 (false) option?
|
||||
/// @return number of default values added
|
||||
static size_t setOptionDefaults(isc::data::ElementPtr option, bool v6);
|
||||
|
||||
/// @brief Sets option defaults for the whole options list
|
||||
///
|
||||
/// This method sets default values for a list of options.
|
||||
///
|
||||
/// @param option_list an option data to be filled in with defaults.
|
||||
/// @param v6 is it v6 (true) or v4 (false) option?
|
||||
/// @return number of default values added
|
||||
static size_t setOptionListDefaults(isc::data::ElementPtr option_list, bool v6);
|
||||
|
||||
/// @brief Sets option defaults for a single option definition
|
||||
///
|
||||
/// This method sets default values for a single option definition.
|
||||
///
|
||||
/// @param option_def an option defintion to be filled in with defaults.
|
||||
/// @param v6 is it v6 (true) or v4 (false) option defintion?
|
||||
/// @return number of default values added
|
||||
static size_t setOptionDefDefaults(isc::data::ElementPtr option_def, bool v6);
|
||||
|
||||
/// @brief Sets option defaults for the whole option definitions list
|
||||
///
|
||||
/// This method sets default values for a list of option definitions.
|
||||
///
|
||||
/// @param option_def_list a list of option defintions to be filled in with defaults.
|
||||
/// @param v6 is it v6 (true) or v4 (false) option?
|
||||
/// @return number of default values added
|
||||
static size_t setOptionDefListDefaults(isc::data::ElementPtr option_def_list,
|
||||
bool v6);
|
||||
|
||||
/// @brief Sets defaults for the whole configuration
|
||||
///
|
||||
/// This method sets global, options and option definition defaults. Note
|
||||
/// it does set the defaults for scopes lower than global. If you want to
|
||||
/// set the global defaults only, see @ref setGlobalDefaults for that.
|
||||
///
|
||||
/// @param global scope to be filled in with defaults.
|
||||
/// @return number of default values added
|
||||
static size_t setAllDefaults(isc::data::ElementPtr global, bool v6);
|
||||
|
||||
/// @brief Utility method that returns position of an element
|
||||
///
|
||||
/// It's mostly useful for logging.
|
||||
///
|
||||
/// @param name position of that element will be returned
|
||||
/// @param parent parent element (optional)
|
||||
/// @return position of the element specified.
|
||||
const data::Element::Position&
|
||||
getPosition(const std::string& name, const data::ConstElementPtr parent =
|
||||
data::ConstElementPtr()) const;
|
||||
|
||||
/// @destructor
|
||||
///
|
||||
/// It's really simple, isn't it?
|
||||
virtual ~SimpleParser() {}
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief Returns a string parameter from a scope
|
||||
///
|
||||
/// Unconditionally returns a parameter. If the parameter is not there or
|
||||
/// is not of appropriate type, BadValue exception is thrown.
|
||||
///
|
||||
/// @param scope specified parameter will be extracted from this scope
|
||||
/// @param name name of the parameter
|
||||
/// @return a string value of the parameter
|
||||
static std::string getString(isc::data::ConstElementPtr scope, const std::string& name);
|
||||
|
||||
/// @brief Returns an integer parameter from a scope
|
||||
///
|
||||
/// Unconditionally returns a parameter. If the parameter is not there or
|
||||
/// is not of appropriate type, BadValue exception is thrown.
|
||||
///
|
||||
/// @param scope specified parameter will be extracted from this scope
|
||||
/// @param name name of the parameter
|
||||
/// @return an integer value of the parameter
|
||||
static int64_t getInteger(isc::data::ConstElementPtr scope, const std::string& name);
|
||||
|
||||
/// @brief Returns a boolean parameter from a scope
|
||||
///
|
||||
/// Unconditionally returns a parameter. If the parameter is not there or
|
||||
/// is not of appropriate type, BadValue exception is thrown.
|
||||
///
|
||||
/// @param scope specified parameter will be extracted from this scope
|
||||
/// @param name name of the parameter
|
||||
/// @return a boolean value of the parameter
|
||||
static bool getBoolean(isc::data::ConstElementPtr scope, const std::string& name);
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
@@ -16,6 +16,7 @@
|
||||
#include <dhcpsrv/subnet.h>
|
||||
#include <dhcpsrv/cfg_mac_source.h>
|
||||
#include <dhcpsrv/parsers/dhcp_parsers.h>
|
||||
#include <dhcpsrv/parsers/simple_parser.h>
|
||||
#include <dhcpsrv/tests/test_libraries.h>
|
||||
#include <dhcpsrv/testutils/config_result_check.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
@@ -310,6 +311,16 @@ public:
|
||||
const std::map<std::string, ConstElementPtr>& values_map =
|
||||
config_set->mapValue();
|
||||
BOOST_FOREACH(config_pair, values_map) {
|
||||
|
||||
// These are the simple parsers. No need to go through
|
||||
// the ParserPtr hooplas with them.
|
||||
if ( (config_pair.first == "option-data") ||
|
||||
(config_pair.first == "option-def")) {
|
||||
continue;
|
||||
}
|
||||
// Remaining ones are old style parsers. Need go do
|
||||
// the build/commit dance with them.
|
||||
|
||||
// Create the parser based on element name.
|
||||
ParserPtr parser(createConfigParser(config_pair.first));
|
||||
// Options must be parsed last
|
||||
@@ -322,12 +333,27 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
int family = parser_context_->universe_ == Option::V4
|
||||
? AF_INET : AF_INET6;
|
||||
|
||||
// The option definition parser is the next one to be run.
|
||||
std::map<std::string, ConstElementPtr>::const_iterator
|
||||
def_config = values_map.find("option-def");
|
||||
if (def_config != values_map.end()) {
|
||||
|
||||
CfgOptionDefPtr cfg_def = CfgMgr::instance().getStagingCfg()->getCfgOptionDef();
|
||||
OptionDefListParser def_list_parser(family);
|
||||
def_list_parser.parse(cfg_def, def_config->second);
|
||||
}
|
||||
|
||||
// The option values parser is the next one to be run.
|
||||
std::map<std::string, ConstElementPtr>::const_iterator
|
||||
option_config = values_map.find("option-data");
|
||||
if (option_config != values_map.end()) {
|
||||
option_parser->build(option_config->second);
|
||||
option_parser->commit();
|
||||
CfgOptionPtr cfg_option = CfgMgr::instance().getStagingCfg()->getCfgOption();
|
||||
|
||||
OptionDataListParser option_list_parser(family);
|
||||
option_list_parser.parse(cfg_option, option_config->second);
|
||||
}
|
||||
|
||||
// Everything was fine. Configuration is successful.
|
||||
@@ -359,17 +385,9 @@ public:
|
||||
/// @throw throws NotImplemented if element name isn't supported.
|
||||
ParserPtr createConfigParser(const std::string& config_id) {
|
||||
ParserPtr parser;
|
||||
int family = parser_context_->universe_ == Option::V4 ?
|
||||
AF_INET : AF_INET6;
|
||||
if (config_id.compare("option-data") == 0) {
|
||||
parser.reset(new OptionDataListParser(config_id, CfgOptionPtr(),
|
||||
family));
|
||||
|
||||
} else if (config_id.compare("option-def") == 0) {
|
||||
parser.reset(new OptionDefListParser(config_id,
|
||||
parser_context_));
|
||||
|
||||
} else if (config_id.compare("hooks-libraries") == 0) {
|
||||
// option-data and option-def converted to SimpleParser, so they
|
||||
// are no longer here.
|
||||
if (config_id.compare("hooks-libraries") == 0) {
|
||||
parser.reset(new HooksLibrariesParser(config_id));
|
||||
hooks_libraries_parser_ =
|
||||
boost::dynamic_pointer_cast<HooksLibrariesParser>(parser);
|
||||
@@ -392,13 +410,15 @@ public:
|
||||
///
|
||||
/// @return retuns 0 if the configuration parsed successfully,
|
||||
/// non-zero otherwise failure.
|
||||
int parseConfiguration(const std::string& config) {
|
||||
int parseConfiguration(const std::string& config, bool v6 = false) {
|
||||
int rcode_ = 1;
|
||||
// Turn config into elements.
|
||||
// Test json just to make sure its valid.
|
||||
ElementPtr json = Element::fromJSON(config);
|
||||
EXPECT_TRUE(json);
|
||||
if (json) {
|
||||
SimpleParser::setAllDefaults(json, v6);
|
||||
|
||||
ConstElementPtr status = parseElementSet(json);
|
||||
ConstElementPtr comment = parseAnswer(rcode_, status);
|
||||
error_text_ = comment->stringValue();
|
||||
@@ -566,7 +586,7 @@ TEST_F(ParseConfigTest, defaultSpaceOptionDefTest) {
|
||||
"}";
|
||||
|
||||
// Verify that the configuration string parses.
|
||||
int rcode = parseConfiguration(config);
|
||||
int rcode = parseConfiguration(config, true);
|
||||
ASSERT_EQ(0, rcode);
|
||||
|
||||
|
||||
@@ -828,7 +848,7 @@ TEST_F(ParseConfigTest, optionDataCSVFormatNoOptionDef) {
|
||||
" } ]"
|
||||
"}";
|
||||
int rcode = 0;
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config));
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config, true));
|
||||
EXPECT_NE(0, rcode);
|
||||
|
||||
CfgMgr::instance().clear();
|
||||
@@ -844,7 +864,7 @@ TEST_F(ParseConfigTest, optionDataCSVFormatNoOptionDef) {
|
||||
" \"data\": \"0\""
|
||||
" } ]"
|
||||
"}";
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config));
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config, true));
|
||||
EXPECT_NE(0, rcode);
|
||||
|
||||
CfgMgr::instance().clear();
|
||||
@@ -859,7 +879,7 @@ TEST_F(ParseConfigTest, optionDataCSVFormatNoOptionDef) {
|
||||
" \"data\": \"0\""
|
||||
" } ]"
|
||||
"}";
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config));
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config, true));
|
||||
ASSERT_EQ(0, rcode);
|
||||
OptionPtr opt = getOptionPtr(DHCP6_OPTION_SPACE, 25000);
|
||||
ASSERT_TRUE(opt);
|
||||
@@ -875,10 +895,11 @@ TEST_F(ParseConfigTest, optionDataCSVFormatNoOptionDef) {
|
||||
" \"name\": \"foo-name\","
|
||||
" \"space\": \"dhcp6\","
|
||||
" \"code\": 25000,"
|
||||
" \"csv-format\": false,"
|
||||
" \"data\": \"123456\""
|
||||
" } ]"
|
||||
"}";
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config));
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config, true));
|
||||
EXPECT_EQ(0, rcode);
|
||||
opt = getOptionPtr(DHCP6_OPTION_SPACE, 25000);
|
||||
ASSERT_TRUE(opt);
|
||||
@@ -899,7 +920,7 @@ TEST_F(ParseConfigTest, optionDataNoName) {
|
||||
" } ]"
|
||||
"}";
|
||||
int rcode = 0;
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config));
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config, true));
|
||||
EXPECT_EQ(0, rcode);
|
||||
Option6AddrLstPtr opt = boost::dynamic_pointer_cast<
|
||||
Option6AddrLst>(getOptionPtr(DHCP6_OPTION_SPACE, 23));
|
||||
@@ -919,7 +940,7 @@ TEST_F(ParseConfigTest, optionDataNoCode) {
|
||||
" } ]"
|
||||
"}";
|
||||
int rcode = 0;
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config));
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config, true));
|
||||
EXPECT_EQ(0, rcode);
|
||||
Option6AddrLstPtr opt = boost::dynamic_pointer_cast<
|
||||
Option6AddrLst>(getOptionPtr(DHCP6_OPTION_SPACE, 23));
|
||||
@@ -938,7 +959,7 @@ TEST_F(ParseConfigTest, optionDataMinimal) {
|
||||
" } ]"
|
||||
"}";
|
||||
int rcode = 0;
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config));
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config, true));
|
||||
EXPECT_EQ(0, rcode);
|
||||
Option6AddrLstPtr opt = boost::dynamic_pointer_cast<
|
||||
Option6AddrLst>(getOptionPtr(DHCP6_OPTION_SPACE, 23));
|
||||
@@ -955,7 +976,7 @@ TEST_F(ParseConfigTest, optionDataMinimal) {
|
||||
" } ]"
|
||||
"}";
|
||||
rcode = 0;
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config));
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config, true));
|
||||
EXPECT_EQ(0, rcode);
|
||||
opt = boost::dynamic_pointer_cast<Option6AddrLst>(getOptionPtr(DHCP6_OPTION_SPACE,
|
||||
23));
|
||||
@@ -984,7 +1005,7 @@ TEST_F(ParseConfigTest, optionDataMinimalWithOptionDef) {
|
||||
"}";
|
||||
|
||||
int rcode = 0;
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config));
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config, true));
|
||||
EXPECT_EQ(0, rcode);
|
||||
Option6AddrLstPtr opt = boost::dynamic_pointer_cast<
|
||||
Option6AddrLst>(getOptionPtr(DHCP6_OPTION_SPACE, 2345));
|
||||
@@ -1010,7 +1031,7 @@ TEST_F(ParseConfigTest, optionDataMinimalWithOptionDef) {
|
||||
"}";
|
||||
|
||||
rcode = 0;
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config));
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config, true));
|
||||
EXPECT_EQ(0, rcode);
|
||||
opt = boost::dynamic_pointer_cast<Option6AddrLst>(getOptionPtr(DHCP6_OPTION_SPACE,
|
||||
2345));
|
||||
@@ -1031,7 +1052,7 @@ TEST_F(ParseConfigTest, emptyOptionData) {
|
||||
"}";
|
||||
|
||||
int rcode = 0;
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config));
|
||||
ASSERT_NO_THROW(rcode = parseConfiguration(config, true));
|
||||
EXPECT_EQ(0, rcode);
|
||||
const Option6AddrLstPtr opt = boost::dynamic_pointer_cast<
|
||||
Option6AddrLst>(getOptionPtr(DHCP6_OPTION_SPACE, D6O_DHCPV4_O_DHCPV6_SERVER));
|
||||
|
Reference in New Issue
Block a user