Browse Source

[5014_phase2] Use parser in place of fromJSON

Francis Dupont 8 years ago
parent
commit
55ad23aa80

+ 16 - 0
src/bin/dhcp6/dhcp6_lexer.ll

@@ -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:

+ 108 - 17
src/bin/dhcp6/dhcp6_parser.yy

@@ -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 ------------------------------------
 

+ 2 - 0
src/bin/dhcp6/parser_context.cc

@@ -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:

+ 3 - 1
src/bin/dhcp6/parser_context.h

@@ -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,

File diff suppressed because it is too large
+ 254 - 209
src/bin/dhcp6/tests/config_parser_unittest.cc


+ 4 - 2
src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc

@@ -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();

+ 6 - 4
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

@@ -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);
 

+ 2 - 1
src/bin/dhcp6/tests/dhcp6_test_utils.cc

@@ -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

+ 37 - 0
src/bin/dhcp6/tests/dhcp6_test_utils.h

@@ -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

+ 4 - 2
src/bin/dhcp6/tests/hooks_unittest.cc

@@ -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

+ 3 - 3
src/bin/dhcp6/tests/sarr_unittest.cc

@@ -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\" }"
     "}",