Commit 9fe0906d authored by Francis Dupont's avatar Francis Dupont

[904-add-ability-to-force-a-cb-update-remotely] Added server-update command

parent 4fe28306
...@@ -129,6 +129,7 @@ api/reservation-get-all.json ...@@ -129,6 +129,7 @@ api/reservation-get-all.json
api/reservation-get-by-hostname.json api/reservation-get-by-hostname.json
api/reservation-get-page.json api/reservation-get-page.json
api/server-tag-get.json api/server-tag-get.json
api/server-update.json
api/shutdown.json api/shutdown.json
api/statistic-get-all.json api/statistic-get-all.json
api/statistic-get.json api/statistic-get.json
......
{
"avail": "1.7.1",
"brief": [
"This command forces an immediate update of the server using Config Backends.",
"This command does not take any parameters."
],
"cmd-syntax": [
"{",
" \"command\": \"server-update\"",
"}"
],
"description": "See <xref linkend=\"command-server-update\"/>",
"name": "server-update",
"resp-comment": [
"When no Config Backends are configured this command returns empty (3); ",
"If an error occurs error (1) is returned with the error details; ",
"otherwise success (0) is returned."
],
"resp-syntax": [
"{",
" \"result\": 0,",
" \"text\": \"Server update successful.\"",
"}"
],
"support": [
"kea-dhcp4",
"kea-dhcp6"
]
}
...@@ -159,8 +159,6 @@ the list of supported configuration parameters, can be found in ...@@ -159,8 +159,6 @@ the list of supported configuration parameters, can be found in
.. _cb-sharing: .. _cb-sharing:
.. _command-server-tag-get:
Configuration Sharing and Server Tags Configuration Sharing and Server Tags
------------------------------------- -------------------------------------
......
...@@ -538,6 +538,23 @@ The ``dhcp-enable`` command globally enables the DHCP service. ...@@ -538,6 +538,23 @@ The ``dhcp-enable`` command globally enables the DHCP service.
"command": "dhcp-enable" "command": "dhcp-enable"
} }
.. _command-server-tag-get:
The server-tag-get Command:
---------------------------
The ``server-tag-get`` command returns the configured server tag of
the DHCPv4 or DHCPv6 server (:ref:`cb-sharing` explains the server tag concept)
.. _command-server-update:
The server-update Command:
--------------------------
The ``server-update`` command triggers the polling of Config Backends
(which should be configured for this command to do something)
explained in :ref:`dhcp4-cb-json`.
.. _command-version-get: .. _command-version-get:
The version-get Command The version-get Command
......
...@@ -5891,6 +5891,10 @@ server's performance, because the server needs to make at least one query ...@@ -5891,6 +5891,10 @@ server's performance, because the server needs to make at least one query
to the database to discover the pending configuration updates. The to the database to discover the pending configuration updates. The
default value of the ``config-fetch-wait-time`` is 30 seconds. default value of the ``config-fetch-wait-time`` is 30 seconds.
To trigger an immediate polling the ``server-update`` command is
available for both DHCPv4 and DHCPv6 servers since the 1.7.1 Kea
release.
Finally, in the configuration example above, two hooks libraries are Finally, in the configuration example above, two hooks libraries are
loaded. The first, ``libdhcp_mysql_cb.so``, is the implementation of loaded. The first, ``libdhcp_mysql_cb.so``, is the implementation of
the Configuration Backend for MySQL. It must be always present when the the Configuration Backend for MySQL. It must be always present when the
......
...@@ -544,6 +544,34 @@ ControlledDhcpv4Srv::commandServerTagGetHandler(const std::string&, ...@@ -544,6 +544,34 @@ ControlledDhcpv4Srv::commandServerTagGetHandler(const std::string&,
return (createAnswer(CONTROL_RESULT_SUCCESS, response)); return (createAnswer(CONTROL_RESULT_SUCCESS, response));
} }
ConstElementPtr
ControlledDhcpv4Srv::commandServerUpdateHandler(const std::string&,
ConstElementPtr) {
auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo();
if (!ctl_info) {
return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend."));
}
// Reschedule the periodic CB fetch.
if (TimerMgr::instance()->isTimerRegistered("Dhcp4CBFetchTimer")) {
TimerMgr::instance()->cancel("Dhcp4CBFetchTimer");
TimerMgr::instance()->setup("Dhcp4CBFetchTimer");
}
// Code from cbFetchUpdates.
try {
auto srv_cfg = CfgMgr::instance().getStagingCfg();
auto mode = CBControlDHCPv4::FetchMode::FETCH_UPDATE;
server_->getCBControl()->databaseConfigFetch(srv_cfg, mode);
} catch (const std::exception& ex) {
LOG_ERROR(dhcp4_logger, DHCP4_CB_FETCH_UPDATES_FAIL)
.arg(ex.what());
return (createAnswer(CONTROL_RESULT_ERROR,
"Server update failed: " + string(ex.what())));
}
return (createAnswer(CONTROL_RESULT_SUCCESS, "Server update successful."));
}
ConstElementPtr ConstElementPtr
ControlledDhcpv4Srv::processCommand(const string& command, ControlledDhcpv4Srv::processCommand(const string& command,
ConstElementPtr args) { ConstElementPtr args) {
...@@ -601,6 +629,9 @@ ControlledDhcpv4Srv::processCommand(const string& command, ...@@ -601,6 +629,9 @@ ControlledDhcpv4Srv::processCommand(const string& command,
} else if (command == "server-tag-get") { } else if (command == "server-tag-get") {
return (srv->commandServerTagGetHandler(command, args)); return (srv->commandServerTagGetHandler(command, args));
} else if (command == "server-update") {
return (srv->commandServerUpdateHandler(command, args));
} }
ConstElementPtr answer = isc::config::createAnswer(1, ConstElementPtr answer = isc::config::createAnswer(1,
"Unrecognized command:" + command); "Unrecognized command:" + command);
...@@ -838,6 +869,9 @@ ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_P ...@@ -838,6 +869,9 @@ ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t server_port /*= DHCP4_SERVER_P
CommandMgr::instance().registerCommand("server-tag-get", CommandMgr::instance().registerCommand("server-tag-get",
boost::bind(&ControlledDhcpv4Srv::commandServerTagGetHandler, this, _1, _2)); boost::bind(&ControlledDhcpv4Srv::commandServerTagGetHandler, this, _1, _2));
CommandMgr::instance().registerCommand("server-update",
boost::bind(&ControlledDhcpv4Srv::commandServerUpdateHandler, this, _1, _2));
CommandMgr::instance().registerCommand("shutdown", CommandMgr::instance().registerCommand("shutdown",
boost::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, _1, _2)); boost::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, _1, _2));
...@@ -898,14 +932,15 @@ ControlledDhcpv4Srv::~ControlledDhcpv4Srv() { ...@@ -898,14 +932,15 @@ ControlledDhcpv4Srv::~ControlledDhcpv4Srv() {
CommandMgr::instance().deregisterCommand("build-report"); CommandMgr::instance().deregisterCommand("build-report");
CommandMgr::instance().deregisterCommand("config-get"); CommandMgr::instance().deregisterCommand("config-get");
CommandMgr::instance().deregisterCommand("config-reload"); CommandMgr::instance().deregisterCommand("config-reload");
CommandMgr::instance().deregisterCommand("config-set");
CommandMgr::instance().deregisterCommand("config-test"); CommandMgr::instance().deregisterCommand("config-test");
CommandMgr::instance().deregisterCommand("config-write"); CommandMgr::instance().deregisterCommand("config-write");
CommandMgr::instance().deregisterCommand("leases-reclaim");
CommandMgr::instance().deregisterCommand("libreload");
CommandMgr::instance().deregisterCommand("config-set");
CommandMgr::instance().deregisterCommand("dhcp-disable"); CommandMgr::instance().deregisterCommand("dhcp-disable");
CommandMgr::instance().deregisterCommand("dhcp-enable"); CommandMgr::instance().deregisterCommand("dhcp-enable");
CommandMgr::instance().deregisterCommand("leases-reclaim");
CommandMgr::instance().deregisterCommand("libreload");
CommandMgr::instance().deregisterCommand("server-tag-get"); CommandMgr::instance().deregisterCommand("server-tag-get");
CommandMgr::instance().deregisterCommand("server-update");
CommandMgr::instance().deregisterCommand("shutdown"); CommandMgr::instance().deregisterCommand("shutdown");
CommandMgr::instance().deregisterCommand("statistic-get"); CommandMgr::instance().deregisterCommand("statistic-get");
CommandMgr::instance().deregisterCommand("statistic-get-all"); CommandMgr::instance().deregisterCommand("statistic-get-all");
......
...@@ -304,6 +304,19 @@ private: ...@@ -304,6 +304,19 @@ private:
commandServerTagGetHandler(const std::string& command, commandServerTagGetHandler(const std::string& command,
isc::data::ConstElementPtr args); isc::data::ConstElementPtr args);
/// @brief handler for server-update command
///
/// This method handles the server-update command, which updates
/// the server configuration from the Config Backends immediately.
///
/// @param command (parameter ignored)
/// @param args (ignored)
///
/// @return status of the command/
isc::data::ConstElementPtr
commandServerUpdateHandler(const std::string& command,
isc::data::ConstElementPtr args);
/// @brief Reclaims expired IPv4 leases and reschedules timer. /// @brief Reclaims expired IPv4 leases and reschedules timer.
/// ///
/// This is a wrapper method for @c AllocEngine::reclaimExpiredLeases4. /// This is a wrapper method for @c AllocEngine::reclaimExpiredLeases4.
......
...@@ -485,6 +485,7 @@ TEST_F(CtrlChannelDhcpv4SrvTest, commandsRegistration) { ...@@ -485,6 +485,7 @@ TEST_F(CtrlChannelDhcpv4SrvTest, commandsRegistration) {
EXPECT_TRUE(command_list.find("\"leases-reclaim\"") != string::npos); EXPECT_TRUE(command_list.find("\"leases-reclaim\"") != string::npos);
EXPECT_TRUE(command_list.find("\"libreload\"") != string::npos); EXPECT_TRUE(command_list.find("\"libreload\"") != string::npos);
EXPECT_TRUE(command_list.find("\"server-tag-get\"") != string::npos); EXPECT_TRUE(command_list.find("\"server-tag-get\"") != string::npos);
EXPECT_TRUE(command_list.find("\"server-update\"") != string::npos);
EXPECT_TRUE(command_list.find("\"shutdown\"") != string::npos); EXPECT_TRUE(command_list.find("\"shutdown\"") != string::npos);
EXPECT_TRUE(command_list.find("\"statistic-get\"") != string::npos); EXPECT_TRUE(command_list.find("\"statistic-get\"") != string::npos);
EXPECT_TRUE(command_list.find("\"statistic-get-all\"") != string::npos); EXPECT_TRUE(command_list.find("\"statistic-get-all\"") != string::npos);
...@@ -1025,6 +1026,19 @@ TEST_F(CtrlChannelDhcpv4SrvTest, serverTagGet) { ...@@ -1025,6 +1026,19 @@ TEST_F(CtrlChannelDhcpv4SrvTest, serverTagGet) {
expected = "{ \"arguments\": { \"server-tag\": \"foobar\" }, \"result\": 0 }"; expected = "{ \"arguments\": { \"server-tag\": \"foobar\" }, \"result\": 0 }";
} }
// This test verifies that the DHCP server handles server-update command
TEST_F(CtrlChannelDhcpv4SrvTest, serverUpdate) {
createUnixChannelServer();
std::string response;
std::string expected;
// Send the server-update command. Note there is no configured backed.
sendUnixCommand("{ \"command\": \"server-update\" }", response);
expected = "{ \"result\": 3, \"text\": \"No config backend.\" }";
EXPECT_EQ(expected, response);
}
// This test verifies that the DHCP server immediately reclaims expired // This test verifies that the DHCP server immediately reclaims expired
// leases on leases-reclaim command // leases on leases-reclaim command
TEST_F(CtrlChannelDhcpv4SrvTest, controlLeasesReclaim) { TEST_F(CtrlChannelDhcpv4SrvTest, controlLeasesReclaim) {
...@@ -1145,6 +1159,7 @@ TEST_F(CtrlChannelDhcpv4SrvTest, listCommands) { ...@@ -1145,6 +1159,7 @@ TEST_F(CtrlChannelDhcpv4SrvTest, listCommands) {
checkListCommands(rsp, "libreload"); checkListCommands(rsp, "libreload");
checkListCommands(rsp, "version-get"); checkListCommands(rsp, "version-get");
checkListCommands(rsp, "server-tag-get"); checkListCommands(rsp, "server-tag-get");
checkListCommands(rsp, "server-update");
checkListCommands(rsp, "shutdown"); checkListCommands(rsp, "shutdown");
checkListCommands(rsp, "statistic-get"); checkListCommands(rsp, "statistic-get");
checkListCommands(rsp, "statistic-get-all"); checkListCommands(rsp, "statistic-get-all");
......
...@@ -217,7 +217,8 @@ public: ...@@ -217,7 +217,8 @@ public:
/// @brief This test verifies that the timer used to fetch the configuration /// @brief This test verifies that the timer used to fetch the configuration
/// updates from the database works as expected. /// updates from the database works as expected.
void testConfigBackendTimer(const int config_wait_fetch_time, void testConfigBackendTimer(const int config_wait_fetch_time,
const bool throw_during_fetch = false) { const bool throw_during_fetch = false,
const bool call_command = false) {
std::ostringstream config; std::ostringstream config;
config << config <<
"{ \"Dhcp4\": {" "{ \"Dhcp4\": {"
...@@ -261,7 +262,40 @@ public: ...@@ -261,7 +262,40 @@ public:
EXPECT_EQ(1, cb_control->getDatabaseConfigFetchCalls()); EXPECT_EQ(1, cb_control->getDatabaseConfigFetchCalls());
if ((config_wait_fetch_time > 0) && (!throw_during_fetch)) { if (call_command) {
// The case where there is no backend is tested in the
// controlled server tests so we have only to verify
// that the command calls the database config fetch.
// Count the startup.
EXPECT_EQ(cb_control->getDatabaseConfigFetchCalls(), 1);
ConstElementPtr result =
ControlledDhcpv4Srv::processCommand("server-update",
ConstElementPtr());
EXPECT_EQ(cb_control->getDatabaseConfigFetchCalls(), 2);
std::string expected;
if (throw_during_fetch) {
expected = "{ \"result\": 1, \"text\": ";
expected += "\"Server update failed: ";
expected += "testing if exceptions are corectly handled\" }";
} else {
expected = "{ \"result\": 0, \"text\": ";
expected += "\"Server update successful.\" }";
}
EXPECT_EQ(expected, result->str());
// No good way to check the rescheduling...
ASSERT_NO_THROW(runTimersWithTimeout(srv->getIOService(), 15));
if (config_wait_fetch_time > 0) {
EXPECT_GE(cb_control->getDatabaseConfigFetchCalls(), 12);
} else {
EXPECT_EQ(cb_control->getDatabaseConfigFetchCalls(), 2);
}
} else if ((config_wait_fetch_time > 0) && (!throw_during_fetch)) {
// If we're configured to run the timer, we expect that it was // If we're configured to run the timer, we expect that it was
// invoked at least 3 times. This is sufficient to verify that // invoked at least 3 times. This is sufficient to verify that
// the timer was scheduled and that the timer continued to run // the timer was scheduled and that the timer continued to run
...@@ -857,6 +891,24 @@ TEST_F(JSONFileBackendTest, configBackendTimerWithThrow) { ...@@ -857,6 +891,24 @@ TEST_F(JSONFileBackendTest, configBackendTimerWithThrow) {
testConfigBackendTimer(1, true); testConfigBackendTimer(1, true);
} }
// This test verifies that the server will be updated by the server-update
// command.
TEST_F(JSONFileBackendTest, configBackendCommand) {
testConfigBackendTimer(0, false, true);
}
// This test verifies that the server will be updated by the server-update
// command even when updates fail.
TEST_F(JSONFileBackendTest, configBackendCommandWithThrow) {
testConfigBackendTimer(0, true, true);
}
// This test verifies that the server will be updated by the server-update
// command and the timer rescheduled.
TEST_F(JSONFileBackendTest, configBackendCommandWithTimer) {
testConfigBackendTimer(1, false, true);
}
// Starting tests which require MySQL backend availability. Those tests // Starting tests which require MySQL backend availability. Those tests
// will not be executed if Kea has been compiled without the // will not be executed if Kea has been compiled without the
// --with-mysql. // --with-mysql.
......
...@@ -544,6 +544,34 @@ ControlledDhcpv6Srv::commandServerTagGetHandler(const std::string&, ...@@ -544,6 +544,34 @@ ControlledDhcpv6Srv::commandServerTagGetHandler(const std::string&,
return (createAnswer(CONTROL_RESULT_SUCCESS, response)); return (createAnswer(CONTROL_RESULT_SUCCESS, response));
} }
ConstElementPtr
ControlledDhcpv6Srv::commandServerUpdateHandler(const std::string&,
ConstElementPtr) {
auto ctl_info = CfgMgr::instance().getCurrentCfg()->getConfigControlInfo();
if (!ctl_info) {
return (createAnswer(CONTROL_RESULT_EMPTY, "No config backend."));
}
// Reschedule the periodic CB fetch.
if (TimerMgr::instance()->isTimerRegistered("Dhcp6CBFetchTimer")) {
TimerMgr::instance()->cancel("Dhcp6CBFetchTimer");
TimerMgr::instance()->setup("Dhcp6CBFetchTimer");
}
// Code from cbFetchUpdates.
try {
auto srv_cfg = CfgMgr::instance().getStagingCfg();
auto mode = CBControlDHCPv6::FetchMode::FETCH_UPDATE;
server_->getCBControl()->databaseConfigFetch(srv_cfg, mode);
} catch (const std::exception& ex) {
LOG_ERROR(dhcp6_logger, DHCP6_CB_FETCH_UPDATES_FAIL)
.arg(ex.what());
return (createAnswer(CONTROL_RESULT_ERROR,
"Server update failed: " + string(ex.what())));
}
return (createAnswer(CONTROL_RESULT_SUCCESS, "Server update successful."));
}
isc::data::ConstElementPtr isc::data::ConstElementPtr
ControlledDhcpv6Srv::processCommand(const std::string& command, ControlledDhcpv6Srv::processCommand(const std::string& command,
isc::data::ConstElementPtr args) { isc::data::ConstElementPtr args) {
...@@ -601,6 +629,9 @@ ControlledDhcpv6Srv::processCommand(const std::string& command, ...@@ -601,6 +629,9 @@ ControlledDhcpv6Srv::processCommand(const std::string& command,
} else if (command == "server-tag-get") { } else if (command == "server-tag-get") {
return (srv->commandServerTagGetHandler(command, args)); return (srv->commandServerTagGetHandler(command, args));
} else if (command == "server-update") {
return (srv->commandServerUpdateHandler(command, args));
} }
return (isc::config::createAnswer(1, "Unrecognized command:" return (isc::config::createAnswer(1, "Unrecognized command:"
...@@ -851,6 +882,9 @@ ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port, ...@@ -851,6 +882,9 @@ ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t server_port,
CommandMgr::instance().registerCommand("server-tag-get", CommandMgr::instance().registerCommand("server-tag-get",
boost::bind(&ControlledDhcpv6Srv::commandServerTagGetHandler, this, _1, _2)); boost::bind(&ControlledDhcpv6Srv::commandServerTagGetHandler, this, _1, _2));
CommandMgr::instance().registerCommand("server-update",
boost::bind(&ControlledDhcpv6Srv::commandServerUpdateHandler, this, _1, _2));
CommandMgr::instance().registerCommand("libreload", CommandMgr::instance().registerCommand("libreload",
boost::bind(&ControlledDhcpv6Srv::commandLibReloadHandler, this, _1, _2)); boost::bind(&ControlledDhcpv6Srv::commandLibReloadHandler, this, _1, _2));
...@@ -925,6 +959,7 @@ ControlledDhcpv6Srv::~ControlledDhcpv6Srv() { ...@@ -925,6 +959,7 @@ ControlledDhcpv6Srv::~ControlledDhcpv6Srv() {
CommandMgr::instance().deregisterCommand("leases-reclaim"); CommandMgr::instance().deregisterCommand("leases-reclaim");
CommandMgr::instance().deregisterCommand("libreload"); CommandMgr::instance().deregisterCommand("libreload");
CommandMgr::instance().deregisterCommand("server-tag-get"); CommandMgr::instance().deregisterCommand("server-tag-get");
CommandMgr::instance().deregisterCommand("server-update");
CommandMgr::instance().deregisterCommand("shutdown"); CommandMgr::instance().deregisterCommand("shutdown");
CommandMgr::instance().deregisterCommand("statistic-get"); CommandMgr::instance().deregisterCommand("statistic-get");
CommandMgr::instance().deregisterCommand("statistic-get-all"); CommandMgr::instance().deregisterCommand("statistic-get-all");
......
...@@ -303,6 +303,19 @@ private: ...@@ -303,6 +303,19 @@ private:
commandServerTagGetHandler(const std::string& command, commandServerTagGetHandler(const std::string& command,
isc::data::ConstElementPtr args); isc::data::ConstElementPtr args);
/// @brief handler for server-update command
///
/// This method handles the server-update command, which updates
/// the server configuration from the Config Backends immediately.
///
/// @param command (parameter ignored)
/// @param args (ignored)
///
/// @return status of the command/
isc::data::ConstElementPtr
commandServerUpdateHandler(const std::string& command,
isc::data::ConstElementPtr args);
/// @brief Reclaims expired IPv6 leases and reschedules timer. /// @brief Reclaims expired IPv6 leases and reschedules timer.
/// ///
/// This is a wrapper method for @c AllocEngine::reclaimExpiredLeases6. /// This is a wrapper method for @c AllocEngine::reclaimExpiredLeases6.
......
...@@ -504,6 +504,7 @@ TEST_F(CtrlDhcpv6SrvTest, commandsRegistration) { ...@@ -504,6 +504,7 @@ TEST_F(CtrlDhcpv6SrvTest, commandsRegistration) {
EXPECT_TRUE(command_list.find("\"leases-reclaim\"") != string::npos); EXPECT_TRUE(command_list.find("\"leases-reclaim\"") != string::npos);
EXPECT_TRUE(command_list.find("\"libreload\"") != string::npos); EXPECT_TRUE(command_list.find("\"libreload\"") != string::npos);
EXPECT_TRUE(command_list.find("\"server-tag-get\"") != string::npos); EXPECT_TRUE(command_list.find("\"server-tag-get\"") != string::npos);
EXPECT_TRUE(command_list.find("\"server-update\"") != string::npos);
EXPECT_TRUE(command_list.find("\"shutdown\"") != string::npos); EXPECT_TRUE(command_list.find("\"shutdown\"") != string::npos);
EXPECT_TRUE(command_list.find("\"statistic-get\"") != string::npos); EXPECT_TRUE(command_list.find("\"statistic-get\"") != string::npos);
EXPECT_TRUE(command_list.find("\"statistic-get-all\"") != string::npos); EXPECT_TRUE(command_list.find("\"statistic-get-all\"") != string::npos);
...@@ -937,6 +938,19 @@ TEST_F(CtrlChannelDhcpv6SrvTest, serverTagGet) { ...@@ -937,6 +938,19 @@ TEST_F(CtrlChannelDhcpv6SrvTest, serverTagGet) {
expected = "{ \"arguments\": { \"server-tag\": \"foobar\" }, \"result\": 0 }"; expected = "{ \"arguments\": { \"server-tag\": \"foobar\" }, \"result\": 0 }";
} }
// This test verifies that the DHCP server handles server-update command
TEST_F(CtrlChannelDhcpv6SrvTest, serverUpdate) {
createUnixChannelServer();
std::string response;
std::string expected;
// Send the server-update command. Note there is no configured backed.
sendUnixCommand("{ \"command\": \"server-update\" }", response);
expected = "{ \"result\": 3, \"text\": \"No config backend.\" }";
EXPECT_EQ(expected, response);
}
// This test verifies that the DHCP server immediately reclaims expired // This test verifies that the DHCP server immediately reclaims expired
// leases on leases-reclaim command // leases on leases-reclaim command
TEST_F(CtrlChannelDhcpv6SrvTest, controlLeasesReclaim) { TEST_F(CtrlChannelDhcpv6SrvTest, controlLeasesReclaim) {
...@@ -1176,6 +1190,7 @@ TEST_F(CtrlChannelDhcpv6SrvTest, listCommands) { ...@@ -1176,6 +1190,7 @@ TEST_F(CtrlChannelDhcpv6SrvTest, listCommands) {
checkListCommands(rsp, "libreload"); checkListCommands(rsp, "libreload");
checkListCommands(rsp, "version-get"); checkListCommands(rsp, "version-get");
checkListCommands(rsp, "server-tag-get"); checkListCommands(rsp, "server-tag-get");
checkListCommands(rsp, "server-update");
checkListCommands(rsp, "shutdown"); checkListCommands(rsp, "shutdown");
checkListCommands(rsp, "statistic-get"); checkListCommands(rsp, "statistic-get");
checkListCommands(rsp, "statistic-get-all"); checkListCommands(rsp, "statistic-get-all");
......
...@@ -203,7 +203,8 @@ public: ...@@ -203,7 +203,8 @@ public:
/// @brief This test verifies that the timer used to fetch the configuration /// @brief This test verifies that the timer used to fetch the configuration
/// updates from the database works as expected. /// updates from the database works as expected.
void testConfigBackendTimer(const int config_wait_fetch_time, void testConfigBackendTimer(const int config_wait_fetch_time,
const bool throw_during_fetch = false) { const bool throw_during_fetch = false,
const bool call_command = false) {
std::ostringstream config; std::ostringstream config;
config << config <<
"{ \"Dhcp6\": {" "{ \"Dhcp6\": {"
...@@ -247,7 +248,40 @@ public: ...@@ -247,7 +248,40 @@ public:
EXPECT_EQ(1, cb_control->getDatabaseConfigFetchCalls()); EXPECT_EQ(1, cb_control->getDatabaseConfigFetchCalls());
if ((config_wait_fetch_time > 0) && (!throw_during_fetch)) { if (call_command) {
// The case where there is no backend is tested in the
// controlled server tests so we have only to verify
// that the command calls the database config fetch.
// Count the startup.
EXPECT_EQ(cb_control->getDatabaseConfigFetchCalls(), 1);
ConstElementPtr result =
ControlledDhcpv6Srv::processCommand("server-update",
ConstElementPtr());
EXPECT_EQ(cb_control->getDatabaseConfigFetchCalls(), 2);
std::string expected;
if (throw_during_fetch) {
expected = "{ \"result\": 1, \"text\": ";
expected += "\"Server update failed: ";
expected += "testing if exceptions are corectly handled\" }";
} else {
expected = "{ \"result\": 0, \"text\": ";
expected += "\"Server update successful.\" }";
}
EXPECT_EQ(expected, result->str());
// No good way to check the rescheduling...
ASSERT_NO_THROW(runTimersWithTimeout(srv->getIOService(), 15));
if (config_wait_fetch_time > 0) {
EXPECT_GE(cb_control->getDatabaseConfigFetchCalls(), 12);
} else {
EXPECT_EQ(cb_control->getDatabaseConfigFetchCalls(), 2);
}
} else if ((config_wait_fetch_time > 0) && (!throw_during_fetch)) {
// If we're configured to run the timer, we expect that it was // If we're configured to run the timer, we expect that it was
// invoked at least 3 times. This is sufficient to verify that // invoked at least 3 times. This is sufficient to verify that
// the timer was scheduled and that the timer continued to run // the timer was scheduled and that the timer continued to run
...@@ -844,6 +878,24 @@ TEST_F(JSONFileBackendTest, configBackendTimerWithThrow) { ...@@ -844,6 +878,24 @@ TEST_F(JSONFileBackendTest, configBackendTimerWithThrow) {
testConfigBackendTimer(1, true); testConfigBackendTimer(1, true);
} }
// This test verifies that the server will be updated by the server-update
// command.
TEST_F(JSONFileBackendTest, configBackendCommand) {
testConfigBackendTimer(0, false, true);
}
// This test verifies that the server will be updated by the server-update
// command even when updates fail.
TEST_F(JSONFileBackendTest, configBackendCommandWithThrow) {
testConfigBackendTimer(0, true, true);
}
// This test verifies that the server will be updated by the server-update
// command and the timer rescheduled.
TEST_F(JSONFileBackendTest, configBackendCommandWithTimer) {
testConfigBackendTimer(1, false, true);
}
// Starting tests which require MySQL backend availability. Those tests // Starting tests which require MySQL backend availability. Those tests
// will not be executed if Kea has been compiled without the // will not be executed if Kea has been compiled without the
// --with-mysql. // --with-mysql.
......