// *********************** D2CfgContext *************************
D2CfgContext::D2CfgContext()
- : forward_mgr_(new DdnsDomainListMgr("forward_mgr")),
+ : d2_params_(new D2Params()),
+ forward_mgr_(new DdnsDomainListMgr("forward_mgr")),
reverse_mgr_(new DdnsDomainListMgr("reverse_mgr")),
keys_(new TSIGKeyInfoMap()) {
}
D2CfgContext::D2CfgContext(const D2CfgContext& rhs) : DCfgContextBase(rhs) {
+ d2_params_ = rhs.d2_params_;
if (rhs.forward_mgr_) {
forward_mgr_.reset(new DdnsDomainListMgr(rhs.forward_mgr_->getName()));
forward_mgr_->setDomains(rhs.forward_mgr_->getDomains());
D2CfgMgr::D2CfgMgr() : DCfgMgrBase(DCfgContextBasePtr(new D2CfgContext())) {
// TSIG keys need to parse before the Domains, so we can catch Domains
// that specify undefined keys. Create the necessary parsing order now.
- addToParseOrder("interface");
- addToParseOrder("ip_address");
- addToParseOrder("port");
addToParseOrder("tsig_keys");
addToParseOrder("forward_ddns");
addToParseOrder("reverse_ddns");
D2CfgMgr::~D2CfgMgr() {
}
+DCfgContextBasePtr
+D2CfgMgr::createNewContext() {
+ return (DCfgContextBasePtr(new D2CfgContext()));
+}
+
bool
D2CfgMgr::forwardUpdatesEnabled() {
// Forward updates are not enabled if no forward servers are defined.
return(stream.str());
}
+const D2ParamsPtr&
+D2CfgMgr::getD2Params() {
+ return (getD2CfgContext()->getD2Params());
+}
+
+void
+D2CfgMgr::buildParams(isc::data::ConstElementPtr params_config) {
+ // Base class build creates parses and invokes build on each parser.
+ // This populate the context scalar stores with all of the parameters.
+ DCfgMgrBase::buildParams(params_config);
+
+ // Fetch the parameters from the context to create the D2Params.
+ D2CfgContextPtr context = getD2CfgContext();
+ isc::dhcp::StringStoragePtr& strings = context->getStringStorage();
+ asiolink::IOAddress ip_address(strings->
+ getOptionalParam("ip_address",
+ D2Params::DFT_IP_ADDRESS));
+
+ isc::dhcp::Uint32StoragePtr& ints = context->getUint32Storage();
+ uint32_t port = ints->getOptionalParam("port", D2Params::DFT_PORT);
+
+ uint32_t dns_server_timeout
+ = ints->getOptionalParam("dns_server_timeout",
+ D2Params::DFT_DNS_SERVER_TIMEOUT);
+
+ dhcp_ddns::NameChangeProtocol ncr_protocol
+ = dhcp_ddns::stringToNcrProtocol(strings->
+ getOptionalParam("ncr_protocol",
+ D2Params::
+ DFT_NCR_PROTOCOL));
+ dhcp_ddns::NameChangeFormat ncr_format
+ = dhcp_ddns::stringToNcrFormat(strings->
+ getOptionalParam("ncr_format",
+ D2Params::
+ DFT_NCR_FORMAT));
+ // Attempt to create the new client config.
+ D2ParamsPtr params(new D2Params(ip_address, port, dns_server_timeout,
+ ncr_protocol, ncr_format));
+
+ context->getD2Params() = params;
+}
isc::dhcp::ParserPtr
D2CfgMgr::createConfigParser(const std::string& config_id) {
D2CfgContextPtr context = getD2CfgContext();
// Create parser instance based on element_id.
- isc::dhcp::DhcpConfigParser* parser = NULL;
- if ((config_id == "interface") ||
- (config_id == "ip_address")) {
- parser = new isc::dhcp::StringParser(config_id,
- context->getStringStorage());
- } else if (config_id == "port") {
- parser = new isc::dhcp::Uint32Parser(config_id,
- context->getUint32Storage());
+ isc::dhcp::ParserPtr parser;
+ if ((config_id.compare("port") == 0) ||
+ (config_id.compare("dns_server_timeout") == 0)) {
+ parser.reset(new isc::dhcp::Uint32Parser(config_id,
+ context->getUint32Storage()));
+ } else if ((config_id.compare("ip_address") == 0) ||
+ (config_id.compare("ncr_protocol") == 0) ||
+ (config_id.compare("ncr_format") == 0)) {
+ parser.reset(new isc::dhcp::StringParser(config_id,
+ context->getStringStorage()));
} else if (config_id == "forward_ddns") {
- parser = new DdnsDomainListMgrParser("forward_mgr",
- context->getForwardMgr(),
- context->getKeys());
+ parser.reset(new DdnsDomainListMgrParser("forward_mgr",
+ context->getForwardMgr(),
+ context->getKeys()));
} else if (config_id == "reverse_ddns") {
- parser = new DdnsDomainListMgrParser("reverse_mgr",
- context->getReverseMgr(),
- context->getKeys());
+ parser.reset(new DdnsDomainListMgrParser("reverse_mgr",
+ context->getReverseMgr(),
+ context->getKeys()));
} else if (config_id == "tsig_keys") {
- parser = new TSIGKeyInfoListParser("tsig_key_list", context->getKeys());
+ parser.reset(new TSIGKeyInfoListParser("tsig_key_list",
+ context->getKeys()));
} else {
isc_throw(NotImplemented,
"parser error: D2CfgMgr parameter not supported: "
<< config_id);
}
- return (isc::dhcp::ParserPtr(parser));
+ return (parser);
}
}; // end of isc::dhcp namespace
public:
/// @brief Constructor
- D2CfgMgrTest():cfg_mgr_(new D2CfgMgr) {
+ D2CfgMgrTest():cfg_mgr_(new D2CfgMgr), d2_params_() {
}
/// @brief Destructor
/// @brief Configuration manager instance.
D2CfgMgrPtr cfg_mgr_;
+
+ /// @brief Build JSON configuration string for a D2Params element
+ ///
+ /// Constructs a JSON string for "params" element using replacable
+ /// parameters.
+ ///
+ /// @param ip_address string to insert as ip_address value
+ /// @param port integer to insert as port value
+ /// @param dns_server_timeout integer to insert as dns_server_timeout value
+ /// @param ncr_protocol string to insert as ncr_protocol value
+ /// @param ncr_format string to insert as ncr_format value
+ ///
+ /// @return std::string containing the JSON configuration text
+ std::string makeParamsConfigString(const std::string& ip_address,
+ const int port,
+ const int dns_server_timeout,
+ const std::string& ncr_protocol,
+ const std::string& ncr_format) {
+ std::ostringstream config;
+ config <<
+ "{"
+ " \"ip_address\": \"" << ip_address << "\" , "
+ " \"port\": " << port << " , "
+ " \"dns_server_timeout\": " << dns_server_timeout << " , "
+ " \"ncr_protocol\": \"" << ncr_protocol << "\" , "
+ " \"ncr_format\": \"" << ncr_format << "\", "
+ "\"tsig_keys\": [], "
+ "\"forward_ddns\" : {}, "
+ "\"reverse_ddns\" : {} "
+ "}";
+
+ return (config.str());
+ }
+
+ void runConfig(std::string config_str, bool should_fail=false) {
+ // We assume the config string is valid JSON.
+ ASSERT_TRUE(fromJSON(config_str));
+
+ // Parse the configuration and verify we got the expected outcome.
+ answer_ = cfg_mgr_->parseConfig(config_set_);
+ ASSERT_TRUE(checkAnswer(should_fail));
+
+ // Verify that the D2 context can be retrieved and is not null.
+ D2CfgContextPtr context;
+ ASSERT_NO_THROW(context = cfg_mgr_->getD2CfgContext());
+
+ // Verify that the global scalars have the proper values.
+ d2_params_ = context->getD2Params();
+ ASSERT_TRUE(d2_params_);
+ }
+
+ D2ParamsPtr d2_params_;
};
/// @brief Tests that the spec file is valid.
isc::dhcp::ParserPtr parser_;
};
+/// @brief Tests a basic valid configuration for D2Param.
+TEST_F(D2CfgMgrTest, validParamsEntry) {
+ // Verify that ip_address can be valid v4 address.
+ std::string config = makeParamsConfigString ("192.0.0.1", 777, 333,
+ "UDP", "JSON");
+ runConfig(config);
+
+ EXPECT_EQ(isc::asiolink::IOAddress("192.0.0.1"),
+ d2_params_->getIpAddress());
+ EXPECT_EQ(777, d2_params_->getPort());
+ EXPECT_EQ(333, d2_params_->getDnsServerTimeout());
+ EXPECT_EQ(dhcp_ddns::NCR_UDP, d2_params_->getNcrProtocol());
+ EXPECT_EQ(dhcp_ddns::FMT_JSON, d2_params_->getNcrFormat());
+
+ // Verify that ip_address can be valid v6 address.
+ config = makeParamsConfigString ("3001::5", 777, 333, "UDP", "JSON");
+ runConfig(config);
+
+ // Verify that the global scalars have the proper values.
+ EXPECT_EQ(isc::asiolink::IOAddress("3001::5"),
+ d2_params_->getIpAddress());
+}
+
+/// @brief Tests default values for D2Params.
+/// It verifies that D2Params is populated with default value for optional
+/// parameter if not supplied in the configuration.
+/// Currently they are all optional.
+TEST_F(D2CfgMgrTest, defaultValues) {
+
+ // Check that omitting ip_address gets you its default
+ std::string config =
+ "{"
+ " \"port\": 777 , "
+ " \"dns_server_timeout\": 333 , "
+ " \"ncr_protocol\": \"UDP\" , "
+ " \"ncr_format\": \"JSON\", "
+ "\"tsig_keys\": [], "
+ "\"forward_ddns\" : {}, "
+ "\"reverse_ddns\" : {} "
+ "}";
+
+ runConfig(config);
+ EXPECT_EQ(isc::asiolink::IOAddress(D2Params::DFT_IP_ADDRESS),
+ d2_params_->getIpAddress());
+
+ // Check that omitting port gets you its default
+ config =
+ "{"
+ " \"ip_address\": \"192.0.0.1\" , "
+ " \"dns_server_timeout\": 333 , "
+ " \"ncr_protocol\": \"UDP\" , "
+ " \"ncr_format\": \"JSON\", "
+ "\"tsig_keys\": [], "
+ "\"forward_ddns\" : {}, "
+ "\"reverse_ddns\" : {} "
+ "}";
+
+ runConfig(config);
+ EXPECT_EQ(D2Params::DFT_PORT, d2_params_->getPort());
+
+ // Check that omitting timeout gets you its default
+ config =
+ "{"
+ " \"ip_address\": \"192.0.0.1\" , "
+ " \"port\": 777 , "
+ " \"ncr_protocol\": \"UDP\" , "
+ " \"ncr_format\": \"JSON\", "
+ "\"tsig_keys\": [], "
+ "\"forward_ddns\" : {}, "
+ "\"reverse_ddns\" : {} "
+ "}";
+
+ runConfig(config);
+ EXPECT_EQ(D2Params::DFT_DNS_SERVER_TIMEOUT,
+ d2_params_->getDnsServerTimeout());
+
+ // Check that protocol timeout gets you its default
+ config =
+ "{"
+ " \"ip_address\": \"192.0.0.1\" , "
+ " \"port\": 777 , "
+ " \"dns_server_timeout\": 333 , "
+ " \"ncr_format\": \"JSON\", "
+ "\"tsig_keys\": [], "
+ "\"forward_ddns\" : {}, "
+ "\"reverse_ddns\" : {} "
+ "}";
+
+ runConfig(config);
+ EXPECT_EQ(dhcp_ddns::stringToNcrProtocol(D2Params::DFT_NCR_PROTOCOL),
+ d2_params_->getNcrProtocol());
+
+ // Check that format timeout gets you its default
+ config =
+ "{"
+ " \"ip_address\": \"192.0.0.1\" , "
+ " \"port\": 777 , "
+ " \"dns_server_timeout\": 333 , "
+ " \"ncr_protocol\": \"UDP\", "
+ "\"tsig_keys\": [], "
+ "\"forward_ddns\" : {}, "
+ "\"reverse_ddns\" : {} "
+ "}";
+
+ runConfig(config);
+ EXPECT_EQ(dhcp_ddns::stringToNcrFormat(D2Params::DFT_NCR_FORMAT),
+ d2_params_->getNcrFormat());
+}
+
+/// @brief Tests the enforcement of data validation when parsing D2Params.
+/// It verifies that:
+/// -# ip_address cannot be "0.0.0.0"
+/// -# ip_address cannot be "::"
+/// -# port cannot be 0
+/// -# dns_server_timeout cannat be 0
+/// -# ncr_protocol must be valid
+/// -# ncr_format must be valid
+TEST_F(D2CfgMgrTest, invalidEntry) {
+ // Cannot use IPv4 ANY address
+ std::string config = makeParamsConfigString ("0.0.0.0", 777, 333,
+ "UDP", "JSON");
+ runConfig(config, 1);
+
+ // Cannot use IPv6 ANY address
+ config = makeParamsConfigString ("::", 777, 333, "UDP", "JSON");
+ runConfig(config, 1);
+
+ // Cannot use port 0
+ config = makeParamsConfigString ("127.0.0.1", 0, 333, "UDP", "JSON");
+ runConfig(config, 1);
+
+ // Cannot use dns server timeout of 0
+ config = makeParamsConfigString ("127.0.0.1", 777, 0, "UDP", "JSON");
+ runConfig(config, 1);
+
+ // Invalid protocol
+ config = makeParamsConfigString ("127.0.0.1", 777, 333, "BOGUS", "JSON");
+ runConfig(config, 1);
+
+ // Invalid format
+ config = makeParamsConfigString ("127.0.0.1", 777, 333, "UDP", "BOGUS");
+ runConfig(config, 1);
+}
+
/// @brief Tests the enforcement of data validation when parsing TSIGKeyInfos.
/// It verifies that:
/// 1. Name cannot be blank.
EXPECT_NO_THROW(delete cfg_mgr);
}
+TEST_F(D2CfgMgrTest, paramsConfig) {
+}
+
/// @brief Tests the parsing of a complete, valid DHCP-DDNS configuration.
/// This tests passes the configuration into an instance of D2CfgMgr just
/// as it would be done by d2_process in response to a configuration update
// both the forward and reverse ddns managers. Both managers have two
// domains with three servers per domain.
std::string config = "{ "
- "\"interface\" : \"eth1\" , "
"\"ip_address\" : \"192.168.1.33\" , "
"\"port\" : 88 , "
+ " \"dns_server_timeout\": 333 , "
+ " \"ncr_protocol\": \"UDP\" , "
+ " \"ncr_format\": \"JSON\", "
"\"tsig_keys\": ["
"{"
" \"name\": \"d2_key.tmark.org\" , "
" { \"hostname\": \"six.rev\" } "
" ] } "
"] } }";
+
ASSERT_TRUE(fromJSON(config));
// Verify that we can parse the configuration.
D2CfgContextPtr context;
ASSERT_NO_THROW(context = cfg_mgr_->getD2CfgContext());
- // Verify that the application level scalars have the proper values.
- std::string interface;
- EXPECT_NO_THROW (context->getParam("interface", interface));
- EXPECT_EQ("eth1", interface);
-
- std::string ip_address;
- EXPECT_NO_THROW (context->getParam("ip_address", ip_address));
- EXPECT_EQ("192.168.1.33", ip_address);
+ // Verify that the global scalars have the proper values.
+ D2ParamsPtr& d2_params = context->getD2Params();
+ ASSERT_TRUE(d2_params);
- uint32_t port = 0;
- EXPECT_NO_THROW (context->getParam("port", port));
- EXPECT_EQ(88, port);
+ EXPECT_EQ(isc::asiolink::IOAddress("192.168.1.33"),
+ d2_params->getIpAddress());
+ EXPECT_EQ(88, d2_params->getPort());
+ EXPECT_EQ(333, d2_params->getDnsServerTimeout());
+ EXPECT_EQ(dhcp_ddns::NCR_UDP, d2_params->getNcrProtocol());
+ EXPECT_EQ(dhcp_ddns::FMT_JSON, d2_params->getNcrFormat());
// Verify that the forward manager can be retrieved.
DdnsDomainListMgrPtr mgr = context->getForwardMgr();
// Create configuration with one domain, one sub domain, and the wild
// card.
std::string config = "{ "
- "\"interface\" : \"eth1\" , "
"\"ip_address\" : \"192.168.1.33\" , "
"\"port\" : 88 , "
"\"tsig_keys\": [] ,"
TEST_F(D2CfgMgrTest, matchNoWildcard) {
// Create a configuration with one domain, one sub-domain, and NO wild card.
std::string config = "{ "
- "\"interface\" : \"eth1\" , "
"\"ip_address\" : \"192.168.1.33\" , "
"\"port\" : 88 , "
"\"tsig_keys\": [] ,"
/// This test verifies that any FQDN matches the wild card.
TEST_F(D2CfgMgrTest, matchAll) {
std::string config = "{ "
- "\"interface\" : \"eth1\" , "
"\"ip_address\" : \"192.168.1.33\" , "
"\"port\" : 88 , "
"\"tsig_keys\": [] ,"
/// as a match.
TEST_F(D2CfgMgrTest, matchReverse) {
std::string config = "{ "
- "\"interface\" : \"eth1\" , "
"\"ip_address\" : \"192.168.1.33\" , "
"\"port\" : 88 , "
"\"tsig_keys\": [] ,"