2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-29 13:07:50 +00:00

[master] Merge branch 'master' of gitlab.isc.org:isc-projects/kea

Re-merged with master.
This commit is contained in:
Thomas Markwalder 2018-12-10 11:15:32 -05:00
commit 8d87c46a3c
10 changed files with 84 additions and 275 deletions

View File

@ -1,3 +1,10 @@
1498. [bug] marcin
Corrected behavior of the DHCP servers with respect to the
"reconnect-wait-time" parameter setting. This parameter is
specified in milliseconds, but the servers used to interpret
it as specified in seconds.
(Gitlab #173,!154, git 377f49e84ad6ebc91cbeac4116d24a15571c522d)
1497. [func] fdupont 1497. [func] fdupont
All YANG modules now have a revision specified. When starting, All YANG modules now have a revision specified. When starting,
kea-netconf daemon will now check if the required modules are kea-netconf daemon will now check if the required modules are

View File

@ -496,14 +496,28 @@ recovery and the server will exit immediately upon detecting a loss of connectiv
(MySQL and Postgres only). (MySQL and Postgres only).
</para> </para>
<para> <para>
The number of seconds the server will wait in between attempts to reconnect to the The number of milliseconds the server will wait in between attempts to reconnect to the
lease database after connectivity has been lost may also be specified: lease database after connectivity has been lost may also be specified:
<screen> <screen>
"Dhcp4": { "lease-database": { <userinput>"reconnect-wait-time" : <replaceable>number-of-seconds</replaceable></userinput>, ... }, ... } "Dhcp4": { "lease-database": { <userinput>"reconnect-wait-time" : <replaceable>number-of-milliseconds</replaceable></userinput>, ... }, ... }
</screen> </screen>
A value of zero (the default) disables automatic recovery and the server will exit The default value for MySQL and Postgres is 0, which disables automatic recovery and
immediately upon detecting a loss of connectivity (MySQL and Postgres only). causes the server to exit immediately upon detecting the loss of connectivity.
The default value for Cassandra is 2000 ms.
</para> </para>
<note>
<para>
Automatic reconnect to database backends is configured individually per backend.
This allows you to tailor the recovery parameters to the each backend you use.
We do suggest that you either enable it for all backends or no backends so you
have consistent behavior. Losing connectivity to a backend for which reconnect
is disabled will result in the server shutting itself down. This includes the
cases when lease database backend and hosts database backend is connected to
the same database instance.
</para>
</note>
<para>Finally, the credentials of the account under which the server will <para>Finally, the credentials of the account under which the server will
access the database should be set: access the database should be set:
<screen> <screen>
@ -662,15 +676,27 @@ recovery and the server will exit immediately upon detecting a loss of connectiv
(MySQL and Postgres only). (MySQL and Postgres only).
</para> </para>
<para> <para>
The number of seconds the server will wait in between attempts to reconnect to the The number of milliseconds the server will wait in between attempts to reconnect to the
host database after connectivity has been lost may also be specified: host database after connectivity has been lost may also be specified:
<screen> <screen>
"Dhcp4": { "hosts-database": { <userinput>"reconnect-wait-time" : <replaceable>number-of-seconds</replaceable></userinput>, ... }, ... } "Dhcp4": { "hosts-database": { <userinput>"reconnect-wait-time" : <replaceable>number-of-milliseconds</replaceable></userinput>, ... }, ... }
</screen> </screen>
A value of zero (the default) disables automatic recovery and the server will exit The default value for MySQL and Postgres is 0, which disables automatic recovery and
immediately upon detecting a loss of connectivity (MySQL and Postgres only). causes the server to exit immediately upon detecting the loss of connectivity.
The default value for Cassandra is 2000 ms.
</para> </para>
<note>
<para>
Automatic reconnect to database backends is configured individually per backend.
This allows you to tailor the recovery parameters to the each backend you use.
We do suggest that you either enable it for all backends or no backends so you
have consistent behavior. Losing connectivity to a backend for which reconnect
is disabled will result in the server shutting itself down. This includes the
cases when lease database backend and hosts database backend is connected to
the same database instance.
</para>
</note>
</para> </para>
<para>Finally, the credentials of the account under which the server will <para>Finally, the credentials of the account under which the server will
access the database should be set: access the database should be set:

View File

@ -493,14 +493,28 @@ recovery and the server will exit immediately upon detecting a loss of connectiv
(MySQL and Postgres only). (MySQL and Postgres only).
</para> </para>
<para> <para>
The number of seconds the server will wait in between attempts to reconnect to the The number of milliseconds the server will wait in between attempts to reconnect to the
lease database after connectivity has been lost may also be specified: lease database after connectivity has been lost may also be specified:
<screen> <screen>
"Dhcp6": { "lease-database": { <userinput>"reconnect-wait-time" : <replaceable>number-of-seconds</replaceable></userinput>, ... }, ... } "Dhcp6": { "lease-database": { <userinput>"reconnect-wait-time" : <replaceable>number-of-milliseconds</replaceable></userinput>, ... }, ... }
</screen> </screen>
A value of zero (the default) disables automatic recovery and the server will exit The default value for MySQL and Postgres is 0, which disables automatic recovery and
immediately upon detecting a loss of connectivity (MySQL and Postgres only). causes the server to exit immediately upon detecting the loss of connectivity.
The default value for Cassandra is 2000 ms.
</para> </para>
<note>
<para>
Automatic reconnect to database backends is configured individually per backend.
This allows you to tailor the recovery parameters to the each backend you use.
We do suggest that you either enable it for all backends or no backends so you
have consistent behavior. Losing connectivity to a backend for which reconnect
is disabled will result in the server shutting itself down. This includes the
cases when lease database backend and hosts database backend is connected to
the same database instance.
</para>
</note>
<para> <para>
Note that host parameter is used by MySQL and PostgreSQL Note that host parameter is used by MySQL and PostgreSQL
backends. Cassandra has a concept of contact points that could be backends. Cassandra has a concept of contact points that could be
@ -599,14 +613,28 @@ recovery and the server will exit immediately upon detecting a loss of connectiv
(MySQL and Postgres only). (MySQL and Postgres only).
</para> </para>
<para> <para>
The number of seconds the server will wait in between attempts to reconnect to the The number of milliseconds the server will wait in between attempts to reconnect to the
host database after connectivity has been lost may also be specified: host database after connectivity has been lost may also be specified:
<screen> <screen>
"Dhcp6": { "hosts-database": { <userinput>"reconnect-wait-time" : <replaceable>number-of-seconds</replaceable></userinput>, ... }, ... } "Dhcp6": { "hosts-database": { <userinput>"reconnect-wait-time" : <replaceable>number-of-milliseconds</replaceable></userinput>, ... }, ... }
</screen> </screen>
A value of zero (the default) disables automatic recovery and the server will exit The default value for MySQL and Postgres is 0, which disables automatic recovery and
immediately upon detecting a loss of connectivity (MySQL and Postgres only). causes the server to exit immediately upon detecting the loss of connectivity.
The default value for Cassandra is 2000 ms.
</para> </para>
<note>
<para>
Automatic reconnect to database backends is configured individually per backend.
This allows you to tailor the recovery parameters to the each backend you use.
We do suggest that you either enable it for all backends or no backends so you
have consistent behavior. Losing connectivity to a backend for which reconnect
is disabled will result in the server shutting itself down. This includes the
cases when lease database backend and hosts database backend is connected to
the same database instance.
</para>
</note>
<para>Finally, the credentials of the account under which the server will <para>Finally, the credentials of the account under which the server will
access the database should be set: access the database should be set:
<screen> <screen>

View File

@ -904,7 +904,7 @@ ControlledDhcpv4Srv::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
TimerMgr::instance()->registerTimer("Dhcp4DbReconnectTimer", TimerMgr::instance()->registerTimer("Dhcp4DbReconnectTimer",
boost::bind(&ControlledDhcpv4Srv::dbReconnect, this, boost::bind(&ControlledDhcpv4Srv::dbReconnect, this,
db_reconnect_ctl), db_reconnect_ctl),
db_reconnect_ctl->retryInterval() * 1000, db_reconnect_ctl->retryInterval(),
asiolink::IntervalTimer::ONE_SHOT); asiolink::IntervalTimer::ONE_SHOT);
} }

View File

@ -158,7 +158,7 @@ An error message indicating that an attempt to reconnect to the lease and/or
host data bases has failed. This occurs after connectivity to either one host data bases has failed. This occurs after connectivity to either one
has been lost and an automatic attempt to reconnect has failed. has been lost and an automatic attempt to reconnect has failed.
% DHCP4_DB_RECONNECT_ATTEMPT_SCHEDULE scheduling attempt %1 of %2 in %3 seconds % DHCP4_DB_RECONNECT_ATTEMPT_SCHEDULE scheduling attempt %1 of %2 in %3 milliseconds
An informational message indicating that the server is scheduling the next An informational message indicating that the server is scheduling the next
attempt to reconnect to its lease and/or host databases. This occurs when the attempt to reconnect to its lease and/or host databases. This occurs when the
server has lost databse connectivity and is attempting to reconnect server has lost databse connectivity and is attempting to reconnect

View File

@ -924,7 +924,7 @@ ControlledDhcpv6Srv::dbReconnect(ReconnectCtlPtr db_reconnect_ctl) {
TimerMgr::instance()->registerTimer("Dhcp6DbReconnectTimer", TimerMgr::instance()->registerTimer("Dhcp6DbReconnectTimer",
boost::bind(&ControlledDhcpv6Srv::dbReconnect, this, boost::bind(&ControlledDhcpv6Srv::dbReconnect, this,
db_reconnect_ctl), db_reconnect_ctl),
db_reconnect_ctl->retryInterval() * 1000, db_reconnect_ctl->retryInterval(),
asiolink::IntervalTimer::ONE_SHOT); asiolink::IntervalTimer::ONE_SHOT);
} }

View File

@ -118,7 +118,7 @@ An error message indicating that an attempt to reconnect to the lease and/or
host data bases has failed. This occurs after connectivity to either one host data bases has failed. This occurs after connectivity to either one
has been lost and an automatic attempt to reconnect has failed. has been lost and an automatic attempt to reconnect has failed.
% DHCP6_DB_RECONNECT_ATTEMPT_SCHEDULE scheduling attempt %1 of %2 in %3 seconds % DHCP6_DB_RECONNECT_ATTEMPT_SCHEDULE scheduling attempt %1 of %2 in %3 milliseconds
An informational message indicating that the server is scheduling the next An informational message indicating that the server is scheduling the next
attempt to reconnect to its lease and/or host databases. This occurs when the attempt to reconnect to its lease and/or host databases. This occurs when the
server has lost databse connectivity and is attempting to reconnect server has lost databse connectivity and is attempting to reconnect

View File

@ -67,7 +67,7 @@ TEST_F(DatabaseConnectionCallbackTest, NoDbLostCallback) {
DatabaseConnection::ParameterMap pmap; DatabaseConnection::ParameterMap pmap;
pmap[std::string("type")] = std::string("test"); pmap[std::string("type")] = std::string("test");
pmap[std::string("max-reconnect-tries")] = std::string("3"); pmap[std::string("max-reconnect-tries")] = std::string("3");
pmap[std::string("reconnect-wait-time")] = std::string("60"); pmap[std::string("reconnect-wait-time")] = std::string("60000");
DatabaseConnection datasrc(pmap); DatabaseConnection datasrc(pmap);
bool ret = false; bool ret = false;
@ -87,7 +87,7 @@ TEST_F(DatabaseConnectionCallbackTest, dbLostCallback) {
DatabaseConnection::ParameterMap pmap; DatabaseConnection::ParameterMap pmap;
pmap[std::string("type")] = std::string("test"); pmap[std::string("type")] = std::string("test");
pmap[std::string("max-reconnect-tries")] = std::string("3"); pmap[std::string("max-reconnect-tries")] = std::string("3");
pmap[std::string("reconnect-wait-time")] = std::string("60"); pmap[std::string("reconnect-wait-time")] = std::string("60000");
/// Install the callback. /// Install the callback.
DatabaseConnection::db_lost_callback = DatabaseConnection::db_lost_callback =
@ -104,7 +104,7 @@ TEST_F(DatabaseConnectionCallbackTest, dbLostCallback) {
ASSERT_EQ("test", db_reconnect_ctl_->backendType()); ASSERT_EQ("test", db_reconnect_ctl_->backendType());
ASSERT_EQ(3, db_reconnect_ctl_->maxRetries()); ASSERT_EQ(3, db_reconnect_ctl_->maxRetries());
ASSERT_EQ(3, db_reconnect_ctl_->retriesLeft()); ASSERT_EQ(3, db_reconnect_ctl_->retriesLeft());
EXPECT_EQ(60, db_reconnect_ctl_->retryInterval()); EXPECT_EQ(60000, db_reconnect_ctl_->retryInterval());
/// Verify that checkRetries() correctly decrements /// Verify that checkRetries() correctly decrements
/// down to zero, and that retriesLeft() returns /// down to zero, and that retriesLeft() returns

View File

@ -84,7 +84,6 @@ libdhcpsrv_unittests_SOURCES += csv_lease_file4_unittest.cc
libdhcpsrv_unittests_SOURCES += csv_lease_file6_unittest.cc libdhcpsrv_unittests_SOURCES += csv_lease_file6_unittest.cc
libdhcpsrv_unittests_SOURCES += d2_client_unittest.cc libdhcpsrv_unittests_SOURCES += d2_client_unittest.cc
libdhcpsrv_unittests_SOURCES += d2_udp_unittest.cc libdhcpsrv_unittests_SOURCES += d2_udp_unittest.cc
libdhcpsrv_unittests_SOURCES += database_connection_unittest.cc
libdhcpsrv_unittests_SOURCES += dhcp_queue_control_parser_unittest.cc libdhcpsrv_unittests_SOURCES += dhcp_queue_control_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += dhcp4o6_ipc_unittest.cc libdhcpsrv_unittests_SOURCES += dhcp4o6_ipc_unittest.cc
libdhcpsrv_unittests_SOURCES += duid_config_parser_unittest.cc libdhcpsrv_unittests_SOURCES += duid_config_parser_unittest.cc

View File

@ -1,251 +0,0 @@
// Copyright (C) 2015-2018 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
#include <exceptions/exceptions.h>
#include <database/database_connection.h>
#include <gtest/gtest.h>
#include <boost/bind.hpp>
// using namespace isc::dhcp;
using namespace isc::db;
/// @brief Test fixture for exercising DbLostCallback invocation
class DatabaseConnectionCallbackTest : public ::testing::Test {
public:
/// Constructor
DatabaseConnectionCallbackTest()
: db_reconnect_ctl_(0) {
DatabaseConnection::db_lost_callback = 0;
}
/// @brief Callback to register with a DatabaseConnection
///
/// @param db_reconnect_ctl ReconnectCtl containing reconnect
/// parameters
bool dbLostCallback(ReconnectCtlPtr db_reconnect_ctl) {
if (!db_reconnect_ctl) {
isc_throw(isc::BadValue, "db_reconnect_ctl should not be null");
}
db_reconnect_ctl_ = db_reconnect_ctl;
return (true);
}
/// @brief Retainer for the control passed into the callback
ReconnectCtlPtr db_reconnect_ctl_;
};
/// @brief getParameter test
///
/// This test checks if the LeaseMgr can be instantiated and that it
/// parses parameters string properly.
TEST(DatabaseConnectionTest, getParameter) {
DatabaseConnection::ParameterMap pmap;
pmap[std::string("param1")] = std::string("value1");
pmap[std::string("param2")] = std::string("value2");
DatabaseConnection datasrc(pmap);
EXPECT_EQ("value1", datasrc.getParameter("param1"));
EXPECT_EQ("value2", datasrc.getParameter("param2"));
EXPECT_THROW(datasrc.getParameter("param3"), isc::BadValue);
}
/// @brief NoDbLostCallback
///
/// This test verifies that DatabaseConnection::invokeDbLostCallback
/// returns a false if there is connection has no registered
/// DbLostCallback.
TEST_F(DatabaseConnectionCallbackTest, NoDbLostCallback) {
DatabaseConnection::ParameterMap pmap;
pmap[std::string("type")] = std::string("test");
pmap[std::string("max-reconnect-tries")] = std::string("3");
pmap[std::string("reconnect-wait-time")] = std::string("60");
DatabaseConnection datasrc(pmap);
bool ret = false;
ASSERT_NO_THROW(ret = datasrc.invokeDbLostCallback());
EXPECT_FALSE(ret);
EXPECT_FALSE(db_reconnect_ctl_);
}
/// @brief dbLostCallback
///
/// This test verifies that DatabaseConnection::invokeDbLostCallback
/// safely invokes the registered DbLostCallback. It also tests
/// operation of DbReconnectCtl retry accounting methods.
TEST_F(DatabaseConnectionCallbackTest, dbLostCallback) {
/// Create a Database configuration that includes the reconnect
/// control parameters.
DatabaseConnection::ParameterMap pmap;
pmap[std::string("type")] = std::string("test");
pmap[std::string("max-reconnect-tries")] = std::string("3");
pmap[std::string("reconnect-wait-time")] = std::string("60");
/// Install the callback.
DatabaseConnection::db_lost_callback =
boost::bind(&DatabaseConnectionCallbackTest::dbLostCallback, this, _1);
/// Create the connection..
DatabaseConnection datasrc(pmap);
/// We should be able to invoke the callback and glean
/// the correct reconnect contorl parameters from it.
bool ret = false;
ASSERT_NO_THROW(ret = datasrc.invokeDbLostCallback());
EXPECT_TRUE(ret);
ASSERT_TRUE(db_reconnect_ctl_);
ASSERT_EQ("test", db_reconnect_ctl_->backendType());
ASSERT_EQ(3, db_reconnect_ctl_->maxRetries());
ASSERT_EQ(3, db_reconnect_ctl_->retriesLeft());
EXPECT_EQ(60, db_reconnect_ctl_->retryInterval());
/// Verify that checkRetries() correctly decrements
/// down to zero, and that retriesLeft() returns
/// the correct value.
for (int i = 3; i > 1 ; --i) {
ASSERT_EQ(i, db_reconnect_ctl_->retriesLeft());
ASSERT_TRUE(db_reconnect_ctl_->checkRetries());
}
/// Retries are exhausted, verify that's reflected.
EXPECT_FALSE(db_reconnect_ctl_->checkRetries());
EXPECT_EQ(0, db_reconnect_ctl_->retriesLeft());
EXPECT_EQ(3, db_reconnect_ctl_->maxRetries());
}
// This test checks that a database access string can be parsed correctly.
TEST(DatabaseConnectionTest, parse) {
DatabaseConnection::ParameterMap parameters = DatabaseConnection::parse(
"user=me password=forbidden name=kea somethingelse= type=mysql");
EXPECT_EQ(5, parameters.size());
EXPECT_EQ("me", parameters["user"]);
EXPECT_EQ("forbidden", parameters["password"]);
EXPECT_EQ("kea", parameters["name"]);
EXPECT_EQ("mysql", parameters["type"]);
EXPECT_EQ("", parameters["somethingelse"]);
}
// This test checks that an invalid database access string behaves as expected.
TEST(DatabaseConnectionTest, parseInvalid) {
// No tokens in the string, so we expect no parameters
std::string invalid = "";
DatabaseConnection::ParameterMap parameters = DatabaseConnection::parse(invalid);
EXPECT_EQ(0, parameters.size());
// With spaces, there are some tokens so we expect invalid parameter
// as there are no equals signs.
invalid = " \t ";
EXPECT_THROW(DatabaseConnection::parse(invalid), isc::InvalidParameter);
invalid = " noequalshere ";
EXPECT_THROW(DatabaseConnection::parse(invalid), isc::InvalidParameter);
// A single "=" is valid string, but is placed here as the result is
// expected to be nothing.
invalid = "=";
parameters = DatabaseConnection::parse(invalid);
EXPECT_EQ(1, parameters.size());
EXPECT_EQ("", parameters[""]);
}
/// @brief redactConfigString test
///
/// Checks that the redacted configuration string includes the password only
/// as a set of asterisks.
TEST(DatabaseConnectionTest, redactAccessString) {
DatabaseConnection::ParameterMap parameters =
DatabaseConnection::parse("user=me password=forbidden name=kea type=mysql");
EXPECT_EQ(4, parameters.size());
EXPECT_EQ("me", parameters["user"]);
EXPECT_EQ("forbidden", parameters["password"]);
EXPECT_EQ("kea", parameters["name"]);
EXPECT_EQ("mysql", parameters["type"]);
// Redact the result. To check, break the redacted string down into its
// components.
std::string redacted = DatabaseConnection::redactedAccessString(parameters);
parameters = DatabaseConnection::parse(redacted);
EXPECT_EQ(4, parameters.size());
EXPECT_EQ("me", parameters["user"]);
EXPECT_EQ("*****", parameters["password"]);
EXPECT_EQ("kea", parameters["name"]);
EXPECT_EQ("mysql", parameters["type"]);
}
/// @brief redactConfigString test - empty password
///
/// Checks that the redacted configuration string includes the password only
/// as a set of asterisks, even if the password is null.
TEST(DatabaseConnectionTest, redactAccessStringEmptyPassword) {
DatabaseConnection::ParameterMap parameters =
DatabaseConnection::parse("user=me name=kea type=mysql password=");
EXPECT_EQ(4, parameters.size());
EXPECT_EQ("me", parameters["user"]);
EXPECT_EQ("", parameters["password"]);
EXPECT_EQ("kea", parameters["name"]);
EXPECT_EQ("mysql", parameters["type"]);
// Redact the result. To check, break the redacted string down into its
// components.
std::string redacted = DatabaseConnection::redactedAccessString(parameters);
parameters = DatabaseConnection::parse(redacted);
EXPECT_EQ(4, parameters.size());
EXPECT_EQ("me", parameters["user"]);
EXPECT_EQ("*****", parameters["password"]);
EXPECT_EQ("kea", parameters["name"]);
EXPECT_EQ("mysql", parameters["type"]);
// ... and again to check that the position of the empty password in the
// string does not matter.
parameters = DatabaseConnection::parse("user=me password= name=kea type=mysql");
EXPECT_EQ(4, parameters.size());
EXPECT_EQ("me", parameters["user"]);
EXPECT_EQ("", parameters["password"]);
EXPECT_EQ("kea", parameters["name"]);
EXPECT_EQ("mysql", parameters["type"]);
redacted = DatabaseConnection::redactedAccessString(parameters);
parameters = DatabaseConnection::parse(redacted);
EXPECT_EQ(4, parameters.size());
EXPECT_EQ("me", parameters["user"]);
EXPECT_EQ("*****", parameters["password"]);
EXPECT_EQ("kea", parameters["name"]);
EXPECT_EQ("mysql", parameters["type"]);
}
/// @brief redactConfigString test - no password
///
/// Checks that the redacted configuration string excludes the password if there
/// was no password to begin with.
TEST(DatabaseConnectionTest, redactAccessStringNoPassword) {
DatabaseConnection::ParameterMap parameters =
DatabaseConnection::parse("user=me name=kea type=mysql");
EXPECT_EQ(3, parameters.size());
EXPECT_EQ("me", parameters["user"]);
EXPECT_EQ("kea", parameters["name"]);
EXPECT_EQ("mysql", parameters["type"]);
// Redact the result. To check, break the redacted string down into its
// components.
std::string redacted = DatabaseConnection::redactedAccessString(parameters);
parameters = DatabaseConnection::parse(redacted);
EXPECT_EQ(3, parameters.size());
EXPECT_EQ("me", parameters["user"]);
EXPECT_EQ("kea", parameters["name"]);
EXPECT_EQ("mysql", parameters["type"]);
}