From 7f19e7a2549a098236d06b29b7076bb037533f05 Mon Sep 17 00:00:00 2001 From: Wangda Tan Date: Wed, 13 May 2015 13:43:17 -0700 Subject: [PATCH] YARN-3521. Support return structured NodeLabel objects in REST API (Sunil G via wangda) --- hadoop-yarn-project/CHANGES.txt | 8 +- .../resourcemanager/webapp/NodeIDsInfo.java | 2 + .../resourcemanager/webapp/RMWebServices.java | 71 +++--- .../webapp/dao/LabelsToNodesInfo.java | 6 +- .../webapp/dao/NodeLabelInfo.java | 86 +++++++ .../webapp/dao/NodeLabelsInfo.java | 56 ++++- .../webapp/dao/NodeToLabelsEntry.java | 54 +++++ .../webapp/dao/NodeToLabelsEntryList.java | 41 ++++ .../webapp/dao/NodeToLabelsInfo.java | 14 +- .../webapp/TestRMWebServicesNodeLabels.java | 225 ++++++++++++------ 10 files changed, 428 insertions(+), 135 deletions(-) create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeLabelInfo.java create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeToLabelsEntry.java create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeToLabelsEntryList.java diff --git a/hadoop-yarn-project/CHANGES.txt b/hadoop-yarn-project/CHANGES.txt index 16c2dd9e940..38f5e81b98f 100644 --- a/hadoop-yarn-project/CHANGES.txt +++ b/hadoop-yarn-project/CHANGES.txt @@ -233,6 +233,11 @@ Release 2.8.0 - UNRELEASED YARN-3613. TestContainerManagerSecurity should init and start Yarn cluster in setup instead of individual methods. (nijel via kasha) + YARN-3579. CommonNodeLabelsManager should support NodeLabel instead of string + label name when getting node-to-label/label-to-label mappings. (Sunil G via wangda) + + YARN-3521. Support return structured NodeLabel objects in REST API (Sunil G via wangda) + OPTIMIZATIONS YARN-3339. TestDockerContainerExecutor should pull a single image and not @@ -420,9 +425,6 @@ Release 2.7.1 - UNRELEASED YARN-3539. Updated timeline server documentation and marked REST APIs evolving. (Steve Loughran via zjshen) - YARN-3579. CommonNodeLabelsManager should support NodeLabel instead of string - label name when getting node-to-label/label-to-label mappings. (Sunil G via wangda) - OPTIMIZATIONS BUG FIXES diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/NodeIDsInfo.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/NodeIDsInfo.java index 39d636d1613..c23b02ac07a 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/NodeIDsInfo.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/NodeIDsInfo.java @@ -23,6 +23,7 @@ import java.util.List; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "labelsToNodesInfo") @@ -32,6 +33,7 @@ public class NodeIDsInfo { /** * Set doesn't support default no arg constructor which is req by JAXB */ + @XmlElement(name="nodes") protected ArrayList nodeIDsList = new ArrayList(); public NodeIDsInfo() { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java index 4ce2b5478ee..a0a31234525 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java @@ -93,6 +93,7 @@ import org.apache.hadoop.yarn.api.records.ContainerLaunchContext; import org.apache.hadoop.yarn.api.records.FinalApplicationStatus; import org.apache.hadoop.yarn.api.records.LocalResource; import org.apache.hadoop.yarn.api.records.NodeId; +import org.apache.hadoop.yarn.api.records.NodeLabel; import org.apache.hadoop.yarn.api.records.NodeState; import org.apache.hadoop.yarn.api.records.Priority; import org.apache.hadoop.yarn.api.records.QueueACL; @@ -135,8 +136,11 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.LabelsToNodesInf import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.LocalResourceInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NewApplication; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntry; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ResourceInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerInfo; @@ -796,18 +800,18 @@ public class RMWebServices { @GET @Path("/get-node-to-labels") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public NodeToLabelsInfo getNodeToLabels(@Context HttpServletRequest hsr) - throws IOException { + public NodeToLabelsInfo getNodeToLabels(@Context HttpServletRequest hsr) + throws IOException { init(); NodeToLabelsInfo ntl = new NodeToLabelsInfo(); HashMap ntlMap = ntl.getNodeToLabels(); - Map> nodeIdToLabels = - rm.getRMContext().getNodeLabelManager().getNodeLabels(); - + Map> nodeIdToLabels = rm.getRMContext() + .getNodeLabelManager().getNodeLabels(); + for (Map.Entry> nitle : nodeIdToLabels.entrySet()) { - ntlMap.put(nitle.getKey().toString(), - new NodeLabelsInfo(nitle.getValue())); + ntlMap.put(nitle.getKey().toString(), + new NodeLabelsInfo(nitle.getValue())); } return ntl; @@ -821,7 +825,7 @@ public class RMWebServices { init(); LabelsToNodesInfo lts = new LabelsToNodesInfo(); - Map ltsMap = lts.getLabelsToNodes(); + Map ltsMap = lts.getLabelsToNodes(); Map> labelsToNodeId = null; if (labels == null || labels.size() == 0) { labelsToNodeId = @@ -836,7 +840,8 @@ public class RMWebServices { for (NodeId nodeId : entry.getValue()) { nodeIdStrList.add(nodeId.toString()); } - ltsMap.put(entry.getKey(), new NodeIDsInfo(nodeIdStrList)); + ltsMap.put(new NodeLabelInfo(entry.getKey()), new NodeIDsInfo( + nodeIdStrList)); } return lts; } @@ -844,16 +849,15 @@ public class RMWebServices { @POST @Path("/replace-node-to-labels") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response replaceLabelsOnNodes(final NodeToLabelsInfo newNodeToLabels, + public Response replaceLabelsOnNodes(final NodeToLabelsEntryList newNodeToLabels, @Context HttpServletRequest hsr) throws IOException { Map> nodeIdToLabels = new HashMap>(); - for (Map.Entry nitle : newNodeToLabels - .getNodeToLabels().entrySet()) { + for (NodeToLabelsEntry nitle : newNodeToLabels.getNodeToLabels()) { nodeIdToLabels.put( - ConverterUtils.toNodeIdWithDefaultPort(nitle.getKey()), - new HashSet(nitle.getValue().getNodeLabels())); + ConverterUtils.toNodeIdWithDefaultPort(nitle.getNodeId()), + new HashSet(nitle.getNodeLabels())); } return replaceLabelsOnNode(nodeIdToLabels, hsr, "/replace-node-to-labels"); @@ -862,16 +866,18 @@ public class RMWebServices { @POST @Path("/nodes/{nodeId}/replace-labels") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response replaceLabelsOnNode(NodeLabelsInfo newNodeLabelsInfo, + public Response replaceLabelsOnNode( + @QueryParam("labels") Set newNodeLabelsName, @Context HttpServletRequest hsr, @PathParam("nodeId") String nodeId) throws Exception { NodeId nid = ConverterUtils.toNodeIdWithDefaultPort(nodeId); Map> newLabelsForNode = new HashMap>(); newLabelsForNode.put(nid, - new HashSet(newNodeLabelsInfo.getNodeLabels())); + new HashSet(newNodeLabelsName)); - return replaceLabelsOnNode(newLabelsForNode, hsr, "/nodes/nodeid/replace-labels"); + return replaceLabelsOnNode(newLabelsForNode, hsr, + "/nodes/nodeid/replace-labels"); } private Response replaceLabelsOnNode( @@ -909,9 +915,9 @@ public class RMWebServices { throws IOException { init(); - NodeLabelsInfo ret = - new NodeLabelsInfo(rm.getRMContext().getNodeLabelManager() - .getClusterNodeLabelNames()); + List nodeLabels = rm.getRMContext().getNodeLabelManager() + .getClusterNodeLabels(); + NodeLabelsInfo ret = new NodeLabelsInfo(nodeLabels); return ret; } @@ -937,8 +943,7 @@ public class RMWebServices { } rm.getRMContext().getNodeLabelManager() - .addToCluserNodeLabelsWithDefaultExclusivity(new HashSet( - newNodeLabels.getNodeLabels())); + .addToCluserNodeLabels(newNodeLabels.getNodeLabels()); return Response.status(Status.OK).build(); @@ -947,29 +952,29 @@ public class RMWebServices { @POST @Path("/remove-node-labels") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - public Response removeFromCluserNodeLabels(final NodeLabelsInfo oldNodeLabels, - @Context HttpServletRequest hsr) - throws Exception { + public Response removeFromCluserNodeLabels( + @QueryParam("labels") Set oldNodeLabels, + @Context HttpServletRequest hsr) throws Exception { init(); UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); if (callerUGI == null) { String msg = "Unable to obtain user name, user not authenticated for" - + " post to .../remove-node-labels"; + + " post to .../remove-node-labels"; throw new AuthorizationException(msg); } if (!rm.getRMContext().getNodeLabelManager().checkAccess(callerUGI)) { String msg = "User " + callerUGI.getShortUserName() + " not authorized" - + " for post to .../remove-node-labels "; + + " for post to .../remove-node-labels "; throw new AuthorizationException(msg); } - - rm.getRMContext().getNodeLabelManager() - .removeFromClusterNodeLabels(new HashSet( - oldNodeLabels.getNodeLabels())); - - return Response.status(Status.OK).build(); + rm.getRMContext() + .getNodeLabelManager() + .removeFromClusterNodeLabels( + new HashSet(oldNodeLabels)); + + return Response.status(Status.OK).build(); } @GET diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/LabelsToNodesInfo.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/LabelsToNodesInfo.java index 625feddba79..41dd410d334 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/LabelsToNodesInfo.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/LabelsToNodesInfo.java @@ -31,13 +31,13 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.NodeIDsInfo; @XmlAccessorType(XmlAccessType.FIELD) public class LabelsToNodesInfo { - protected Map labelsToNodes = - new HashMap(); + protected Map labelsToNodes = + new HashMap(); public LabelsToNodesInfo() { } // JAXB needs this - public Map getLabelsToNodes() { + public Map getLabelsToNodes() { return labelsToNodes; } } \ No newline at end of file diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeLabelInfo.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeLabelInfo.java new file mode 100644 index 00000000000..e507c465e3c --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeLabelInfo.java @@ -0,0 +1,86 @@ +/** + * 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.yarn.server.resourcemanager.webapp.dao; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +import org.apache.hadoop.yarn.api.records.NodeLabel; + +@XmlRootElement(name = "nodeLabelInfo") +@XmlAccessorType(XmlAccessType.FIELD) +public class NodeLabelInfo { + + private String name; + private boolean exclusivity; + + public NodeLabelInfo() { + // JAXB needs this + } + + public NodeLabelInfo(String name) { + this.name = name; + this.exclusivity = true; + } + + public NodeLabelInfo(String name, boolean exclusivity) { + this.name = name; + this.exclusivity = exclusivity; + } + + public NodeLabelInfo(NodeLabel label) { + this.name = label.getName(); + this.exclusivity = label.isExclusive(); + } + + public String getName() { + return name; + } + + public boolean getExclusivity() { + return exclusivity; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + NodeLabelInfo other = (NodeLabelInfo) obj; + if (!getName().equals(other.getName())) { + return false; + } + if (getExclusivity() != other.getExclusivity()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return (getName().hashCode() << 16) + (getExclusivity() ? 1 : 0); + } +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeLabelsInfo.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeLabelsInfo.java index 1cb895aa6b0..2c3a8a507ab 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeLabelsInfo.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeLabelsInfo.java @@ -22,31 +22,63 @@ import java.util.*; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; +import org.apache.hadoop.yarn.api.records.NodeLabel; + @XmlRootElement(name = "nodeLabelsInfo") @XmlAccessorType(XmlAccessType.FIELD) public class NodeLabelsInfo { - protected ArrayList nodeLabels = new ArrayList(); + @XmlElement(name = "nodeLabelInfo") + private ArrayList nodeLabelsInfo = + new ArrayList(); public NodeLabelsInfo() { - } // JAXB needs this - - public NodeLabelsInfo(ArrayList nodeLabels) { - this.nodeLabels = nodeLabels; + // JAXB needs this + } + + public NodeLabelsInfo(ArrayList nodeLabels) { + this.nodeLabelsInfo = nodeLabels; + } + + public NodeLabelsInfo(List nodeLabels) { + this.nodeLabelsInfo = new ArrayList(); + for (NodeLabel label : nodeLabels) { + this.nodeLabelsInfo.add(new NodeLabelInfo(label)); + } } - public NodeLabelsInfo(Set nodeLabelsSet) { - this.nodeLabels = new ArrayList(nodeLabelsSet); + public NodeLabelsInfo(Set nodeLabelsName) { + this.nodeLabelsInfo = new ArrayList(); + for (String labelName : nodeLabelsName) { + this.nodeLabelsInfo.add(new NodeLabelInfo(labelName)); + } } - - public ArrayList getNodeLabels() { + + public ArrayList getNodeLabelsInfo() { + return nodeLabelsInfo; + } + + public Set getNodeLabels() { + Set nodeLabels = new HashSet(); + for (NodeLabelInfo label : nodeLabelsInfo) { + nodeLabels.add(NodeLabel.newInstance(label.getName(), + label.getExclusivity())); + } return nodeLabels; } - public void setNodeLabels(ArrayList nodeLabels) { - this.nodeLabels = nodeLabels; + public List getNodeLabelsName() { + ArrayList nodeLabelsName = new ArrayList(); + for (NodeLabelInfo label : nodeLabelsInfo) { + nodeLabelsName.add(label.getName()); + } + return nodeLabelsName; + } + + public void setNodeLabelsInfo(ArrayList nodeLabelInfo) { + this.nodeLabelsInfo = nodeLabelInfo; } - } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeToLabelsEntry.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeToLabelsEntry.java new file mode 100644 index 00000000000..702d6f0d1a4 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeToLabelsEntry.java @@ -0,0 +1,54 @@ +/** + * 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.yarn.server.resourcemanager.webapp.dao; + +import java.util.*; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlElement; + +@XmlRootElement(name = "nodeToLabelsEntry") +@XmlAccessorType(XmlAccessType.FIELD) +public class NodeToLabelsEntry { + + @XmlElement(name = "nodeId") + private String nodeId; + + @XmlElement(name = "labels") + private ArrayList labels = new ArrayList(); + + public NodeToLabelsEntry() { + // JAXB needs this + } + + public NodeToLabelsEntry(String nodeId, ArrayList labels) { + this.nodeId = nodeId; + this.labels = labels; + } + + public String getNodeId() { + return nodeId; + } + + public ArrayList getNodeLabels() { + return labels; + } +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeToLabelsEntryList.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeToLabelsEntryList.java new file mode 100644 index 00000000000..dc9543e194e --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeToLabelsEntryList.java @@ -0,0 +1,41 @@ +/** + * 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.yarn.server.resourcemanager.webapp.dao; + +import java.util.*; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "nodeToLabelsName") +@XmlAccessorType(XmlAccessType.FIELD) +public class NodeToLabelsEntryList { + + protected ArrayList nodeToLabels = + new ArrayList(); + + public NodeToLabelsEntryList() { + // JAXB needs this + } + + public ArrayList getNodeToLabels() { + return nodeToLabels; + } +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeToLabelsInfo.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeToLabelsInfo.java index f2e64418f1a..0b6e4bc868c 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeToLabelsInfo.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/NodeToLabelsInfo.java @@ -28,14 +28,14 @@ import javax.xml.bind.annotation.XmlRootElement; @XmlAccessorType(XmlAccessType.FIELD) public class NodeToLabelsInfo { - protected HashMap nodeToLabels = - new HashMap(); + private HashMap nodeToLabels = + new HashMap(); public NodeToLabelsInfo() { - } // JAXB needs this - - public HashMap getNodeToLabels() { - return nodeToLabels; + // JAXB needs this + } + + public HashMap getNodeToLabels() { + return nodeToLabels; } - } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesNodeLabels.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesNodeLabels.java index 2d5518dc03c..54fe00d2fd4 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesNodeLabels.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesNodeLabels.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.StringWriter; +import java.util.ArrayList; import javax.ws.rs.core.MediaType; @@ -34,13 +35,14 @@ import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.server.resourcemanager.MockRM; import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.LabelsToNodesInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeLabelsInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntry; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeToLabelsEntryList; import org.apache.hadoop.yarn.webapp.GenericExceptionHandler; import org.apache.hadoop.yarn.webapp.JerseyTestBase; -import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONException; -import org.codehaus.jettison.json.JSONObject; import org.junit.Test; import com.google.inject.Guice; @@ -113,15 +115,15 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { WebResource r = resource(); ClientResponse response; - JSONObject json; - JSONArray jarr; // Add a label + NodeLabelsInfo nlsifo = new NodeLabelsInfo(); + nlsifo.getNodeLabelsInfo().add(new NodeLabelInfo("a")); response = r.path("ws").path("v1").path("cluster") .path("add-node-labels").queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON) - .entity("{\"nodeLabels\":\"a\"}", MediaType.APPLICATION_JSON) + .entity(toJson(nlsifo, NodeLabelsInfo.class), MediaType.APPLICATION_JSON) .post(ClientResponse.class); // Verify @@ -130,15 +132,18 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { .path("get-node-labels").queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); - json = response.getEntity(JSONObject.class); - assertEquals("a", json.getString("nodeLabels")); + nlsifo = response.getEntity(NodeLabelsInfo.class); + assertEquals("a", nlsifo.getNodeLabelsInfo().get(0).getName()); + assertEquals(1, nlsifo.getNodeLabels().size()); // Add another + nlsifo = new NodeLabelsInfo(); + nlsifo.getNodeLabelsInfo().add(new NodeLabelInfo("b")); response = r.path("ws").path("v1").path("cluster") .path("add-node-labels").queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON) - .entity("{\"nodeLabels\":\"b\"}", MediaType.APPLICATION_JSON) + .entity(toJson(nlsifo, NodeLabelsInfo.class), MediaType.APPLICATION_JSON) .post(ClientResponse.class); // Verify @@ -147,43 +152,45 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { .path("get-node-labels").queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); - json = response.getEntity(JSONObject.class); - jarr = json.getJSONArray("nodeLabels"); - assertEquals(2, jarr.length()); + nlsifo = response.getEntity(NodeLabelsInfo.class); + assertEquals(2, nlsifo.getNodeLabels().size()); // Add labels to a node + MultivaluedMapImpl params = new MultivaluedMapImpl(); + params.add("labels", "a"); response = r.path("ws").path("v1").path("cluster") .path("nodes").path("nid:0") .path("replace-labels") .queryParam("user.name", userName) + .queryParams(params) .accept(MediaType.APPLICATION_JSON) - .entity("{\"nodeLabels\": [\"a\"]}", - MediaType.APPLICATION_JSON) .post(ClientResponse.class); LOG.info("posted node nodelabel"); // Add labels to another node + params = new MultivaluedMapImpl(); + params.add("labels", "b"); response = r.path("ws").path("v1").path("cluster") .path("nodes").path("nid1:0") .path("replace-labels") .queryParam("user.name", userName) + .queryParams(params) .accept(MediaType.APPLICATION_JSON) - .entity("{\"nodeLabels\": [\"b\"]}", - MediaType.APPLICATION_JSON) .post(ClientResponse.class); LOG.info("posted node nodelabel"); // Add labels to another node + params = new MultivaluedMapImpl(); + params.add("labels", "b"); response = r.path("ws").path("v1").path("cluster") .path("nodes").path("nid2:0") .path("replace-labels") .queryParam("user.name", userName) + .queryParams(params) .accept(MediaType.APPLICATION_JSON) - .entity("{\"nodeLabels\": [\"b\"]}", - MediaType.APPLICATION_JSON) .post(ClientResponse.class); LOG.info("posted node nodelabel"); @@ -195,14 +202,14 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); LabelsToNodesInfo ltni = response.getEntity(LabelsToNodesInfo.class); assertEquals(2, ltni.getLabelsToNodes().size()); - NodeIDsInfo nodes = ltni.getLabelsToNodes().get("b"); + NodeIDsInfo nodes = ltni.getLabelsToNodes().get(new NodeLabelInfo("b")); assertTrue(nodes.getNodeIDs().contains("nid2:0")); assertTrue(nodes.getNodeIDs().contains("nid1:0")); - nodes = ltni.getLabelsToNodes().get("a"); + nodes = ltni.getLabelsToNodes().get(new NodeLabelInfo("a")); assertTrue(nodes.getNodeIDs().contains("nid:0")); - // Verify, using get-labels-to-Nodes for specifiedset of labels - MultivaluedMapImpl params = new MultivaluedMapImpl(); + // Verify, using get-labels-to-Nodes for specified set of labels + params = new MultivaluedMapImpl(); params.add("labels", "a"); response = r.path("ws").path("v1").path("cluster") @@ -213,7 +220,7 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); ltni = response.getEntity(LabelsToNodesInfo.class); assertEquals(1, ltni.getLabelsToNodes().size()); - nodes = ltni.getLabelsToNodes().get("a"); + nodes = ltni.getLabelsToNodes().get(new NodeLabelInfo("a")); assertTrue(nodes.getNodeIDs().contains("nid:0")); // Verify @@ -223,18 +230,20 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { .path("get-labels").queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); - json = response.getEntity(JSONObject.class); - assertEquals("a", json.getString("nodeLabels")); + nlsifo = response.getEntity(NodeLabelsInfo.class); + assertTrue(nlsifo.getNodeLabelsName().contains("a")); // Replace + params = new MultivaluedMapImpl(); + params.add("labels", "b"); response = r.path("ws").path("v1").path("cluster") .path("nodes").path("nid:0") .path("replace-labels") .queryParam("user.name", userName) + .queryParams(params) .accept(MediaType.APPLICATION_JSON) - .entity("{\"nodeLabels\":\"b\"}", MediaType.APPLICATION_JSON) .post(ClientResponse.class); LOG.info("posted node nodelabel"); @@ -245,20 +254,21 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { .path("get-labels").queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); - json = response.getEntity(JSONObject.class); - assertEquals("b", json.getString("nodeLabels")); + nlsifo = response.getEntity(NodeLabelsInfo.class); + assertTrue(nlsifo.getNodeLabelsName().contains("b")); // Replace labels using node-to-labels - NodeToLabelsInfo ntli = new NodeToLabelsInfo(); - NodeLabelsInfo nli = new NodeLabelsInfo(); - nli.getNodeLabels().add("a"); - ntli.getNodeToLabels().put("nid:0", nli); + NodeToLabelsEntryList ntli = new NodeToLabelsEntryList(); + ArrayList labels = new ArrayList(); + labels.add("a"); + NodeToLabelsEntry nli = new NodeToLabelsEntry("nid:0", labels); + ntli.getNodeToLabels().add(nli); response = r.path("ws").path("v1").path("cluster") .path("replace-node-to-labels") .queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON) - .entity(toJson(ntli, NodeToLabelsInfo.class), + .entity(toJson(ntli, NodeToLabelsEntryList.class), MediaType.APPLICATION_JSON) .post(ClientResponse.class); @@ -268,19 +278,21 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { .path("get-node-to-labels").queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); - ntli = response.getEntity(NodeToLabelsInfo.class); - nli = ntli.getNodeToLabels().get("nid:0"); - assertEquals(1, nli.getNodeLabels().size()); - assertTrue(nli.getNodeLabels().contains("a")); + NodeToLabelsInfo ntlinfo = response.getEntity(NodeToLabelsInfo.class); + NodeLabelsInfo nlinfo = ntlinfo.getNodeToLabels().get("nid:0"); + assertEquals(1, nlinfo.getNodeLabels().size()); + assertTrue(nlinfo.getNodeLabelsName().contains("a")); // Remove all + params = new MultivaluedMapImpl(); + params.add("labels", ""); response = r.path("ws").path("v1").path("cluster") .path("nodes").path("nid:0") .path("replace-labels") .queryParam("user.name", userName) + .queryParams(params) .accept(MediaType.APPLICATION_JSON) - .entity("{\"nodeLabels\"}", MediaType.APPLICATION_JSON) .post(ClientResponse.class); LOG.info("posted node nodelabel"); // Verify @@ -290,18 +302,19 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { .path("get-labels").queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); - json = response.getEntity(JSONObject.class); - assertEquals("", json.getString("nodeLabels")); + nlsifo = response.getEntity(NodeLabelsInfo.class); + assertTrue(nlsifo.getNodeLabelsName().contains("")); // Add a label back for auth tests + params = new MultivaluedMapImpl(); + params.add("labels", "a"); response = r.path("ws").path("v1").path("cluster") .path("nodes").path("nid:0") .path("replace-labels") .queryParam("user.name", userName) + .queryParams(params) .accept(MediaType.APPLICATION_JSON) - .entity("{\"nodeLabels\": \"a\"}", - MediaType.APPLICATION_JSON) .post(ClientResponse.class); LOG.info("posted node nodelabel"); @@ -312,18 +325,19 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { .path("get-labels").queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); - json = response.getEntity(JSONObject.class); - assertEquals("a", json.getString("nodeLabels")); + nlsifo = response.getEntity(NodeLabelsInfo.class); + assertTrue(nlsifo.getNodeLabelsName().contains("a")); // Auth fail replace labels on node + params = new MultivaluedMapImpl(); + params.add("labels", "b"); response = r.path("ws").path("v1").path("cluster") .path("nodes").path("nid:0") .path("replace-labels") .queryParam("user.name", notUserName) + .queryParams(params) .accept(MediaType.APPLICATION_JSON) - .entity("{\"nodeLabels\": [\"b\"]}", - MediaType.APPLICATION_JSON) .post(ClientResponse.class); // Verify response = @@ -332,8 +346,8 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { .path("get-labels").queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); - json = response.getEntity(JSONObject.class); - assertEquals("a", json.getString("nodeLabels")); + nlsifo = response.getEntity(NodeLabelsInfo.class); + assertTrue(nlsifo.getNodeLabelsName().contains("a")); // Fail to add a label with post response = @@ -349,17 +363,18 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { .path("get-node-labels").queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); - json = response.getEntity(JSONObject.class); - jarr = json.getJSONArray("nodeLabels"); - assertEquals(2, jarr.length()); + nlsifo = response.getEntity(NodeLabelsInfo.class); + assertEquals(2, nlsifo.getNodeLabels().size()); // Remove cluster label (succeed, we no longer need it) + params = new MultivaluedMapImpl(); + params.add("labels", "b"); response = r.path("ws").path("v1").path("cluster") .path("remove-node-labels") .queryParam("user.name", userName) + .queryParams(params) .accept(MediaType.APPLICATION_JSON) - .entity("{\"nodeLabels\":\"b\"}", MediaType.APPLICATION_JSON) .post(ClientResponse.class); // Verify response = @@ -367,17 +382,19 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { .path("get-node-labels").queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); - json = response.getEntity(JSONObject.class); - assertEquals("a", json.getString("nodeLabels")); - + nlsifo = response.getEntity(NodeLabelsInfo.class); + assertEquals("a", nlsifo.getNodeLabelsInfo().get(0).getName()); + assertEquals(1, nlsifo.getNodeLabels().size()); // Remove cluster label with post + params = new MultivaluedMapImpl(); + params.add("labels", "a"); response = r.path("ws").path("v1").path("cluster") .path("remove-node-labels") .queryParam("user.name", userName) + .queryParams(params) .accept(MediaType.APPLICATION_JSON) - .entity("{\"nodeLabels\":\"a\"}", MediaType.APPLICATION_JSON) .post(ClientResponse.class); // Verify response = @@ -385,12 +402,15 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { .path("get-node-labels").queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); - String res = response.getEntity(String.class); - assertTrue(res.equals("null")); + nlsifo = response.getEntity(NodeLabelsInfo.class); + assertEquals(0, nlsifo.getNodeLabels().size()); // Following test cases are to test replace when distributed node label // configuration is on // Reset for testing : add cluster labels + nlsifo = new NodeLabelsInfo(); + nlsifo.getNodeLabelsInfo().add(new NodeLabelInfo("x")); + nlsifo.getNodeLabelsInfo().add(new NodeLabelInfo("y")); response = r.path("ws") .path("v1") @@ -398,14 +418,18 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { .path("add-node-labels") .queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON) - .entity("{\"nodeLabels\":[\"x\",\"y\"]}", + .entity(toJson(nlsifo, NodeLabelsInfo.class), MediaType.APPLICATION_JSON).post(ClientResponse.class); // Reset for testing : Add labels to a node + nlsifo = new NodeLabelsInfo(); + nlsifo.getNodeLabelsInfo().add(new NodeLabelInfo("y")); + params = new MultivaluedMapImpl(); + params.add("labels", "y"); response = r.path("ws").path("v1").path("cluster").path("nodes").path("nid:0") .path("replace-labels").queryParam("user.name", userName) + .queryParams(params) .accept(MediaType.APPLICATION_JSON) - .entity("{\"nodeLabels\": [\"y\"]}", MediaType.APPLICATION_JSON) .post(ClientResponse.class); LOG.info("posted node nodelabel"); @@ -413,10 +437,11 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { rmWebService.isDistributedNodeLabelConfiguration = true; // Case1 : Replace labels using node-to-labels - ntli = new NodeToLabelsInfo(); - nli = new NodeLabelsInfo(); - nli.getNodeLabels().add("x"); - ntli.getNodeToLabels().put("nid:0", nli); + ntli = new NodeToLabelsEntryList(); + labels = new ArrayList(); + labels.add("x"); + nli = new NodeToLabelsEntry("nid:0", labels); + ntli.getNodeToLabels().add(nli); response = r.path("ws") .path("v1") @@ -424,7 +449,7 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { .path("replace-node-to-labels") .queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON) - .entity(toJson(ntli, NodeToLabelsInfo.class), + .entity(toJson(ntli, NodeToLabelsEntryList.class), MediaType.APPLICATION_JSON).post(ClientResponse.class); // Verify, using node-to-labels that previous operation has failed @@ -433,17 +458,17 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { .queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); - ntli = response.getEntity(NodeToLabelsInfo.class); - nli = ntli.getNodeToLabels().get("nid:0"); - assertEquals(1, nli.getNodeLabels().size()); - assertFalse(nli.getNodeLabels().contains("x")); + ntlinfo = response.getEntity(NodeToLabelsInfo.class); + nlinfo = ntlinfo.getNodeToLabels().get("nid:0"); + assertEquals(1, nlinfo.getNodeLabels().size()); + assertFalse(nlinfo.getNodeLabels().contains("x")); // Case2 : failure to Replace labels using replace-labels response = r.path("ws").path("v1").path("cluster").path("nodes").path("nid:0") .path("replace-labels").queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON) - .entity("{\"nodeLabels\": [\"x\"]}", MediaType.APPLICATION_JSON) + .entity("{\"nodeLabelName\": [\"x\"]}", MediaType.APPLICATION_JSON) .post(ClientResponse.class); LOG.info("posted node nodelabel"); @@ -453,18 +478,20 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { .queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); - ntli = response.getEntity(NodeToLabelsInfo.class); - nli = ntli.getNodeToLabels().get("nid:0"); - assertEquals(1, nli.getNodeLabels().size()); - assertFalse(nli.getNodeLabels().contains("x")); + ntlinfo = response.getEntity(NodeToLabelsInfo.class); + nlinfo = ntlinfo.getNodeToLabels().get("nid:0"); + assertEquals(1, nlinfo.getNodeLabels().size()); + assertFalse(nlinfo.getNodeLabels().contains("x")); - // Case3 : Remove cluster label should be successfull + // Case3 : Remove cluster label should be successful + params = new MultivaluedMapImpl(); + params.add("labels", "x"); response = r.path("ws").path("v1").path("cluster") .path("remove-node-labels") .queryParam("user.name", userName) + .queryParams(params) .accept(MediaType.APPLICATION_JSON) - .entity("{\"nodeLabels\":\"x\"}", MediaType.APPLICATION_JSON) .post(ClientResponse.class); // Verify response = @@ -472,8 +499,52 @@ public class TestRMWebServicesNodeLabels extends JerseyTestBase { .path("get-node-labels").queryParam("user.name", userName) .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); - json = response.getEntity(JSONObject.class); - assertEquals("y", json.getString("nodeLabels")); + nlsifo = response.getEntity(NodeLabelsInfo.class); + assertEquals("y", nlsifo.getNodeLabelsInfo().get(0).getName()); + + // Remove y + params = new MultivaluedMapImpl(); + params.add("labels", "y"); + response = + r.path("ws").path("v1").path("cluster") + .path("remove-node-labels") + .queryParam("user.name", userName) + .queryParams(params) + .accept(MediaType.APPLICATION_JSON) + .post(ClientResponse.class); + + // Verify + response = + r.path("ws").path("v1").path("cluster") + .path("get-node-labels").queryParam("user.name", userName) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); + nlsifo = response.getEntity(NodeLabelsInfo.class); + assertTrue(nlsifo.getNodeLabelsInfo().isEmpty()); + + // add a new nodelabel with exclusity + nlsifo = new NodeLabelsInfo(); + nlsifo.getNodeLabelsInfo().add(new NodeLabelInfo("z", false)); + response = + r.path("ws") + .path("v1") + .path("cluster") + .path("add-node-labels") + .queryParam("user.name", userName) + .accept(MediaType.APPLICATION_JSON) + .entity(toJson(nlsifo, NodeLabelsInfo.class), + MediaType.APPLICATION_JSON).post(ClientResponse.class); + + // Verify + response = + r.path("ws").path("v1").path("cluster") + .path("get-node-labels").queryParam("user.name", userName) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); + nlsifo = response.getEntity(NodeLabelsInfo.class); + assertEquals("z", nlsifo.getNodeLabelsInfo().get(0).getName()); + assertEquals(false, nlsifo.getNodeLabelsInfo().get(0).getExclusivity()); + assertEquals(1, nlsifo.getNodeLabels().size()); } @SuppressWarnings("rawtypes")