]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1024] Implemented state handlers
authorMarcin Siodelski <marcin@isc.org>
Tue, 14 Jan 2020 10:20:33 +0000 (11:20 +0100)
committerMarcin Siodelski <marcin@isc.org>
Mon, 27 Jan 2020 12:55:17 +0000 (13:55 +0100)
There are now new handlers for the maintained and partner-maintained state.

src/hooks/dhcp/high_availability/ha_service.cc
src/hooks/dhcp/high_availability/tests/ha_service_unittest.cc

index 3a1d64fc1267ecca2d33cbd32efb0c122ab58611..d02ccdfc25872b3fec1ee1725c3c900b88a5f6f4 100644 (file)
@@ -203,6 +203,24 @@ HAService::normalStateHandler() {
 
 void
 HAService::maintainedStateHandler() {
+    // If we are transitioning from another state, we have to define new
+    // serving scopes appropriate for the new state. We don't do it if
+    // we remain in this state.
+    if (doOnEntry()) {
+        // In this state the server remains silent and waits for being
+        // shutdown.
+        query_filter_.serveNoScopes();
+        adjustNetworkState();
+
+        // Log if the state machine is paused.
+        conditionalLogPausedState();
+    }
+
+    scheduleHeartbeat();
+
+    // We don't transition out of this state unless explicitly mandated
+    // by the administrator via a dedicated command which cancels
+    // the maintenance.
     postNextEvent(NOP_EVT);
 }
 
@@ -265,7 +283,46 @@ HAService::partnerDownStateHandler() {
 
 void
 HAService::partnerMaintainedStateHandler() {
-    postNextEvent(NOP_EVT);
+    // If we are transitioning from another state, we have to define new
+    // serving scopes appropriate for the new state. We don't do it if
+    // we remain in this state.
+    if (doOnEntry()) {
+        // It may be administratively disabled to handle partner's scope
+        // in case of failure. If this is the case we'll just handle our
+        // default scope (or no scope at all). The user will need to
+        // manually enable this server to handle partner's scope.
+        if (config_->getThisServerConfig()->isAutoFailover()) {
+            query_filter_.serveFailoverScopes();
+        } else {
+            query_filter_.serveDefaultScopes();
+        }
+        adjustNetworkState();
+
+        // Log if the state machine is paused.
+        conditionalLogPausedState();
+    }
+
+    scheduleHeartbeat();
+
+    if (isModelPaused()) {
+        postNextEvent(NOP_EVT);
+        return;
+    }
+
+    // Check if the clock skew is still acceptable. If not, transition to
+    // the terminated state.
+    if (shouldTerminate()) {
+        verboseTransition(HA_TERMINATED_ST);
+        return;
+    }
+
+    switch (communication_state_->getPartnerState()) {
+    case HA_UNAVAILABLE_ST:
+        verboseTransition(HA_PARTNER_DOWN_ST);
+
+    default:
+        postNextEvent(NOP_EVT);
+    }
 }
 
 void
@@ -645,6 +702,7 @@ HAService::adjustNetworkState() {
     const bool should_enable = ((getCurrState() == HA_LOAD_BALANCING_ST) ||
                                 (getCurrState() == HA_HOT_STANDBY_ST) ||
                                 (getCurrState() == HA_PARTNER_DOWN_ST) ||
+                                (getCurrState() == HA_PARTNER_MAINTAINED_ST) ||
                                 (getCurrState() == HA_TERMINATED_ST));
 
     if (!should_enable && network_state_->isServiceEnabled()) {
@@ -928,6 +986,7 @@ HAService::shouldSendLeaseUpdates(const HAConfig::PeerConfigPtr& peer_config) co
     switch (getCurrState()) {
     case HA_HOT_STANDBY_ST:
     case HA_LOAD_BALANCING_ST:
+    case HA_PARTNER_MAINTAINED_ST:
         return (true);
 
     default:
index 6b67daa019806a80b5b347e6837cd056ab0be934..18c51441ed51afc4bec2fda9f3c0ea4e2e5db5fc 100644 (file)
@@ -4045,10 +4045,12 @@ TEST_F(HAServiceStateMachineTest, scopesServingLoadBalancing) {
     expectScopes(MyState(HA_LOAD_BALANCING_ST), { "server1" }, true);
     expectScopes(MyState(HA_TERMINATED_ST), { "server1" }, true);
 
-    // PARTNER DOWN: serving both scopes.
+    // PARTNER DOWN and PARTNER MAINTAINED: serving both scopes.
     expectScopes(MyState(HA_PARTNER_DOWN_ST), { "server1", "server2" }, true);
+    expectScopes(MyState(HA_PARTNER_MAINTAINED_ST), { "server1", "server2" }, true);
 
-    // READY & WAITING: serving no scopes.
+    // MAINTAINED, READY & WAITING: serving no scopes.
+    expectScopes(MyState(HA_MAINTAINED_ST), { }, false);
     expectScopes(MyState(HA_READY_ST), { }, false);
     expectScopes(MyState(HA_WAITING_ST), { }, false);
 }
@@ -4064,11 +4066,13 @@ TEST_F(HAServiceStateMachineTest, scopesServingLoadBalancingNoFailover) {
     expectScopes(MyState(HA_LOAD_BALANCING_ST), { "server1" }, true);
     expectScopes(MyState(HA_TERMINATED_ST), { "server1" }, true);
 
-    // PARTNER DOWN: still serving my own scope because auto-failover
-    // is disabled.
+    // PARTNER MAINTAINED & PARTNER DOWN: still serving my own scope
+    // because auto-failover is disabled.
     expectScopes(MyState(HA_PARTNER_DOWN_ST), { "server1" }, true);
+    expectScopes(MyState(HA_PARTNER_MAINTAINED_ST), { "server1" }, true);
 
-    // READY & WAITING: serving no scopes.
+    // MAINTAINED, READY & WAITING: serving no scopes.
+    expectScopes(MyState(HA_MAINTAINED_ST), { }, false);
     expectScopes(MyState(HA_READY_ST), { }, false);
     expectScopes(MyState(HA_WAITING_ST), { }, false);
 }
@@ -4082,7 +4086,9 @@ TEST_F(HAServiceStateMachineTest, shouldSendLeaseUpdatesLoadBalancing) {
     HAConfig::PeerConfigPtr peer_config = valid_config->getFailoverPeerConfig();
 
     EXPECT_TRUE(expectLeaseUpdates(MyState(HA_LOAD_BALANCING_ST), peer_config));
+    EXPECT_FALSE(expectLeaseUpdates(MyState(HA_MAINTAINED_ST), peer_config));
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_PARTNER_DOWN_ST), peer_config));
+    EXPECT_TRUE(expectLeaseUpdates(MyState(HA_PARTNER_MAINTAINED_ST), peer_config));
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_READY_ST), peer_config));
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_SYNCING_ST), peer_config));
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_TERMINATED_ST), peer_config));
@@ -4100,7 +4106,9 @@ TEST_F(HAServiceStateMachineTest, shouldSendLeaseUpdatesDisabledLoadBalancing) {
     HAConfig::PeerConfigPtr peer_config = valid_config->getFailoverPeerConfig();
 
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_LOAD_BALANCING_ST), peer_config));
+    EXPECT_FALSE(expectLeaseUpdates(MyState(HA_MAINTAINED_ST), peer_config));
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_PARTNER_DOWN_ST), peer_config));
+    EXPECT_FALSE(expectLeaseUpdates(MyState(HA_PARTNER_MAINTAINED_ST), peer_config));
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_READY_ST), peer_config));
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_SYNCING_ST), peer_config));
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_TERMINATED_ST), peer_config));
@@ -4114,7 +4122,9 @@ TEST_F(HAServiceStateMachineTest, heartbeatLoadBalancing) {
     startService(valid_config);
 
     EXPECT_TRUE(expectHeartbeat(MyState(HA_LOAD_BALANCING_ST)));
+    EXPECT_TRUE(expectHeartbeat(MyState(HA_MAINTAINED_ST)));
     EXPECT_TRUE(expectHeartbeat(MyState(HA_PARTNER_DOWN_ST)));
+    EXPECT_TRUE(expectHeartbeat(MyState(HA_PARTNER_MAINTAINED_ST)));
     EXPECT_TRUE(expectHeartbeat(MyState(HA_READY_ST)));
     EXPECT_FALSE(expectHeartbeat(MyState(HA_TERMINATED_ST)));
     EXPECT_TRUE(expectHeartbeat(MyState(HA_WAITING_ST)));
@@ -4519,10 +4529,12 @@ TEST_F(HAServiceStateMachineTest, scopesServingHotStandbyPrimary) {
     expectScopes(MyState(HA_HOT_STANDBY_ST), { "server1" }, true);
     expectScopes(MyState(HA_TERMINATED_ST), { "server1" }, true);
 
-    // PARTNER DOWN: still serving my own scope.
+    // PARTNER DOWN and PARTNER MAINTAINED: still serving my own scope.
     expectScopes(MyState(HA_PARTNER_DOWN_ST), { "server1" }, true);
+    expectScopes(MyState(HA_PARTNER_MAINTAINED_ST), { "server1" }, true);
 
-    // READY & WAITING: serving no scopes.
+    // MAINTAINED, READY & WAITING: serving no scopes.
+    expectScopes(MyState(HA_MAINTAINED_ST), { }, false);
     expectScopes(MyState(HA_READY_ST), { }, false);
     expectScopes(MyState(HA_WAITING_ST), { }, false);
 }
@@ -4544,10 +4556,12 @@ TEST_F(HAServiceStateMachineTest, scopesServingHotStandbyPrimaryNoFailover) {
     expectScopes(MyState(HA_HOT_STANDBY_ST), { "server1" }, true);
     expectScopes(MyState(HA_TERMINATED_ST), { "server1" }, true);
 
-    // PARTNER DOWN: still serving my own scope.
+    // PARTNER MAINTAINED & PARTNER DOWN: still serving my own scope.
     expectScopes(MyState(HA_PARTNER_DOWN_ST), { "server1" }, true);
+    expectScopes(MyState(HA_PARTNER_MAINTAINED_ST), { "server1" }, true);
 
-    // READY & WAITING: serving no scopes.
+    // MAINTAINED, READY & WAITING: serving no scopes.
+    expectScopes(MyState(HA_MAINTAINED_ST), { }, false);
     expectScopes(MyState(HA_READY_ST), { }, false);
     expectScopes(MyState(HA_WAITING_ST), { }, false);
 }
@@ -4567,7 +4581,9 @@ TEST_F(HAServiceStateMachineTest, shouldSendLeaseUpdatesHotStandbyPrimary) {
     HAConfig::PeerConfigPtr peer_config = valid_config->getFailoverPeerConfig();
 
     EXPECT_TRUE(expectLeaseUpdates(MyState(HA_HOT_STANDBY_ST), peer_config));
+    EXPECT_FALSE(expectLeaseUpdates(MyState(HA_MAINTAINED_ST), peer_config));
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_PARTNER_DOWN_ST), peer_config));
+    EXPECT_TRUE(expectLeaseUpdates(MyState(HA_PARTNER_MAINTAINED_ST), peer_config));
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_READY_ST), peer_config));
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_SYNCING_ST), peer_config));
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_TERMINATED_ST), peer_config));
@@ -4576,7 +4592,7 @@ TEST_F(HAServiceStateMachineTest, shouldSendLeaseUpdatesHotStandbyPrimary) {
 
 // This test verifies if the server would send heartbeat to the partner
 // while being in various states. The HA configuration is hot standby.
-TEST_F(HAServiceStateMachineTest, heartbeatHotstandby) {
+TEST_F(HAServiceStateMachineTest, heartbeatHotStandby) {
     HAConfigPtr valid_config = createValidConfiguration();
 
     // Turn it into hot-standby configuration.
@@ -4586,7 +4602,9 @@ TEST_F(HAServiceStateMachineTest, heartbeatHotstandby) {
     startService(valid_config);
 
     EXPECT_TRUE(expectHeartbeat(MyState(HA_HOT_STANDBY_ST)));
+    EXPECT_TRUE(expectHeartbeat(MyState(HA_MAINTAINED_ST)));
     EXPECT_TRUE(expectHeartbeat(MyState(HA_PARTNER_DOWN_ST)));
+    EXPECT_TRUE(expectHeartbeat(MyState(HA_PARTNER_MAINTAINED_ST)));
     EXPECT_TRUE(expectHeartbeat(MyState(HA_READY_ST)));
     EXPECT_FALSE(expectHeartbeat(MyState(HA_TERMINATED_ST)));
     EXPECT_TRUE(expectHeartbeat(MyState(HA_WAITING_ST)));
@@ -4613,10 +4631,12 @@ TEST_F(HAServiceStateMachineTest, scopesServingHotStandbyStandby) {
     // TERMINATED: serving no scopes because the primary is active.
     expectScopes(MyState(HA_TERMINATED_ST), { }, true);
 
-    // PARTNER DOWN: serving server1's scope.
+    // PARTNER MAINTAINED & PARTNER DOWN: serving server1's scope.
     expectScopes(MyState(HA_PARTNER_DOWN_ST), { "server1" }, true);
+    expectScopes(MyState(HA_PARTNER_MAINTAINED_ST), { "server1" }, true);
 
-    // READY & WAITING: serving no scopes.
+    // MAINTAINED, READY & WAITING: serving no scopes.
+    expectScopes(MyState(HA_MAINTAINED_ST), { }, false);
     expectScopes(MyState(HA_READY_ST), { }, false);
     expectScopes(MyState(HA_WAITING_ST), { }, false);
 }
@@ -4644,11 +4664,13 @@ TEST_F(HAServiceStateMachineTest, scopesServingHotStandbyStandbyNoFailover) {
     // TERMINATED: serving no scopes because the primary is active.
     expectScopes(MyState(HA_TERMINATED_ST), { }, true);
 
-    // PARTNER DOWN: still serving no scopes because auto-failover is
+    // PARTNER MAINTAINED & PARTNER DOWN: still serving no scopes because auto-failover is
     // set to false.
     expectScopes(MyState(HA_PARTNER_DOWN_ST), { }, true);
+    expectScopes(MyState(HA_PARTNER_MAINTAINED_ST), { }, true);
 
-    // READY & WAITING: serving no scopes.
+    // MAINTAINED, READY & WAITING: serving no scopes.
+    expectScopes(MyState(HA_MAINTAINED_ST), { }, false);
     expectScopes(MyState(HA_READY_ST), { }, false);
     expectScopes(MyState(HA_WAITING_ST), { }, false);
 }
@@ -4669,7 +4691,9 @@ TEST_F(HAServiceStateMachineTest, shouldSendLeaseUpdatesHotStandbyStandby) {
     HAConfig::PeerConfigPtr peer_config = valid_config->getFailoverPeerConfig();
 
     EXPECT_TRUE(expectLeaseUpdates(MyState(HA_HOT_STANDBY_ST), peer_config));
+    EXPECT_FALSE(expectLeaseUpdates(MyState(HA_MAINTAINED_ST), peer_config));
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_PARTNER_DOWN_ST), peer_config));
+    EXPECT_TRUE(expectLeaseUpdates(MyState(HA_PARTNER_MAINTAINED_ST), peer_config));
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_READY_ST), peer_config));
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_SYNCING_ST), peer_config));
     EXPECT_FALSE(expectLeaseUpdates(MyState(HA_TERMINATED_ST), peer_config));