]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1402] Implemented ha-reset command
authorMarcin Siodelski <marcin@isc.org>
Mon, 11 Jan 2021 09:35:18 +0000 (10:35 +0100)
committerMarcin Siodelski <marcin@isc.org>
Wed, 13 Jan 2021 09:12:32 +0000 (10:12 +0100)
src/hooks/dhcp/high_availability/ha_callouts.cc
src/hooks/dhcp/high_availability/ha_impl.cc
src/hooks/dhcp/high_availability/ha_impl.h
src/hooks/dhcp/high_availability/ha_messages.cc
src/hooks/dhcp/high_availability/ha_messages.h
src/hooks/dhcp/high_availability/ha_messages.mes
src/hooks/dhcp/high_availability/ha_service.cc
src/hooks/dhcp/high_availability/ha_service.h
src/hooks/dhcp/high_availability/tests/ha_impl_unittest.cc
src/hooks/dhcp/high_availability/tests/ha_service_unittest.cc

index 2a9c4568e8b8dffa7f7031acf1999208e9415176..4c3d801dc494513e9ec795fc175e5237bdae0f19 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2017-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2017-2021 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
@@ -270,6 +270,17 @@ int maintenance_cancel_command(CalloutHandle& handle) {
     return (0);
 }
 
+/// @brief ha-reset command handler implementation.
+int ha_reset_command(CalloutHandle& handle) {
+    try {
+        impl->haResetHandler(handle);
+
+    } catch (const std::exception& ex) {
+        LOG_ERROR(ha_logger, HA_RESET_HANDLER_FAILED)
+            .arg(ex.what());
+    }
+}
+
 /// @brief This function is called when the library is loaded.
 ///
 /// @param handle library handle
@@ -307,6 +318,7 @@ int load(LibraryHandle& handle) {
         handle.registerCommandCallout("ha-maintenance-notify", maintenance_notify_command);
         handle.registerCommandCallout("ha-maintenance-start", maintenance_start_command);
         handle.registerCommandCallout("ha-maintenance-cancel", maintenance_cancel_command);
+        handle.registerCommandCallout("ha-reset", ha_reset_command);
 
     } catch (const std::exception& ex) {
         LOG_ERROR(ha_logger, HA_CONFIGURATION_FAILED)
index d7b7c45a8e8c241bc4bd6cac11b577376a1a8b99..84d92eb91e2dec7748807245e28d19e07f892fec 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2018-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2018-2021 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
@@ -461,5 +461,11 @@ HAImpl::maintenanceCancelHandler(hooks::CalloutHandle& callout_handle) {
     callout_handle.setArgument("response", response);
 }
 
+void
+HAImpl::haResetHandler(hooks::CalloutHandle& callout_handle) {
+    ConstElementPtr response = service_->processHAReset();
+    callout_handle.setArgument("response", response);
+}
+
 } // end of namespace isc::ha
 } // end of namespace isc
index b4bc346d9d5e9843b2515481796142cf46ca1ef1..969de358ccf9ce3c8e4b9ea632de1daeb9164abd 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2018-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2018-2021 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
@@ -159,6 +159,11 @@ public:
     /// @param callout_handle Callout handle provided to the callout.
     void maintenanceCancelHandler(hooks::CalloutHandle& callout_handle);
 
+    /// @brief Implements handler for the ha-reset command.
+    ///
+    /// @param callout_handle Callout handle provided to the callout.
+    void haResetHandler(hooks::CalloutHandle& callout_handle);
+
 protected:
 
     /// @brief Holds parsed configuration.
index c32a2329f21e60d89a8463836a38c567e4033d28..8b96d81ed7d836cefaab4b6ea33a82d695f5a875 100644 (file)
@@ -82,6 +82,7 @@ extern const isc::log::MessageID HA_MAINTENANCE_STARTED = "HA_MAINTENANCE_STARTE
 extern const isc::log::MessageID HA_MAINTENANCE_STARTED_IN_PARTNER_DOWN = "HA_MAINTENANCE_STARTED_IN_PARTNER_DOWN";
 extern const isc::log::MessageID HA_MAINTENANCE_START_HANDLER_FAILED = "HA_MAINTENANCE_START_HANDLER_FAILED";
 extern const isc::log::MessageID HA_MISSING_CONFIGURATION = "HA_MISSING_CONFIGURATION";
+extern const isc::log::MessageID HA_RESET_HANDLER_FAILED = "HA_RESET_HANDLER_FAILED";
 extern const isc::log::MessageID HA_SCOPES_HANDLER_FAILED = "HA_SCOPES_HANDLER_FAILED";
 extern const isc::log::MessageID HA_SERVICE_STARTED = "HA_SERVICE_STARTED";
 extern const isc::log::MessageID HA_STATE_MACHINE_CONTINUED = "HA_STATE_MACHINE_CONTINUED";
@@ -176,6 +177,7 @@ const char* values[] = {
     "HA_MAINTENANCE_STARTED_IN_PARTNER_DOWN", "the server is now in the partner-down mode as a result of requested maintenance",
     "HA_MAINTENANCE_START_HANDLER_FAILED", "ha-maintenance-start command failed: %1",
     "HA_MISSING_CONFIGURATION", "high-availability parameter not specified for High Availability hooks library",
+    "HA_RESET_HANDLER_FAILED", "ha-reset command failed: %1",
     "HA_SCOPES_HANDLER_FAILED", "ha-scopes command failed: %1",
     "HA_SERVICE_STARTED", "started high availability service in %1 mode as %2 server",
     "HA_STATE_MACHINE_CONTINUED", "state machine is un-paused",
index 0e72ebb13a145368f967cc7461fd67171646193d..600bc1b453898374baddf99a2e35382a3c2b0029 100644 (file)
@@ -83,6 +83,7 @@ extern const isc::log::MessageID HA_MAINTENANCE_STARTED;
 extern const isc::log::MessageID HA_MAINTENANCE_STARTED_IN_PARTNER_DOWN;
 extern const isc::log::MessageID HA_MAINTENANCE_START_HANDLER_FAILED;
 extern const isc::log::MessageID HA_MISSING_CONFIGURATION;
+extern const isc::log::MessageID HA_RESET_HANDLER_FAILED;
 extern const isc::log::MessageID HA_SCOPES_HANDLER_FAILED;
 extern const isc::log::MessageID HA_SERVICE_STARTED;
 extern const isc::log::MessageID HA_STATE_MACHINE_CONTINUED;
index 9b2e3f6d2afc8646a8a785793637c7e9d21b26af..c9e0240b7130ecfee9f8d98cc313bf73673f8755 100644 (file)
@@ -470,6 +470,11 @@ This error message is issued to indicate that the configuration for the
 High Availability hooks library hasn't been specified. The 'high-availability'
 parameter must be specified for the hooks library to load properly.
 
+% HA_RESET_HANDLER_FAILED ha-reset command failed: %1
+This error message is issued to indicate that the ha-reset command handler
+failed while processing the command. The argument provides the reason for
+failure.
+
 % HA_SCOPES_HANDLER_FAILED ha-scopes command failed: %1
 This error message is issued to indicate that the ha-scopes command handler
 failed while processing the command. The argument provides reason for
index cd8ca98bbbdb2e9c2aba350bc57b5ba7f8ec13f8..c1c87f7e434b346b4fc0a5efaceb28a719ba4b3b 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2018-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2018-2021 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
@@ -1506,6 +1506,13 @@ HAService::processHeartbeat() {
                          arguments));
 }
 
+ConstElementPtr
+HAService::processHAReset() {
+    verboseTransition(HA_WAITING_ST);
+    runModel(NOP_EVT);
+    return (createAnswer(CONTROL_RESULT_SUCCESS, "HA state machine reset."));
+}
+
 void
 HAService::asyncSendHeartbeat() {
     HAConfig::PeerConfigPtr partner_config = config_->getFailoverPeerConfig();
index c9aebafc317430fa4a7f9f46fb4201fdcd18e70b..9cd153544594861dcee578474bb549f6639a054b 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2018-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2018-2021 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
@@ -638,12 +638,24 @@ public:
 
     /// @brief Processes status-get command and returns a response.
     ///
-    ///
-    ///
     /// @c HAImpl::commandProcessed calls this to add information about the
     /// HA servers status into the status-get response.
     data::ConstElementPtr processStatusGet() const;
 
+    /// @brief Processes ha-reset command and returns a response.
+    ///
+    /// This method processes ha-reset command which instructs the server to
+    /// transition to the waiting state. A partner may send this command when
+    /// the communication is re-established between the servers in the
+    /// communication-recovery state and full lease database synchronization is
+    /// required. This command may also be sent by an operator if the server's
+    /// state is invalid and the reset operation may help correct the situation.
+    ///
+    /// The ha-reset takes no arguments.
+    ///
+    /// @return Pointer to a response to the ha-reset command.
+    data::ConstElementPtr processHAReset();
+
 protected:
 
     /// @brief Starts asynchronous heartbeat to a peer.
index 38d634af97e7658c53de035bdba6c440bc0d5b57..900c39df373ad4bc457d6599d9854c9650e96f23 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2018-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2018-2021 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
@@ -731,4 +731,32 @@ TEST_F(HAImplTest, maintenanceNotify) {
     checkAnswer(response, CONTROL_RESULT_SUCCESS, "Server is in-maintenance state.");
 }
 
+// Test ha-reset command handler.
+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.startService(io_service_, network_state,
+                                         HAServerType::DHCPv4));
+
+    ConstElementPtr command = Element::fromJSON(
+        "{"
+        "    \"command\": \"ha-reset\""
+        "}"
+    );
+
+    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 reset.");
+}
+
 }
index d5dfaf22235ae051eaa8361b03683ad7f1e33e35..dbfe177045c7afeb71828856503507dfb5dc772d 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2018-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2018-2021 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
@@ -4371,6 +4371,29 @@ TEST_F(HAServiceTest, processMaintenanceCancelPartnerUnauthorized) {
     EXPECT_EQ(HA_PARTNER_IN_MAINTENANCE_ST, service.getCurrState());
 }
 
+// This test verifies that the ha-reset command is processed successfully.
+TEST_F(HAServiceTest, processHAReset) {
+    HAConfigPtr config_storage = createValidConfiguration();
+    TestHAService service(io_service_, network_state_, config_storage);
+
+    // Transion the server to the load-balancing state.
+    EXPECT_NO_THROW(service.transition(HA_LOAD_BALANCING_ST, HAService::NOP_EVT));
+
+    // Process ha-reset command that should cause the server to transition
+    // to the waiting state.
+    ConstElementPtr rsp;
+    ASSERT_NO_THROW(rsp = service.processHAReset());
+
+    // The server should have responded.
+    ASSERT_TRUE(rsp);
+    checkAnswer(rsp, CONTROL_RESULT_SUCCESS, "HA state machine reset.");
+
+    // Response should include no arguments.
+    EXPECT_FALSE(rsp->get("arguments"));
+
+    // The server should be in the waiting state.
+    EXPECT_EQ(HA_WAITING_ST, service.getCurrState());
+}
 
 /// @brief HA partner to the server under test.
 ///