diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-api/src/main/java/org/apache/hadoop/yarn/service/client/ApiServiceClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-api/src/main/java/org/apache/hadoop/yarn/service/client/ApiServiceClient.java index 63378dc5a44..3654d4a83bf 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-api/src/main/java/org/apache/hadoop/yarn/service/client/ApiServiceClient.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-api/src/main/java/org/apache/hadoop/yarn/service/client/ApiServiceClient.java @@ -472,18 +472,33 @@ public int actionFlex(String appName, Map componentCounts) throws IOException, YarnException { int result = EXIT_SUCCESS; try { + // We have to check the original number of container of the app + // so that we can do relative changes. + ClientResponse response = getApiClient(getServicePath(appName)) + .get(ClientResponse.class); + if (response.getStatus() == 404 || response.getStatus() != 200) { + throw new YarnException( + MessageFormat.format( + "Fail to check the current application status: {0}", + appName)); + } + Service currentService = jsonSerDeser.fromJson( + response.getEntity(String.class)); Service service = new Service(); service.setName(appName); service.setState(ServiceState.FLEX); for (Map.Entry entry : componentCounts.entrySet()) { Component component = new Component(); component.setName(entry.getKey()); - Long numberOfContainers = Long.parseLong(entry.getValue()); + Long currentNumberOfContainer = currentService.getComponent( + entry.getKey()).getNumberOfContainers(); + Long numberOfContainers = ServiceApiUtil.parseNumberOfContainers( + currentNumberOfContainer, entry.getValue(), entry.getKey()); component.setNumberOfContainers(numberOfContainers); service.addComponent(component); } String buffer = jsonSerDeser.toJson(service); - ClientResponse response = getApiClient(getServicePath(appName)) + response = getApiClient(getServicePath(appName)) .put(ClientResponse.class, buffer); result = processResponse(response); } catch (Exception e) { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-api/src/test/java/org/apache/hadoop/yarn/service/client/TestApiServiceClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-api/src/test/java/org/apache/hadoop/yarn/service/client/TestApiServiceClient.java index 6cf08807c15..e3f99aced9c 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-api/src/test/java/org/apache/hadoop/yarn/service/client/TestApiServiceClient.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-api/src/test/java/org/apache/hadoop/yarn/service/client/TestApiServiceClient.java @@ -16,6 +16,7 @@ */ package org.apache.hadoop.yarn.service.client; +import static org.apache.hadoop.yarn.service.utils.ServiceApiUtil.jsonSerDeser; import static org.junit.Assert.*; import java.io.IOException; @@ -29,6 +30,7 @@ import com.google.common.collect.Lists; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.yarn.exceptions.YarnException; +import org.apache.hadoop.yarn.service.api.records.Service; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.servlet.ServletContextHandler; @@ -62,6 +64,29 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) if (req.getPathInfo() != null && req.getPathInfo().contains("nonexistent-app")) { resp.setStatus(HttpServletResponse.SC_NOT_FOUND); + } else if (req.getPathInfo().contains("flex-app")) { + Service service = jsonSerDeser + .fromJson("{\n" + + " \"name\": \"example-app\",\n" + + " \"version\": \"1.0.0\",\n" + + " \"components\" :\n" + + " [\n" + + " {\n" + + " \"name\": \"simple\",\n" + + " \"number_of_containers\": 1,\n" + + " \"launch_command\": \"sleep 2\",\n" + + " \"resource\": {\n" + + " \"cpus\": 1,\n" + + " \"memory\": \"128\"\n" + + " }\n" + + " }\n" + + " ]\n" + + "}"); + resp.setStatus(HttpServletResponse.SC_OK); + String responseToClient = jsonSerDeser.toJson(service); + resp.getWriter().write(responseToClient); + resp.getWriter().flush(); + resp.getWriter().close(); } else { resp.setStatus(HttpServletResponse.SC_OK); } @@ -230,7 +255,7 @@ public void testBadSave() { @Test public void testFlex() { - String appName = "example-app"; + String appName = "flex-app"; HashMap componentCounts = new HashMap(); try { int result = asc.actionFlex(appName, componentCounts); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/client/ServiceClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/client/ServiceClient.java index 5cdb8c91dc7..153390e3e5b 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/client/ServiceClient.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/client/ServiceClient.java @@ -588,37 +588,16 @@ public int actionFlex(String serviceName, Map throw new IllegalArgumentException(entry.getKey() + " does not exist !"); } long numberOfContainers = - parseNumberOfContainers(component, entry.getValue()); + ServiceApiUtil.parseNumberOfContainers( + component.getNumberOfContainers(), + entry.getValue(), + component.getName()); componentCounts.put(compName, numberOfContainers); } flexComponents(serviceName, componentCounts, persistedService); return EXIT_SUCCESS; } - // Parse the number of containers requested by user, e.g. - // +5 means add 5 additional containers - // -5 means reduce 5 containers, if it goes to negative, sets it to 0 - // 5 means sets it to 5 containers. - private long parseNumberOfContainers(Component component, String newNumber) { - - long orig = component.getNumberOfContainers(); - if (newNumber.startsWith("+")) { - return orig + Long.parseLong(newNumber.substring(1)); - } else if (newNumber.startsWith("-")) { - long ret = orig - Long.parseLong(newNumber.substring(1)); - if (ret < 0) { - LOG.warn(MessageFormat.format( - "[COMPONENT {0}]: component count goes to negative ({1}{2} = {3})," - + " ignore and reset it to 0.", - component.getName(), orig, newNumber, ret)); - ret = 0; - } - return ret; - } else { - return Long.parseLong(newNumber); - } - } - // Called by Rest Service public Map flexByRestService(String serviceName, Map componentCounts) throws YarnException, IOException { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/utils/ServiceApiUtil.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/utils/ServiceApiUtil.java index c681093a306..d163569bdaa 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/utils/ServiceApiUtil.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/utils/ServiceApiUtil.java @@ -784,4 +784,31 @@ public static void checkServiceDependencySatisified(Service service) { } } } + + // Parse the number of containers requested by user, e.g. + // +5 means add 5 additional containers + // -5 means reduce 5 containers, if it goes to negative, sets it to 0 + // 5 means sets it to 5 containers. + public static long parseNumberOfContainers(long orig, + String newNumber, + String compName) { + + if (newNumber.startsWith("+")) { + return orig + Long.parseLong(newNumber.substring(1)); + } else if (newNumber.startsWith("-")) { + long ret = orig - Long.parseLong(newNumber.substring(1)); + if (ret < 0) { + LOG.warn(MessageFormat.format( + "[COMPONENT {0}]: component count goes to " + + " negative ({1}{2} = {3})," + + " ignore and reset it to 0.", + compName, orig, newNumber, ret)); + ret = 0; + } + return ret; + } else { + return Long.parseLong(newNumber); + } + } + } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/test/java/org/apache/hadoop/yarn/service/utils/TestServiceApiUtil.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/test/java/org/apache/hadoop/yarn/service/utils/TestServiceApiUtil.java index 2bf59b8afc8..c4383726618 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/test/java/org/apache/hadoop/yarn/service/utils/TestServiceApiUtil.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/test/java/org/apache/hadoop/yarn/service/utils/TestServiceApiUtil.java @@ -765,6 +765,14 @@ public void run() { Assert.assertTrue(thread.isAlive()); } + @Test + public void testParseNumberOfContainers() { + assertEquals(ServiceApiUtil.parseNumberOfContainers(3, "1", "appName"), 1); + assertEquals(ServiceApiUtil.parseNumberOfContainers(3, "+1", "appName"), 4); + assertEquals(ServiceApiUtil.parseNumberOfContainers(3, "-1", "appName"), 2); + assertEquals(ServiceApiUtil.parseNumberOfContainers(3, "-4", "appName"), 0); + } + public static Service createExampleApplication() { Service exampleApp = new Service();