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/JAXBContextResolver.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/JAXBContextResolver.java index 2e4204e08af..f3e1a08d959 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/JAXBContextResolver.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/JAXBContextResolver.java @@ -60,7 +60,8 @@ public JAXBContextResolver() throws Exception { final Class[] rootUnwrappedTypes = { NewApplication.class, ApplicationSubmissionContextInfo.class, ContainerLaunchContextInfo.class, LocalResourceInfo.class, - DelegationToken.class, AppQueue.class, AppPriority.class }; + DelegationToken.class, AppQueue.class, AppPriority.class, + ResourceOptionInfo.class }; this.typesContextMap = new HashMap(); context = 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/RMWSConsts.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWSConsts.java index a3fd2a95d23..87afc8070f2 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWSConsts.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWSConsts.java @@ -57,6 +57,9 @@ /** Path for {@code RMWebServiceProtocol#getNode}. */ public static final String NODES_NODEID = "/nodes/{nodeId}"; + /** Path for {@code RMWebServiceProtocol#updateNodeResource}. */ + public static final String NODE_RESOURCE = "/nodes/{nodeId}/resource"; + /** * Path for {@code RMWebServiceProtocol#getApps} and * {@code RMWebServiceProtocol#getApp}. 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/RMWebServiceProtocol.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServiceProtocol.java index a310853dd37..fc605e84b2b 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServiceProtocol.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServiceProtocol.java @@ -58,6 +58,8 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ResourceInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ResourceOptionInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerTypeInfo; /** @@ -148,6 +150,19 @@ String dumpSchedulerLogs(String time, HttpServletRequest hsr) */ NodeInfo getNode(String nodeId); + /** + * This method changes the resources of a specific node, and it is reachable + * by using {@link RMWSConsts#NODE_RESOURCE}. + * + * @param hsr the servlet request + * @param nodeId the node we want to retrieve the information. It is a + * PathParam. + * @param resourceOption the resource change. + * @throws AuthorizationException if the user is not authorized + */ + ResourceInfo updateNodeResource(HttpServletRequest hsr, String nodeId, + ResourceOptionInfo resourceOption) throws AuthorizationException; + /** * This method retrieves all the app reports in the cluster, and it is * reachable by using {@link RMWSConsts#APPS}. 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 01173768c14..09fec8573b8 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 @@ -56,8 +56,6 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.CommonConfigurationKeys; import org.apache.hadoop.http.JettyUtils; @@ -118,6 +116,7 @@ import org.apache.hadoop.yarn.api.records.ReservationRequestInterpreter; import org.apache.hadoop.yarn.api.records.ReservationRequests; import org.apache.hadoop.yarn.api.records.Resource; +import org.apache.hadoop.yarn.api.records.ResourceOption; import org.apache.hadoop.yarn.api.records.YarnApplicationState; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.exceptions.YarnException; @@ -125,8 +124,11 @@ import org.apache.hadoop.yarn.factories.RecordFactory; import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider; import org.apache.hadoop.yarn.security.client.RMDelegationTokenIdentifier; +import org.apache.hadoop.yarn.server.api.protocolrecords.UpdateNodeResourceRequest; +import org.apache.hadoop.yarn.server.resourcemanager.AdminService; import org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger; import org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger.AuditConstants; +import org.apache.hadoop.yarn.server.resourcemanager.RMContext; import org.apache.hadoop.yarn.server.resourcemanager.RMServerUtils; import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager; import org.apache.hadoop.yarn.server.resourcemanager.nodelabels.NodeLabelsUtils; @@ -185,6 +187,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateResponseInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ResourceInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ResourceOptionInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerTypeInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.StatisticsItemInfo; @@ -201,6 +204,8 @@ import org.apache.hadoop.yarn.webapp.ForbiddenException; import org.apache.hadoop.yarn.webapp.NotFoundException; import org.apache.hadoop.yarn.webapp.util.WebAppUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.apache.hadoop.yarn.webapp.dao.SchedConfUpdateInfo; import com.google.common.annotations.VisibleForTesting; @@ -211,8 +216,8 @@ @Path(RMWSConsts.RM_WEB_SERVICE_PATH) public class RMWebServices extends WebServices implements RMWebServiceProtocol { - private static final Log LOG = - LogFactory.getLog(RMWebServices.class.getName()); + private static final Logger LOG = + LoggerFactory.getLogger(RMWebServices.class.getName()); private final ResourceManager rm; private static RecordFactory recordFactory = @@ -484,6 +489,61 @@ public NodeInfo getNode(@PathParam(RMWSConsts.NODEID) String nodeId) { return nodeInfo; } + @POST + @Path(RMWSConsts.NODE_RESOURCE) + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + public ResourceInfo updateNodeResource( + @Context HttpServletRequest hsr, + @PathParam("nodeId") String nodeId, + ResourceOptionInfo resourceOption) throws AuthorizationException { + + UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); + initForWritableEndpoints(callerUGI, false); + + RMNode rmNode = getRMNode(nodeId); + Map nodeResourceMap = + Collections.singletonMap( + rmNode.getNodeID(), resourceOption.getResourceOption()); + UpdateNodeResourceRequest updateRequest = + UpdateNodeResourceRequest.newInstance(nodeResourceMap); + + AdminService admin = this.rm.getRMContext().getRMAdminService(); + try { + admin.updateNodeResource(updateRequest); + } catch (YarnException e) { + String message = "Failed to update the node resource " + + rmNode.getNodeID() + "."; + LOG.error(message, e); + throw new YarnRuntimeException(message, e); + } catch (IOException e) { + LOG.error("Failed to update the node resource {}.", + rmNode.getNodeID(), e); + } + + return new ResourceInfo(rmNode.getTotalCapability()); + } + + /** + * Get the RMNode in the RM from the node identifier. + * @param nodeId Node identifier. + * @return The RMNode in the RM. + */ + private RMNode getRMNode(final String nodeId) { + if (nodeId == null || nodeId.isEmpty()) { + throw new NotFoundException("nodeId, " + nodeId + ", is empty or null"); + } + NodeId nid = NodeId.fromString(nodeId); + RMContext rmContext = this.rm.getRMContext(); + RMNode ni = rmContext.getRMNodes().get(nid); + if (ni == null) { + ni = rmContext.getInactiveRMNodes().get(nid.getHost()); + if (ni == null) { + throw new NotFoundException("nodeId, " + nodeId + ", is not found"); + } + } + return ni; + } + @GET @Path(RMWSConsts.APPS) @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8, 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/NodeInfo.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/NodeInfo.java index 7e5d20ab003..585b3a5307d 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/NodeInfo.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/NodeInfo.java @@ -64,6 +64,7 @@ protected ResourceInfo usedResource; protected ResourceInfo availableResource; protected NodeAttributesInfo nodeAttributesInfo; + protected ResourceInfo totalResource; public NodeInfo() { } // JAXB needs this @@ -92,6 +93,7 @@ public NodeInfo(RMNode ni, ResourceScheduler sched) { this.lastHealthUpdate = ni.getLastHealthReportTime(); this.healthReport = String.valueOf(ni.getHealthReport()); this.version = ni.getNodeManagerVersion(); + this.totalResource = new ResourceInfo(ni.getTotalCapability()); // Status of opportunistic containers. this.numRunningOpportContainers = 0; @@ -242,4 +244,7 @@ public void setLastHealthUpdate(long lastHealthUpdate) { this.lastHealthUpdate = lastHealthUpdate; } + public ResourceInfo getResource() { + return this.totalResource; + } } 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/ResourceOptionInfo.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/ResourceOptionInfo.java new file mode 100644 index 00000000000..5a574fdce9a --- /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/ResourceOptionInfo.java @@ -0,0 +1,64 @@ +/** + * 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.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import org.apache.hadoop.yarn.api.records.ResourceOption; + + +/** + * A JAXB representation of a {link ResourceOption}. + */ +@XmlRootElement(name = "resourceOption") +@XmlAccessorType(XmlAccessType.NONE) +public class ResourceOptionInfo { + + @XmlElement(name = "resource") + ResourceInfo resource; + @XmlElement(name = "overCommitTimeout") + int overCommitTimeout; + + /** Internal resource option for caching. */ + private ResourceOption resourceOption; + + + public ResourceOptionInfo() { + } // JAXB needs this + + public ResourceOptionInfo(ResourceOption resourceOption) { + this.resource = new ResourceInfo(resourceOption.getResource()); + this.overCommitTimeout = resourceOption.getOverCommitTimeout(); + } + + public ResourceOption getResourceOption() { + if (resourceOption == null) { + resourceOption = ResourceOption.newInstance( + resource.getResource(), overCommitTimeout); + } + return resourceOption; + } + + @Override + public String toString() { + return getResourceOption().toString(); + } +} 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/TestRMWebServicesNodes.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesNodes.java index f7d470d7cdd..684f69b52fe 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesNodes.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesNodes.java @@ -25,28 +25,37 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.EnumSet; +import java.util.Enumeration; import java.util.Map; +import java.util.Properties; import java.util.Set; import java.util.HashSet; import java.util.TreeMap; import java.util.Iterator; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; import javax.ws.rs.core.MediaType; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; -import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.http.JettyUtils; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.security.authentication.server.AuthenticationFilter; +import org.apache.hadoop.security.authentication.server.PseudoAuthenticationHandler; import org.apache.hadoop.yarn.api.records.ContainerStatus; import org.apache.hadoop.yarn.api.records.NodeAttribute; import org.apache.hadoop.yarn.api.records.NodeAttributeType; import org.apache.hadoop.yarn.api.records.NodeId; import org.apache.hadoop.yarn.api.records.NodeState; import org.apache.hadoop.yarn.api.records.Resource; +import org.apache.hadoop.yarn.api.records.ResourceOption; import org.apache.hadoop.yarn.api.records.ResourceUtilization; +import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.server.utils.BuilderUtils; import org.apache.hadoop.yarn.server.api.records.NodeHealthStatus; import org.apache.hadoop.yarn.server.api.records.NodeStatus; @@ -66,6 +75,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.SchedulerNodeReport; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.constraint.AllocationTagsManager; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ResourceOptionInfo; import org.apache.hadoop.yarn.util.Records; import org.apache.hadoop.yarn.util.RackResolver; import org.apache.hadoop.yarn.util.YarnVersionInfo; @@ -85,6 +95,7 @@ import com.google.common.base.Joiner; import com.google.inject.Guice; +import com.google.inject.Singleton; import com.google.inject.servlet.ServletModule; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.ClientResponse.Status; @@ -96,22 +107,58 @@ public class TestRMWebServicesNodes extends JerseyTestBase { private static MockRM rm; + private static YarnConfiguration conf; + + private static String userName; private static class WebServletModule extends ServletModule { @Override protected void configureServlets() { bind(JAXBContextResolver.class); + try { + userName = UserGroupInformation.getCurrentUser().getShortUserName(); + } catch (IOException ioe) { + throw new RuntimeException("Unable to get current user name " + + ioe.getMessage(), ioe); + } + conf = new YarnConfiguration(); + conf.set(YarnConfiguration.YARN_ADMIN_ACL, userName); bind(RMWebServices.class); bind(GenericExceptionHandler.class); - rm = new MockRM(new Configuration()); + rm = new MockRM(conf); rm.getRMContext().getContainerTokenSecretManager().rollMasterKey(); rm.getRMContext().getNMTokenSecretManager().rollMasterKey(); rm.disableDrainEventsImplicitly(); bind(ResourceManager.class).toInstance(rm); + filter("/*").through(TestRMCustomAuthFilter.class); serve("/*").with(GuiceContainer.class); } } + /** + * Custom filter to be able to test auth methods and let the other ones go. + */ + @Singleton + public static class TestRMCustomAuthFilter extends AuthenticationFilter { + + @Override + protected Properties getConfiguration(String configPrefix, + FilterConfig filterConfig) throws ServletException { + Properties props = new Properties(); + Enumeration names = filterConfig.getInitParameterNames(); + while (names.hasMoreElements()) { + String name = (String) names.nextElement(); + if (name.startsWith(configPrefix)) { + String value = filterConfig.getInitParameter(name); + props.put(name.substring(configPrefix.length()), value); + } + } + props.put(AuthenticationFilter.AUTH_TYPE, "simple"); + props.put(PseudoAuthenticationHandler.ANONYMOUS_ALLOWED, "true"); + return props; + } + } + static { GuiceServletConfig.setInjector( Guice.createInjector(new WebServletModule())); @@ -541,7 +588,7 @@ public void testNonexistNodeXML() throws JSONException, Exception { } private void verifyNonexistNodeException(String message, String type, String classname) { - assertTrue("exception message incorrect", + assertTrue("exception message incorrect: " + message, "java.lang.Exception: nodeId, node_invalid:99, is not found" .matches(message)); assertTrue("exception type incorrect", "NotFoundException".matches(type)); @@ -714,6 +761,56 @@ public void testNodesResourceUtilization() throws JSONException, Exception { verifyNodeInfo(info, rmnode1); } + @Test + public void testUpdateNodeResource() throws Exception { + WebResource r = resource().path("ws").path("v1").path("cluster"); + + r = r.queryParam("user.name", userName); + RMNode rmnode = getRunningRMNode("h1", 1234, 5120); + String rmnodeId = rmnode.getNodeID().toString(); + assertEquals("h1:1234", rmnodeId); + + // assert memory and default vcores + ClientResponse response = r.path("nodes").path(rmnodeId) + .accept(MediaType.APPLICATION_JSON) + .get(ClientResponse.class); + JSONObject json = response.getEntity(JSONObject.class); + JSONObject info = json.getJSONObject("node"); + JSONObject totalResource = info.getJSONObject("totalResource"); + assertEquals(5120, totalResource.getInt("memory")); + assertEquals(4, totalResource.getInt("vCores")); + + // the RM needs to be running to process the resource update + rm.start(); + + // update memory to 8192 and 5 cores + Resource resource = Resource.newInstance(8192, 5); + ResourceOptionInfo resourceOption = new ResourceOptionInfo( + ResourceOption.newInstance( + resource, ResourceOption.OVER_COMMIT_TIMEOUT_MILLIS_DEFAULT)); + response = r.path("nodes").path(rmnodeId).path("resource") + .entity(resourceOption, MediaType.APPLICATION_JSON_TYPE) + .accept(MediaType.APPLICATION_JSON) + .post(ClientResponse.class); + assertResponseStatusCode(Status.OK, response.getStatusInfo()); + json = response.getEntity(JSONObject.class); + totalResource = json.getJSONObject("resourceInfo"); + assertEquals(8192, totalResource.getLong("memory")); + assertEquals(5, totalResource.getLong("vCores")); + + // assert updated memory and cores + response = r.path("nodes").path(rmnodeId) + .accept(MediaType.APPLICATION_JSON) + .get(ClientResponse.class); + json = response.getEntity(JSONObject.class); + info = json.getJSONObject("node"); + totalResource = info.getJSONObject("totalResource"); + assertEquals(8192, totalResource.getInt("memory")); + assertEquals(5, totalResource.getInt("vCores")); + + rm.stop(); + } + public void verifyNodesXML(NodeList nodes, RMNode nm) throws JSONException, Exception { @@ -750,7 +847,7 @@ public void verifyNodesXML(NodeList nodes, RMNode nm) public void verifyNodeInfo(JSONObject nodeInfo, RMNode nm) throws JSONException, Exception { - assertEquals("incorrect number of elements", 20, nodeInfo.length()); + assertEquals("incorrect number of elements", 21, nodeInfo.length()); JSONObject resourceInfo = nodeInfo.getJSONObject("resourceUtilization"); verifyNodeInfoGeneric(nm, nodeInfo.getString("state"), diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/ResourceManagerRest.md b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/ResourceManagerRest.md index 041af4c00f0..f141eea469e 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/ResourceManagerRest.md +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/ResourceManagerRest.md @@ -2919,6 +2919,84 @@ Response Body: ``` +Cluster Node Update Resource API +-------------------------------- + +Wit the node update resource API, you can update the resources in a node. + +### URI + +Use the following URI to update the resources of a Node Object identified by the nodeid value. + + * http://rm-http-address:port/ws/v1/cluster/nodes/{nodeid}/resource + +### HTTP Operations Supported + + * POST + +### Query Parameters Supported + + None + +### Elements of the *resourceOption* object + +| Item | Data Type | Description | +|:---- |:---- |:---- | +| memory | long | The total amount of memory currently available on the node (in MB) | +| vcores | long | The total number of vCores currently used on the node | +| overCommitTimeout | long | The timeout to preempt containers | + +### Response Examples + +**JSON response** + +HTTP Request: + + POST http://rm-http-address:port/ws/v1/cluster/nodes/h2:1235/resource + +Response Header: + + HTTP/1.1 200 OK + Content-Type: application/json + Transfer-Encoding: chunked + Server: Jetty(6.1.26) + +Response Body: + +```json +{ + "resourceInfo": + { + "memory": 8192, + "vCores": 5 + } +} +``` + +**XML response** + +HTTP Request: + + GET http://rm-http-address:port/ws/v1/cluster/node/h2:1235/resource + Accept: application/xml + +Response Header: + + HTTP/1.1 200 OK + Content-Type: application/xml + Content-Length: 552 + Server: Jetty(6.1.26) + +Response Body: + +```xml + + + 8192 + 5 + +``` + Cluster Writeable APIs ----------------------