You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@slider.apache.org by st...@apache.org on 2014/11/02 15:25:48 UTC
[36/50] git commit: SLIDER-587 test for role history on dynamic roles
SLIDER-587 test for role history on dynamic roles
Project: http://git-wip-us.apache.org/repos/asf/incubator-slider/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-slider/commit/34f78ada
Tree: http://git-wip-us.apache.org/repos/asf/incubator-slider/tree/34f78ada
Diff: http://git-wip-us.apache.org/repos/asf/incubator-slider/diff/34f78ada
Branch: refs/heads/feature/SLIDER-531-registry-enhancements
Commit: 34f78ada7282a781dc6e440d9f4e4fd38d455f8d
Parents: 22b4b5e
Author: Steve Loughran <st...@apache.org>
Authored: Fri Oct 31 19:39:16 2014 +0000
Committer: Steve Loughran <st...@apache.org>
Committed: Fri Oct 31 19:39:16 2014 +0000
----------------------------------------------------------------------
.../slider/server/appmaster/state/AppState.java | 30 +--
.../server/appmaster/state/RoleHistory.java | 4 -
.../TestMockAppStateDynamicHistory.groovy | 188 +++++++++++++++++++
.../TestMockAppStateDynamicRoles.groovy | 50 +----
.../appmaster/model/mock/Allocator.groovy | 8 +-
.../model/mock/BaseMockAppStateTest.groovy | 2 +-
6 files changed, 214 insertions(+), 68 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/34f78ada/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 406086a..2b5d0ee 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
@@ -641,33 +641,36 @@ public class AppState {
/**
* The resource configuration is updated -review and update state.
* @param resources updated resources specification
+ * @return a list of any dynamically added provider roles
+ * (purely for testing purposes)
*/
- public synchronized void updateResourceDefinitions(ConfTree resources)
+ public synchronized List<ProviderRole> updateResourceDefinitions(ConfTree resources)
throws BadConfigException, IOException {
log.debug("Updating resources to {}", resources);
instanceDefinition.setResources(resources);
onInstanceDefinitionUpdated();
-
-
+
//propagate the role table
-
Map<String, Map<String, String>> updated = resources.components;
getClusterStatus().roles = SliderUtils.deepClone(updated);
getClusterStatus().updateTime = now();
- buildRoleRequirementsFromResources();
+ return buildRoleRequirementsFromResources();
}
/**
* build the role requirements from the cluster specification
+ * @return a list of any dynamically added provider roles
*/
- private void buildRoleRequirementsFromResources() throws BadConfigException {
+ private List<ProviderRole> buildRoleRequirementsFromResources() throws BadConfigException {
+ List<ProviderRole> newRoles = new ArrayList<ProviderRole>(0);
+
//now update every role's desired count.
//if there are no instance values, that role count goes to zero
ConfTreeOperations resources =
- instanceDefinition.getResourceOperations();
+ instanceDefinition.getResourceOperations();
// Add all the existing roles
for (RoleStatus roleStatus : getRoleStatusMap().values()) {
@@ -678,33 +681,38 @@ public class AppState {
int currentDesired = roleStatus.getDesired();
String role = roleStatus.getName();
MapOperations comp =
- resources.getComponent(role);
+ resources.getComponent(role);
int desiredInstanceCount = getDesiredInstanceCount(resources, role);
if (desiredInstanceCount == 0) {
log.info("Role {} has 0 instances specified", role);
- }
+ }
if (currentDesired != desiredInstanceCount) {
log.info("Role {} flexed from {} to {}", role, currentDesired,
- desiredInstanceCount);
+ desiredInstanceCount);
roleStatus.setDesired(desiredInstanceCount);
}
}
+
//now the dynamic ones. Iterate through the the cluster spec and
//add any role status entries not in the role status
Set<String> roleNames = resources.getComponentNames();
for (String name : roleNames) {
if (!roles.containsKey(name)) {
// this is a new value
- MapOperations component = resources.getComponent(name);
log.info("Adding new role {}", name);
+ MapOperations component = resources.getComponent(name);
ProviderRole dynamicRole = createDynamicProviderRole(name,
component);
RoleStatus roleStatus = buildRole(dynamicRole);
roleStatus.setDesired(getDesiredInstanceCount(resources, name));
log.info("New role {}", roleStatus);
roleHistory.addNewProviderRole(dynamicRole);
+ newRoles.add(dynamicRole);
+ } else {
+ log.debug("known role: {}", name);
}
}
+ return newRoles;
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/34f78ada/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 2b0ee18..33c3442 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
@@ -462,10 +462,6 @@ public class RoleHistory {
}
}
- public synchronized void onAMRestart() {
- //TODO once AM restart is implemented and we know what to expect
- }
-
/**
* Find a node for use
* @param role role
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/34f78ada/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicHistory.groovy
----------------------------------------------------------------------
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicHistory.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicHistory.groovy
new file mode 100644
index 0000000..9a9ad23
--- /dev/null
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicHistory.groovy
@@ -0,0 +1,188 @@
+/*
+ * 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.slider.server.appmaster.model.appstate
+
+import groovy.transform.CompileStatic
+import groovy.util.logging.Slf4j
+import org.apache.hadoop.conf.Configuration
+import org.apache.hadoop.yarn.api.records.ContainerId
+import org.apache.slider.api.ResourceKeys
+import org.apache.slider.core.conf.ConfTreeOperations
+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.MockRoles
+import org.apache.slider.server.appmaster.model.mock.MockYarnEngine
+import org.apache.slider.server.appmaster.operations.ContainerRequestOperation
+import org.apache.slider.server.appmaster.state.AppState
+import org.apache.slider.server.appmaster.state.NodeInstance
+import org.apache.slider.server.appmaster.state.RoleInstance
+import org.apache.slider.server.appmaster.state.SimpleReleaseSelector
+import org.junit.Test
+
+/**
+ * Test that if you have >1 role, the right roles are chosen for release.
+ */
+@CompileStatic
+@Slf4j
+class TestMockAppStateDynamicHistory extends BaseMockAppStateTest
+ implements MockRoles {
+
+ @Override
+ String getTestName() {
+ return "TestMockAppStateDynamicHistory"
+ }
+
+ /**
+ * Small cluster with multiple containers per node,
+ * to guarantee many container allocations on each node
+ * @return
+ */
+ @Override
+ MockYarnEngine createYarnEngine() {
+ return new MockYarnEngine(8, 1)
+ }
+
+ @Override
+ void initApp() {
+ super.initApp()
+ appState = new MockAppState()
+ appState.setContainerLimits(RM_MAX_RAM, RM_MAX_CORES)
+
+ def instance = factory.newInstanceDefinition(0,0,0)
+
+ appState.buildInstance(
+ instance,
+ new Configuration(),
+ new Configuration(false),
+ factory.ROLES,
+ fs,
+ historyPath,
+ null,
+ null, new SimpleReleaseSelector())
+ }
+
+
+ @Test
+ public void testDynamicRoleHistory() throws Throwable {
+
+ def dynamic = "dynamicRole"
+ int priority_num_8 = 8
+ int desired = 1
+ int placementPolicy = 0
+ // snapshot and patch existing spec
+ def resources = ConfTreeOperations.fromInstance(
+ appState.resourcesSnapshot.confTree)
+ def opts = [
+ (ResourceKeys.COMPONENT_INSTANCES): ""+desired,
+ (ResourceKeys.COMPONENT_PRIORITY) : "" +priority_num_8,
+ (ResourceKeys.COMPONENT_PLACEMENT_POLICY): "" + placementPolicy
+ ]
+
+ resources.components[dynamic] = opts
+
+
+ // write the definitions
+ def updates = appState.updateResourceDefinitions(resources.confTree);
+ assert updates.size() == 1
+ def updatedRole = updates[0]
+ assert updatedRole.placementPolicy == placementPolicy
+
+ // verify the new role was persisted
+ def snapshotDefinition = appState.resourcesSnapshot.getMandatoryComponent(
+ dynamic)
+ assert snapshotDefinition.getMandatoryOptionInt(
+ ResourceKeys.COMPONENT_PRIORITY) == priority_num_8
+
+ // now look at the role map
+ assert appState.roleMap[dynamic] != null
+ def mappedRole = appState.roleMap[dynamic]
+ assert mappedRole.id == priority_num_8
+
+ def priorityMap = appState.rolePriorityMap
+ assert priorityMap.size() == 4
+ ProviderRole dynamicProviderRole
+ assert (dynamicProviderRole = priorityMap[priority_num_8]) != null
+ assert dynamicProviderRole.id == priority_num_8
+
+ assert null != appState.roleStatusMap[priority_num_8]
+ def dynamicRoleStatus = appState.roleStatusMap[priority_num_8]
+ assert dynamicRoleStatus.desired == desired
+
+
+ // before allocating the nodes, fill up the capacity of some of the
+ // hosts
+ engine.allocator.nextIndex()
+
+ def targetNode = 2
+ assert targetNode == engine.allocator.nextIndex()
+ def targetHostname = engine.cluster.nodeAt(targetNode).hostname
+
+ // allocate the nodes
+ def actions = appState.reviewRequestAndReleaseNodes()
+ assert actions.size() == 1
+ def action0 = (ContainerRequestOperation)actions[0]
+
+ def request = action0.request
+ assert !request.nodes
+
+ List<ContainerId> released = []
+ List<RoleInstance> allocations = submitOperations(actions, released)
+ processSubmissionOperations(allocations, [], released)
+ assert allocations.size() == 1
+ RoleInstance ri = allocations[0]
+
+ assert ri.role == dynamic
+ assert ri.roleId == priority_num_8
+ assert ri.host.host == targetHostname
+
+ // now look at the role history
+
+ def roleHistory = appState.roleHistory
+ def activeNodes = roleHistory.listActiveNodes(priority_num_8)
+ assert activeNodes.size() == 1
+ NodeInstance activeNode = activeNodes[0]
+
+ assert activeNode.hostname == targetHostname
+
+ // now trigger a termination event on that role
+
+
+ def cid = ri.id
+ // failure
+ AppState.NodeCompletionResult result = appState.onCompletedNode(
+ containerStatus(cid, 1))
+ assert result.roleInstance == ri
+ assert result.containerFailed
+
+ def nodeForNewInstance = roleHistory.findNodeForNewInstance(
+ dynamicRoleStatus)
+ assert nodeForNewInstance
+
+ // make sure new nodes will default to a different host in the engine
+ assert targetNode < engine.allocator.nextIndex()
+
+ actions = appState.reviewRequestAndReleaseNodes()
+ assert actions.size() == 1
+ def action1 = (ContainerRequestOperation) actions[0]
+ def request1 = action1.request
+ assert request1.nodes
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/34f78ada/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicRoles.groovy
----------------------------------------------------------------------
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicRoles.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicRoles.groovy
index 5ef639b..902752c 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicRoles.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicRoles.groovy
@@ -28,7 +28,6 @@ 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.MockRoles
import org.apache.slider.server.appmaster.model.mock.MockYarnEngine
-import org.apache.slider.server.appmaster.operations.AbstractRMOperation
import org.apache.slider.server.appmaster.state.RoleInstance
import org.apache.slider.server.appmaster.state.SimpleReleaseSelector
import org.junit.Test
@@ -86,55 +85,10 @@ class TestMockAppStateDynamicRoles extends BaseMockAppStateTest
@Test
public void testAllocateReleaseRealloc() throws Throwable {
- List<RoleInstance> instances = createAndStartNodes()
- List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes()
+ createAndStartNodes()
+ appState.reviewRequestAndReleaseNodes()
appState.getRoleHistory().dump();
}
-
- @Test
- public void testDynamicRoleHistory() throws Throwable {
-
- // snapshot and patch existing spec
- def resources = ConfTreeOperations.fromInstance(
- appState.resourcesSnapshot.confTree)
-
- def name = "dynamic"
- def dynamicComp = resources.getOrAddComponent(name)
- int priority = 8
- int placement = 3
- dynamicComp.put(ResourceKeys.COMPONENT_PRIORITY, "8")
- dynamicComp.put(ResourceKeys.COMPONENT_INSTANCES, "1")
- dynamicComp.put(ResourceKeys.COMPONENT_PLACEMENT_POLICY, "3")
-
- def component = resources.getComponent(name)
- String priOpt = component.getMandatoryOption(
- ResourceKeys.COMPONENT_PRIORITY);
- int parsedPriority = SliderUtils.parseAndValidate(
- "value of " + name + " " + ResourceKeys.COMPONENT_PRIORITY,
- priOpt, 0, 1, -1);
- assert priority == parsedPriority
-
- def newRole = appState.createDynamicProviderRole(name, component)
- assert newRole.id == priority
-
- appState.updateResourceDefinitions(resources.confTree);
- assert appState.roleMap[name] != null
- def mappedRole = appState.roleMap[name]
- assert mappedRole.id == priority
-
- def priorityMap = appState.rolePriorityMap
- assert priorityMap.size() == 4
- def dynamicProviderRole
- assert (dynamicProviderRole = priorityMap[priority]) != null
- assert dynamicProviderRole.id == priority
-
- // allocate the nodes
- def allocations = createAndStartNodes()
- assert allocations.size() == 1
- RoleInstance ri = allocations[0]
- assert ri.role == name
- assert ri.roleId == priority
- }
}
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/34f78ada/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/Allocator.groovy
----------------------------------------------------------------------
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/Allocator.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/Allocator.groovy
index 639c632..a027098 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/Allocator.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/Allocator.groovy
@@ -51,11 +51,11 @@ class Allocator {
MockContainer allocate(AMRMClient.ContainerRequest request) {
MockYarnCluster.MockYarnClusterNode node = null
MockYarnCluster.MockYarnClusterContainer allocated = null
- if (request.nodes != null) {
+ if (request.nodes) {
for (String host : request.nodes) {
node = cluster.lookup(host)
allocated = node.allocate()
- if (allocated != null) {
+ if (allocated) {
break
}
}
@@ -64,7 +64,7 @@ class Allocator {
if (allocated) {
return createContainerRecord(request, allocated, node)
} else {
- if (request.relaxLocality || request.nodes.isEmpty()) {
+ if (request.relaxLocality || request.nodes.empty) {
// fallback to anywhere
return allocateRandom(request)
} else {
@@ -117,7 +117,7 @@ class Allocator {
return container;
}
- private int nextIndex() {
+ public int nextIndex() {
rollingIndex = (rollingIndex + 1) % cluster.clusterSize;
return rollingIndex;
}
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/34f78ada/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/BaseMockAppStateTest.groovy
----------------------------------------------------------------------
diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/BaseMockAppStateTest.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/BaseMockAppStateTest.groovy
index fa54256..c48d7fa 100644
--- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/BaseMockAppStateTest.groovy
+++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/mock/BaseMockAppStateTest.groovy
@@ -136,7 +136,7 @@ abstract class BaseMockAppStateTest extends SliderTestBase implements MockRoles
Container target = assigned.container
RoleInstance ri = new RoleInstance(target)
ri.roleId = assigned.role.priority
- ri.role = assigned.role
+ ri.role = assigned.role.name
return ri
}