Commit e9198441 authored by Francis Dupont's avatar Francis Dupont
Browse files

[5351] Added client classes. Todo: update doc

parent ff211701
......@@ -5625,6 +5625,11 @@ TEST_F(Dhcp4ParserTest, comments) {
" \"data\": \"ABCDEF0105\",\n"
" \"csv-format\": false\n"
" } ],\n"
"\"client-classes\": [ {\n"
" \"name\": \"all\",\n"
" \"comment\": \"match all\",\n"
" \"test\": \"'' == ''\"\n"
" } ],\n"
"\"shared-networks\": [ {\n"
" \"name\": \"foo\"\n,"
" \"comment\": \"A shared network\"\n,"
......@@ -5683,6 +5688,23 @@ TEST_F(Dhcp4ParserTest, comments) {
ASSERT_TRUE(ctx_opt_desc->get("comment"));
EXPECT_EQ("\"Set option value\"", ctx_opt_desc->get("comment")->str());
// And there is a client class.
ClientClassDictionaryPtr dict =
CfgMgr::instance().getStagingCfg()->getClientClassDictionary();
ASSERT_TRUE(dict);
EXPECT_EQ(1, dict->getClasses()->size());
ClientClassDefPtr cclass = dict->findClass("all");
ASSERT_TRUE(cclass);
EXPECT_EQ("all", cclass->getName());
EXPECT_EQ("'' == ''", cclass->getTest());
// Check client class user context.
ConstElementPtr ctx_class = cclass->getContext();
ASSERT_TRUE(ctx_class);
ASSERT_EQ(1, ctx_class->size());
ASSERT_TRUE(ctx_class->get("comment"));
EXPECT_EQ("\"match all\"", ctx_class->get("comment")->str());
// Now verify that the shared network was indeed configured.
CfgSharedNetworks4Ptr cfg_net = CfgMgr::instance().getStagingCfg()
->getCfgSharedNetworks4();
......
......@@ -1588,6 +1588,21 @@ const char* EXTRACTED_CONFIGS[] = {
// CONFIGURATION 58
"{\n"
" \"comment\": \"A DHCPv4 server\",\n"
" \"client-classes\": [\n"
" {\n"
" \"comment\": \"match all\",\n"
" \"name\": \"all\",\n"
" \"test\": \"'' == ''\"\n"
" }\n"
" ],\n"
" \"option-data\": [\n"
" {\n"
" \"comment\": \"Set option value\",\n"
" \"csv-format\": false,\n"
" \"data\": \"ABCDEF0105\",\n"
" \"name\": \"dhcp-message\"\n"
" }\n"
" ],\n"
" \"option-def\": [\n"
" {\n"
" \"comment\": \"An option definition\",\n"
......@@ -6262,6 +6277,18 @@ const char* UNPARSED_CONFIGS[] = {
// CONFIGURATION 58
"{\n"
" \"comment\": \"A DHCPv4 server\",\n"
" \"client-classes\": [\n"
" {\n"
" \"comment\": \"match all\",\n"
" \"boot-file-name\": \"\",\n"
" \"name\": \"all\",\n"
" \"next-server\": \"0.0.0.0\",\n"
" \"option-data\": [ ],\n"
" \"option-def\": [ ],\n"
" \"server-hostname\": \"\",\n"
" \"test\": \"'' == ''\"\n"
" }\n"
" ],\n"
" \"decline-probation-period\": 86400,\n"
" \"dhcp-ddns\": {\n"
" \"always-include-fqdn\": false,\n"
......@@ -6298,7 +6325,17 @@ const char* UNPARSED_CONFIGS[] = {
" \"lease-database\": {\n"
" \"type\": \"memfile\"\n"
" },\n"
" \"option-data\": [ ],\n"
" \"option-data\": [\n"
" {\n"
" \"comment\": \"Set option value\",\n"
" \"always-send\": false,\n"
" \"code\": 56,\n"
" \"csv-format\": false,\n"
" \"data\": \"ABCDEF0105\",\n"
" \"name\": \"dhcp-message\",\n"
" \"space\": \"dhcp4\"\n"
" }\n"
" ],\n"
" \"option-def\": [\n"
" {\n"
" \"comment\": \"An option definition\",\n"
......
......@@ -6067,6 +6067,11 @@ TEST_F(Dhcp6ParserTest, comments) {
" \"data\": \"ABCDEF0105\",\n"
" \"csv-format\": false\n"
" } ],\n"
"\"client-classes\": [ {\n"
" \"name\": \"all\",\n"
" \"comment\": \"match all\",\n"
" \"test\": \"'' == ''\"\n"
" } ],\n"
"\"shared-networks\": [ {\n"
" \"name\": \"foo\"\n,"
" \"comment\": \"A shared network\"\n,"
......@@ -6133,6 +6138,23 @@ TEST_F(Dhcp6ParserTest, comments) {
ASSERT_TRUE(ctx_opt_desc->get("comment"));
EXPECT_EQ("\"Set option value\"", ctx_opt_desc->get("comment")->str());
// And there is a client class.
ClientClassDictionaryPtr dict =
CfgMgr::instance().getStagingCfg()->getClientClassDictionary();
ASSERT_TRUE(dict);
EXPECT_EQ(1, dict->getClasses()->size());
ClientClassDefPtr cclass = dict->findClass("all");
ASSERT_TRUE(cclass);
EXPECT_EQ("all", cclass->getName());
EXPECT_EQ("'' == ''", cclass->getTest());
// Check client class user context.
ConstElementPtr ctx_class = cclass->getContext();
ASSERT_TRUE(ctx_class);
ASSERT_EQ(1, ctx_class->size());
ASSERT_TRUE(ctx_class->get("comment"));
EXPECT_EQ("\"match all\"", ctx_class->get("comment")->str());
// Now verify that the shared network was indeed configured.
CfgSharedNetworks6Ptr cfg_net = CfgMgr::instance().getStagingCfg()
->getCfgSharedNetworks6();
......
......@@ -1463,6 +1463,21 @@ const char* EXTRACTED_CONFIGS[] = {
// CONFIGURATION 51
"{\n"
" \"comment\": \"A DHCPv6 server\",\n"
" \"client-classes\": [\n"
" {\n"
" \"comment\": \"match all\",\n"
" \"name\": \"all\",\n"
" \"test\": \"'' == ''\"\n"
" }\n"
" ],\n"
" \"option-data\": [\n"
" {\n"
" \"comment\": \"Set option value\",\n"
" \"csv-format\": false,\n"
" \"data\": \"ABCDEF0105\",\n"
" \"name\": \"subscriber-id\"\n"
" }\n"
" ],\n"
" \"option-def\": [\n"
" {\n"
" \"comment\": \"An option definition\",\n"
......@@ -5873,6 +5888,14 @@ const char* UNPARSED_CONFIGS[] = {
// CONFIGURATION 51
"{\n"
" \"comment\": \"A DHCPv6 server\",\n"
" \"client-classes\": [\n"
" {\n"
" \"comment\": \"match all\",\n"
" \"name\": \"all\",\n"
" \"option-data\": [ ],\n"
" \"test\": \"'' == ''\"\n"
" }\n"
" ],\n"
" \"decline-probation-period\": 86400,\n"
" \"dhcp-ddns\": {\n"
" \"always-include-fqdn\": false,\n"
......@@ -5909,7 +5932,17 @@ const char* UNPARSED_CONFIGS[] = {
" \"type\": \"memfile\"\n"
" },\n"
" \"mac-sources\": [ \"any\" ],\n"
" \"option-data\": [ ],\n"
" \"option-data\": [\n"
" {\n"
" \"comment\": \"Set option value\",\n"
" \"always-send\": false,\n"
" \"code\": 38,\n"
" \"csv-format\": false,\n"
" \"data\": \"ABCDEF0105\",\n"
" \"name\": \"subscriber-id\",\n"
" \"space\": \"dhcp6\"\n"
" }\n"
" ],\n"
" \"option-def\": [\n"
" {\n"
" \"comment\": \"An option definition\",\n"
......
......@@ -132,6 +132,8 @@ ElementPtr
ClientClassDef:: toElement() const {
uint16_t family = CfgMgr::instance().getFamily();
ElementPtr result = Element::createMap();
// Set user-context
contextToElement(result);
// Set name
result->set("name", Element::create(name_));
// Set original match expression (empty string won't parse)
......@@ -185,12 +187,14 @@ ClientClassDictionary::addClass(const std::string& name,
const std::string& test,
const CfgOptionPtr& cfg_option,
CfgOptionDefPtr cfg_option_def,
ConstElementPtr user_context,
asiolink::IOAddress next_server,
const std::string& sname,
const std::string& filename) {
ClientClassDefPtr cclass(new ClientClassDef(name, match_expr, cfg_option));
cclass->setTest(test);
cclass->setCfgOptionDef(cfg_option_def);
cclass->setContext(user_context),
cclass->setNextServer(next_server);
cclass->setSname(sname);
cclass->setFilename(filename);
......
......@@ -8,6 +8,7 @@
#define CLIENT_CLASS_DEF_H
#include <cc/cfg_to_element.h>
#include <cc/user_context.h>
#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/cfg_option_def.h>
#include <eval/token.h>
......@@ -39,7 +40,7 @@ public:
};
/// @brief Embodies a single client class definition
class ClientClassDef : public isc::data::CfgToElement {
class ClientClassDef : public UserContext, public isc::data::CfgToElement {
public:
/// @brief Constructor
///
......@@ -236,6 +237,7 @@ public:
/// @param test Original version of match_expr
/// @param options Collection of options members should be given
/// @param defs Option definitions (optional)
/// @param user_context User context (optional)
/// @param next_server next-server value for this class (optional)
/// @param sname server-name value for this class (optional)
/// @param filename boot-file-name value for this class (optional)
......@@ -246,6 +248,7 @@ public:
void addClass(const std::string& name, const ExpressionPtr& match_expr,
const std::string& test, const CfgOptionPtr& options,
CfgOptionDefPtr defs = CfgOptionDefPtr(),
isc::data::ConstElementPtr user_context = isc::data::ConstElementPtr(),
asiolink::IOAddress next_server = asiolink::IOAddress("0.0.0.0"),
const std::string& sname = std::string(),
const std::string& filename = std::string());
......
......@@ -127,6 +127,9 @@ ClientClassDefParser::parse(ClientClassDictionaryPtr& class_dictionary,
opts_parser.parse(options, option_data);
}
// Parse user context
ConstElementPtr user_context = class_def_cfg->get("user-context");
// Let's try to parse the next-server field
IOAddress next_server("0.0.0.0");
if (class_def_cfg->contains("next-server")) {
......@@ -182,8 +185,8 @@ ClientClassDefParser::parse(ClientClassDictionaryPtr& class_dictionary,
// Add the client class definition
try {
class_dictionary->addClass(name, match_expr, test, options,
defs, next_server, sname, filename);
class_dictionary->addClass(name, match_expr, test, options, defs,
user_context, next_server, sname, filename);
} catch (const std::exception& ex) {
isc_throw(DhcpConfigError, "Can't add class: " << ex.what()
<< " (" << class_def_cfg->getPosition() << ")");
......
......@@ -386,6 +386,9 @@ TEST(ClientClassDef, unparseDef) {
ASSERT_NO_THROW(cclass.reset(new ClientClassDef(name, expr)));
std::string test = "option[12].text == 'foo'";
cclass->setTest(test);
std::string comment = "bar";
std::string user_context = "{ \"comment\": \"" + comment + "\" }";
cclass->setContext(isc::data::Element::fromJSON(user_context));
std::string next_server = "1.2.3.4";
cclass->setNextServer(IOAddress(next_server));
std::string sname = "my-server.example.com";
......@@ -395,6 +398,7 @@ TEST(ClientClassDef, unparseDef) {
// Unparse it
std::string expected = "{\n"
"\"comment\": \"" + comment + "\",\n"
"\"name\": \"" + name + "\",\n"
"\"test\": \"" + test + "\",\n"
"\"next-server\": \"" + next_server + "\",\n"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment