You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@slider.apache.org by sm...@apache.org on 2014/10/16 23:06:06 UTC

git commit: SLIDER-81. Support placement of containers on labeled YARN nodes

Repository: incubator-slider
Updated Branches:
  refs/heads/develop 4dcb62cf2 -> b99019633


SLIDER-81. Support placement of containers on labeled YARN nodes


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

Branch: refs/heads/develop
Commit: b9901963395a710bb67cd8e63c4d1e9d4b7cf96e
Parents: 4dcb62c
Author: Sumit Mohanty <sm...@hortonworks.com>
Authored: Thu Oct 16 13:58:56 2014 -0700
Committer: Sumit Mohanty <sm...@hortonworks.com>
Committed: Thu Oct 16 13:58:56 2014 -0700

----------------------------------------------------------------------
 .../org/apache/slider/api/ResourceKeys.java     | 15 +++++-
 .../slider/core/launch/AbstractLauncher.java    | 13 +++++
 .../slider/core/launch/AppMasterLauncher.java   |  1 +
 .../slider/server/appmaster/state/AppState.java | 26 +++++++--
 .../appmaster/state/OutstandingRequest.java     |  8 +--
 .../server/appmaster/state/RoleHistory.java     | 24 +++++++--
 .../providers/agent/TestBuildBasicAgent.groovy  | 55 +++++++++++++++++++-
 .../TestRoleHistoryRequestTracking.groovy       |  3 +-
 .../agent/tests/good/resources_with_label.json  | 25 +++++++++
 9 files changed, 154 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/b9901963/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 56961c9..f2b9d76 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
@@ -65,10 +65,21 @@ public interface ResourceKeys {
    *  {@value}
    */
   String YARN_CORES = "yarn.vcores";
-  
+
   /** {@value} */
   int DEF_YARN_CORES = 1;
-  
+
+
+  /**
+   * Label expression that this container must satisfy
+   *  {@value}
+   */
+  String YARN_LABEL_EXPRESSION = "yarn.label.expression";
+
+  /** {@value} */
+  String DEF_YARN_LABEL_EXPRESSION = null;
+
+
   /**
    * Constant to indicate that the requirements of a YARN resource limit
    * (cores, memory, ...) should be set to the maximum allowed by

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/b9901963/slider-core/src/main/java/org/apache/slider/core/launch/AbstractLauncher.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/core/launch/AbstractLauncher.java b/slider-core/src/main/java/org/apache/slider/core/launch/AbstractLauncher.java
index 0d0f1c6..0694438 100644
--- a/slider-core/src/main/java/org/apache/slider/core/launch/AbstractLauncher.java
+++ b/slider-core/src/main/java/org/apache/slider/core/launch/AbstractLauncher.java
@@ -384,5 +384,18 @@ public abstract class AbstractLauncher extends Configured {
     addLocalResources(confResources);
   }
 
+  /**
+   * Return the label expression and if not set null
+   * @param map
+   * @return
+   */
+  public String extractLabelExpression(Map<String, String> map) {
+    if (map != null) {
+      MapOperations options = new MapOperations("", map);
+      return options.getOption(ResourceKeys.YARN_LABEL_EXPRESSION, null);
+    }
+    return null;
+  }
+
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/b9901963/slider-core/src/main/java/org/apache/slider/core/launch/AppMasterLauncher.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/core/launch/AppMasterLauncher.java b/slider-core/src/main/java/org/apache/slider/core/launch/AppMasterLauncher.java
index f1eeabd..303f777 100644
--- a/slider-core/src/main/java/org/apache/slider/core/launch/AppMasterLauncher.java
+++ b/slider-core/src/main/java/org/apache/slider/core/launch/AppMasterLauncher.java
@@ -96,6 +96,7 @@ public class AppMasterLauncher extends AbstractLauncher {
     if (!applicationTags.isEmpty()) {
       submissionContext.setApplicationTags(applicationTags);
     }
+    submissionContext.setNodeLabelExpression(extractLabelExpression(options));
     extractResourceRequirements(resource, options);
     extractLogAggregationContext(resourceGlobalOptions);
   }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/b9901963/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 63032b0..706b0d2 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
@@ -77,8 +77,10 @@ import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import static org.apache.slider.api.ResourceKeys.DEF_YARN_CORES;
+import static org.apache.slider.api.ResourceKeys.DEF_YARN_LABEL_EXPRESSION;
 import static org.apache.slider.api.ResourceKeys.DEF_YARN_MEMORY;
 import static org.apache.slider.api.ResourceKeys.YARN_CORES;
+import static org.apache.slider.api.ResourceKeys.YARN_LABEL_EXPRESSION;
 import static org.apache.slider.api.ResourceKeys.YARN_MEMORY;
 import static org.apache.slider.api.RoleKeys.ROLE_FAILED_INSTANCES;
 import static org.apache.slider.api.RoleKeys.ROLE_FAILED_STARTING_INSTANCES;
@@ -1050,9 +1052,10 @@ public class AppState {
         RoleStatus role,
         Resource capability) {
     buildResourceRequirements(role, capability);
+    String labelExpression = getLabelExpression(role);
     //get the role history to select a suitable node, if available
     AMRMClient.ContainerRequest containerRequest =
-    createContainerRequest(role, capability);
+      createContainerRequest(role, capability, labelExpression);
     return  containerRequest;
   }
 
@@ -1062,15 +1065,16 @@ public class AppState {
    * This is where role history information will be used for placement decisions -
    * @param role role
    * @param resource requirements
+   * @param labelExpression label expression to satisfy
    * @return the container request to submit
    */
   public AMRMClient.ContainerRequest createContainerRequest(RoleStatus role,
-                                                            Resource resource) {
+                                                            Resource resource,
+                                                            String labelExpression) {
     
     
     AMRMClient.ContainerRequest request;
-    int key = role.getKey();
-    request = roleHistory.requestNode(role, resource);
+    request = roleHistory.requestNode(role, resource, labelExpression);
     role.incRequested();
 
     return request;
@@ -1105,6 +1109,7 @@ public class AppState {
     }
     return intVal;
   }
+
   
   /**
    * Build up the resource requirements for this role from the
@@ -1131,6 +1136,17 @@ public class AppState {
   }
 
   /**
+   * Extract the label expression for this role.
+   * @param role role
+   */
+  public String getLabelExpression(RoleStatus role) {
+    // Set up resource requirements from role values
+    String name = role.getName();
+    ConfTreeOperations resources = getResourcesSnapshot();
+    return resources.getComponentOpt(name, YARN_LABEL_EXPRESSION, DEF_YARN_LABEL_EXPRESSION);
+  }
+
+  /**
    * add a launched container to the node map for status responses
    * @param container id
    * @param node node details
@@ -1614,7 +1630,7 @@ public class AppState {
         Resource capability = recordFactory.newResource();
         AMRMClient.ContainerRequest containerAsk =
           buildContainerResourceAndRequest(role, capability);
-        log.info("Container ask is {}", containerAsk);
+        log.info("Container ask is {} and label = {}", containerAsk, containerAsk.getNodeLabelExpression());
         if (containerAsk.getCapability().getMemory() >
             this.containerMaxMemory) {
           log.warn(

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/b9901963/slider-core/src/main/java/org/apache/slider/server/appmaster/state/OutstandingRequest.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/OutstandingRequest.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/OutstandingRequest.java
index 0d8b56c..4a05a1a 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/OutstandingRequest.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/OutstandingRequest.java
@@ -97,10 +97,11 @@ public final class OutstandingRequest {
    * @param resource resource
    * @param role role
    * @param time: time to record
+   * @param labelExpression label to satisfy
    * @return the request to raise
    */
   public AMRMClient.ContainerRequest buildContainerRequest(Resource resource,
-      RoleStatus role, long time) {
+      RoleStatus role, long time, String labelExpression) {
     String[] hosts;
     boolean relaxLocality;
     requestedTime = time;
@@ -122,8 +123,9 @@ public final class OutstandingRequest {
                                       hosts,
                                       null,
                                       pri,
-                                      relaxLocality);
-    
+                                      relaxLocality,
+                                      labelExpression);
+
     return request;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/b9901963/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleHistory.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleHistory.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleHistory.java
index e82162f..dca7384 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleHistory.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/RoleHistory.java
@@ -233,7 +233,7 @@ public class RoleHistory {
 
   /**
    * Get the node instance for the specific node -creating it if needed
-   * @param nodeAddr node address
+   * @param hostname node address
    * @return the instance
    */
   public synchronized NodeInstance getOrCreateNodeInstance(String hostname) {
@@ -495,12 +495,28 @@ public class RoleHistory {
    *
    * @param node node to target or null for "any"
    * @param role role to request
+   * @param labelExpression label to satisfy
    * @return the container priority
    */
   public synchronized AMRMClient.ContainerRequest requestInstanceOnNode(
-    NodeInstance node, RoleStatus role, Resource resource) {
+    NodeInstance node, RoleStatus role, Resource resource, String labelExpression) {
     OutstandingRequest outstanding = outstandingRequests.addRequest(node, role.getKey());
-    return outstanding.buildContainerRequest(resource, role, now());
+    return outstanding.buildContainerRequest(resource, role, now(), labelExpression);
+  }
+
+  /**
+   * Find a node for a role and request an instance on that (or a location-less
+   * instance) with a label expression
+   * @param role role status
+   * @param resource resource capabilities
+   * @param labelExpression label to satisfy
+   * @return a request ready to go
+   */
+  public synchronized AMRMClient.ContainerRequest requestNode(RoleStatus role,
+                                                              Resource resource,
+                                                              String labelExpression) {
+    NodeInstance node = findNodeForNewInstance(role);
+    return requestInstanceOnNode(node, role, resource, labelExpression);
   }
 
   /**
@@ -513,7 +529,7 @@ public class RoleHistory {
   public synchronized AMRMClient.ContainerRequest requestNode(RoleStatus role,
                                                               Resource resource) {
     NodeInstance node = findNodeForNewInstance(role);
-    return requestInstanceOnNode(node, role, resource);
+    return requestInstanceOnNode(node, role, resource, null);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/b9901963/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestBuildBasicAgent.groovy
----------------------------------------------------------------------
diff --git a/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestBuildBasicAgent.groovy b/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestBuildBasicAgent.groovy
index d0129c5..7e352e9 100644
--- a/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestBuildBasicAgent.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/providers/agent/TestBuildBasicAgent.groovy
@@ -243,7 +243,60 @@ class TestBuildBasicAgent extends AgentTestBase {
         true, false,
         false)
   }
-  
+
+  @Test
+  public void testLabelExpressionArgs() throws Throwable {
+    String clustername = createMiniCluster(
+        "",
+        configuration,
+        1,
+        1,
+        1,
+        true,
+        false)
+
+    try {
+      buildAgentCluster(clustername,
+          [:],
+          [
+              ARG_OPTION, CONTROLLER_URL, "http://localhost",
+              ARG_PACKAGE, ".",
+              ARG_OPTION, APP_DEF, "file://" + appDef.absolutePath,
+              ARG_RESOURCES, TEST_FILES + "good/resources_with_label.json",
+              ARG_TEMPLATE, TEST_FILES + "good/appconf.json"
+          ],
+          true, false,
+          false)
+    } catch (BadConfigException exception) {
+      log.error(
+          "Build operation should not have failed with exception : \n$exception")
+      fail("Build operation should not fail")
+    }
+
+    AggregateConf instanceDefinition = loadInstanceDefinition(clustername)
+    def opt = instanceDefinition.getResourceOperations().getComponentOpt(
+        "echo",
+        ResourceKeys.YARN_LABEL_EXPRESSION,
+        null)
+    assert opt == null, "Expect null"
+
+    opt = instanceDefinition.getResourceOperations().getComponentOpt(
+        "hbase-master",
+        ResourceKeys.YARN_LABEL_EXPRESSION,
+        null)
+    assert opt == "", "Expect empty string"
+
+    opt = instanceDefinition.getResourceOperations().getComponentOpt(
+        "hbase-rs",
+        ResourceKeys.YARN_LABEL_EXPRESSION,
+        null)
+    assert opt == "coquelicot && amaranth", "Expect colors you have not heard of"
+
+    def label = instanceDefinition.getInternalOperations().get(
+        InternalKeys.INTERNAL_QUEUE)
+    assert label == null, "Default queue expected"
+  }
+
   @Test
   public void testUpdateBasicAgent() throws Throwable {
 

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/b9901963/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRequestTracking.groovy
----------------------------------------------------------------------
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRequestTracking.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRequestTracking.groovy
index 0a2ba60..8f577e5 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRequestTracking.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/history/TestRoleHistoryRequestTracking.groovy
@@ -77,7 +77,8 @@ class TestRoleHistoryRequestTracking extends BaseMockAppStateTest {
     assert age3Active0 == ni
     AMRMClient.ContainerRequest req = roleHistory.requestInstanceOnNode(ni,
                                                                         roleStatus,
-                                                                        resource)
+                                                                        resource,
+                                                                        "")
     List<NodeInstance> a2 = roleHistory.cloneAvailableList(0)
     assertListEquals([age2Active0], a2)
   }

http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/b9901963/slider-core/src/test/resources/org/apache/slider/providers/agent/tests/good/resources_with_label.json
----------------------------------------------------------------------
diff --git a/slider-core/src/test/resources/org/apache/slider/providers/agent/tests/good/resources_with_label.json b/slider-core/src/test/resources/org/apache/slider/providers/agent/tests/good/resources_with_label.json
new file mode 100644
index 0000000..a2ce107
--- /dev/null
+++ b/slider-core/src/test/resources/org/apache/slider/providers/agent/tests/good/resources_with_label.json
@@ -0,0 +1,25 @@
+{
+  "schema": "http://example.org/specification/v2.0.0",
+
+  "global": {
+  },
+  "components": {
+    "echo": {
+      "yarn.memory": "256",
+      "yarn.component.instances": "1",
+      "yarn.role.priority":"1"
+    },
+    "hbase-master": {
+      "yarn.memory": "257",
+      "yarn.component.instances": "1",
+      "yarn.role.priority":"2",
+      "yarn.label.expression":""
+    },
+    "hbase-rs": {
+      "yarn.memory": "258",
+      "yarn.component.instances": "0",
+      "yarn.role.priority":"4",
+      "yarn.label.expression":"coquelicot && amaranth"
+    }
+  }
+}