From befd64e0689b54d0c17b6fb88732e9fcce788c3f Mon Sep 17 00:00:00 2001 From: Nandakumar Vadivelu Date: Tue, 10 Dec 2024 02:38:16 +0530 Subject: [PATCH] HDDS-11694. Safemode Improvement: Introduce factory class to create safemode rules. (#7433) --- .../scm/safemode/ContainerSafeModeRule.java | 6 + .../hdds/scm/safemode/SCMSafeModeManager.java | 40 ++---- .../scm/safemode/SafeModeRuleFactory.java | 131 ++++++++++++++++++ .../scm/pipeline/TestPipelineManagerImpl.java | 5 +- .../TestHealthyPipelineSafeModeRule.java | 15 +- .../TestOneReplicaPipelineSafeModeRule.java | 8 +- .../scm/safemode/TestSCMSafeModeManager.java | 47 +++++-- .../scm/safemode/TestSafeModeRuleFactory.java | 85 ++++++++++++ 8 files changed, 290 insertions(+), 47 deletions(-) create mode 100644 hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/safemode/SafeModeRuleFactory.java create mode 100644 hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/safemode/TestSafeModeRuleFactory.java diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/safemode/ContainerSafeModeRule.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/safemode/ContainerSafeModeRule.java index accd805602e..bdd7160de4c 100644 --- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/safemode/ContainerSafeModeRule.java +++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/safemode/ContainerSafeModeRule.java @@ -68,6 +68,12 @@ public class ContainerSafeModeRule extends private AtomicLong ecContainerWithMinReplicas = new AtomicLong(0); private final ContainerManager containerManager; + public ContainerSafeModeRule(String ruleName, EventQueue eventQueue, + ConfigurationSource conf, + ContainerManager containerManager, SCMSafeModeManager manager) { + this(ruleName, eventQueue, conf, containerManager.getContainers(), containerManager, manager); + } + public ContainerSafeModeRule(String ruleName, EventQueue eventQueue, ConfigurationSource conf, List containers, diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/safemode/SCMSafeModeManager.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/safemode/SCMSafeModeManager.java index 39530de16b6..78ce994af73 100644 --- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/safemode/SCMSafeModeManager.java +++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/safemode/SCMSafeModeManager.java @@ -23,6 +23,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; import org.apache.commons.lang3.tuple.Pair; import org.apache.hadoop.hdds.HddsConfigKeys; @@ -90,7 +91,7 @@ public class SCMSafeModeManager implements SafeModeManager { private AtomicBoolean preCheckComplete = new AtomicBoolean(false); private AtomicBoolean forceExitSafeMode = new AtomicBoolean(false); - private Map exitRules = new HashMap(1); + private Map exitRules = new HashMap<>(1); private Set preCheckRules = new HashSet<>(1); private ConfigurationSource config; private static final String CONT_EXIT_RULE = "ContainerSafeModeRule"; @@ -110,6 +111,8 @@ public class SCMSafeModeManager implements SafeModeManager { private final SafeModeMetrics safeModeMetrics; + + // TODO: Remove allContainers argument. (HDDS-11795) public SCMSafeModeManager(ConfigurationSource conf, List allContainers, ContainerManager containerManager, PipelineManager pipelineManager, @@ -126,30 +129,17 @@ public SCMSafeModeManager(ConfigurationSource conf, if (isSafeModeEnabled) { this.safeModeMetrics = SafeModeMetrics.create(); - ContainerSafeModeRule containerSafeModeRule = - new ContainerSafeModeRule(CONT_EXIT_RULE, eventQueue, config, - allContainers, containerManager, this); - DataNodeSafeModeRule dataNodeSafeModeRule = - new DataNodeSafeModeRule(DN_EXIT_RULE, eventQueue, config, this); - exitRules.put(CONT_EXIT_RULE, containerSafeModeRule); - exitRules.put(DN_EXIT_RULE, dataNodeSafeModeRule); - preCheckRules.add(DN_EXIT_RULE); - if (conf.getBoolean( - HddsConfigKeys.HDDS_SCM_SAFEMODE_PIPELINE_AVAILABILITY_CHECK, - HddsConfigKeys.HDDS_SCM_SAFEMODE_PIPELINE_AVAILABILITY_CHECK_DEFAULT) - && pipelineManager != null) { - HealthyPipelineSafeModeRule healthyPipelineSafeModeRule = - new HealthyPipelineSafeModeRule(HEALTHY_PIPELINE_EXIT_RULE, - eventQueue, pipelineManager, - this, config, scmContext); - OneReplicaPipelineSafeModeRule oneReplicaPipelineSafeModeRule = - new OneReplicaPipelineSafeModeRule( - ATLEAST_ONE_DATANODE_REPORTED_PIPELINE_EXIT_RULE, eventQueue, - pipelineManager, this, conf); - exitRules.put(HEALTHY_PIPELINE_EXIT_RULE, healthyPipelineSafeModeRule); - exitRules.put(ATLEAST_ONE_DATANODE_REPORTED_PIPELINE_EXIT_RULE, - oneReplicaPipelineSafeModeRule); - } + + // TODO: Remove the cyclic ("this") dependency (HDDS-11797) + SafeModeRuleFactory.initialize(config, scmContext, eventQueue, + this, pipelineManager, containerManager); + SafeModeRuleFactory factory = SafeModeRuleFactory.getInstance(); + + exitRules = factory.getSafeModeRules().stream().collect( + Collectors.toMap(SafeModeExitRule::getRuleName, rule -> rule)); + + preCheckRules = factory.getPreCheckRules().stream() + .map(SafeModeExitRule::getRuleName).collect(Collectors.toSet()); } else { this.safeModeMetrics = null; exitSafeMode(eventQueue, true); diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/safemode/SafeModeRuleFactory.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/safemode/SafeModeRuleFactory.java new file mode 100644 index 00000000000..8e75f51b962 --- /dev/null +++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/safemode/SafeModeRuleFactory.java @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements.  See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership.  The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License.  You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hdds.scm.safemode; + + +import org.apache.hadoop.hdds.HddsConfigKeys; +import org.apache.hadoop.hdds.conf.ConfigurationSource; +import org.apache.hadoop.hdds.scm.container.ContainerManager; +import org.apache.hadoop.hdds.scm.ha.SCMContext; +import org.apache.hadoop.hdds.scm.pipeline.PipelineManager; +import org.apache.hadoop.hdds.server.events.EventQueue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * Factory to create SafeMode rules. + */ +public final class SafeModeRuleFactory { + + + private static final Logger LOG = LoggerFactory.getLogger(SafeModeRuleFactory.class); + + // TODO: Move the rule names to respective rules. (HDDS-11798) + private static final String CONT_EXIT_RULE = "ContainerSafeModeRule"; + private static final String DN_EXIT_RULE = "DataNodeSafeModeRule"; + private static final String HEALTHY_PIPELINE_EXIT_RULE = + "HealthyPipelineSafeModeRule"; + private static final String ATLEAST_ONE_DATANODE_REPORTED_PIPELINE_EXIT_RULE = + "AtleastOneDatanodeReportedRule"; + + private final ConfigurationSource config; + private final SCMContext scmContext; + private final EventQueue eventQueue; + + // TODO: Remove dependency on safeModeManager (HDDS-11797) + private final SCMSafeModeManager safeModeManager; + private final PipelineManager pipelineManager; + private final ContainerManager containerManager; + + private final List> safeModeRules; + private final List> preCheckRules; + + private static SafeModeRuleFactory instance; + + private SafeModeRuleFactory(final ConfigurationSource config, + final SCMContext scmContext, + final EventQueue eventQueue, + final SCMSafeModeManager safeModeManager, + final PipelineManager pipelineManager, + final ContainerManager containerManager) { + this.config = config; + this.scmContext = scmContext; + this.eventQueue = eventQueue; + this.safeModeManager = safeModeManager; + this.pipelineManager = pipelineManager; + this.containerManager = containerManager; + this.safeModeRules = new ArrayList<>(); + this.preCheckRules = new ArrayList<>(); + loadRules(); + } + + private void loadRules() { + // TODO: Use annotation to load the rules. (HDDS-11730) + safeModeRules.add(new ContainerSafeModeRule(CONT_EXIT_RULE, eventQueue, config, + containerManager, safeModeManager)); + SafeModeExitRule dnRule = new DataNodeSafeModeRule(DN_EXIT_RULE, eventQueue, config, safeModeManager); + safeModeRules.add(dnRule); + preCheckRules.add(dnRule); + + // TODO: Move isRuleEnabled check to the Rule implementation. (HDDS-11799) + if (config.getBoolean( + HddsConfigKeys.HDDS_SCM_SAFEMODE_PIPELINE_AVAILABILITY_CHECK, + HddsConfigKeys.HDDS_SCM_SAFEMODE_PIPELINE_AVAILABILITY_CHECK_DEFAULT) + && pipelineManager != null) { + + safeModeRules.add(new HealthyPipelineSafeModeRule(HEALTHY_PIPELINE_EXIT_RULE, + eventQueue, pipelineManager, safeModeManager, config, scmContext)); + safeModeRules.add(new OneReplicaPipelineSafeModeRule( + ATLEAST_ONE_DATANODE_REPORTED_PIPELINE_EXIT_RULE, eventQueue, + pipelineManager, safeModeManager, config)); + } + + } + + public static synchronized SafeModeRuleFactory getInstance() { + if (instance != null) { + return instance; + } + throw new IllegalStateException("SafeModeRuleFactory not initialized," + + " call initialize method before getInstance."); + } + + // TODO: Refactor and reduce the arguments. (HDDS-11800) + public static synchronized void initialize( + final ConfigurationSource config, + final SCMContext scmContext, + final EventQueue eventQueue, + final SCMSafeModeManager safeModeManager, + final PipelineManager pipelineManager, + final ContainerManager containerManager) { + instance = new SafeModeRuleFactory(config, scmContext, eventQueue, + safeModeManager, pipelineManager, containerManager); + } + + public List> getSafeModeRules() { + return safeModeRules; + } + + public List> getPreCheckRules() { + return preCheckRules; + } +} diff --git a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelineManagerImpl.java b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelineManagerImpl.java index dd994f35b64..1dfbfd32785 100644 --- a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelineManagerImpl.java +++ b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelineManagerImpl.java @@ -358,7 +358,8 @@ public void testClosePipelineShouldFailOnFollower() throws Exception { public void testPipelineReport() throws Exception { try (PipelineManagerImpl pipelineManager = createPipelineManager(true)) { SCMSafeModeManager scmSafeModeManager = - new SCMSafeModeManager(conf, new ArrayList<>(), null, pipelineManager, + new SCMSafeModeManager(conf, new ArrayList<>(), + mock(ContainerManager.class), pipelineManager, new EventQueue(), serviceManager, scmContext); Pipeline pipeline = pipelineManager .createPipeline(RatisReplicationConfig @@ -469,7 +470,7 @@ public void testPipelineOpenOnlyWhenLeaderReported() throws Exception { SCMSafeModeManager scmSafeModeManager = new SCMSafeModeManager(new OzoneConfiguration(), new ArrayList<>(), - null, pipelineManager, new EventQueue(), + mock(ContainerManager.class), pipelineManager, new EventQueue(), serviceManager, scmContext); PipelineReportHandler pipelineReportHandler = new PipelineReportHandler(scmSafeModeManager, pipelineManager, diff --git a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/safemode/TestHealthyPipelineSafeModeRule.java b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/safemode/TestHealthyPipelineSafeModeRule.java index 98f16394902..13eb4be724c 100644 --- a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/safemode/TestHealthyPipelineSafeModeRule.java +++ b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/safemode/TestHealthyPipelineSafeModeRule.java @@ -31,6 +31,7 @@ import org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationFactor; import org.apache.hadoop.hdds.scm.HddsTestUtils; import org.apache.hadoop.hdds.scm.container.ContainerInfo; +import org.apache.hadoop.hdds.scm.container.ContainerManager; import org.apache.hadoop.hdds.scm.container.MockNodeManager; import org.apache.hadoop.hdds.scm.events.SCMEvents; import org.apache.hadoop.hdds.scm.ha.SCMHAManagerStub; @@ -50,6 +51,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; /** * This class tests HealthyPipelineSafeMode rule. @@ -69,6 +72,8 @@ public void testHealthyPipelineSafeModeRuleWithNoPipelines() OzoneConfiguration config = new OzoneConfiguration(); MockNodeManager nodeManager = new MockNodeManager(true, 0); + ContainerManager containerManager = mock(ContainerManager.class); + when(containerManager.getContainers()).thenReturn(containers); config.set(HddsConfigKeys.OZONE_METADATA_DIRS, tempFile.getPath()); // enable pipeline check config.setBoolean( @@ -94,7 +99,7 @@ public void testHealthyPipelineSafeModeRuleWithNoPipelines() pipelineManager.setPipelineProvider(HddsProtos.ReplicationType.RATIS, mockRatisProvider); SCMSafeModeManager scmSafeModeManager = new SCMSafeModeManager( - config, containers, null, pipelineManager, eventQueue, + config, containers, containerManager, pipelineManager, eventQueue, serviceManager, scmContext); HealthyPipelineSafeModeRule healthyPipelineSafeModeRule = @@ -121,6 +126,8 @@ public void testHealthyPipelineSafeModeRuleWithPipelines() throws Exception { // stale and last one is dead, and this repeats. So for a 12 node, 9 // healthy, 2 stale and one dead. MockNodeManager nodeManager = new MockNodeManager(true, 12); + ContainerManager containerManager = mock(ContainerManager.class); + when(containerManager.getContainers()).thenReturn(containers); config.set(HddsConfigKeys.OZONE_METADATA_DIRS, tempFile.getPath()); // enable pipeline check config.setBoolean( @@ -172,7 +179,7 @@ public void testHealthyPipelineSafeModeRuleWithPipelines() throws Exception { MockRatisPipelineProvider.markPipelineHealthy(pipeline3); SCMSafeModeManager scmSafeModeManager = new SCMSafeModeManager( - config, containers, null, pipelineManager, eventQueue, + config, containers, containerManager, pipelineManager, eventQueue, serviceManager, scmContext); HealthyPipelineSafeModeRule healthyPipelineSafeModeRule = @@ -215,6 +222,8 @@ public void testHealthyPipelineSafeModeRuleWithMixedPipelines() // stale and last one is dead, and this repeats. So for a 12 node, 9 // healthy, 2 stale and one dead. MockNodeManager nodeManager = new MockNodeManager(true, 12); + ContainerManager containerManager = mock(ContainerManager.class); + when(containerManager.getContainers()).thenReturn(containers); config.set(HddsConfigKeys.OZONE_METADATA_DIRS, tempFile.getPath()); // enable pipeline check config.setBoolean( @@ -266,7 +275,7 @@ public void testHealthyPipelineSafeModeRuleWithMixedPipelines() MockRatisPipelineProvider.markPipelineHealthy(pipeline3); SCMSafeModeManager scmSafeModeManager = new SCMSafeModeManager( - config, containers, null, pipelineManager, eventQueue, + config, containers, containerManager, pipelineManager, eventQueue, serviceManager, scmContext); HealthyPipelineSafeModeRule healthyPipelineSafeModeRule = diff --git a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/safemode/TestOneReplicaPipelineSafeModeRule.java b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/safemode/TestOneReplicaPipelineSafeModeRule.java index e070a2b6036..76bafa8b1fb 100644 --- a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/safemode/TestOneReplicaPipelineSafeModeRule.java +++ b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/safemode/TestOneReplicaPipelineSafeModeRule.java @@ -35,6 +35,7 @@ import org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.PipelineReport; import org.apache.hadoop.hdds.scm.HddsTestUtils; import org.apache.hadoop.hdds.scm.container.ContainerInfo; +import org.apache.hadoop.hdds.scm.container.ContainerManager; import org.apache.hadoop.hdds.scm.container.MockNodeManager; import org.apache.hadoop.hdds.scm.events.SCMEvents; import org.apache.hadoop.hdds.scm.ha.SCMHAManagerStub; @@ -58,6 +59,8 @@ import org.slf4j.LoggerFactory; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; /** * This class tests OneReplicaPipelineSafeModeRule. @@ -86,7 +89,8 @@ private void setup(int nodes, int pipelineFactorThreeCount, List containers = new ArrayList<>(); containers.addAll(HddsTestUtils.getContainerInfo(1)); mockNodeManager = new MockNodeManager(true, nodes); - + ContainerManager containerManager = mock(ContainerManager.class); + when(containerManager.getContainers()).thenReturn(containers); eventQueue = new EventQueue(); serviceManager = new SCMServiceManager(); scmContext = SCMContext.emptyContext(); @@ -116,7 +120,7 @@ private void setup(int nodes, int pipelineFactorThreeCount, HddsProtos.ReplicationFactor.ONE); SCMSafeModeManager scmSafeModeManager = - new SCMSafeModeManager(ozoneConfiguration, containers, null, + new SCMSafeModeManager(ozoneConfiguration, containers, containerManager, pipelineManager, eventQueue, serviceManager, scmContext); rule = scmSafeModeManager.getOneReplicaPipelineSafeModeRule(); diff --git a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/safemode/TestSCMSafeModeManager.java b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/safemode/TestSCMSafeModeManager.java index 05e23177659..fc8ec9c1912 100644 --- a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/safemode/TestSCMSafeModeManager.java +++ b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/safemode/TestSCMSafeModeManager.java @@ -81,6 +81,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.params.provider.Arguments.arguments; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; /** Test class for SCMSafeModeManager. */ @@ -123,12 +124,6 @@ public void testSafeModeState(int numContainers) throws Exception { testSafeMode(numContainers); } - @Test - public void testSafeModeStateWithNullContainers() { - new SCMSafeModeManager(config, Collections.emptyList(), - null, null, queue, serviceManager, scmContext); - } - private void testSafeMode(int numContainers) throws Exception { containers = new ArrayList<>(); containers.addAll(HddsTestUtils.getContainerInfo(numContainers)); @@ -138,8 +133,10 @@ private void testSafeMode(int numContainers) throws Exception { container.setState(HddsProtos.LifeCycleState.CLOSED); container.setNumberOfKeys(10); } + ContainerManager containerManager = mock(ContainerManager.class); + when(containerManager.getContainers()).thenReturn(containers); scmSafeModeManager = new SCMSafeModeManager( - config, containers, null, null, queue, + config, containers, containerManager, null, queue, serviceManager, scmContext); assertTrue(scmSafeModeManager.getInSafeMode()); @@ -175,8 +172,10 @@ public void testSafeModeExitRule() throws Exception { container.setState(HddsProtos.LifeCycleState.CLOSED); container.setNumberOfKeys(10); } + ContainerManager containerManager = mock(ContainerManager.class); + when(containerManager.getContainers()).thenReturn(containers); scmSafeModeManager = new SCMSafeModeManager( - config, containers, null, null, queue, + config, containers, containerManager, null, queue, serviceManager, scmContext); long cutOff = (long) Math.ceil(numContainers * config.getDouble( @@ -242,8 +241,11 @@ public void testHealthyPipelinePercentWithIncorrectValue(double healthyPercent, scmContext, serviceManager, Clock.system(ZoneOffset.UTC)); + ContainerManager containerManager = mock(ContainerManager.class); + when(containerManager.getContainers()).thenReturn(containers); IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, - () -> new SCMSafeModeManager(conf, containers, null, pipelineManager, queue, serviceManager, scmContext)); + () -> new SCMSafeModeManager(conf, containers, containerManager, + pipelineManager, queue, serviceManager, scmContext)); assertThat(exception).hasMessageEndingWith("value should be >= 0.0 and <= 1.0"); } @@ -305,8 +307,11 @@ public void testSafeModeExitRuleWithPipelineAvailabilityCheck( container.setState(HddsProtos.LifeCycleState.CLOSED); } + ContainerManager containerManager = mock(ContainerManager.class); + when(containerManager.getContainers()).thenReturn(containers); + scmSafeModeManager = new SCMSafeModeManager( - conf, containers, null, pipelineManager, queue, serviceManager, + conf, containers, containerManager, pipelineManager, queue, serviceManager, scmContext); assertTrue(scmSafeModeManager.getInSafeMode()); @@ -439,8 +444,10 @@ public void testDisableSafeMode() { OzoneConfiguration conf = new OzoneConfiguration(config); conf.setBoolean(HddsConfigKeys.HDDS_SCM_SAFEMODE_ENABLED, false); PipelineManager pipelineManager = mock(PipelineManager.class); + ContainerManager containerManager = mock(ContainerManager.class); + when(containerManager.getContainers()).thenReturn(containers); scmSafeModeManager = new SCMSafeModeManager( - conf, containers, null, pipelineManager, queue, serviceManager, + conf, containers, containerManager, pipelineManager, queue, serviceManager, scmContext); assertFalse(scmSafeModeManager.getInSafeMode()); } @@ -478,8 +485,11 @@ public void testContainerSafeModeRule() throws Exception { container.setNumberOfKeys(0); } + ContainerManager containerManager = mock(ContainerManager.class); + when(containerManager.getContainers()).thenReturn(containers); + scmSafeModeManager = new SCMSafeModeManager( - config, containers, null, null, queue, serviceManager, scmContext); + config, containers, containerManager, null, queue, serviceManager, scmContext); assertTrue(scmSafeModeManager.getInSafeMode()); @@ -575,8 +585,10 @@ public void testContainerSafeModeRuleEC(int data, int parity) throws Exception { private void testSafeModeDataNodes(int numOfDns) throws Exception { OzoneConfiguration conf = new OzoneConfiguration(config); conf.setInt(HddsConfigKeys.HDDS_SCM_SAFEMODE_MIN_DATANODE, numOfDns); + ContainerManager containerManager = mock(ContainerManager.class); + when(containerManager.getContainers()).thenReturn(containers); scmSafeModeManager = new SCMSafeModeManager( - conf, containers, null, null, queue, + conf, containers, containerManager, null, queue, serviceManager, scmContext); // Assert SCM is in Safe mode. @@ -686,9 +698,11 @@ public void testSafeModePipelineExitRule() throws Exception { pipeline = pipelineManager.getPipeline(pipeline.getId()); MockRatisPipelineProvider.markPipelineHealthy(pipeline); + ContainerManager containerManager = mock(ContainerManager.class); + when(containerManager.getContainers()).thenReturn(containers); scmSafeModeManager = new SCMSafeModeManager( - config, containers, null, pipelineManager, queue, serviceManager, + config, containers, containerManager, pipelineManager, queue, serviceManager, scmContext); SCMDatanodeProtocolServer.NodeRegistrationContainerReport nodeRegistrationContainerReport = @@ -739,8 +753,11 @@ public void testPipelinesNotCreatedUntilPreCheckPasses() throws Exception { pipelineManager.setPipelineProvider(HddsProtos.ReplicationType.RATIS, mockRatisProvider); + ContainerManager containerManager = mock(ContainerManager.class); + when(containerManager.getContainers()).thenReturn(containers); + scmSafeModeManager = new SCMSafeModeManager( - config, containers, null, pipelineManager, queue, serviceManager, + config, containers, containerManager, pipelineManager, queue, serviceManager, scmContext); // Assert SCM is in Safe mode. diff --git a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/safemode/TestSafeModeRuleFactory.java b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/safemode/TestSafeModeRuleFactory.java new file mode 100644 index 00000000000..837012429be --- /dev/null +++ b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/safemode/TestSafeModeRuleFactory.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package org.apache.hadoop.hdds.scm.safemode; + +import org.apache.hadoop.hdds.conf.OzoneConfiguration; +import org.apache.hadoop.hdds.scm.container.ContainerManager; +import org.apache.hadoop.hdds.scm.ha.SCMContext; +import org.apache.hadoop.hdds.scm.pipeline.PipelineManager; +import org.apache.hadoop.hdds.server.events.EventQueue; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Field; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class TestSafeModeRuleFactory { + + @Test + public void testIllegalState() { + // If the initialization is already done by different test, we have to reset it. + try { + final Field instance = SafeModeRuleFactory.class.getDeclaredField("instance"); + instance.setAccessible(true); + instance.set(null, null); + } catch (Exception e) { + throw new RuntimeException(); + } + assertThrows(IllegalStateException.class, SafeModeRuleFactory::getInstance); + } + + @Test + public void testLoadedSafeModeRules() { + initializeSafeModeRuleFactory(); + final SafeModeRuleFactory factory = SafeModeRuleFactory.getInstance(); + + // Currently we assert the total count against hardcoded value + // as the rules are hardcoded in SafeModeRuleFactory. + + // This will be fixed once we load rules using annotation. + assertEquals(4, factory.getSafeModeRules().size(), + "The total safemode rules count doesn't match"); + + } + + @Test + public void testLoadedPreCheckRules() { + initializeSafeModeRuleFactory(); + final SafeModeRuleFactory factory = SafeModeRuleFactory.getInstance(); + + // Currently we assert the total count against hardcoded value + // as the rules are hardcoded in SafeModeRuleFactory. + + // This will be fixed once we load rules using annotation. + assertEquals(1, factory.getPreCheckRules().size(), + "The total safemode rules count doesn't match"); + + } + + private void initializeSafeModeRuleFactory() { + final SCMSafeModeManager safeModeManager = mock(SCMSafeModeManager.class); + when(safeModeManager.getSafeModeMetrics()).thenReturn(mock(SafeModeMetrics.class)); + SafeModeRuleFactory.initialize(new OzoneConfiguration(), + SCMContext.emptyContext(), new EventQueue(), safeModeManager, mock( + PipelineManager.class), mock(ContainerManager.class)); + } + +}