diff --git a/hadoop-yarn-project/CHANGES.txt b/hadoop-yarn-project/CHANGES.txt index fa0ba447dc..9b642047a9 100644 --- a/hadoop-yarn-project/CHANGES.txt +++ b/hadoop-yarn-project/CHANGES.txt @@ -1428,6 +1428,9 @@ Release 2.8.0 - UNRELEASED YARN-4667. RM Admin CLI for refreshNodesResources throws NPE when nothing is configured. (Naganarasimha G R via devaraj) + YARN-4654. Yarn node label CLI should parse "=" correctly when trying to + remove all labels on a node. (Naganarasimha G R via rohithsharmaks) + Release 2.7.3 - UNRELEASED INCOMPATIBLE CHANGES diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/RMAdminCLI.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/RMAdminCLI.java index 5c3b1d8b8f..d407c206f5 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/RMAdminCLI.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/RMAdminCLI.java @@ -59,8 +59,8 @@ import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshAdminAclsRequest; import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshClusterMaxPriorityRequest; import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshNodesRequest; -import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshQueuesRequest; import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshNodesResourcesRequest; +import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshQueuesRequest; import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshServiceAclsRequest; import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshSuperUserGroupsConfigurationRequest; import org.apache.hadoop.yarn.server.api.protocolrecords.RefreshUserToGroupsMappingsRequest; @@ -592,26 +592,29 @@ private Map> buildNodeLabelsMapFromStr(String args) { continue; } - // "," also supported for compatibility String[] splits = nodeToLabels.split("="); - int index = 0; - if (splits.length != 2) { + int labelsStartIndex = 0; + String nodeIdStr = splits[0]; + + if (splits.length == 2) { + splits = splits[1].split(","); + } else if (nodeToLabels.endsWith("=")) { + //case where no labels are mapped to a node + splits = new String[0]; + } else { + // "," also supported for compatibility splits = nodeToLabels.split(","); - index = 1; + nodeIdStr = splits[0]; + labelsStartIndex = 1; } - String nodeIdStr = splits[0]; - if (index == 0) { - splits = splits[1].split(","); - } - Preconditions.checkArgument(!nodeIdStr.trim().isEmpty(), "node name cannot be empty"); NodeId nodeId = ConverterUtils.toNodeIdWithDefaultPort(nodeIdStr); map.put(nodeId, new HashSet()); - for (int i = index; i < splits.length; i++) { + for (int i = labelsStartIndex; i < splits.length; i++) { if (!splits[i].trim().isEmpty()) { map.get(nodeId).add(splits[i].trim()); } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/cli/TestRMAdminCLI.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/cli/TestRMAdminCLI.java index 08e63eaf92..057594d5bb 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/cli/TestRMAdminCLI.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/test/java/org/apache/hadoop/yarn/client/cli/TestRMAdminCLI.java @@ -36,7 +36,9 @@ import java.io.IOException; import java.io.PrintStream; import java.util.HashSet; +import java.util.Iterator; import java.util.Map; +import java.util.Set; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.ha.HAServiceProtocol; @@ -145,7 +147,20 @@ protected HAServiceTarget resolveTarget(String rmId) { private void initDummyNodeLabelsManager() { Configuration conf = new YarnConfiguration(); conf.setBoolean(YarnConfiguration.NODE_LABELS_ENABLED, true); - dummyNodeLabelsManager = new DummyCommonNodeLabelsManager(); + dummyNodeLabelsManager = new DummyCommonNodeLabelsManager() { + @Override + public void replaceLabelsOnNode( + Map> replaceLabelsToNode) throws IOException { + Iterator iterator = replaceLabelsToNode.keySet().iterator(); + while(iterator.hasNext()) { + NodeId nodeId=iterator.next(); + if(nodeId.getHost().endsWith("=")){ + throw new IOException("Parsing of Input String failed"); + } + } + super.replaceLabelsOnNode(replaceLabelsToNode); + } + }; dummyNodeLabelsManager.init(conf); } @@ -712,6 +727,21 @@ public void testReplaceMultipleLabelsOnSingleNode() throws Exception { assertTrue(0 != rmAdminCLI.run(args)); } + @Test + public void testRemoveLabelsOnNodes() throws Exception { + // Successfully replace labels + dummyNodeLabelsManager + .addToCluserNodeLabelsWithDefaultExclusivity(ImmutableSet.of("x", "y")); + String[] args = { "-replaceLabelsOnNode", "node1=x node2=y", + "-directlyAccessNodeLabelStore" }; + assertTrue(0 == rmAdminCLI.run(args)); + + args = new String[] { "-replaceLabelsOnNode", "node1= node2=", + "-directlyAccessNodeLabelStore" }; + assertTrue("Labels should get replaced even '=' is used ", + 0 == rmAdminCLI.run(args)); + } + private void testError(String[] args, String template, ByteArrayOutputStream data, int resultCode) throws Exception { int actualResultCode = rmAdminCLI.run(args);