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 <[email protected]> Authored: Thu Oct 16 13:58:56 2014 -0700 Committer: Sumit Mohanty <[email protected]> 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" + } + } +}
