2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-30 21:45:37 +00:00

[#3106] Added server-name to HA commands

This commit is contained in:
Marcin Siodelski
2023-10-16 12:40:16 +02:00
parent 64350a679a
commit c0f3a7f353
7 changed files with 726 additions and 55 deletions

View File

@@ -65,15 +65,21 @@ CommandCreator::createDHCPEnable(const unsigned int origin,
}
ConstElementPtr
CommandCreator::createHAReset(const HAServerType& server_type) {
ConstElementPtr command = config::createCommand("ha-reset");
CommandCreator::createHAReset(const std::string& server_name,
const HAServerType& server_type) {
auto args = Element::createMap();
args->set("server-name", Element::create(server_name));
ConstElementPtr command = config::createCommand("ha-reset", args);
insertService(command, server_type);
return (command);
}
ConstElementPtr
CommandCreator::createHeartbeat(const HAServerType& server_type) {
ConstElementPtr command = config::createCommand("ha-heartbeat");
CommandCreator::createHeartbeat(const std::string& server_name,
const HAServerType& server_type) {
auto args = Element::createMap();
args->set("server-name", Element::create(server_name));
ConstElementPtr command = config::createCommand("ha-heartbeat", args);
insertService(command, server_type);
return (command);
}
@@ -250,8 +256,11 @@ CommandCreator::createMaintenanceNotify(const bool cancel, const HAServerType& s
}
ConstElementPtr
CommandCreator::createSyncCompleteNotify(const HAServerType& server_type) {
auto command = config::createCommand("ha-sync-complete-notify");
CommandCreator::createSyncCompleteNotify(const std::string& server_name,
const HAServerType& server_type) {
auto args = Element::createMap();
args->set("server-name", Element::create(server_name));
auto command = config::createCommand("ha-sync-complete-notify", args);
insertService(command, server_type);
return (command);
}

View File

@@ -49,16 +49,22 @@ public:
/// @brief Creates ha-reset command.
///
/// @param server_name name of the server sending the command allowing
/// for associating the command with the relationship.
/// @param server_type type of the DHCP server, i.e. v4 or v6.
/// @return Pointer to the JSON representation of the command.
static data::ConstElementPtr
createHAReset(const HAServerType& server_type);
createHAReset(const std::string& server_name,
const HAServerType& server_type);
/// @brief Creates ha-heartbeat command for DHCP server.
///
/// @param server_name name of the server sending the command allowing
/// for associating the command with the relationship.
/// @return Pointer to the JSON representation of the command.
static data::ConstElementPtr
createHeartbeat(const HAServerType& server_type);
createHeartbeat(const std::string& server_name,
const HAServerType& server_type);
/// @brief Creates lease4-update command.
///
@@ -174,10 +180,13 @@ public:
/// @brief Creates ha-sync-complete-notify command.
///
/// @param server_name name of the server sending the command allowing
/// for associating the command with the relationship.
/// @param server_type type of the DHCP server, i.e. v4 or v6.
/// @return Pointer to the JSON representation of the command.
static data::ConstElementPtr
createSyncCompleteNotify(const HAServerType& server_type);
createSyncCompleteNotify(const std::string& server_name,
const HAServerType& server_type);
/// @brief List of commands used by the High Availability in v4.
static std::unordered_set<std::string> ha_commands4_;

View File

@@ -319,22 +319,43 @@ HAImpl::commandProcessed(hooks::CalloutHandle& callout_handle) {
ElementPtr mutable_resp_args =
boost::const_pointer_cast<Element>(resp_args);
/// @todo Today we support only one HA relationship per Kea server.
/// In the future there will be more of them. Therefore we enclose
/// our sole relationship in a list.
// Process the status get command for each HA service.
auto ha_relationships = Element::createList();
auto ha_relationship = Element::createMap();
ConstElementPtr ha_servers = services_->get()->processStatusGet();
ha_relationship->set("ha-servers", ha_servers);
ha_relationship->set("ha-mode", Element::create(HAConfig::HAModeToString(config_->get()->getHAMode())));
ha_relationships->add(ha_relationship);
mutable_resp_args->set("high-availability", ha_relationships);
for (auto service : services_->getAll()) {
auto ha_relationship = Element::createMap();
ConstElementPtr ha_servers = service->processStatusGet();
ha_relationship->set("ha-servers", ha_servers);
ha_relationship->set("ha-mode", Element::create(HAConfig::HAModeToString(config_->get()->getHAMode())));
ha_relationships->add(ha_relationship);
mutable_resp_args->set("high-availability", ha_relationships);
}
}
}
void
HAImpl::heartbeatHandler(CalloutHandle& callout_handle) {
ConstElementPtr response = services_->get()->processHeartbeat();
// Command must always be provided.
ConstElementPtr command;
callout_handle.getArgument("command", command);
// Retrieve arguments.
ConstElementPtr args;
static_cast<void>(parseCommand(args, command));
HAServicePtr service;
try {
service = getHAServiceByServerName("ha-heartbeat", args);
} catch (const std::exception& ex) {
// There was an error while parsing command arguments. Return an error status
// code to notify the user.
ConstElementPtr response = createAnswer(CONTROL_RESULT_ERROR, ex.what());
callout_handle.setArgument("response", response);
return;
}
// Command parsing was successful, so let's process the command.
ConstElementPtr response = service->processHeartbeat();
callout_handle.setArgument("response", response);
}
@@ -351,6 +372,7 @@ HAImpl::synchronizeHandler(hooks::CalloutHandle& callout_handle) {
ConstElementPtr server_name;
unsigned int max_period_value = 0;
HAServicePtr service;
try {
// Arguments are required for the ha-sync command.
if (!args) {
@@ -386,6 +408,8 @@ HAImpl::synchronizeHandler(hooks::CalloutHandle& callout_handle) {
max_period_value = static_cast<unsigned int>(max_period->intValue());
}
service = getHAServiceByServerName("ha-sync", args);
} catch (const std::exception& ex) {
// There was an error while parsing command arguments. Return an error status
// code to notify the user.
@@ -395,8 +419,8 @@ HAImpl::synchronizeHandler(hooks::CalloutHandle& callout_handle) {
}
// Command parsing was successful, so let's process the command.
ConstElementPtr response = services_->get()->processSynchronize(server_name->stringValue(),
max_period_value);
ConstElementPtr response = service->processSynchronize(server_name->stringValue(),
max_period_value);
callout_handle.setArgument("response", response);
}
@@ -410,8 +434,8 @@ HAImpl::scopesHandler(hooks::CalloutHandle& callout_handle) {
ConstElementPtr args;
static_cast<void>(parseCommand(args, command));
HAServicePtr service;
std::vector<std::string> scopes_vector;
try {
// Arguments must be present.
if (!args) {
@@ -444,6 +468,8 @@ HAImpl::scopesHandler(hooks::CalloutHandle& callout_handle) {
scopes_vector.push_back(scope->stringValue());
}
service = getHAServiceByServerName("ha-sync", args);
} catch (const std::exception& ex) {
// There was an error while parsing command arguments. Return an error status
// code to notify the user.
@@ -453,13 +479,32 @@ HAImpl::scopesHandler(hooks::CalloutHandle& callout_handle) {
}
// Command parsing was successful, so let's process the command.
ConstElementPtr response = services_->get()->processScopes(scopes_vector);
ConstElementPtr response = service->processScopes(scopes_vector);
callout_handle.setArgument("response", response);
}
void
HAImpl::continueHandler(hooks::CalloutHandle& callout_handle) {
ConstElementPtr response = services_->get()->processContinue();
// Command must always be provided.
ConstElementPtr command;
callout_handle.getArgument("command", command);
// Retrieve arguments.
ConstElementPtr args;
static_cast<void>(parseCommand(args, command));
HAServicePtr service;
try {
service = getHAServiceByServerName("ha-continue", args);
} catch (const std::exception& ex) {
// There was an error while parsing command arguments. Return an error status
// code to notify the user.
ConstElementPtr response = createAnswer(CONTROL_RESULT_ERROR, ex.what());
callout_handle.setArgument("response", response);
return;
}
ConstElementPtr response = service->processContinue();
callout_handle.setArgument("response", response);
}
@@ -469,46 +514,139 @@ HAImpl::maintenanceNotifyHandler(hooks::CalloutHandle& callout_handle) {
ConstElementPtr command;
callout_handle.getArgument("command", command);
// Retrieve arguments.
ConstElementPtr args;
static_cast<void>(parseCommandWithArgs(args, command));
HAServicePtr service;
try {
// Retrieve arguments.
ConstElementPtr args;
static_cast<void>(parseCommandWithArgs(args, command));
ConstElementPtr cancel_op = args->get("cancel");
if (!cancel_op) {
isc_throw(BadValue, "'cancel' is mandatory for the 'ha-maintenance-notify' command");
ConstElementPtr cancel_op = args->get("cancel");
if (!cancel_op) {
isc_throw(BadValue, "'cancel' is mandatory for the 'ha-maintenance-notify' command");
}
if (cancel_op->getType() != Element::boolean) {
isc_throw(BadValue, "'cancel' must be a boolean in the 'ha-maintenance-notify' command");
}
service = getHAServiceByServerName("ha-maintenance-notify", args);
ConstElementPtr response = service->processMaintenanceNotify(cancel_op->boolValue());
callout_handle.setArgument("response", response);
} catch (const std::exception& ex) {
// There was an error while parsing command arguments. Return an error status
// code to notify the user.
ConstElementPtr response = createAnswer(CONTROL_RESULT_ERROR, ex.what());
callout_handle.setArgument("response", response);
}
if (cancel_op->getType() != Element::boolean) {
isc_throw(BadValue, "'cancel' must be a boolean in the 'ha-maintenance-notify' command");
}
ConstElementPtr response = services_->get()->processMaintenanceNotify(cancel_op->boolValue());
callout_handle.setArgument("response", response);
}
void
HAImpl::maintenanceStartHandler(hooks::CalloutHandle& callout_handle) {
ConstElementPtr response = services_->get()->processMaintenanceStart();
ConstElementPtr response;
for (auto service : services_->getAll()) {
response = service->processMaintenanceStart();
int rcode = CONTROL_RESULT_SUCCESS;
static_cast<void>(parseAnswer(rcode, response));
if (rcode != CONTROL_RESULT_SUCCESS) {
break;
}
}
callout_handle.setArgument("response", response);
}
void
HAImpl::maintenanceCancelHandler(hooks::CalloutHandle& callout_handle) {
ConstElementPtr response = services_->get()->processMaintenanceCancel();
ConstElementPtr response;
for (auto service : services_->getAll()) {
response = service->processMaintenanceCancel();
}
callout_handle.setArgument("response", response);
}
void
HAImpl::haResetHandler(hooks::CalloutHandle& callout_handle) {
// Command must always be provided.
ConstElementPtr command;
callout_handle.getArgument("command", command);
// Retrieve arguments.
ConstElementPtr args;
static_cast<void>(parseCommand(args, command));
HAServicePtr service;
try {
service = getHAServiceByServerName("ha-reset", args);
} catch (const std::exception& ex) {
// There was an error while parsing command arguments. Return an error status
// code to notify the user.
ConstElementPtr response = createAnswer(CONTROL_RESULT_ERROR, ex.what());
callout_handle.setArgument("response", response);
return;
}
ConstElementPtr response = services_->get()->processHAReset();
callout_handle.setArgument("response", response);
}
void
HAImpl::syncCompleteNotifyHandler(hooks::CalloutHandle& callout_handle) {
// Command must always be provided.
ConstElementPtr command;
callout_handle.getArgument("command", command);
// Retrieve arguments.
ConstElementPtr args;
static_cast<void>(parseCommand(args, command));
HAServicePtr service;
try {
service = getHAServiceByServerName("ha-sync-complete-notify", args);
} catch (const std::exception& ex) {
// There was an error while parsing command arguments. Return an error status
// code to notify the user.
ConstElementPtr response = createAnswer(CONTROL_RESULT_ERROR, ex.what());
callout_handle.setArgument("response", response);
return;
}
ConstElementPtr response = services_->get()->processSyncCompleteNotify();
callout_handle.setArgument("response", response);
}
HAServicePtr
HAImpl::getHAServiceByServerName(const std::string& command_name, ConstElementPtr args) const {
HAServicePtr service;
if (args) {
// Arguments must be a map.
if (args->getType() != Element::map) {
isc_throw(BadValue, "arguments in the '" << command_name << "' command are not a map");
}
auto server_name = args->get("server-name");
if (server_name) {
if (server_name->getType() != Element::string) {
isc_throw(BadValue, "'server-name' must be a string in the '" << command_name << "' command");
}
service = services_->get(server_name->stringValue());
if (!service) {
isc_throw(BadValue, server_name->stringValue() << " matches no configured"
<< " 'server-name'");
}
}
}
if (!service) {
service = services_->get();
}
return (service);
}
} // end of namespace isc::ha
} // end of namespace isc

View File

@@ -178,6 +178,20 @@ public:
/// @param callout_handle Callout handle provided to the callout.
void syncCompleteNotifyHandler(hooks::CalloutHandle& callout_handle);
/// @brief Attempts to get an @c HAService by server name.
///
/// The function expects that the arguments contain the "server-name"
/// parameter. If the parameter is not specified, a default @c HAService
/// name is returned.
///
/// @param command_name command name.
/// @param args command arguments or null.
/// @return Pointer to an @c HAService instance.
/// @throw BadValue if the specified server-name doesn't exist or if the
/// server-name wasn't specified and more than one @c HAService exists.
HAServicePtr getHAServiceByServerName(const std::string& command_name,
data::ConstElementPtr args) const;
protected:
/// @brief Holds parsed configuration.

View File

@@ -1692,7 +1692,8 @@ HAService::asyncSendHeartbeat() {
(HttpRequest::Method::HTTP_POST, "/", HttpVersion::HTTP_11(),
HostHttpHeader(partner_config->getUrl().getStrippedHostname()));
partner_config->addBasicAuthHttpHeader(request);
request->setBodyAsJson(CommandCreator::createHeartbeat(server_type_));
request->setBodyAsJson(CommandCreator::createHeartbeat(config_->getThisServerConfig()->getName(),
server_type_));
request->finalize();
// Response object should also be created because the HTTP client needs
@@ -2507,7 +2508,8 @@ void
HAService::asyncSendHAReset(HttpClient& http_client,
const HAConfig::PeerConfigPtr& config,
PostRequestCallback post_request_action) {
ConstElementPtr command = CommandCreator::createHAReset(server_type_);
ConstElementPtr command = CommandCreator::createHAReset(config_->getThisServerConfig()->getName(),
server_type_);
// Create HTTP/1.1 request including our command.
PostHttpRequestJsonPtr request = boost::make_shared<PostHttpRequestJson>
@@ -2867,7 +2869,8 @@ HAService::asyncSyncCompleteNotify(HttpClient& http_client,
HostHttpHeader(remote_config->getUrl().getStrippedHostname()));
remote_config->addBasicAuthHttpHeader(request);
request->setBodyAsJson(CommandCreator::createSyncCompleteNotify(server_type_));
request->setBodyAsJson(CommandCreator::createSyncCompleteNotify(config_->getThisServerConfig()->getName(),
server_type_));
request->finalize();
// Response object should also be created because the HTTP client needs

View File

@@ -191,14 +191,24 @@ TEST(CommandCreatorTest, createDHCPEnable4) {
// This test verifies that the ha-reset command sent to DHCPv4 server is correct.
TEST(CommandCreatorTest, createHAReset4) {
ConstElementPtr command = CommandCreator::createHAReset(HAServerType::DHCPv4);
ASSERT_NO_FATAL_FAILURE(testCommandBasics(command, "ha-reset", "dhcp4"));
ConstElementPtr command = CommandCreator::createHAReset("server1", HAServerType::DHCPv4);
ConstElementPtr arguments;
ASSERT_NO_FATAL_FAILURE(testCommandBasics(command, "ha-reset", "dhcp4", arguments));
auto server_name = arguments->get("server-name");
ASSERT_TRUE(server_name);
ASSERT_EQ(Element::string, server_name->getType());
EXPECT_EQ("server1", server_name->stringValue());
}
// This test verifies that the ha-heartbeat command is correct.
TEST(CommandCreatorTest, createHeartbeat4) {
ConstElementPtr command = CommandCreator::createHeartbeat(HAServerType::DHCPv4);
ASSERT_NO_FATAL_FAILURE(testCommandBasics(command, "ha-heartbeat", "dhcp4"));
ConstElementPtr command = CommandCreator::createHeartbeat("server1", HAServerType::DHCPv4);
ConstElementPtr arguments;
ASSERT_NO_FATAL_FAILURE(testCommandBasics(command, "ha-heartbeat", "dhcp4", arguments));
auto server_name = arguments->get("server-name");
ASSERT_TRUE(server_name);
ASSERT_EQ(Element::string, server_name->getType());
EXPECT_EQ("server1", server_name->stringValue());
}
// This test verifies that the command generated for the lease update
@@ -326,8 +336,13 @@ TEST(CommandCreatorTest, createDHCPEnable6) {
// This test verifies that the ha-reset command sent to DHCPv6 server is correct.
TEST(CommandCreatorTest, createHAReset6) {
ConstElementPtr command = CommandCreator::createHAReset(HAServerType::DHCPv6);
ASSERT_NO_FATAL_FAILURE(testCommandBasics(command, "ha-reset", "dhcp6"));
ConstElementPtr arguments;
ConstElementPtr command = CommandCreator::createHAReset("server1", HAServerType::DHCPv6);
ASSERT_NO_FATAL_FAILURE(testCommandBasics(command, "ha-reset", "dhcp6", arguments));
auto server_name = arguments->get("server-name");
ASSERT_TRUE(server_name);
ASSERT_EQ(Element::string, server_name->getType());
EXPECT_EQ("server1", server_name->stringValue());
}
// This test verifies that the command generated for the lease update
@@ -520,16 +535,25 @@ TEST(CommandCreatorTest, createMaintenanceNotify6) {
// This test verifies that the ha-sync-complete-notify command sent to a
// DHCPv4 server is correct.
TEST(CommandCreatorTest, createSyncCompleteNotify4) {
ConstElementPtr command = CommandCreator::createSyncCompleteNotify(HAServerType::DHCPv4);
ASSERT_NO_FATAL_FAILURE(testCommandBasics(command, "ha-sync-complete-notify", "dhcp4"));
ConstElementPtr command = CommandCreator::createSyncCompleteNotify("server1", HAServerType::DHCPv4);
ConstElementPtr arguments;
ASSERT_NO_FATAL_FAILURE(testCommandBasics(command, "ha-sync-complete-notify", "dhcp4", arguments));
auto server_name = arguments->get("server-name");
ASSERT_TRUE(server_name);
ASSERT_EQ(Element::string, server_name->getType());
EXPECT_EQ("server1", server_name->stringValue());
}
// This test verifies that the ha-sync-complete-notify command sent to a
// DHCPv4 server is correct.
TEST(CommandCreatorTest, createSyncCompleteNotify6) {
ConstElementPtr command = CommandCreator::createSyncCompleteNotify(HAServerType::DHCPv6);
ConstElementPtr command = CommandCreator::createSyncCompleteNotify("server1", HAServerType::DHCPv6);
ConstElementPtr arguments;
ASSERT_NO_FATAL_FAILURE(testCommandBasics(command, "ha-sync-complete-notify", "dhcp6"));
ASSERT_NO_FATAL_FAILURE(testCommandBasics(command, "ha-sync-complete-notify", "dhcp6", arguments));
auto server_name = arguments->get("server-name");
ASSERT_TRUE(server_name);
ASSERT_EQ(Element::string, server_name->getType());
EXPECT_EQ("server1", server_name->stringValue());
}
}

View File

@@ -571,13 +571,53 @@ TEST_F(HAImplTest, synchronizeHandler) {
" command");
}
{
SCOPED_TRACE("Server name must be valid");
testSynchronizeHandler("{"
" \"command\": \"ha-sync\","
" \"arguments\": {"
" \"server-name\": \"server5\","
" \"max-period\": 20"
" }"
"}", "server5 matches no configured 'server-name'");
}
}
// Tests ha-continue command handler.
// Tests ha-continue command handler with a specified server name.
TEST_F(HAImplTest, continueHandler) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON("{"
"\"command\": \"ha-continue\","
"\"arguments\": {"
" \"server-name\": \"server1\""
"}"
"}");
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
callout_handle->setArgument("command", command);
ASSERT_NO_THROW(ha_impl.continueHandler(*callout_handle));
ConstElementPtr response;
callout_handle->getArgument("response", response);
ASSERT_TRUE(response);
checkAnswer(response, CONTROL_RESULT_SUCCESS, "HA state machine is not paused.");
}
// Tests ha-continue command handler without a server name.
TEST_F(HAImplTest, continueHandlerWithNoServerName) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
@@ -597,6 +637,35 @@ TEST_F(HAImplTest, continueHandler) {
checkAnswer(response, CONTROL_RESULT_SUCCESS, "HA state machine is not paused.");
}
// Tests ha-continue command handler with wrong server name.
TEST_F(HAImplTest, continueHandlerWithWrongServerName) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON("{"
"\"command\": \"ha-continue\","
"\"arguments\": {"
" \"server-name\": \"server5\""
"}"
"}");
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
callout_handle->setArgument("command", command);
ASSERT_NO_THROW(ha_impl.continueHandler(*callout_handle));
ConstElementPtr response;
callout_handle->getArgument("response", response);
ASSERT_TRUE(response);
checkAnswer(response, CONTROL_RESULT_ERROR, "server5 matches no configured 'server-name'");
}
// Tests status-get command processed handler.
TEST_F(HAImplTest, statusGet) {
HAImpl ha_impl;
@@ -752,11 +821,43 @@ TEST_F(HAImplTest, statusGetPassiveBackup) {
EXPECT_TRUE(isEquivalent(got, Element::fromJSON(expected)));
}
// Test ha-maintenance-notify command handler.
// Test ha-maintenance-notify command handler with server name.
TEST_F(HAImplTest, maintenanceNotify) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON(
"{"
" \"command\": \"ha-maintenance-notify\","
" \"arguments\": {"
" \"cancel\": false,"
" \"server-name\": \"server1\""
" }"
"}"
);
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
callout_handle->setArgument("command", command);
ASSERT_NO_THROW(ha_impl.maintenanceNotifyHandler(*callout_handle));
ConstElementPtr response;
callout_handle->getArgument("response", response);
ASSERT_TRUE(response);
checkAnswer(response, CONTROL_RESULT_SUCCESS, "Server is in-maintenance state.");
}
// Test ha-maintenance-notify command handler without server name.
TEST_F(HAImplTest, maintenanceNotifyNoServerName) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
@@ -783,11 +884,75 @@ TEST_F(HAImplTest, maintenanceNotify) {
checkAnswer(response, CONTROL_RESULT_SUCCESS, "Server is in-maintenance state.");
}
// Test ha-reset command handler.
// Test ha-maintenance-notify command handler without server name.
TEST_F(HAImplTest, maintenanceNotifyBadServerName) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON(
"{"
" \"command\": \"ha-maintenance-notify\","
" \"arguments\": {"
" \"cancel\": false,"
" \"server-name\": \"server5\""
" }"
"}"
);
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
callout_handle->setArgument("command", command);
ASSERT_NO_THROW(ha_impl.maintenanceNotifyHandler(*callout_handle));
ConstElementPtr response;
callout_handle->getArgument("response", response);
ASSERT_TRUE(response);
checkAnswer(response, CONTROL_RESULT_ERROR, "server5 matches no configured 'server-name'");
}
// Test ha-reset command handler with a specified server name.
TEST_F(HAImplTest, haReset) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON(
"{"
" \"command\": \"ha-reset\","
" \"arguments\": {"
" \"server-name\": \"server1\""
" }"
"}"
);
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
callout_handle->setArgument("command", command);
ASSERT_NO_THROW(ha_impl.haResetHandler(*callout_handle));
ConstElementPtr response;
callout_handle->getArgument("response", response);
ASSERT_TRUE(response);
checkAnswer(response, CONTROL_RESULT_SUCCESS, "HA state machine already in WAITING state.");
}
// Test ha-reset command handler without a specified server name.
TEST_F(HAImplTest, haResetNoServerName) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
@@ -811,4 +976,313 @@ TEST_F(HAImplTest, haReset) {
checkAnswer(response, CONTROL_RESULT_SUCCESS, "HA state machine already in WAITING state.");
}
// Test ha-reset command handler with a wrong server name.
TEST_F(HAImplTest, haResetBadServerName) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON(
"{"
" \"command\": \"ha-reset\","
" \"arguments\": {"
" \"server-name\": \"server5\""
" }"
"}"
);
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
callout_handle->setArgument("command", command);
ASSERT_NO_THROW(ha_impl.haResetHandler(*callout_handle));
ConstElementPtr response;
callout_handle->getArgument("response", response);
ASSERT_TRUE(response);
checkAnswer(response, CONTROL_RESULT_ERROR, "server5 matches no configured 'server-name'");
}
// Test ha-heartbeat command handler with a specified server name.
TEST_F(HAImplTest, haHeartbeat) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON(
"{"
" \"command\": \"ha-heartbeat\","
" \"arguments\": {"
" \"server-name\": \"server1\""
" }"
"}"
);
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
callout_handle->setArgument("command", command);
ASSERT_NO_THROW(ha_impl.heartbeatHandler(*callout_handle));
ConstElementPtr response;
callout_handle->getArgument("response", response);
ASSERT_TRUE(response);
checkAnswer(response, CONTROL_RESULT_SUCCESS, "HA peer status returned.");
}
// Test ha-heartbeat command handler without a specified server name.
TEST_F(HAImplTest, haHeartbeatNoServerName) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON(
"{"
" \"command\": \"ha-heartbeat\""
"}"
);
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
callout_handle->setArgument("command", command);
ASSERT_NO_THROW(ha_impl.heartbeatHandler(*callout_handle));
ConstElementPtr response;
callout_handle->getArgument("response", response);
ASSERT_TRUE(response);
checkAnswer(response, CONTROL_RESULT_SUCCESS, "HA peer status returned.");
}
// Test ha-heartbeat command handler with a wrong server name.
TEST_F(HAImplTest, haHeartbeatBadServerName) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON(
"{"
" \"command\": \"ha-heartbeat\","
" \"arguments\": {"
" \"server-name\": \"server5\""
" }"
"}"
);
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
callout_handle->setArgument("command", command);
ASSERT_NO_THROW(ha_impl.heartbeatHandler(*callout_handle));
ConstElementPtr response;
callout_handle->getArgument("response", response);
ASSERT_TRUE(response);
checkAnswer(response, CONTROL_RESULT_ERROR, "server5 matches no configured 'server-name'");
}
// Test ha-sync-complete-notify command handler with a specified server name.
TEST_F(HAImplTest, haSyncCompleteNotify) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON(
"{"
" \"command\": \"ha-sync-complete-notify\","
" \"arguments\": {"
" \"server-name\": \"server1\""
" }"
"}"
);
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
callout_handle->setArgument("command", command);
ASSERT_NO_THROW(ha_impl.syncCompleteNotifyHandler(*callout_handle));
ConstElementPtr response;
callout_handle->getArgument("response", response);
ASSERT_TRUE(response);
checkAnswer(response, CONTROL_RESULT_SUCCESS,
"Server successfully notified about the synchronization completion.");
}
// Test ha-sync-complete-notify command handler without a specified server name.
TEST_F(HAImplTest, haSyncCompleteNotifyNoServerName) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON(
"{"
" \"command\": \"ha-sync-complete-notify\""
"}"
);
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
callout_handle->setArgument("command", command);
ASSERT_NO_THROW(ha_impl.syncCompleteNotifyHandler(*callout_handle));
ConstElementPtr response;
callout_handle->getArgument("response", response);
ASSERT_TRUE(response);
checkAnswer(response, CONTROL_RESULT_SUCCESS,
"Server successfully notified about the synchronization completion.");
}
// Test ha-sync-complete-notify command handler with a wrong server name.
TEST_F(HAImplTest, haSyncCompleteNotifyBadServerName) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON(
"{"
" \"command\": \"ha-sync-complete-notify\","
" \"arguments\": {"
" \"server-name\": \"server5\""
" }"
"}"
);
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
callout_handle->setArgument("command", command);
ASSERT_NO_THROW(ha_impl.syncCompleteNotifyHandler(*callout_handle));
ConstElementPtr response;
callout_handle->getArgument("response", response);
ASSERT_TRUE(response);
checkAnswer(response, CONTROL_RESULT_ERROR, "server5 matches no configured 'server-name'");
}
// Test ha-scopes command handler with a specified server name.
TEST_F(HAImplTest, haScopes) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON(
"{"
" \"command\": \"ha-scopes\","
" \"arguments\": {"
" \"scopes\": [ \"server1\", \"server2\" ],"
" \"server-name\": \"server1\""
" }"
"}"
);
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
callout_handle->setArgument("command", command);
ASSERT_NO_THROW(ha_impl.scopesHandler(*callout_handle));
ConstElementPtr response;
callout_handle->getArgument("response", response);
ASSERT_TRUE(response);
checkAnswer(response, CONTROL_RESULT_SUCCESS, "New HA scopes configured.");
}
// Test ha-scopes command handler without a specified server name.
TEST_F(HAImplTest, haScopesNoServerName) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON(
"{"
" \"command\": \"ha-scopes\","
" \"arguments\": {"
" \"scopes\": [ \"server1\", \"server2\" ]"
" }"
"}"
);
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
callout_handle->setArgument("command", command);
ASSERT_NO_THROW(ha_impl.scopesHandler(*callout_handle));
ConstElementPtr response;
callout_handle->getArgument("response", response);
ASSERT_TRUE(response);
checkAnswer(response, CONTROL_RESULT_SUCCESS, "New HA scopes configured.");
}
// Test ha-scopes command handler with a wrong server name.
TEST_F(HAImplTest, haScopesBadServerName) {
HAImpl ha_impl;
ASSERT_NO_THROW(ha_impl.configure(createValidJsonConfiguration()));
// Starting the service is required prior to running any callouts.
NetworkStatePtr network_state(new NetworkState(NetworkState::DHCPv4));
ASSERT_NO_THROW(ha_impl.startServices(io_service_, network_state,
HAServerType::DHCPv4));
ConstElementPtr command = Element::fromJSON(
"{"
" \"command\": \"ha-scopes\","
" \"arguments\": {"
" \"scopes\": [ \"server1\", \"server2\" ],"
" \"server-name\": \"server5\""
" }"
"}"
);
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
callout_handle->setArgument("command", command);
ASSERT_NO_THROW(ha_impl.scopesHandler(*callout_handle));
ConstElementPtr response;
callout_handle->getArgument("response", response);
ASSERT_TRUE(response);
checkAnswer(response, CONTROL_RESULT_ERROR, "server5 matches no configured 'server-name'");
}
}