if (config_pair.first == "client-classes") {
ClientClassDefListParser parser;
- parser.parse(config_pair.second, AF_INET);
+ ClientClassDictionaryPtr dictionary =
+ parser.parse(config_pair.second, AF_INET);
+ CfgMgr::instance().getStagingCfg()->setClientClassDictionary(dictionary);
continue;
}
continue;
}
- if (config_pair.first =="client-classes") {
- ClientClassDefListParser parser;
- parser.parse(config_pair.second, AF_INET6);
- continue;
- }
+ if (config_pair.first =="client-classes") {
+ ClientClassDefListParser parser;
+ ClientClassDictionaryPtr dictionary =
+ parser.parse(config_pair.second, AF_INET6);
+ CfgMgr::instance().getStagingCfg()->setClientClassDictionary(dictionary);
+ continue;
+ }
ParserPtr parser(createGlobal6DhcpConfigParser(config_pair.first,
config_pair.second));
// ********************** ExpressionParser ****************************
-ExpressionParser::ExpressionParser(ExpressionPtr& expression)
- : local_expression_(ExpressionPtr()), expression_(expression) {
-}
-
void
-ExpressionParser::parse(ConstElementPtr expression_cfg, uint16_t family) {
+ExpressionParser::parse(ExpressionPtr& expression,
+ ConstElementPtr expression_cfg,
+ uint16_t family) {
if (expression_cfg->getType() != Element::string) {
isc_throw(DhcpConfigError, "expression ["
<< expression_cfg->str() << "] must be a string, at ("
try {
EvalContext eval_ctx(family == AF_INET ? Option::V4 : Option::V6);
eval_ctx.parseString(value);
- local_expression_.reset(new Expression());
- *local_expression_ = eval_ctx.expression;
+ expression.reset(new Expression());
+ *expression = eval_ctx.expression;
} catch (const std::exception& ex) {
// Append position if there is a failure.
isc_throw(DhcpConfigError,
<< "] error: " << ex.what() << " at ("
<< expression_cfg->getPosition() << ")");
}
-
- // Success so commit.
- expression_ = local_expression_;
}
// ********************** ClientClassDefParser ****************************
-ClientClassDefParser::ClientClassDefParser(ClientClassDictionaryPtr& class_dictionary)
- : match_expr_(ExpressionPtr()),
- options_(new CfgOption()),
- class_dictionary_(class_dictionary) {
-}
-
void
-ClientClassDefParser::parse(ConstElementPtr class_def_cfg, uint16_t family) {
+ClientClassDefParser::parse(ClientClassDictionaryPtr& class_dictionary,
+ ConstElementPtr class_def_cfg,
+ uint16_t family) {
try {
std::string name;
std::string next_server_txt = "0.0.0.0";
std::string sname;
std::string filename;
+ ExpressionPtr match_expr;
+ CfgOptionPtr options(new CfgOption());
// Parse the elements that make up the client class definition.
BOOST_FOREACH(ConfigPair param, class_def_cfg->mapValue()) {
name = value->stringValue();
} else if (entry == "test") {
- ExpressionParser parser(match_expr_);
- parser.parse(value, family);
+ ExpressionParser parser;
+ parser.parse(match_expr, value, family);
} else if (entry == "option-data") {
OptionDataListParser opts_parser(family);
- opts_parser.parse(options_, value);
+ opts_parser.parse(options, value);
} else if (entry == "next-server") {
next_server_txt = value->stringValue();
}
}
- // Make name mandatory?
+ // name is now mandatory
+ if (name.empty()) {
+ isc_throw(DhcpConfigError,
+ "not empty parameter 'name' is required");
+ }
// Let's parse the next-server field
IOAddress next_server("0.0.0.0");
}
// Add the client class definition
- class_dictionary_->addClass(name, match_expr_, options_, next_server,
- sname, filename);
+ class_dictionary->addClass(name, match_expr, options, next_server,
+ sname, filename);
} catch (const std::exception& ex) {
isc_throw(DhcpConfigError, ex.what()
<< " (" << class_def_cfg->getPosition() << ")");
// ****************** ClientClassDefListParser ************************
-ClientClassDefListParser::ClientClassDefListParser()
- : local_dictionary_(new ClientClassDictionary()) {
-}
-
-void
+ClientClassDictionaryPtr
ClientClassDefListParser::parse(ConstElementPtr client_class_def_list,
uint16_t family) {
+ ClientClassDictionaryPtr dictionary(new ClientClassDictionary());
BOOST_FOREACH(ConstElementPtr client_class_def,
client_class_def_list->listValue()) {
- ClientClassDefParser parser(local_dictionary_);
- parser.parse(client_class_def, family);
+ ClientClassDefParser parser;
+ parser.parse(dictionary, client_class_def, family);
}
- // Success so commit
- CfgMgr::instance().getStagingCfg()->setClientClassDictionary(local_dictionary_);
+ return (dictionary);
}
} // end of namespace isc::dhcp
/// stored into the ExpressionPtr reference passed into the constructor.
class ExpressionParser : public isc::data::SimpleParser {
public:
- /// @brief Constructor.
- ///
- /// @param expression variable in which to store the new expression
- ExpressionParser(ExpressionPtr& expression);
/// @brief Parses an expression configuration element into an Expression
///
+ /// @param expression variable in which to store the new expression
/// @param expression_cfg the configuration entry to be parsed.
/// @param family the address family of the expression.
///
/// @throw DhcpConfigError if parsing was unsuccessful.
- void parse(isc::data::ConstElementPtr expression_cfg, uint16_t family);
-
-private:
- /// @brief Local storage for the parsed expression
- ExpressionPtr local_expression_;
-
- /// @brief Storage into which the parsed expression should be committed
- ExpressionPtr& expression_;
+ void parse(ExpressionPtr& expression,
+ isc::data::ConstElementPtr expression_cfg, uint16_t family);
};
/// @brief Parser for a single client class definition.
/// This parser creates an instance of a client class definition.
class ClientClassDefParser : public isc::data::SimpleParser {
public:
- /// @brief Constructor.
- ///
- /// @param class_dictionary dictionary into which the class should be added
- ClientClassDefParser(ClientClassDictionaryPtr& class_dictionary);
/// @brief Parses an entry that describes single client class definition.
///
/// Attempts to add the new class directly into the given dictionary.
/// This done here to detect duplicate classes prior to commit().
+ /// @param class_dictionary dictionary into which the class should be added
/// @param client_class_def a configuration entry to be parsed.
/// @param family the address family of the client class.
///
/// @throw DhcpConfigError if parsing was unsuccessful.
- void parse(isc::data::ConstElementPtr client_class_def, uint16_t family);
-
-private:
-
- /// @brief Storage for the class match expression
- ExpressionPtr match_expr_;
-
- /// @brief Storage for the class options
- CfgOptionPtr options_;
-
- /// @brief Dictionary to which the new class should be added
- ClientClassDictionaryPtr& class_dictionary_;
+ void parse(ClientClassDictionaryPtr& class_dictionary,
+ isc::data::ConstElementPtr client_class_def, uint16_t family);
};
/// @brief Defines a pointer to a ClientClassDefParser
class ClientClassDefListParser : public isc::data::SimpleParser {
public:
- /// @brief Constructor.
- ClientClassDefListParser();
-
/// @brief Parse configuration entries.
///
/// This function parses configuration entries, creates instances
- /// of client class definitions and tries to adds them to the a
- /// local dictionary. At the end class definitions are committed
- /// to CfgMgr's global storage.
+ /// of client class definitions and tries to adds them to the
+ /// local dictionary. At the end the dictionary is returned.
///
/// @param class_def_list pointer to an element that holds entries
/// for client class definitions.
/// @param family the address family of the client class definitions.
+ /// @return a pointer to the filled dictionary
/// @throw DhcpConfigError if configuration parsing fails.
- void parse(isc::data::ConstElementPtr class_def_list, uint16_t family);
-
- /// @brief Local class dictionary to store classes as they are being parsed
- ///
- /// Left public for easier unit testing.
- ClientClassDictionaryPtr local_dictionary_;
+ ClientClassDictionaryPtr
+ parse(isc::data::ConstElementPtr class_def_list, uint16_t family);
};
} // end of namespace isc::dhcp
-// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
class_dictionary_ = dictionary;
}
- /// @brief Copies the currnet configuration to a new configuration.
+ /// @brief Copies the current configuration to a new configuration.
///
/// This method copies the parameters stored in the configuration to
/// an object passed as parameter. The configuration sequence is not
const std::string& expression,
const std::string& option_string) {
ExpressionPtr parsed_expr;
- ExpressionParser parser(parsed_expr);
+ ExpressionParser parser;
// Turn config into elements. This may emit exceptions.
ElementPtr config_element = Element::fromJSON(expression);
// Expression should parse.
- ASSERT_NO_THROW(parser.parse(config_element, family));
+ ASSERT_NO_THROW(parser.parse(parsed_expr, config_element, family));
// Parsed expression should exist.
ASSERT_TRUE(parsed_expr);
/// or by the parsing itself are not caught
ClientClassDefPtr parseClientClassDef(const std::string& config,
uint16_t family) {
- // Create local dicitonary to which the parser add the class.
+ // Create local dictionary to which the parser add the class.
ClientClassDictionaryPtr dictionary(new ClientClassDictionary());
// Turn config into elements. This may emit exceptions.
ElementPtr config_element = Element::fromJSON(config);
// Parse the configuration. This may emit exceptions.
- ClientClassDefParser parser(dictionary);
- parser.parse(config_element, family);
+ ClientClassDefParser parser;
+ parser.parse(dictionary, config_element, family);
// If we didn't throw, then return the first and only class
ClientClassDefMapPtr classes = dictionary->getClasses();
// Parse the configuration. This may emit exceptions.
ClientClassDefListParser parser;
- parser.parse(config_element, family);
-
- // Return the parser's local dicationary
- return (parser.local_dictionary_);
+ return (parser.parse(config_element, family));
}
};
// Create the parser.
ExpressionPtr parsed_expr;
- ExpressionParser parser(parsed_expr);
+ ExpressionParser parser;
// Expression parsing should fail.
- ASSERT_THROW(parser.parse(config_element, AF_INET), DhcpConfigError);
+ ASSERT_THROW(parser.parse(parsed_expr, config_element, AF_INET6),
+ DhcpConfigError);
}
// Verifies that given an invalid expression with a syntax error,
// Create the parser.
ExpressionPtr parsed_expr;
- ExpressionParser parser(parsed_expr);
+ ExpressionParser parser;
// Expression parsing should fail.
- ASSERT_THROW(parser.parse(config_element, AF_INET), DhcpConfigError);
+ ASSERT_THROW(parser.parse(parsed_expr, config_element, AF_INET),
+ DhcpConfigError);
+}
+
+// Verifies that the name parameter is required and must not be empty
+TEST_F(ExpressionParserTest, nameEmpty) {
+ std::string cfg_txt = "{ \"name\": \"\" }";
+ ElementPtr config_element = Element::fromJSON(cfg_txt);
+
+ // Create the parser.
+ ExpressionPtr parsed_expr;
+ ExpressionParser parser;
+
+ // Expression parsing should fail.
+ ASSERT_THROW(parser.parse(parsed_expr, config_element, AF_INET6),
+ DhcpConfigError);
}
// Verifies you can create a class with only a name
// Verifies you can create a class with a name, expression,
// but no options.
+// @todo same with AF_INET6
TEST_F(ClientClassDefParserTest, nameAndExpressionClass) {
std::string cfg_text =
// Verifies you can create a class with a name and options,
// but no expression.
+// @todo same with AF_INET6
TEST_F(ClientClassDefParserTest, nameAndOptionsClass) {
std::string cfg_text =
// Verifies you can create a class with a name, expression,
// and options.
+// @todo same with AF_INET6
TEST_F(ClientClassDefParserTest, basicValidClass) {
std::string cfg_text =
"} \n";
ClientClassDefPtr cclass;
- ASSERT_THROW(cclass = parseClientClassDef(cfg_text, AF_INET),
+ ASSERT_THROW(cclass = parseClientClassDef(cfg_text, AF_INET6),
DhcpConfigError);
}
// Parsing the list should succeed.
ClientClassDictionaryPtr dictionary;
- ASSERT_NO_THROW(dictionary = parseClientClassDefList(cfg_text, AF_INET));
+ ASSERT_NO_THROW(dictionary = parseClientClassDefList(cfg_text, AF_INET6));
ASSERT_TRUE(dictionary);
// We should have three classes in the dictionary.
// For good measure, make sure we can't find a non-existant class.
ASSERT_NO_THROW(cclass = dictionary->findClass("bogus"));
EXPECT_FALSE(cclass);
-
- // Verify that the dictionary was pushed to the CfgMgr's staging config.
- SrvConfigPtr staging = CfgMgr::instance().getStagingCfg();
- ASSERT_TRUE(staging);
- ClientClassDictionaryPtr staged_dictionary = staging->getClientClassDictionary();
- ASSERT_TRUE(staged_dictionary);
- EXPECT_TRUE(*staged_dictionary == *dictionary);
}
// Verifies that class list containing a duplicate class entries, fails
"] \n";
ClientClassDictionaryPtr dictionary;
- ASSERT_THROW(dictionary = parseClientClassDefList(cfg_text, AF_INET),
+ ASSERT_THROW(dictionary = parseClientClassDefList(cfg_text, AF_INET6),
DhcpConfigError);
}
// Test verifies that without any class specified, the fixed fields have their
// default, empty value.
+// @todo same with AF_INET6
TEST_F(ClientClassDefParserTest, noFixedFields) {
std::string cfg_text =