Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.io.IOException;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
Expand Down Expand Up @@ -492,6 +493,9 @@ private void validateConfiguration(ContainerBalancerConfiguration conf)
LOG.warn(msg);
throw new InvalidContainerBalancerConfigurationException(msg);
}

validateNodeList(conf.getIncludeNodes(), "included");
validateNodeList(conf.getExcludeNodes(), "excluded");
}

public ContainerBalancerMetrics getMetrics() {
Expand All @@ -510,4 +514,29 @@ public String toString() {
"%-30s %b%n", "Key", "Value", "Running", isBalancerRunning());
return status + config.toString();
}

/**
* Validates if the provided datanodes are known by SCM.
*
* @param nodes set of datanode hostnames or IP addresses
* @param type context label for the error message
* @throws InvalidContainerBalancerConfigurationException if a node is unknown
*/
private void validateNodeList(Set<String> nodes, String type)
Comment thread
sravani-revuri marked this conversation as resolved.
throws InvalidContainerBalancerConfigurationException {
if (nodes == null || nodes.isEmpty()) {
return;
}

for (String node : nodes) {
// Check if SCM knows about this node by hostname or IP
if (scm.getScmNodeManager().getNodesByAddress(node).isEmpty()) {
String errorMessage = String.format("Invalid configuration: The %s datanode '%s' " +
"does not exist or is not registered with SCM. Please check the hostname/IP.",
type, node);
LOG.warn(errorMessage);
throw new InvalidContainerBalancerConfigurationException(errorMessage);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@

import com.google.protobuf.ByteString;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.scm.ha.SCMContext;
import org.apache.hadoop.hdds.scm.ha.SCMServiceManager;
import org.apache.hadoop.hdds.scm.ha.StatefulServiceStateManager;
Expand Down Expand Up @@ -291,6 +293,41 @@ public void testGetBalancerStatusInfo() throws Exception {
assertSame(ContainerBalancerTask.Status.STOPPED, containerBalancer.getBalancerStatus());
}

@Test
public void testStartBalancerWithInvalidNodes() throws Exception {
NodeManager nm = scm.getScmNodeManager();
String validHost = "1.2.3.4";
String invalidHost = "invalid-host-name";

when(nm.getNodesByAddress(invalidHost)).thenReturn(Collections.emptyList());
when(nm.getNodesByAddress(validHost)).thenReturn(Collections.singletonList(mock(DatanodeDetails.class)));

// Test invalid includeNodes
balancerConfiguration.setIncludeNodes(invalidHost);
InvalidContainerBalancerConfigurationException ex =
assertThrows(InvalidContainerBalancerConfigurationException.class,
() -> containerBalancer.startBalancer(balancerConfiguration));
assertThat(ex.getMessage()).contains(invalidHost);
assertSame(ContainerBalancerTask.Status.STOPPED, containerBalancer.getBalancerStatus());

// Test invalid excludeNodes
balancerConfiguration.setIncludeNodes("");
balancerConfiguration.setExcludeNodes(invalidHost);
ex = assertThrows(InvalidContainerBalancerConfigurationException.class,
() -> containerBalancer.startBalancer(balancerConfiguration));
assertThat(ex.getMessage()).contains(invalidHost);
assertSame(ContainerBalancerTask.Status.STOPPED, containerBalancer.getBalancerStatus());

// Test a valid case
balancerConfiguration.setExcludeNodes("");
balancerConfiguration.setIncludeNodes(validHost);
assertDoesNotThrow(() -> startBalancer(balancerConfiguration));
assertSame(ContainerBalancerTask.Status.RUNNING, containerBalancer.getBalancerStatus());

stopBalancer();
assertSame(ContainerBalancerTask.Status.STOPPED, containerBalancer.getBalancerStatus());
}

private void startBalancer(ContainerBalancerConfiguration config)
throws IllegalContainerBalancerStateException, IOException,
InvalidContainerBalancerConfigurationException, TimeoutException {
Expand Down