Commit 55ad23aa authored by Francis Dupont's avatar Francis Dupont Committed by Tomek Mrugalski

[5014_phase2] Use parser in place of fromJSON

parent a97417d5
......@@ -107,6 +107,8 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_GENERIC_JSON(driver.loc_);
case Parser6Context::PARSER_DHCP6:
return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_DHCP6(driver.loc_);
case Parser6Context::SUBPARSER_DHCP6:
return isc::dhcp::Dhcp6Parser::make_SUB_DHCP6(driver.loc_);
case Parser6Context::SUBPARSER_INTERFACES6:
return isc::dhcp::Dhcp6Parser::make_SUB_INTERFACES6(driver.loc_);
case Parser6Context::SUBPARSER_SUBNET6:
......@@ -220,6 +222,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::OPTION_DEF:
case isc::dhcp::Parser6Context::SERVER_ID:
return isc::dhcp::Dhcp6Parser::make_TYPE(driver.loc_);
default:
......@@ -323,6 +326,15 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
}
}
\"option-def\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::DHCP6:
return isc::dhcp::Dhcp6Parser::make_OPTION_DEF(driver.loc_);
default:
return isc::dhcp::Dhcp6Parser::make_STRING("option-def", driver.loc_);
}
}
\"option-data\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::DHCP6:
......@@ -342,6 +354,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::LEASE_DATABASE:
case isc::dhcp::Parser6Context::HOSTS_DATABASE:
case isc::dhcp::Parser6Context::OPTION_DEF:
case isc::dhcp::Parser6Context::OPTION_DATA:
case isc::dhcp::Parser6Context::CLIENT_CLASSES:
case isc::dhcp::Parser6Context::CLIENT_CLASS:
......@@ -444,6 +457,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"code\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::OPTION_DEF:
case isc::dhcp::Parser6Context::OPTION_DATA:
return isc::dhcp::Dhcp6Parser::make_CODE(driver.loc_);
default:
......@@ -621,6 +635,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"space\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::OPTION_DEF:
case isc::dhcp::Parser6Context::OPTION_DATA:
return isc::dhcp::Dhcp6Parser::make_SPACE(driver.loc_);
default:
......@@ -630,6 +645,7 @@ ControlCharacterFill [^"\\]|\\{JSONEscapeSequence}
\"csv-format\" {
switch(driver.ctx_) {
case isc::dhcp::Parser6Context::OPTION_DEF:
case isc::dhcp::Parser6Context::OPTION_DATA:
return isc::dhcp::Dhcp6Parser::make_CSV_FORMAT(driver.loc_);
default:
......
......@@ -67,6 +67,7 @@ using namespace std;
RENEW_TIMER "renew-timer"
REBIND_TIMER "rebind-timer"
SUBNET6 "subnet6"
OPTION_DEF "option-def"
OPTION_DATA "option-data"
NAME "name"
DATA "data"
......@@ -131,11 +132,13 @@ using namespace std;
// parse.
TOPLEVEL_GENERIC_JSON
TOPLEVEL_DHCP6
SUB_DHCP6
SUB_INTERFACES6
SUB_SUBNET6
SUB_POOL6
SUB_PD_POOL
SUB_RESERVATION
SUB_OPTION_DEF
SUB_OPTION_DATA
SUB_HOOKS_LIBRARY
SUB_JSON
......@@ -159,11 +162,13 @@ using namespace std;
start: TOPLEVEL_GENERIC_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } map2
| TOPLEVEL_DHCP6 { ctx.ctx_ = ctx.CONFIG; } syntax_map
| SUB_DHCP6 { ctx.ctx_ = ctx.DHCP6; } sub_dhcp6
| SUB_INTERFACES6 { ctx.ctx_ = ctx.INTERFACES_CONFIG; } sub_interfaces6
| SUB_SUBNET6 { ctx.ctx_ = ctx.SUBNET6; } sub_subnet6
| SUB_POOL6 { ctx.ctx_ = ctx.POOLS; } sub_pool6
| SUB_PD_POOL { ctx.ctx_ = ctx.PD_POOLS; } sub_pd_pool
| SUB_RESERVATION { ctx.ctx_ = ctx.RESERVATIONS; } sub_reservation
| SUB_OPTION_DEF { ctx.ctx_ = ctx.OPTION_DEF; } sub_option_def
| SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data
| SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library
| SUB_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } sub_json
......@@ -299,6 +304,16 @@ dhcp6_object: DHCP6 {
ctx.leave();
};
// subparser: similar to the corresponding rule but without parent
// so the stack is empty at the rule entry.
sub_dhcp6: LCURLY_BRACKET {
// Parse the Dhcp6 map
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} global_params RCURLY_BRACKET {
// parsing completed
};
global_params: global_param
| global_params COMMA global_param
;
......@@ -317,6 +332,7 @@ global_param: preferred_lifetime
| relay_supplied_options
| host_reservation_identifiers
| client_classes
| option_def_list
| option_data_list
| hooks_libraries
| expired_leases_processing
......@@ -356,8 +372,6 @@ interfaces_config: INTERFACES_CONFIG {
ctx.leave();
};
// subparser: similar to the corresponding rule but without parent
// so the stack is empty at the rule entry.
sub_interfaces6: LCURLY_BRACKET {
// Parse the interfaces-config map
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
......@@ -695,6 +709,95 @@ id: ID COLON INTEGER {
ctx.stack_.back()->set("id", id);
};
// ---- option-def --------------------------
// This defines the "option-def": [ ... ] entry that may appear
// at a global option.
option_def_list: OPTION_DEF {
ElementPtr l(new ListElement(ctx.loc2pos(@1)));
ctx.stack_.back()->set("option-def", l);
ctx.stack_.push_back(l);
ctx.enter(ctx.OPTION_DEF);
} COLON LSQUARE_BRACKET option_def_list_content RSQUARE_BRACKET {
ctx.stack_.pop_back();
ctx.leave();
};
// This defines the content of option-def. It may be empty,
// have one entry or multiple entries separated by comma.
option_def_list_content: %empty
| not_empty_option_def_list
;
not_empty_option_def_list: option_def_entry
| not_empty_option_def_list COMMA option_def_entry
;
// This defines the content of a single entry { ... } within
// option-def list.
option_def_entry: LCURLY_BRACKET {
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} option_def_params RCURLY_BRACKET {
ctx.stack_.pop_back();
};
sub_option_def: LCURLY_BRACKET {
// Parse the option-def list entry map
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} option_def_params RCURLY_BRACKET {
// parsing completed
};
// This defines parameters specified inside the map that itself
// is an entry in option-def list.
option_def_params: %empty
| not_empty_option_def_params
;
not_empty_option_def_params: option_def_param
| not_empty_option_def_params COMMA option_def_param
;
option_def_param: option_def_name
| option_def_code
| option_def_type
| option_def_space
| option_def_csv_format
| unknown_map_entry
;
option_def_name: name;
code: CODE COLON INTEGER {
ElementPtr code(new IntElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("code", code);
};
option_def_code: code;
option_def_type: type;
space: SPACE {
ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
ElementPtr space(new StringElement($4, ctx.loc2pos(@4)));
ctx.stack_.back()->set("space", space);
ctx.leave();
};
option_def_space: space;
csv_format: CSV_FORMAT COLON BOOLEAN {
ElementPtr space(new BoolElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("csv-format", space);
};
option_def_csv_format: csv_format;
// ---- option-data --------------------------
// This defines the "option-data": [ ... ] entry that may appear
......@@ -766,23 +869,11 @@ option_data_data: DATA {
ctx.leave();
};
option_data_code: CODE COLON INTEGER {
ElementPtr code(new IntElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("code", code);
};
option_data_code: code;
option_data_space: SPACE {
ctx.enter(ctx.NO_KEYWORD);
} COLON STRING {
ElementPtr space(new StringElement($4, ctx.loc2pos(@4)));
ctx.stack_.back()->set("space", space);
ctx.leave();
};
option_data_space: space;
option_data_csv_format: CSV_FORMAT COLON BOOLEAN {
ElementPtr space(new BoolElement($3, ctx.loc2pos(@3)));
ctx.stack_.back()->set("csv-format", space);
};
option_data_csv_format: csv_format;
// ---- pools ------------------------------------
......
......@@ -139,6 +139,8 @@ Parser6Context::context_name()
return ("hooks-librairies");
case SUBNET6:
return ("subnet6");
case OPTION_DEF:
return ("option-def");
case OPTION_DATA:
return ("option-data");
case CLIENT_CLASSES:
......
......@@ -40,13 +40,14 @@ public:
PARSER_GENERIC_JSON, // This will parse the content as generic JSON
PARSER_DHCP6, // This will parse the content as DHCP6 config
// DHCP6 config subparsers
SUBPARSER_DHCP6,
SUBPARSER_INTERFACES6,
SUBPARSER_SUBNET6,
SUBPARSER_POOL6,
SUBPARSER_PD_POOL,
SUBPARSER_HOST_RESERVATION6,
// Common DHCP subparsers
// SUBPARSER_OPTION_DEF,
SUBPARSER_OPTION_DEF,
SUBPARSER_OPTION_DATA,
SUBPARSER_HOOKS_LIBRARY,
// SUBPARSER_CONTROL_SOCKET,
......@@ -131,6 +132,7 @@ public:
HOST_RESERVATION_IDENTIFIERS,
HOOKS_LIBRARIES,
SUBNET6,
OPTION_DEF,
OPTION_DATA,
CLIENT_CLASSES,
SERVER_ID,
......
......@@ -145,7 +145,8 @@ public:
ASSERT_NO_THROW(server_.reset(new NakedControlledDhcpv6Srv()));
ConstElementPtr config = Element::fromJSON(config_txt);
ConstElementPtr config;
ASSERT_NO_THROW(config = parseJSON(config_txt));
ConstElementPtr answer = server_->processConfig(config);
ASSERT_TRUE(answer);
......@@ -321,7 +322,8 @@ TEST_F(CtrlDhcpv6SrvTest, configReload) {
" } ],"
"\"valid-lifetime\": 4000 }";
ElementPtr config = Element::fromJSON(config_txt);
ConstElementPtr config;
ASSERT_NO_THROW(config = parseDHCP6(config_txt));
// Make sure there are no subnets configured.
CfgMgr::instance().clear();
......
......@@ -75,7 +75,7 @@ const char* CONFIGS[] = {
" {"
" \"name\": \"subscriber-id\","
" \"data\": \"1234\","
" \"csv-format\": False"
" \"csv-format\": false"
" } ]"
" } ],"
"\"valid-lifetime\": 4000 }",
......@@ -1682,7 +1682,7 @@ TEST_F(Dhcpv6SrvTest, vendorOptionsDocsisDefinitions) {
" \"code\": ";
string config_postfix = ","
" \"data\": \"normal_erouter_v6.cm\","
" \"csv-format\": True"
" \"csv-format\": true"
" }],"
"\"subnet6\": [ { "
" \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
......@@ -1704,8 +1704,10 @@ TEST_F(Dhcpv6SrvTest, vendorOptionsDocsisDefinitions) {
// definition, the config should fail.
string config_bogus = config_prefix + "99" + config_postfix;
ElementPtr json_bogus = Element::fromJSON(config_bogus);
ElementPtr json_valid = Element::fromJSON(config_valid);
ConstElementPtr json_bogus;
ASSERT_NO_THROW(json_bogus = parseJSON(config_bogus));
ConstElementPtr json_valid;
ASSERT_NO_THROW(json_valid = parseJSON(config_valid));
NakedDhcpv6Srv srv(0);
......
......@@ -693,7 +693,8 @@ Dhcpv6SrvTest::configure(const std::string& config) {
void
Dhcpv6SrvTest::configure(const std::string& config, NakedDhcpv6Srv& srv) {
ElementPtr json = data::Element::fromJSON(config);
ConstElementPtr json;
ASSERT_NO_THROW(json = parseJSON(config));
ConstElementPtr status;
// Configure the server and make sure the config is accepted
......
......@@ -26,6 +26,7 @@
#include <dhcpsrv/lease_mgr.h>
#include <dhcpsrv/lease_mgr_factory.h>
#include <dhcp6/dhcp6_srv.h>
#include <dhcp6/parser_context.h>
#include <hooks/hooks_manager.h>
#include <list>
......@@ -638,6 +639,42 @@ public:
NakedDhcpv6Srv srv_;
};
// For parser testing (JSON map, no exception expected)
inline isc::data::ConstElementPtr
parseJSON(const std::string& in)
{
isc::dhcp::Parser6Context ctx;
return (ctx.parseString(in, isc::dhcp::Parser6Context::PARSER_GENERIC_JSON));
}
// For parser testing (DHCP6)
inline isc::data::ConstElementPtr
parseDHCP6(const std::string& in)
{
try {
isc::dhcp::Parser6Context ctx;
return (ctx.parseString(in, isc::dhcp::Parser6Context::SUBPARSER_DHCP6));
}
catch (const std::exception& ex) {
std::cout << "EXCEPTION: " << ex.what() << std::endl;
throw;
}
}
// For parser testing (OPTION_DEF)
inline isc::data::ConstElementPtr
parseOPTION_DEF(const std::string& in)
{
try {
isc::dhcp::Parser6Context ctx;
return (ctx.parseString(in, isc::dhcp::Parser6Context::SUBPARSER_OPTION_DEF));
}
catch (const std::exception& ex) {
std::cout << "EXCEPTION: " << ex.what() << std::endl;
throw;
}
}
}; // end of isc::dhcp::test namespace
}; // end of isc::dhcp namespace
}; // end of isc namespace
......
......@@ -1197,7 +1197,8 @@ TEST_F(HooksDhcpv6SrvTest, subnet6Select) {
" } ],"
"\"valid-lifetime\": 4000 }";
ElementPtr json = Element::fromJSON(config);
ConstElementPtr json;
EXPECT_NO_THROW(json = parseDHCP6(config));
ConstElementPtr status;
// Configure the server and make sure the config is accepted
......@@ -1273,7 +1274,8 @@ TEST_F(HooksDhcpv6SrvTest, subnet6SselectChange) {
" } ],"
"\"valid-lifetime\": 4000 }";
ElementPtr json = Element::fromJSON(config);
ConstElementPtr json;
EXPECT_NO_THROW(json = parseDHCP6(config));
ConstElementPtr status;
// Configure the server and make sure the config is accepted
......
......@@ -85,17 +85,17 @@ const char* CONFIGS[] = {
" \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::10\" } ],"
" \"subnet\": \"2001:db8:1::/48\", "
" \"interface\": \"eth0\","
" \"rapid-commit\": True"
" \"rapid-commit\": true"
" },"
" {"
" \"pools\": [ { \"pool\": \"2001:db8:2::1 - 2001:db8:2::10\" } ],"
" \"subnet\": \"2001:db8:2::/48\", "
" \"interface\": \"eth1\","
" \"rapid-commit\": False"
" \"rapid-commit\": false"
" } ],"
"\"valid-lifetime\": 4000,"
" \"dhcp-ddns\" : {"
" \"enable-updates\" : True, "
" \"enable-updates\" : true, "
" \"qualifying-suffix\" : \"example.com\" }"
"}",
......
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