Commit 26be56de authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰

[5019] Subnet4, Subne6 parsers migrated to SimpleParser

parent d7992941
......@@ -108,9 +108,8 @@ class Subnet4ConfigParser : public SubnetConfigParser {
public:
/// @brief Constructor
///
/// @param ignored first parameter
/// stores global scope parameters, options, option definitions.
Subnet4ConfigParser(const std::string&)
Subnet4ConfigParser()
:SubnetConfigParser("", globalContext(), IOAddress("0.0.0.0")) {
}
......@@ -118,7 +117,8 @@ public:
/// Configuration Manager.
///
/// @param subnet A new subnet being configured.
void build(ConstElementPtr subnet) {
/// @return a pointer to created Subnet4 object
Subnet4Ptr parse(ConstElementPtr subnet) {
/// Parse Pools first.
ConstElementPtr pools = subnet->get("pools");
if (pools) {
......@@ -126,30 +126,18 @@ public:
parser.parse(pools_, pools);
}
SubnetConfigParser::build(subnet);
SubnetPtr generic = SubnetConfigParser::build(subnet);
if (subnet_) {
Subnet4Ptr sub4ptr = boost::dynamic_pointer_cast<Subnet4>(subnet_);
if (!sub4ptr) {
// If we hit this, it is a programming error.
isc_throw(Unexpected,
"Invalid cast in Subnet4ConfigParser::commit");
}
// Set relay information if it was parsed
if (relay_info_) {
sub4ptr->setRelayInfo(*relay_info_);
}
Subnet4Ptr sub4ptr = boost::dynamic_pointer_cast<Subnet4>(generic);
if (!sub4ptr) {
// If we hit this, it is a programming error.
isc_throw(Unexpected,
"Invalid Subnet4 cast in Subnet4ConfigParser::parse");
}
// Adding a subnet to the Configuration Manager may fail if the
// subnet id is invalid (duplicate). Thus, we catch exceptions
// here to append a position in the configuration string.
try {
CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->add(sub4ptr);
} catch (const std::exception& ex) {
isc_throw(DhcpConfigError, ex.what() << " ("
<< subnet->getPosition() << ")");
}
// Set relay information if it was parsed
if (relay_info_) {
sub4ptr->setRelayInfo(*relay_info_);
}
// Parse Host Reservations for this subnet if any.
......@@ -158,13 +146,9 @@ public:
HostReservationsListParser<HostReservationParser4> parser;
parser.parse(subnet_->getID(), reservations);
}
}
/// @brief Commits subnet configuration.
///
/// This function is currently no-op because subnet should already
/// be added into the Config Manager in the build().
void commit() { }
return (sub4ptr);
}
protected:
......@@ -358,40 +342,38 @@ protected:
/// This is a wrapper parser that handles the whole list of Subnet4
/// definitions. It iterates over all entries and creates Subnet4ConfigParser
/// for each entry.
class Subnets4ListConfigParser : public DhcpConfigParser {
class Subnets4ListConfigParser : public isc::data::SimpleParser {
public:
/// @brief constructor
///
/// @param dummy first argument, always ignored. All parsers accept a
/// string parameter "name" as their first argument.
Subnets4ListConfigParser(const std::string&) {
}
/// @brief parses contents of the list
///
/// Iterates over all entries on the list and creates Subnet4ConfigParser
/// for each entry.
/// Iterates over all entries on the list, parses its content
/// (by instantiating Subnet6ConfigParser) and adds to specified
/// configuration.
///
/// @param subnets_list pointer to a list of IPv4 subnets
void build(ConstElementPtr subnets_list) {
BOOST_FOREACH(ConstElementPtr subnet, subnets_list->listValue()) {
ParserPtr parser(new Subnet4ConfigParser("subnet"));
parser->build(subnet);
/// @return number of subnets created
size_t parse(SrvConfigPtr cfg, ConstElementPtr subnets_list) {
size_t cnt = 0;
BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
Subnet4ConfigParser parser;
Subnet4Ptr subnet = parser.parse(subnet_json);
if (subnet) {
// Adding a subnet to the Configuration Manager may fail if the
// subnet id is invalid (duplicate). Thus, we catch exceptions
// here to append a position in the configuration string.
try {
cfg->getCfgSubnets4()->add(subnet);
cnt++;
} catch (const std::exception& ex) {
isc_throw(DhcpConfigError, ex.what() << " ("
<< subnet_json->getPosition() << ")");
}
}
}
}
/// @brief commits subnets definitions.
///
/// Does nothing.
void commit() {
}
/// @brief Returns Subnet4ListConfigParser object
/// @param param_name name of the parameter
/// @return Subnets4ListConfigParser object
static DhcpConfigParser* factory(const std::string& param_name) {
return (new Subnets4ListConfigParser(param_name));
return (cnt);
}
};
......@@ -420,8 +402,7 @@ DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id,
(config_id.compare("dhcp4o6-port") == 0) ) {
parser = new Uint32Parser(config_id,
globalContext()->uint32_values_);
} else if (config_id.compare("subnet4") == 0) {
parser = new Subnets4ListConfigParser(config_id);
// subnet4 has been migrated to SimpleParser already.
// interface-config has been migrated to SimpleParser already.
// option-data and option-def have been converted to SimpleParser already.
} else if ((config_id.compare("next-server") == 0)) {
......@@ -564,7 +545,6 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
// then: option-data parser, subnet4 parser, lease-database parser.
// Please do not change this order!
ParserCollection independent_parsers;
ParserPtr subnet_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
......@@ -601,6 +581,9 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
// Set all default values if not specified by the user.
SimpleParser4::setAllDefaults(mutable_cfg);
// And now derive (inherit) global parameters to subnets, if not specified.
SimpleParser4::deriveParameters(mutable_cfg);
// We need definitions first
ConstElementPtr option_defs = mutable_cfg->get("option-def");
if (option_defs) {
......@@ -660,7 +643,7 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
hooks_parser.verifyLibraries();
continue;
}
// Legacy DhcpConfigParser stuff below
if (config_pair.first == "dhcp-ddns") {
// Apply defaults if not in short cut
......@@ -696,30 +679,27 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
continue;
}
if (config_pair.first == "subnet4") {
SrvConfigPtr srv_cfg = CfgMgr::instance().getStagingCfg();
Subnets4ListConfigParser subnets_parser;
// parse() returns number of subnets parsed. We may log it one day.
subnets_parser.parse(srv_cfg, config_pair.second);
continue;
}
ParserPtr parser(createGlobalDhcp4ConfigParser(config_pair.first,
config_pair.second));
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_PARSER_CREATED)
.arg(config_pair.first);
if (config_pair.first == "subnet4") {
subnet_parser = parser;
} else {
// Those parsers should be started before other
// parsers so we can call build straight away.
independent_parsers.push_back(parser);
parser->build(config_pair.second);
// The commit operation here may modify the global storage
// but we need it so as the subnet6 parser can access the
// parsed data.
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");
if (subnet_config != values_map.end()) {
config_pair.first = "subnet4";
subnet_parser->build(subnet_config->second);
// Those parsers should be started before other
// parsers so we can call build straight away.
independent_parsers.push_back(parser);
parser->build(config_pair.second);
// The commit operation here may modify the global storage
// but we need it so as the subnet6 parser can access the
// parsed data.
parser->commit();
}
// Setup the command channel.
......
......@@ -98,6 +98,20 @@ size_t SimpleParser4::setAllDefaults(isc::data::ElementPtr global) {
cnt += SimpleParser::setDefaults(single_option, OPTION4_DEFAULTS);
}
}
return (cnt);
}
size_t SimpleParser4::deriveParameters(isc::data::ElementPtr global) {
size_t cnt = 0;
// Now derive global parameters into subnets.
ConstElementPtr subnets = global->get("subnet4");
if (subnets) {
BOOST_FOREACH(ElementPtr single_subnet, subnets->listValue()) {
cnt += SimpleParser::deriveParams(global, single_subnet,
INHERIT_GLOBAL_TO_SUBNET4);
}
}
return (cnt);
}
......
......@@ -28,6 +28,14 @@ public:
/// @return number of default values added
static size_t setAllDefaults(isc::data::ElementPtr global);
/// @brief Derives (inherits) all parameters from global to more specific scopes.
///
/// This method currently does the following:
/// - derives global parameters to subnets (lifetimes for now)
/// @param global scope to be modified if needed (subnet4 will be extracted)
/// @return number of default values derived
static size_t deriveParameters(isc::data::ElementPtr global);
// see simple_parser4.cc for comments for those parameters
static const isc::data::SimpleDefaults OPTION4_DEF_DEFAULTS;
static const isc::data::SimpleDefaults OPTION4_DEFAULTS;
......
......@@ -69,15 +69,18 @@ TEST_F(SimpleParser4Test, inheritGlobalToSubnet4) {
ElementPtr global = parseJSON("{ \"renew-timer\": 1,"
" \"rebind-timer\": 2,"
" \"preferred-lifetime\": 3,"
" \"valid-lifetime\": 4"
" \"valid-lifetime\": 4,"
" \"subnet4\": [ { \"renew-timer\": 100 } ] "
"}");
ElementPtr subnet = parseJSON("{ \"renew-timer\": 100 }");
ConstElementPtr subnets = global->find("subnet4");
ASSERT_TRUE(subnets);
ConstElementPtr subnet = subnets->get(0);
ASSERT_TRUE(subnet);
// we should inherit 3 parameters. Renew-timer should remain intact,
// as it was already defined in the subnet scope.
size_t num;
EXPECT_NO_THROW(num = SimpleParser4::deriveParams(global, subnet,
SimpleParser4::INHERIT_GLOBAL_TO_SUBNET4));
EXPECT_NO_THROW(num = SimpleParser4::deriveParameters(global));
EXPECT_EQ(2, num);
// Check the values. 2 of them are inherited, while the third one
......@@ -87,6 +90,7 @@ TEST_F(SimpleParser4Test, inheritGlobalToSubnet4) {
checkIntegerValue(subnet, "valid-lifetime", 4);
}
};
};
};
......@@ -301,9 +301,8 @@ public:
/// @brief Constructor
///
/// @param ignored first parameter
/// stores global scope parameters, options, option definitions.
Subnet6ConfigParser(const std::string&)
Subnet6ConfigParser()
:SubnetConfigParser("", globalContext(), IOAddress("::")) {
}
......@@ -311,7 +310,8 @@ public:
/// Configuration Manager.
///
/// @param subnet A new subnet being configured.
void build(ConstElementPtr subnet) {
/// @return a pointer to created Subnet6 object
Subnet6Ptr parse(ConstElementPtr subnet) {
/// Parse all pools first.
ConstElementPtr pools = subnet->get("pools");
if (pools) {
......@@ -324,45 +324,36 @@ public:
parser.parse(pools_, pd_pools);
}
SubnetConfigParser::build(subnet);
SubnetPtr generic = SubnetConfigParser::build(subnet);
if (subnet_) {
Subnet6Ptr sub6ptr = boost::dynamic_pointer_cast<Subnet6>(subnet_);
if (!sub6ptr) {
// If we hit this, it is a programming error.
isc_throw(Unexpected,
"Invalid cast in Subnet6ConfigParser::commit");
}
if (!generic) {
isc_throw(DhcpConfigError,
"Failed to create an IPv6 subnet (" <<
subnet->getPosition() << ")");
}
// Set relay information if it was provided
if (relay_info_) {
sub6ptr->setRelayInfo(*relay_info_);
}
Subnet6Ptr sub6ptr = boost::dynamic_pointer_cast<Subnet6>(subnet_);
if (!sub6ptr) {
// If we hit this, it is a programming error.
isc_throw(Unexpected,
"Invalid Subnet6 cast in Subnet6ConfigParser::parse");
}
// Adding a subnet to the Configuration Manager may fail if the
// subnet id is invalid (duplicate). Thus, we catch exceptions
// here to append a position in the configuration string.
try {
CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->add(sub6ptr);
} catch (const std::exception& ex) {
isc_throw(DhcpConfigError, ex.what() << " ("
<< subnet->getPosition() << ")");
}
// Set relay information if it was provided
if (relay_info_) {
sub6ptr->setRelayInfo(*relay_info_);
}
// Parse Host Reservations for this subnet if any.
ConstElementPtr reservations = subnet->get("reservations");
if (reservations) {
HostReservationsListParser<HostReservationParser6> parser;
parser.parse(subnet_->getID(), reservations);
}
// Parse Host Reservations for this subnet if any.
ConstElementPtr reservations = subnet->get("reservations");
if (reservations) {
HostReservationsListParser<HostReservationParser6> parser;
parser.parse(subnet_->getID(), reservations);
}
}
/// @brief Commits subnet configuration.
///
/// This function is currently no-op because subnet should already
/// be added into the Config Manager in the build().
void commit() { }
return (sub6ptr);
}
protected:
......@@ -509,51 +500,38 @@ protected:
/// This is a wrapper parser that handles the whole list of Subnet6
/// definitions. It iterates over all entries and creates Subnet6ConfigParser
/// for each entry.
class Subnets6ListConfigParser : public DhcpConfigParser {
class Subnets6ListConfigParser : public isc::data::SimpleParser {
public:
/// @brief constructor
///
/// @param dummy first argument, always ignored. All parsers accept a
/// string parameter "name" as their first argument.
Subnets6ListConfigParser(const std::string&) {
}
/// @brief parses contents of the list
///
/// Iterates over all entries on the list and creates a Subnet6ConfigParser
/// for each entry.
/// Iterates over all entries on the list, parses its content
/// (by instantiating Subnet6ConfigParser) and adds to specified
/// configuration.
///
/// @param cfg configuration (parsed subnets will be stored here)
/// @param subnets_list pointer to a list of IPv6 subnets
void build(ConstElementPtr subnets_list) {
BOOST_FOREACH(ConstElementPtr subnet, subnets_list->listValue()) {
ParserPtr parser(new Subnet6ConfigParser("subnet"));
parser->build(subnet);
subnets_.push_back(parser);
}
/// @throw DhcpConfigError if CfgMgr rejects the subnet (e.g. subnet-id is a duplicate)
size_t parse(SrvConfigPtr cfg, ConstElementPtr subnets_list) {
size_t cnt = 0;
BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
}
Subnet6ConfigParser parser;
Subnet6Ptr subnet = parser.parse(subnet_json);
/// @brief commits subnets definitions.
///
/// Iterates over all Subnet6 parsers. Each parser contains definitions of
/// a single subnet and its parameters and commits each subnet separately.
void commit() {
BOOST_FOREACH(ParserPtr subnet, subnets_) {
subnet->commit();
// Adding a subnet to the Configuration Manager may fail if the
// subnet id is invalid (duplicate). Thus, we catch exceptions
// here to append a position in the configuration string.
try {
cfg->getCfgSubnets6()->add(subnet);
cnt++;
} catch (const std::exception& ex) {
isc_throw(DhcpConfigError, ex.what() << " ("
<< subnet_json->getPosition() << ")");
}
}
}
/// @brief Returns Subnet6ListConfigParser object
/// @param param_name name of the parameter
/// @return Subnets6ListConfigParser object
static DhcpConfigParser* factory(const std::string& param_name) {
return (new Subnets6ListConfigParser(param_name));
return (cnt);
}
/// @brief collection of subnet parsers.
ParserCollection subnets_;
};
/// @brief Parser for list of RSOO options
......@@ -664,8 +642,7 @@ DhcpConfigParser* createGlobal6DhcpConfigParser(const std::string& config_id,
(config_id.compare("dhcp4o6-port") == 0) ) {
parser = new Uint32Parser(config_id,
globalContext()->uint32_values_);
} else if (config_id.compare("subnet6") == 0) {
parser = new Subnets6ListConfigParser(config_id);
// subnet6 has been converted to SimpleParser.
// option-data and option-def are no longer needed here. They're now
// converted to SimpleParser and are handled in configureDhcp6Server.
// interfaces-config has been converted to SimpleParser.
......@@ -796,7 +773,6 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
// lease-database parser.
// Please do not change this order!
ParserCollection independent_parsers;
ParserPtr subnet_parser;
// Some of the parsers alter state of the system that can't easily
// be undone. (Or alter it in a way such that undoing the change
......@@ -830,8 +806,12 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
// default values and will insert derived values as well.
ElementPtr mutable_cfg = boost::const_pointer_cast<Element>(config_set);
// Set all default values if not specified by the user.
SimpleParser6::setAllDefaults(mutable_cfg);
// And now derive (inherit) global parameters to subnets, if not specified.
SimpleParser6::deriveParameters(mutable_cfg);
// Make parsers grouping.
const std::map<std::string, ConstElementPtr>& values_map =
mutable_cfg->mapValue();
......@@ -942,30 +922,27 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
continue;
}
if (config_pair.first == "subnet6") {
SrvConfigPtr srv_cfg = CfgMgr::instance().getStagingCfg();
Subnets6ListConfigParser subnets_parser;
// parse() returns number of subnets parsed. We may log it one day.
subnets_parser.parse(srv_cfg, config_pair.second);
continue;
}
ParserPtr parser(createGlobal6DhcpConfigParser(config_pair.first,
config_pair.second));
LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PARSER_CREATED)
.arg(config_pair.first);
if (config_pair.first == "subnet6") {
subnet_parser = parser;
} else {
// Those parsers should be started before other
// parsers so we can call build straight away.
independent_parsers.push_back(parser);
parser->build(config_pair.second);
// The commit operation here may modify the global storage
// but we need it so as the subnet6 parser can access the
// parsed data.
parser->commit();
}
}
// The subnet parser is the next one to be run.
std::map<std::string, ConstElementPtr>::const_iterator subnet_config =
values_map.find("subnet6");
if (subnet_config != values_map.end()) {
config_pair.first = "subnet6";
subnet_parser->build(subnet_config->second);
// Those parsers should be started before other
// parsers so we can call build straight away.
independent_parsers.push_back(parser);
parser->build(config_pair.second);
// The commit operation here may modify the global storage
// but we need it so as the subnet6 parser can access the
// parsed data.
parser->commit();
}
// Setup the command channel.
......@@ -993,9 +970,6 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
// This operation should be exception safe but let's make sure.
if (!rollback) {
try {
if (subnet_parser) {
subnet_parser->commit();
}
// Apply global options in the staging config.
setGlobalParameters6();
......
......@@ -104,5 +104,19 @@ size_t SimpleParser6::setAllDefaults(isc::data::ElementPtr global) {
return (cnt);
}
size_t SimpleParser6::deriveParameters(isc::data::ElementPtr global) {
size_t cnt = 0;
// Now derive global parameters into subnets.
ConstElementPtr subnets = global->get("subnet6");
if (subnets) {
BOOST_FOREACH(ElementPtr single_subnet, subnets->listValue()) {
cnt += SimpleParser::deriveParams(global, single_subnet,
INHERIT_GLOBAL_TO_SUBNET6);
}
}
return (cnt);
}
};
};
......@@ -29,6 +29,14 @@ public:
/// @return number of default values added
static size_t setAllDefaults(isc::data::ElementPtr global);
/// @brief Derives (inherits) all parameters from global to more specific scopes.
///
/// This method currently does the following:
/// - derives global parameters to subnets (lifetimes for now)
/// @param global scope to be modified if needed (subnet4 will be extracted)
/// @return number of default values derived
static size_t deriveParameters(isc::data::ElementPtr global);
// see simple_parser6.cc for comments for those parameters
static const isc::data::SimpleDefaults OPTION6_DEF_DEFAULTS;
static const isc::data::SimpleDefaults OPTION6_DEFAULTS;
......
......@@ -67,14 +67,18 @@ TEST_F(SimpleParser6Test, inheritGlobalToSubnet6) {
" \"rebind-timer\": 2,"
" \"preferred-lifetime\": 3,"
" \"valid-lifetime\": 4"
" \"subnet6\": [ { \"renew-timer\": 100 } ] "
"}");
ElementPtr subnet = parseJSON("{ \"renew-timer\": 100 }");
ConstElementPtr subnets = global->find("subnet6");
ASSERT_TRUE(subnets);
ConstElementPtr subnet = subnets->get(0);
ASSERT_TRUE(subnet);
// we should inherit 3 parameters. Renew-timer should remain intact,
// as it was already defined in the subnet scope.
size_t num;
EXPECT_NO_THROW(num = SimpleParser::deriveParams(global, subnet,
SimpleParser6::INHERIT_GLOBAL_TO_SUBNET6));
EXPECT_NO_THROW(num = SimpleParser6::deriveParameters(global));
EXPECT_EQ(3, num);
// Check the values. 3 of them are inherited, while the fourth one
......
......@@ -998,7 +998,7 @@ SubnetConfigParser::SubnetConfigParser(const std::string&,
}
void
SubnetPtr
SubnetConfigParser::build(ConstElementPtr subnet) {
BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
// Pools has been converted to SimpleParser.
......@@ -1068,6 +1068,8 @@ SubnetConfigParser::build(ConstElementPtr subnet) {
"subnet configuration failed (" << subnet->getPosition()
<< "): " << ex.what());
}
return (subnet_);