fetch_time = 1000 * fetch_time;
}
+ boost::shared_ptr<unsigned> failure_count(new unsigned(0));
TimerMgr::instance()->
registerTimer("Dhcp4CBFetchTimer",
boost::bind(&ControlledDhcpv4Srv::cbFetchUpdates,
- server_, CfgMgr::instance().getStagingCfg()),
+ server_, CfgMgr::instance().getStagingCfg(),
+ failure_count),
fetch_time,
asiolink::IntervalTimer::ONE_SHOT);
TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
}
void
-ControlledDhcpv4Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg) {
+ControlledDhcpv4Srv::cbFetchUpdates(const SrvConfigPtr& srv_cfg,
+ boost::shared_ptr<unsigned> failure_count) {
try {
// The true value indicates that the server should not reconnect
// to the configuration backends and should take into account
// audit entries stored in the database since last fetch.
server_->getCBControl()->databaseConfigFetch(srv_cfg,
CBControlDHCPv4::FetchMode::FETCH_UPDATE);
+ (*failure_count) = 0;
} catch (const std::exception& ex) {
LOG_ERROR(dhcp4_logger, DHCP4_CB_FETCH_UPDATES_FAIL)
.arg(ex.what());
+
+ // We allow at most 10 consecutive failures after which we stop
+ // making further attempts to fetch the configuration updates.
+ // Let's return without re-scheduling the timer.
+ if (++(*failure_count) > 10) {
+ LOG_ERROR(dhcp4_logger, DHCP4_CB_FETCH_UPDATES_RETRIES_EXHAUSTED);
+ return;
+ }
}
// Reschedule the timer to fetch new updates or re-try if
///
/// @param srv_cfg Server configuration holding the database credentials
/// and server tag.
- void cbFetchUpdates(const SrvConfigPtr& srv_cfg);
+ /// @param failure_count pointer to failure counter which causes this
+ /// callback to stop scheduling the timer after 10 consecutive failures
+ /// to fetch the updates.
+ void cbFetchUpdates(const SrvConfigPtr& srv_cfg,
+ boost::shared_ptr<unsigned> failure_count);
/// @brief Static pointer to the sole instance of the DHCP server.
///
-// File created from ../../../src/bin/dhcp4/dhcp4_messages.mes on Wed Mar 20 2019 11:09
+// File created from ../../../src/bin/dhcp4/dhcp4_messages.mes on Mon Mar 25 2019 20:13
#include <cstddef>
#include <log/message_types.h>
extern const isc::log::MessageID DHCP4_BUFFER_UNPACK = "DHCP4_BUFFER_UNPACK";
extern const isc::log::MessageID DHCP4_BUFFER_WAIT_SIGNAL = "DHCP4_BUFFER_WAIT_SIGNAL";
extern const isc::log::MessageID DHCP4_CB_FETCH_UPDATES_FAIL = "DHCP4_CB_FETCH_UPDATES_FAIL";
+extern const isc::log::MessageID DHCP4_CB_FETCH_UPDATES_RETRIES_EXHAUSTED = "DHCP4_CB_FETCH_UPDATES_RETRIES_EXHAUSTED";
extern const isc::log::MessageID DHCP4_CLASS_ASSIGNED = "DHCP4_CLASS_ASSIGNED";
extern const isc::log::MessageID DHCP4_CLASS_UNCONFIGURED = "DHCP4_CLASS_UNCONFIGURED";
extern const isc::log::MessageID DHCP4_CLASS_UNDEFINED = "DHCP4_CLASS_UNDEFINED";
"DHCP4_BUFFER_UNPACK", "parsing buffer received from %1 to %2 over interface %3",
"DHCP4_BUFFER_WAIT_SIGNAL", "signal received while waiting for next packet, next waiting signal is %1",
"DHCP4_CB_FETCH_UPDATES_FAIL", "error on attempt to fetch configuration updates from the configuration backend(s): %1",
+ "DHCP4_CB_FETCH_UPDATES_RETRIES_EXHAUSTED", "maximum number of configuration fetch attempts: 10, has been exhausted without success",
"DHCP4_CLASS_ASSIGNED", "%1: client packet has been assigned to the following class(es): %2",
"DHCP4_CLASS_UNCONFIGURED", "%1: client packet belongs to an unconfigured class: %2",
"DHCP4_CLASS_UNDEFINED", "required class %1 has no definition",
-// File created from ../../../src/bin/dhcp4/dhcp4_messages.mes on Wed Mar 20 2019 11:09
+// File created from ../../../src/bin/dhcp4/dhcp4_messages.mes on Mon Mar 25 2019 20:13
#ifndef DHCP4_MESSAGES_H
#define DHCP4_MESSAGES_H
extern const isc::log::MessageID DHCP4_BUFFER_UNPACK;
extern const isc::log::MessageID DHCP4_BUFFER_WAIT_SIGNAL;
extern const isc::log::MessageID DHCP4_CB_FETCH_UPDATES_FAIL;
+extern const isc::log::MessageID DHCP4_CB_FETCH_UPDATES_RETRIES_EXHAUSTED;
extern const isc::log::MessageID DHCP4_CLASS_ASSIGNED;
extern const isc::log::MessageID DHCP4_CLASS_UNCONFIGURED;
extern const isc::log::MessageID DHCP4_CLASS_UNDEFINED;
config-fetch-wait-time parameter. The sole argument contains the
reason for failure.
+% DHCP4_CB_FETCH_UPDATES_RETRIES_EXHAUSTED maximum number of configuration fetch attempts: 10, has been exhausted without success
+This error indicates that the server has made a number of unsuccessful
+attempts to fetch configuration updates from a configuration backend.
+The server will continue to operate but won't make any further attempts
+to fetch configuration updates. The administrator must fix the configuration
+in the database and reload (or restart) the server.
+
% DHCP4_CLASS_ASSIGNED %1: client packet has been assigned to the following class(es): %2
This debug message informs that incoming packet has been assigned to specified
class or classes. This is a normal behavior and indicates successful operation.
EXPECT_EQ(1, cb_control->getDatabaseConfigFetchCalls());
- if (config_wait_fetch_time > 0) {
+ if ((config_wait_fetch_time > 0) && (!throw_during_fetch)) {
// If we're configured to run the timer, we expect that it was
// invoked at least 3 times. This is sufficient to verify that
// the timer was scheduled and that the timer continued to run
EXPECT_GE(cb_control->getDatabaseConfigFetchCalls(), 3);
} else {
- // If the server is not configured to schedule the timer,
- // we should still have one fetch attempt recorded.
ASSERT_NO_THROW(runTimersWithTimeout(srv->getIOService(), 500));
- EXPECT_EQ(1, cb_control->getDatabaseConfigFetchCalls());
+
+ if (throw_during_fetch) {
+ // If we're simulating the failure condition the number
+ // of consecutive failures should not exceed 10. Therefore
+ // the number of recorded fetches should be 12. One at
+ // startup, 10 failures and one that causes the timer
+ // to stop.
+ EXPECT_EQ(12, cb_control->getDatabaseConfigFetchCalls());
+
+ } else {
+ // If the server is not configured to schedule the timer,
+ // we should still have one fetch attempt recorded.
+ EXPECT_EQ(1, cb_control->getDatabaseConfigFetchCalls());
+ }
}
}
ASSERT_EQ(0, cb_ctl_.getMergesNum());
}
+// This test verifies that database config fetch failures are handled
+// gracefully.
TEST_F(CBControlBaseTest, fetchFailure) {
auto config_base = makeConfigBase("type=db1");