return isc::dhcp::Dhcp4Parser::make_SUB_POOL4(driver.loc_);
case Parser4Context::PARSER_HOST_RESERVATION:
return isc::dhcp::Dhcp4Parser::make_SUB_RESERVATION(driver.loc_);
+ case Parser4Context::PARSER_OPTION_DEFS:
+ return isc::dhcp::Dhcp4Parser::make_SUB_OPTION_DEFS(driver.loc_);
+ case Parser4Context::PARSER_OPTION_DEF:
+ return isc::dhcp::Dhcp4Parser::make_SUB_OPTION_DEF(driver.loc_);
case Parser4Context::PARSER_OPTION_DATA:
return isc::dhcp::Dhcp4Parser::make_SUB_OPTION_DATA(driver.loc_);
case Parser4Context::PARSER_HOOKS_LIBRARY:
SUB_SUBNET4
SUB_POOL4
SUB_RESERVATION
+ SUB_OPTION_DEFS
SUB_OPTION_DEF
SUB_OPTION_DATA
SUB_HOOKS_LIBRARY
| SUB_SUBNET4 { ctx.ctx_ = ctx.SUBNET4; } sub_subnet4
| SUB_POOL4 { ctx.ctx_ = ctx.POOLS; } sub_pool4
| SUB_RESERVATION { ctx.ctx_ = ctx.RESERVATIONS; } sub_reservation
+ | SUB_OPTION_DEFS { ctx.ctx_ = ctx.DHCP4; } sub_option_def_list
| 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
// map parsing completed. If we ever want to do any wrap up
// (maybe some sanity checking), this would be the best place
// for it.
+
+ // Dhcp4 is required
+ ctx.require("Dhcp4", ctx.loc2pos(@1), ctx.loc2pos(@4));
};
// This represents top-level entries: Control-agent, Dhcp6, Dhcp4,
ctx.stack_.push_back(m);
ctx.enter(ctx.DHCP4);
} COLON LCURLY_BRACKET global_params RCURLY_BRACKET {
- // map parsing completed. If we ever want to do any wrap up
- // (maybe some sanity checking), this would be the best place
- // for it.
+ // No global parameter is required
ctx.stack_.pop_back();
ctx.leave();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} global_params RCURLY_BRACKET {
+ // No global parameter is required
// parsing completed
};
ctx.stack_.push_back(i);
ctx.enter(ctx.INTERFACES_CONFIG);
} COLON LCURLY_BRACKET interfaces_config_params RCURLY_BRACKET {
+ // No interfaces config param is required
ctx.stack_.pop_back();
ctx.leave();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} interfaces_config_params RCURLY_BRACKET {
+ // No interfaces config param is required
// parsing completed
};
ctx.stack_.push_back(i);
ctx.enter(ctx.LEASE_DATABASE);
} COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
+ // The type parameter is required
+ ctx.require("type", ctx.loc2pos(@4), ctx.loc2pos(@6));
ctx.stack_.pop_back();
ctx.leave();
};
ctx.stack_.push_back(i);
ctx.enter(ctx.HOSTS_DATABASE);
} COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
+ // The type parameter is required
+ ctx.require("type", ctx.loc2pos(@4), ctx.loc2pos(@6));
ctx.stack_.pop_back();
ctx.leave();
};
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} hooks_params RCURLY_BRACKET {
+ // The library hooks parameter is required
+ ctx.require("library", ctx.loc2pos(@1), ctx.loc2pos(@4));
ctx.stack_.pop_back();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} hooks_params RCURLY_BRACKET {
+ // The library hooks parameter is required
+ ctx.require("library", ctx.loc2pos(@1), ctx.loc2pos(@4));
// parsing completed
};
ctx.stack_.push_back(m);
ctx.enter(ctx.EXPIRED_LEASES_PROCESSING);
} COLON LCURLY_BRACKET expired_leases_params RCURLY_BRACKET {
+ // No expired lease parameter is required
ctx.stack_.pop_back();
ctx.leave();
};
// ctx.stack_.back()->set("renew-timer", renew);
// }
// }
+
+ // The subnet subnet4 parameter is required
+ ctx.require("subnet", ctx.loc2pos(@1), ctx.loc2pos(@4));
ctx.stack_.pop_back();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} subnet4_params RCURLY_BRACKET {
+ // The subnet subnet4 parameter is required
+ ctx.require("subnet", ctx.loc2pos(@1), ctx.loc2pos(@4));
// parsing completed
};
ctx.leave();
};
+// This defines the top level scope when the parser is told to parse
+// option definitions. It works as a subset limited to option
+// definitions
+sub_option_def_list: LCURLY_BRACKET {
+ ElementPtr m(new MapElement(ctx.loc2pos(@1)));
+ ctx.stack_.push_back(m);
+} option_def_list RCURLY_BRACKET {
+ // parsing completed
+};
+
// 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
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} option_def_params RCURLY_BRACKET {
+ // The name, code and type option def parameters are required.
+ ctx.require("name", ctx.loc2pos(@1), ctx.loc2pos(@4));
+ ctx.require("code", ctx.loc2pos(@1), ctx.loc2pos(@4));
+ ctx.require("type", ctx.loc2pos(@1), ctx.loc2pos(@4));
ctx.stack_.pop_back();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} option_def_params RCURLY_BRACKET {
+ // The name, code and type option def parameters are required.
+ ctx.require("name", ctx.loc2pos(@1), ctx.loc2pos(@4));
+ ctx.require("code", ctx.loc2pos(@1), ctx.loc2pos(@4));
+ ctx.require("type", ctx.loc2pos(@1), ctx.loc2pos(@4));
// parsing completed
};
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} option_data_params RCURLY_BRACKET {
+ /// @todo: the code or name parameters are required.
ctx.stack_.pop_back();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} option_data_params RCURLY_BRACKET {
+ /// @todo: the code or name parameters are required.
// parsing completed
};
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} pool_params RCURLY_BRACKET {
+ // The pool parameter is required.
+ ctx.require("pool", ctx.loc2pos(@1), ctx.loc2pos(@4));
ctx.stack_.pop_back();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} pool_params RCURLY_BRACKET {
+ // The pool parameter is required.
+ ctx.require("pool", ctx.loc2pos(@1), ctx.loc2pos(@4));
// parsing completed
};
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} reservation_params RCURLY_BRACKET {
+ /// @todo: an identifier parameter is required.
ctx.stack_.pop_back();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} reservation_params RCURLY_BRACKET {
+ /// @todo: an identifier parameter is required.
// parsing completed
};
| not_empty_reservation_params COMMA reservation_param
;
-// @todo probably need to add mac-address as well here
+/// @todo probably need to add mac-address as well here
reservation_param: duid
| reservation_client_classes
| client_id_value
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} client_class_params RCURLY_BRACKET {
+ // The name client class parameter is required.
+ ctx.require("name", ctx.loc2pos(@1), ctx.loc2pos(@4));
ctx.stack_.pop_back();
};
ctx.stack_.push_back(m);
ctx.enter(ctx.DHCP_DDNS);
} COLON LCURLY_BRACKET dhcp_ddns_params RCURLY_BRACKET {
+ // The enable updates DHCP DDNS parameter is required.
+ ctx.require("enable-updates", ctx.loc2pos(@4), ctx.loc2pos(@6));
ctx.stack_.pop_back();
ctx.leave();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} dhcp_ddns_params RCURLY_BRACKET {
+ // The enable updates DHCP DDNS parameter is required.
+ ctx.require("enable-updates", ctx.loc2pos(@1), ctx.loc2pos(@4));
// parsing completed
};
}
void
-Parser4Context::error (const std::string& what)
+Parser4Context::error(const std::string& what)
{
isc_throw(Dhcp4ParseError, what);
}
void
-Parser4Context::fatal (const std::string& what)
+Parser4Context::fatal(const std::string& what)
{
isc_throw(Dhcp4ParseError, what);
}
return (isc::data::Element::Position(file, line, pos));
}
+void
+Parser4Context::require(const std::string& name,
+ isc::data::Element::Position open_loc,
+ isc::data::Element::Position close_loc)
+{
+ ConstElementPtr value = stack_.back()->get(name);
+ if (!value) {
+ isc_throw(Dhcp4ParseError,
+ "missing parameter '" << name << "' ("
+ << stack_.back()->getPosition() << ") ["
+ << contextName() << " map between "
+ << open_loc << " and " << close_loc << "]");
+ }
+}
+
void
Parser4Context::enter(const ParserContext& ctx)
{
/// This will parse the input as host-reservation.
PARSER_HOST_RESERVATION,
+ /// This will parse the input option definitions (for tests).
+ PARSER_OPTION_DEFS,
+
/// This will parse the input as option definition.
PARSER_OPTION_DEF,
/// @return Position in format accepted by Element
isc::data::Element::Position loc2pos(isc::dhcp::location& loc);
+ /// @brief Check if a required parameter is present
+ ///
+ /// Check if a required parameter is present in the map at the top
+ /// of the stack and raise an error when it is not.
+ ///
+ /// @param name name of the parameter to check
+ /// @param open_loc location of the opening curly bracket
+ /// @param close_loc ocation of the closing curly bracket
+ /// @throw Dhcp4ParseError
+ void require(const std::string& name,
+ isc::data::Element::Position open_loc,
+ isc::data::Element::Position close_loc);
+
/// @brief Defines syntactic contexts for lexical tie-ins
typedef enum {
///< This one is used in pure JSON mode.
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config, true));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config, true));
extractConfig(config);
// Make sure that the particular option definition does not exist.
// Let's apply empty configuration. This removes the option definitions
// configuration and should result in removal of the option 100 from the
- // libdhcp++.
- config = "{ }";
- ASSERT_NO_THROW(json = parseOPTION_DEF(config, true));
-
+ // libdhcp++. Note DHCP4 or OPTION_DEFS parsers do not accept empty maps.
+ json.reset(new MapElement());
ASSERT_NO_THROW(status = configureDhcp4Server(*srv_, json));
checkResult(status, 0);
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
extractConfig(config);
// Make sure that the particular option definition does not exist.
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
extractConfig(config);
// Make sure that the option definitions do not exist yet.
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Make sure that the option definition does not exist yet.
ASSERT_FALSE(CfgMgr::instance().getStagingCfg()->
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
extractConfig(config);
// Make sure that the particular option definition does not exist.
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
extractConfig(config);
// Make sure that the particular option definition does not exist.
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Use the configuration string to create new option definition.
ConstElementPtr status;
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Use the configuration string to create new option definition.
ConstElementPtr status;
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Use the configuration string to create new option definition.
ConstElementPtr status;
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Use the configuration string to create new option definition.
ConstElementPtr status;
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Use the configuration string to create new option definition.
ConstElementPtr status;
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Use the configuration string to create new option definition.
ConstElementPtr status;
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Use the configuration string to create new option definition.
ConstElementPtr status;
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
extractConfig(config);
OptionDefinitionPtr def = CfgMgr::instance().getStagingCfg()->
" \"space\": \"dhcp4\""
" } ]"
"}";
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Use the configuration string to create new option definition.
EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
" \"space\": \"dhcp4\""
" } ]"
"}";
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
extractConfig(config);
// Use the configuration string to create new option definition.
/// @param verbose display the exception message when it fails
/// @return ElementPtr structure representing parsed JSON
inline isc::data::ElementPtr
-parseOPTION_DEF(const std::string& in, bool verbose = false)
+parseOPTION_DEFS(const std::string& in, bool verbose = false)
{
try {
isc::dhcp::Parser4Context ctx;
- return (ctx.parseString(in, isc::dhcp::Parser4Context::PARSER_OPTION_DEF));
+ return (ctx.parseString(in, isc::dhcp::Parser4Context::PARSER_OPTION_DEFS));
}
catch (const std::exception& ex) {
if (verbose) {
Parser4Context::PARSER_DHCP4,
"<string>:2.2-17: got unexpected keyword "
"\"valid_lifetime\" in Dhcp4 map.");
+
+ // missing parameter
+ testError("{ \"name\": \"foo\",\n"
+ " \"code\": 123 }\n",
+ Parser4Context::PARSER_OPTION_DEF,
+ "missing parameter 'type' (<string>:1:1) "
+ "[option-def map between <string>:1:1 and <string>:2:15]");
}
// Check unicode escapes
return isc::dhcp::Dhcp6Parser::make_SUB_PD_POOL(driver.loc_);
case Parser6Context::PARSER_HOST_RESERVATION:
return isc::dhcp::Dhcp6Parser::make_SUB_RESERVATION(driver.loc_);
+ case Parser6Context::PARSER_OPTION_DEFS:
+ return isc::dhcp::Dhcp6Parser::make_SUB_OPTION_DEFS(driver.loc_);
+ case Parser6Context::PARSER_OPTION_DEF:
+ return isc::dhcp::Dhcp6Parser::make_SUB_OPTION_DEF(driver.loc_);
case Parser6Context::PARSER_OPTION_DATA:
return isc::dhcp::Dhcp6Parser::make_SUB_OPTION_DATA(driver.loc_);
case Parser6Context::PARSER_HOOKS_LIBRARY:
SUB_POOL6
SUB_PD_POOL
SUB_RESERVATION
+ SUB_OPTION_DEFS
SUB_OPTION_DEF
SUB_OPTION_DATA
SUB_HOOKS_LIBRARY
| 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_DEFS { ctx.ctx_ = ctx.DHCP6; } sub_option_def_list
| 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
// map parsing completed. If we ever want to do any wrap up
// (maybe some sanity checking), this would be the best place
// for it.
+
+ // Dhcp6 is required
+ ctx.require("Dhcp6", ctx.loc2pos(@1), ctx.loc2pos(@4));
};
// This represents top-level entries: Dhcp6, Dhcp4, DhcpDdns, Logging
ctx.stack_.push_back(m);
ctx.enter(ctx.DHCP6);
} COLON LCURLY_BRACKET global_params RCURLY_BRACKET {
- // map parsing completed. If we ever want to do any wrap up
- // (maybe some sanity checking), this would be the best place
- // for it.
+ // No global parameter is required
ctx.stack_.pop_back();
ctx.leave();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} global_params RCURLY_BRACKET {
+ // No global parameter is required
// parsing completed
};
ctx.stack_.push_back(i);
ctx.enter(ctx.INTERFACES_CONFIG);
} COLON LCURLY_BRACKET interfaces_config_params RCURLY_BRACKET {
+ // No interfaces config param is required
ctx.stack_.pop_back();
ctx.leave();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} interfaces_config_params RCURLY_BRACKET {
+ // No interfaces config param is required
// parsing completed
};
ctx.stack_.push_back(i);
ctx.enter(ctx.LEASE_DATABASE);
} COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
+ // The type parameter is required
+ ctx.require("type", ctx.loc2pos(@4), ctx.loc2pos(@6));
ctx.stack_.pop_back();
ctx.leave();
};
ctx.stack_.push_back(i);
ctx.enter(ctx.HOSTS_DATABASE);
} COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
+ // The type parameter is required
+ ctx.require("type", ctx.loc2pos(@4), ctx.loc2pos(@6));
ctx.stack_.pop_back();
ctx.leave();
};
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} hooks_params RCURLY_BRACKET {
+ // The library hooks parameter is required
+ ctx.require("library", ctx.loc2pos(@1), ctx.loc2pos(@4));
ctx.stack_.pop_back();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} hooks_params RCURLY_BRACKET {
+ // The library hooks parameter is required
+ ctx.require("library", ctx.loc2pos(@1), ctx.loc2pos(@4));
// parsing completed
};
ctx.stack_.push_back(m);
ctx.enter(ctx.EXPIRED_LEASES_PROCESSING);
} COLON LCURLY_BRACKET expired_leases_params RCURLY_BRACKET {
+ // No expired lease parameter is required
ctx.stack_.pop_back();
ctx.leave();
};
// ctx.stack_.back()->set("renew-timer", renew);
// }
// }
+
+ // The subnet subnet6 parameter is required
+ ctx.require("subnet", ctx.loc2pos(@1), ctx.loc2pos(@4));
ctx.stack_.pop_back();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} subnet6_params RCURLY_BRACKET {
+ // The subnet subnet6 parameter is required
+ ctx.require("subnet", ctx.loc2pos(@1), ctx.loc2pos(@4));
// parsing completed
};
ctx.leave();
};
+// This defines the top level scope when the parser is told to parse
+// option definitions. It works as a subset limited to option
+// definitions
+sub_option_def_list: LCURLY_BRACKET {
+ ElementPtr m(new MapElement(ctx.loc2pos(@1)));
+ ctx.stack_.push_back(m);
+} option_def_list RCURLY_BRACKET {
+ // parsing completed
+};
+
// 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
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} option_def_params RCURLY_BRACKET {
+ // The name, code and type option def parameters are required.
+ ctx.require("name", ctx.loc2pos(@1), ctx.loc2pos(@4));
+ ctx.require("code", ctx.loc2pos(@1), ctx.loc2pos(@4));
+ ctx.require("type", ctx.loc2pos(@1), ctx.loc2pos(@4));
ctx.stack_.pop_back();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} option_def_params RCURLY_BRACKET {
+ // The name, code and type option def parameters are required.
+ ctx.require("name", ctx.loc2pos(@1), ctx.loc2pos(@4));
+ ctx.require("code", ctx.loc2pos(@1), ctx.loc2pos(@4));
+ ctx.require("type", ctx.loc2pos(@1), ctx.loc2pos(@4));
// parsing completed
};
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} option_data_params RCURLY_BRACKET {
+ /// @todo: the code or name parameters are required.
ctx.stack_.pop_back();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} option_data_params RCURLY_BRACKET {
+ /// @todo: the code or name parameters are required.
// parsing completed
};
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} pool_params RCURLY_BRACKET {
+ // The pool parameter is required.
+ ctx.require("pool", ctx.loc2pos(@1), ctx.loc2pos(@4));
ctx.stack_.pop_back();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} pool_params RCURLY_BRACKET {
- // parsing completed
+ // The pool parameter is required.
+ ctx.require("pool", ctx.loc2pos(@1), ctx.loc2pos(@4));
};
pool_params: pool_param
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} pd_pool_params RCURLY_BRACKET {
+ // The prefix, prefix len and delegated len parameters are required.
+ ctx.require("prefix", ctx.loc2pos(@1), ctx.loc2pos(@4));
+ ctx.require("prefix-len", ctx.loc2pos(@1), ctx.loc2pos(@4));
+ ctx.require("delegated-len", ctx.loc2pos(@1), ctx.loc2pos(@4));
ctx.stack_.pop_back();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} pd_pool_params RCURLY_BRACKET {
+ // The prefix, prefix len and delegated len parameters are required.
+ ctx.require("prefix", ctx.loc2pos(@1), ctx.loc2pos(@4));
+ ctx.require("prefix-len", ctx.loc2pos(@1), ctx.loc2pos(@4));
+ ctx.require("delegated-len", ctx.loc2pos(@1), ctx.loc2pos(@4));
// parsing completed
};
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} reservation_params RCURLY_BRACKET {
+ /// @todo: an identifier parameter is required.
ctx.stack_.pop_back();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} reservation_params RCURLY_BRACKET {
+ /// @todo: an identifier parameter is required.
// parsing completed
};
| not_empty_reservation_params COMMA reservation_param
;
-// @todo probably need to add mac-address as well here
+/// @todo probably need to add mac-address as well here
reservation_param: duid
| reservation_client_classes
| ip_addresses
ctx.stack_.back()->add(m);
ctx.stack_.push_back(m);
} client_class_params RCURLY_BRACKET {
+ // The name client class parameter is required.
+ ctx.require("name", ctx.loc2pos(@1), ctx.loc2pos(@4));
ctx.stack_.pop_back();
};
ctx.stack_.push_back(m);
ctx.enter(ctx.SERVER_ID);
} COLON LCURLY_BRACKET server_id_params RCURLY_BRACKET {
+ // The type parameter is required.
+ ctx.require("type", ctx.loc2pos(@4), ctx.loc2pos(@6));
ctx.stack_.pop_back();
ctx.leave();
};
ctx.stack_.push_back(m);
ctx.enter(ctx.DHCP_DDNS);
} COLON LCURLY_BRACKET dhcp_ddns_params RCURLY_BRACKET {
+ // The enable updates DHCP DDNS parameter is required.
+ ctx.require("enable-updates", ctx.loc2pos(@4), ctx.loc2pos(@6));
ctx.stack_.pop_back();
ctx.leave();
};
ElementPtr m(new MapElement(ctx.loc2pos(@1)));
ctx.stack_.push_back(m);
} dhcp_ddns_params RCURLY_BRACKET {
+ // The enable updates DHCP DDNS parameter is required.
+ ctx.require("enable-updates", ctx.loc2pos(@1), ctx.loc2pos(@4));
// parsing completed
};
return (isc::data::Element::Position(file, line, pos));
}
+void
+Parser6Context::require(const std::string& name,
+ isc::data::Element::Position open_loc,
+ isc::data::Element::Position close_loc)
+{
+ ConstElementPtr value = stack_.back()->get(name);
+ if (!value) {
+ isc_throw(Dhcp6ParseError,
+ "missing parameter '" << name << "' ("
+ << stack_.back()->getPosition() << ") ["
+ << contextName() << " map between "
+ << open_loc << " and " << close_loc << "]");
+ }
+}
+
void
Parser6Context::enter(const ParserContext& ctx)
{
/// This will parse the input as host-reservation.
PARSER_HOST_RESERVATION,
+ /// This will parse the input option definitions (for tests).
+ PARSER_OPTION_DEFS,
+
/// This will parse the input as option definition.
PARSER_OPTION_DEF,
/// @return Position in format accepted by Element
isc::data::Element::Position loc2pos(isc::dhcp::location& loc);
+ /// @brief Check if a required parameter is present
+ ///
+ /// Check if a required parameter is present in the map at the top
+ /// of the stack and raise an error when it is not.
+ ///
+ /// @param name name of the parameter expected to be present
+ /// @param open_loc location of the opening curly bracket
+ /// @param close_loc ocation of the closing curly bracket
+ /// @throw Dhcp6ParseError
+ void require(const std::string& name,
+ isc::data::Element::Position open_loc,
+ isc::data::Element::Position close_loc);
+
/// @brief Defines syntactic contexts for lexical tie-ins
typedef enum {
///< This one is used in pure JSON mode.
int num_msgs = sizeof(config)/sizeof(char*);
for (unsigned int i = 0; i < num_msgs; i++) {
// Convert JSON string to Elements.
- ASSERT_NO_THROW(json = parseDHCP6(config[i]));
+ // The 3 first configs should fail to parse.
+ if (i < 3) {
+ EXPECT_THROW(parseDHCP6(config[i]), Dhcp6ParseError);
+ json = parseJSON(config[i]);
+ } else {
+ ASSERT_NO_THROW(json = parseDHCP6(config[i]));
+ }
// Configuration processing should fail without a throw.
ASSERT_NO_THROW(x = configureDhcp6Server(srv_, json));
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
extractConfig(config);
// Make sure that the particular option definition does not exist.
// Let's apply empty configuration. This removes the option definitions
// configuration and should result in removal of the option 100 from the
- // libdhcp++.
- config = "{ }";
- json = parseOPTION_DEF(config);
+ // libdhcp++. Note DHCP6 or OPTION_DEFS parsers do not accept empty maps.
+ json.reset(new MapElement());
ASSERT_NO_THROW(status = configureDhcp6Server(srv_, json));
checkResult(status, 0);
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
extractConfig(config);
// Make sure that the particular option definition does not exist.
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
extractConfig(config);
// Make sure that the option definitions do not exist yet.
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Make sure that the option definition does not exist yet.
ASSERT_FALSE(CfgMgr::instance().getStagingCfg()->
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
extractConfig(config);
// Make sure that the particular option definition does not exist.
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
extractConfig(config);
// Make sure that the particular option definition does not exist.
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Use the configuration string to create new option definition.
ConstElementPtr status;
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Use the configuration string to create new option definition.
ConstElementPtr status;
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Use the configuration string to create new option definition.
ConstElementPtr status;
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Use the configuration string to create new option definition.
ConstElementPtr status;
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Use the configuration string to create new option definition.
ConstElementPtr status;
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Use the configuration string to create new option definition.
ConstElementPtr status;
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
// Use the configuration string to create new option definition.
ConstElementPtr status;
" } ]"
"}";
ConstElementPtr json;
- ASSERT_NO_THROW(json = parseOPTION_DEF(config));
+ ASSERT_NO_THROW(json = parseOPTION_DEFS(config));
OptionDefinitionPtr def = CfgMgr::instance().getStagingCfg()->
getCfgOptionDef()->get(DHCP6_OPTION_SPACE, 100);
" \"space\": \"dhcp6\""
" } ]"
"}";
- json = parseOPTION_DEF(config);
+ json = parseOPTION_DEFS(config);
// Use the configuration string to create new option definition.
EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
" \"space\": \"dhcp6\""
" } ]"
"}";
- json = parseOPTION_DEF(config);
+ json = parseOPTION_DEFS(config);
// Use the configuration string to create new option definition.
EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
/// @param verbose display the exception message when it fails
/// @return ElementPtr structure representing parsed JSON
inline isc::data::ElementPtr
-parseOPTION_DEF(const std::string& in, bool verbose = false)
+parseOPTION_DEFS(const std::string& in, bool verbose = false)
{
try {
isc::dhcp::Parser6Context ctx;
- return (ctx.parseString(in, isc::dhcp::Parser6Context::PARSER_OPTION_DEF));
+ return (ctx.parseString(in, isc::dhcp::Parser6Context::PARSER_OPTION_DEFS));
}
catch (const std::exception& ex) {
if (verbose) {
Parser6Context::PARSER_DHCP6,
"<string>:2.2-21: got unexpected keyword "
"\"preferred_lifetime\" in Dhcp6 map.");
+
+ // missing parameter
+ testError("{ \"name\": \"foo\",\n"
+ " \"code\": 123 }\n",
+ Parser6Context::PARSER_OPTION_DEF,
+ "missing parameter 'type' (<string>:1:1) "
+ "[option-def map between <string>:1:1 and <string>:2:15]");
}
// Check unicode escapes