Repository: incubator-slider
Updated Branches:
  refs/heads/develop 8850d062b -> 8267370dc


SLIDER-1201 Slider should make resource normalization configurable for 
app-owners


Project: http://git-wip-us.apache.org/repos/asf/incubator-slider/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-slider/commit/8267370d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-slider/tree/8267370d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-slider/diff/8267370d

Branch: refs/heads/develop
Commit: 8267370dc2b843b29c77a9926eec94faa2803694
Parents: 8850d06
Author: Gour Saha <gourks...@apache.org>
Authored: Thu Feb 2 13:57:49 2017 -0800
Committer: Gour Saha <gourks...@apache.org>
Committed: Thu Feb 2 13:59:34 2017 -0800

----------------------------------------------------------------------
 .../org/apache/slider/api/ResourceKeys.java     |  8 +++
 .../apache/slider/common/tools/SliderUtils.java | 20 ++++++++
 .../server/appmaster/SliderAppMaster.java       | 21 ++++----
 .../slider/server/appmaster/state/AppState.java | 13 +++--
 ...tRoleHistoryOutstandingRequestTracker.groovy | 52 ++++++++++++++++++++
 .../slider/common/tools/TestSliderUtils.java    | 17 +++++++
 6 files changed, 117 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/8267370d/slider-core/src/main/java/org/apache/slider/api/ResourceKeys.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/api/ResourceKeys.java 
b/slider-core/src/main/java/org/apache/slider/api/ResourceKeys.java
index 92890be..d6d8789 100644
--- a/slider-core/src/main/java/org/apache/slider/api/ResourceKeys.java
+++ b/slider-core/src/main/java/org/apache/slider/api/ResourceKeys.java
@@ -72,6 +72,14 @@ public interface ResourceKeys {
   String YARN_CORES = "yarn.vcores";
 
   /**
+   * If normalization is set to false, then if the resource (memory and/or
+   * vcore) requested by a role is higher than YARN limits, then the resource
+   * request is not normalized. If this causes failures at the YARN level then
+   * applications are expecting that to happen. Default value is false.
+   */
+  String YARN_RESOURCE_NORMALIZATION_ENABLED = 
"yarn.resource.normalization.enabled";
+
+  /**
    * Number of disks per instance to ask YARN for
    *  {@value}
    */

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/8267370d/slider-core/src/main/java/org/apache/slider/common/tools/SliderUtils.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/common/tools/SliderUtils.java 
b/slider-core/src/main/java/org/apache/slider/common/tools/SliderUtils.java
index e9f65ba..9638408 100644
--- a/slider-core/src/main/java/org/apache/slider/common/tools/SliderUtils.java
+++ b/slider-core/src/main/java/org/apache/slider/common/tools/SliderUtils.java
@@ -513,6 +513,26 @@ public final class SliderUtils {
   }
 
   /**
+   * Extract the first line of a multi-line string. This is typically used to
+   * prune the stack trace appended to the end of exception messages returned 
by
+   * YARN in AMRMClientAsync callbacks.
+   * 
+   * @param msg
+   *          message string (most likely multi-lines)
+   * @return the first line of a multi-line string or the original string if it
+   *         is a null, empty or single-line
+   */
+  public static String extractFirstLine(String msg) {
+    if (StringUtils.isNotBlank(msg)) {
+      int newlineIndex = msg.indexOf(System.lineSeparator());
+      if (newlineIndex != -1) {
+        msg = msg.substring(0, newlineIndex);
+      }
+    }
+    return msg;
+  }
+
+  /**
    * Create a configuration with Slider-specific tuning.
    * This is done rather than doing custom configs.
    * @return the config

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/8267370d/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
 
b/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
index 8232225..1337ec5 100644
--- 
a/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
+++ 
b/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java
@@ -27,6 +27,7 @@ import com.google.common.base.Preconditions;
 import com.google.protobuf.BlockingService;
 
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.StringUtils;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
 import org.apache.hadoop.fs.Path;
@@ -2060,14 +2061,13 @@ public class SliderAppMaster extends 
AbstractSliderLaunchedService
 
   @Override //AMRMClientAsync
   public void onError(Throwable e) {
-    //callback says it's time to finish
+    // callback says it's time to finish
     LOG_YARN.error("AMRMClientAsync.onError() received {}", e, e);
-    signalAMComplete(new ActionStopSlider("stop",
-        EXIT_EXCEPTION_THROWN,
+    signalAMComplete(new ActionStopSlider("stop", EXIT_EXCEPTION_THROWN,
         FinalApplicationStatus.FAILED,
-        "AMRMClientAsync.onError() received " + e));
+        SliderUtils.extractFirstLine(e.getLocalizedMessage())));
   }
-  
+
 /* =================================================================== */
 /* RMOperationHandlerActions */
 /* =================================================================== */
@@ -2356,13 +2356,13 @@ public class SliderAppMaster extends 
AbstractSliderLaunchedService
 
   /**
    * Handle any exception in a thread. If the exception provides an exit
-   * code, that is the one that will be used
+   * code, that is the one that will be used.
    * @param thread thread throwing the exception
    * @param exception exception
    */
   public void onExceptionInThread(Thread thread, Throwable exception) {
     log.error("Exception in {}: {}", thread.getName(), exception, exception);
-    
+
     // if there is a teardown in progress, ignore it
     if (amCompletionFlag.get()) {
       log.info("Ignoring exception: shutdown in progress");
@@ -2371,10 +2371,9 @@ public class SliderAppMaster extends 
AbstractSliderLaunchedService
       if (exception instanceof ExitCodeProvider) {
         exitCode = ((ExitCodeProvider) exception).getExitCode();
       }
-      signalAMComplete(new ActionStopSlider("stop",
-          exitCode,
-          FinalApplicationStatus.FAILED,
-          exception.toString()));
+      signalAMComplete(
+          new ActionStopSlider("stop", exitCode, FinalApplicationStatus.FAILED,
+              SliderUtils.extractFirstLine(exception.getLocalizedMessage())));
     }
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/8267370d/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AppState.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AppState.java
 
b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AppState.java
index c5fd38c..3db9388 100644
--- 
a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AppState.java
+++ 
b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/AppState.java
@@ -1385,9 +1385,10 @@ public class AppState {
   }
 
   /**
-   * Build up the resource requirements for this role from the
-   * cluster specification, including substituing max allowed values
-   * if the specification asked for it.
+   * Build up the resource requirements for this role from the cluster
+   * specification, including substituting max allowed values if the
+   * specification asked for it (except when
+   * {@link ResourceKeys#YARN_RESOURCE_NORMALIZATION_ENABLED} is set to false).
    * @param role role
    * @param capability capability to set up. A new one may be created
    * during normalization
@@ -1409,6 +1410,12 @@ public class AppState {
                                      containerMaxMemory);
     capability.setMemory(ram);
     log.debug("Component {} has RAM={}, vCores ={}", name, ram, cores);
+    boolean normalize = resources.getComponentOptBool(group,
+        YARN_RESOURCE_NORMALIZATION_ENABLED, true);
+    if (!normalize) {
+      log.info("Resource normalization: disabled");
+      return Resources.createResource(ram, cores);
+    }
     Resource normalized = recordFactory.normalize(capability, minResource,
         maxResource);
     if (!Resources.equals(normalized, capability)) {

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/8267370d/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryOutstandingRequestTracker.groovy
----------------------------------------------------------------------
diff --git 
a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryOutstandingRequestTracker.groovy
 
b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryOutstandingRequestTracker.groovy
index 0969824..7be01ad 100644
--- 
a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryOutstandingRequestTracker.groovy
+++ 
b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryOutstandingRequestTracker.groovy
@@ -18,10 +18,14 @@
 
 package org.apache.slider.server.appmaster.model.history
 
+import groovy.util.logging.Slf4j
 import org.apache.hadoop.yarn.api.records.Resource
+import org.apache.hadoop.yarn.util.resource.Resources
+import org.apache.slider.api.ResourceKeys
 import org.apache.slider.providers.PlacementPolicy
 import org.apache.slider.providers.ProviderRole
 import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest
+import org.apache.slider.server.appmaster.model.mock.MockAppState
 import org.apache.slider.server.appmaster.model.mock.MockPriority
 import org.apache.slider.server.appmaster.model.mock.MockResource
 import org.apache.slider.server.appmaster.operations.AbstractRMOperation
@@ -36,6 +40,7 @@ import 
org.apache.slider.server.appmaster.state.OutstandingRequestTracker
 import org.apache.slider.server.appmaster.state.RoleStatus
 import org.junit.Test
 
+@Slf4j
 class TestRoleHistoryOutstandingRequestTracker extends BaseMockAppStateTest  {
 
   public static final String WORKERS_LABEL = "workers"
@@ -301,6 +306,53 @@ class TestRoleHistoryOutstandingRequestTracker extends 
BaseMockAppStateTest  {
     assert yarnRequest.nodes.size() == 2
   }
 
+  @Test
+  public void testBuildResourceRequirements() throws Throwable {
+    // Store original values
+    def resources = appState.getResourcesSnapshot()
+    def origMem = resources.getComponentOpt(role0Status.group,
+        ResourceKeys.YARN_MEMORY, null)
+    def origVcores = resources.getComponentOpt(role0Status.group,
+        ResourceKeys.YARN_CORES, null)
+
+    // Resource values to be used for this test
+    def testMem = 32768
+    def testVcores = 2
+    resources.setComponentOpt(role0Status.group, ResourceKeys.YARN_MEMORY,
+        Integer.toString(testMem));
+    resources.setComponentOpt(role0Status.group, ResourceKeys.YARN_CORES,
+        Integer.toString(testVcores));
+    
+    // Test normalization disabled
+    log.info("Test normalization: disabled")
+    resources.setComponentOpt(role0Status.group,
+        ResourceKeys.YARN_RESOURCE_NORMALIZATION_ENABLED, "false");
+    def requestedRes = new MockResource(testMem, testVcores)
+    def expectedRes = new MockResource(testMem, testVcores)
+    log.info("Resource requested: " + requestedRes)
+    def resFinal = appState.buildResourceRequirements(role0Status,
+        new MockResource())
+    log.info("Resource actual: " + resFinal)
+    assert Resources.equals(expectedRes, resFinal)
+
+    // Test normalization enabled
+    log.info("Test normalization: enabled")
+    resources.setComponentOpt(role0Status.group,
+        ResourceKeys.YARN_RESOURCE_NORMALIZATION_ENABLED, "true");
+    expectedRes = new MockResource(MockAppState.RM_MAX_RAM, testVcores)
+    log.info("Resource requested: " + requestedRes)
+    resFinal = appState.buildResourceRequirements(role0Status,
+        new MockResource())
+    log.info("Resource actual: " + resFinal)
+    assert Resources.equals(expectedRes, resFinal)
+
+    // revert resource configuration to original value
+    resources.setComponentOpt(role0Status.group, ResourceKeys.YARN_MEMORY,
+        origMem);
+    resources.setComponentOpt(role0Status.group, ResourceKeys.YARN_CORES,
+        origVcores);
+  }
+
   /**
    * Create a new request (always against host1)
    * @param r role status

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/8267370d/slider-core/src/test/java/org/apache/slider/common/tools/TestSliderUtils.java
----------------------------------------------------------------------
diff --git 
a/slider-core/src/test/java/org/apache/slider/common/tools/TestSliderUtils.java 
b/slider-core/src/test/java/org/apache/slider/common/tools/TestSliderUtils.java
index 20e72c0..deca7a8 100644
--- 
a/slider-core/src/test/java/org/apache/slider/common/tools/TestSliderUtils.java
+++ 
b/slider-core/src/test/java/org/apache/slider/common/tools/TestSliderUtils.java
@@ -156,4 +156,21 @@ public class TestSliderUtils {
     SliderUtils.write(testWriteFile, "test".getBytes("UTF-8"), true);
     Assert.assertTrue(FileUtils.readFileToString(testWriteFile, 
"UTF-8").equals("test"));
   }
+
+  @Test
+  public void testExtractFirstLine() {
+    String firstLine = "hello";
+    String msg = firstLine + "\n2nd line\n3rd line";
+    Assert.assertEquals("Should be first line only", firstLine,
+        SliderUtils.extractFirstLine(msg));
+    msg = "";
+    Assert.assertEquals("Should be empty", msg,
+        SliderUtils.extractFirstLine(msg));
+    msg = "   ";
+    Assert.assertEquals("Should contain spaces only", msg,
+        SliderUtils.extractFirstLine(msg));
+    msg = null;
+    Assert.assertEquals("Should be null", msg,
+        SliderUtils.extractFirstLine(msg));
+  }
 }

Reply via email to