SLIDER-296 ContainerReleaseSelectors have the job of choosing containers to release.
Project: http://git-wip-us.apache.org/repos/asf/incubator-slider/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-slider/commit/5ce953ca Tree: http://git-wip-us.apache.org/repos/asf/incubator-slider/tree/5ce953ca Diff: http://git-wip-us.apache.org/repos/asf/incubator-slider/diff/5ce953ca Branch: refs/heads/feature/SLIDER-151_REST_API Commit: 5ce953ca301a90e27b1cbe193a482a9cb83c3084 Parents: 32fd3f5 Author: Steve Loughran <ste...@apache.org> Authored: Wed Aug 6 16:58:27 2014 +0100 Committer: Steve Loughran <ste...@apache.org> Committed: Wed Aug 6 16:58:27 2014 +0100 ---------------------------------------------------------------------- .../apache/slider/common/tools/Comparators.java | 58 ++++++ .../providers/AbstractProviderService.java | 18 +- .../slider/providers/ProviderService.java | 12 +- .../server/appmaster/SliderAppMaster.java | 4 +- .../slider/server/appmaster/state/AppState.java | 134 +++++++++---- .../state/ContainerReleaseSelector.java | 38 ++++ .../MostRecentContainerReleaseSelector.java | 52 +++++ .../appmaster/state/SimpleReleaseSelector.java | 34 ++++ .../TestAppStateContainerFailure.groovy | 166 ---------------- .../appstate/TestAppStateDynamicRoles.groovy | 93 --------- .../TestAppStateRebuildOnAMRestart.groovy | 124 ------------ .../appstate/TestAppStateRolePlacement.groovy | 99 ---------- .../appstate/TestAppStateRoleRelease.groovy | 82 -------- .../TestContainerResourceAllocations.groovy | 108 ----------- .../model/appstate/TestFlexDynamicRoles.groovy | 189 ------------------ .../TestMockAppStateContainerFailure.groovy | 166 ++++++++++++++++ .../TestMockAppStateDynamicRoles.groovy | 94 +++++++++ .../TestMockAppStateFlexDynamicRoles.groovy | 190 +++++++++++++++++++ .../appstate/TestMockAppStateFlexing.groovy | 126 ++++++++++++ .../TestMockAppStateRMOperations.groovy | 176 +++++++++++++++++ .../TestMockAppStateRebuildOnAMRestart.groovy | 124 ++++++++++++ .../TestMockAppStateRolePlacement.groovy | 99 ++++++++++ .../appstate/TestMockAppStateRoleRelease.groovy | 82 ++++++++ .../TestMockContainerResourceAllocations.groovy | 108 +++++++++++ .../model/appstate/TestMockFlexing.groovy | 128 ------------- .../model/appstate/TestMockRMOperations.groovy | 176 ----------------- .../model/mock/BaseMockAppStateTest.groovy | 2 +- .../model/mock/MockProviderService.groovy | 56 +++--- .../web/rest/agent/TestAMAgentWebServices.java | 3 +- .../management/TestAMManagementWebServices.java | 3 +- 30 files changed, 1510 insertions(+), 1234 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/slider-core/src/main/java/org/apache/slider/common/tools/Comparators.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/common/tools/Comparators.java b/slider-core/src/main/java/org/apache/slider/common/tools/Comparators.java new file mode 100644 index 0000000..0ccca0f --- /dev/null +++ b/slider-core/src/main/java/org/apache/slider/common/tools/Comparators.java @@ -0,0 +1,58 @@ +/* + * 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.common.tools; + +import java.io.Serializable; +import java.util.Comparator; + +public class Comparators { + + public static class LongComparator implements Comparator<Long>, Serializable { + @Override + public int compare(Long o1, Long o2) { + long result = o1 - o2; + // need to comparisons with a diff greater than integer size + if (result < 0 ) { + return -1; + } else if (result >0) { + return 1; + } + return 0; + } + } + + /** + * Little template class to reverse any comparitor + * @param <CompareType> the type that is being compared + */ + public static class ComparatorReverser<CompareType> implements Comparator<CompareType>, + Serializable { + + final Comparator<CompareType> instance; + + public ComparatorReverser(Comparator<CompareType> instance) { + this.instance = instance; + } + + @Override + public int compare(CompareType first, CompareType second) { + return instance.compare(second, first); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/slider-core/src/main/java/org/apache/slider/providers/AbstractProviderService.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/providers/AbstractProviderService.java b/slider-core/src/main/java/org/apache/slider/providers/AbstractProviderService.java index 7639625..7483a8d 100644 --- a/slider-core/src/main/java/org/apache/slider/providers/AbstractProviderService.java +++ b/slider-core/src/main/java/org/apache/slider/providers/AbstractProviderService.java @@ -32,6 +32,8 @@ import org.apache.slider.core.main.ExitCodeProvider; import org.apache.slider.core.registry.info.RegisteredEndpoint; import org.apache.slider.core.registry.info.ServiceInstanceData; import org.apache.slider.server.appmaster.AMViewForProviders; +import org.apache.slider.server.appmaster.state.ContainerReleaseSelector; +import org.apache.slider.server.appmaster.state.MostRecentContainerReleaseSelector; import org.apache.slider.server.appmaster.state.StateAccessForProviders; import org.apache.slider.server.appmaster.web.rest.agent.AgentRestOperations; import org.apache.slider.server.services.registry.RegistryViewForProviders; @@ -318,11 +320,21 @@ public abstract class AbstractProviderService } @Override public void applyInitialRegistryDefinitions(URL unsecureWebAPI, - URL secureWebAPI, - ServiceInstanceData registryInstanceData) throws MalformedURLException, - IOException { + URL secureWebAPI, + ServiceInstanceData registryInstanceData) throws IOException { this.amWebAPI = unsecureWebAPI; this.registryInstanceData = registryInstanceData; } + + /** + * {@inheritDoc} + * + * + * @return The base implementation returns the most recent containers first. + */ + @Override + public ContainerReleaseSelector createContainerReleaseSelector() { + return new MostRecentContainerReleaseSelector(); + } } http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/slider-core/src/main/java/org/apache/slider/providers/ProviderService.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/providers/ProviderService.java b/slider-core/src/main/java/org/apache/slider/providers/ProviderService.java index b9fa34c..4278b09 100644 --- a/slider-core/src/main/java/org/apache/slider/providers/ProviderService.java +++ b/slider-core/src/main/java/org/apache/slider/providers/ProviderService.java @@ -33,6 +33,7 @@ import org.apache.slider.core.launch.ContainerLauncher; import org.apache.slider.core.main.ExitCodeProvider; import org.apache.slider.core.registry.info.ServiceInstanceData; import org.apache.slider.server.appmaster.AMViewForProviders; +import org.apache.slider.server.appmaster.state.ContainerReleaseSelector; import org.apache.slider.server.appmaster.state.StateAccessForProviders; import org.apache.slider.server.appmaster.web.rest.agent.AgentRestOperations; import org.apache.slider.server.services.registry.RegistryViewForProviders; @@ -172,6 +173,13 @@ public interface ProviderService extends ProviderCore, Service, */ void applyInitialRegistryDefinitions(URL unsecureWebAPI, URL secureWebAPI, - ServiceInstanceData registryInstanceData) throws MalformedURLException, - IOException; + ServiceInstanceData registryInstanceData) + throws IOException; + + /** + * Create the container release selector for this provider...any policy + * can be implemented + * @return the selector to use for choosing containers. + */ + ContainerReleaseSelector createContainerReleaseSelector(); } http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/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 b3650ca..dbf08e1 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 @@ -105,6 +105,7 @@ import org.apache.slider.server.appmaster.state.ProviderAppState; import org.apache.slider.server.appmaster.state.RMOperationHandler; import org.apache.slider.server.appmaster.state.RoleInstance; import org.apache.slider.server.appmaster.state.RoleStatus; +import org.apache.slider.server.appmaster.state.SimpleReleaseSelector; import org.apache.slider.server.appmaster.web.AgentService; import org.apache.slider.server.appmaster.web.rest.agent.AgentWebApp; import org.apache.slider.server.appmaster.web.SliderAMWebApp; @@ -677,7 +678,8 @@ public class SliderAppMaster extends AbstractSliderLaunchedService fs.getFileSystem(), historyDir, liveContainers, - appInformation); + appInformation, + new SimpleReleaseSelector()); // add the AM to the list of nodes in the cluster http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/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 08d43db..c20c924 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 @@ -18,7 +18,9 @@ package org.apache.slider.server.appmaster.state; +import com.beust.jcommander.internal.Lists; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; @@ -63,7 +65,9 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -251,6 +255,8 @@ public class AppState { private int failureThreshold = 10; private String logServerURL = ""; + + private ContainerReleaseSelector containerReleaseSelector; public AppState(AbstractRecordFactory recordFactory) { this.recordFactory = recordFactory; @@ -440,22 +446,27 @@ public class AppState { * @param historyDir directory containing history files * @param liveContainers list of live containers supplied on an AM restart * @param applicationInfo + * @param releaseSelector */ public synchronized void buildInstance(AggregateConf instanceDefinition, - Configuration appmasterConfig, Configuration publishedProviderConf, + Configuration appmasterConfig, + Configuration publishedProviderConf, List<ProviderRole> providerRoles, FileSystem fs, Path historyDir, List<Container> liveContainers, - Map<String, String> applicationInfo) throws - BadClusterStateException, - BadConfigException, - IOException { + Map<String, String> applicationInfo, + SimpleReleaseSelector releaseSelector) + throws BadClusterStateException, BadConfigException, IOException { + Preconditions.checkArgument(instanceDefinition != null); + Preconditions.checkArgument(releaseSelector != null); + this.publishedProviderConf = publishedProviderConf; - this.applicationInfo = applicationInfo != null ? applicationInfo - : new HashMap<String, String>(); + this.applicationInfo = applicationInfo != null ? applicationInfo + : new HashMap<String, String>(); clientProperties = new HashMap<>(); + containerReleaseSelector = releaseSelector; Set<String> confKeys = ConfigHelper.sortedConfigKeys(publishedProviderConf); @@ -465,8 +476,8 @@ public class AppState { String val = publishedProviderConf.get(key); clientProperties.put(key, val); } - - + + // set the cluster specification (once its dependency the client properties // is out the way @@ -479,15 +490,16 @@ public class AppState { } ConfTreeOperations resources = - instanceDefinition.getResourceOperations(); - + instanceDefinition.getResourceOperations(); + Set<String> roleNames = resources.getComponentNames(); for (String name : roleNames) { if (!roles.containsKey(name)) { // this is a new value log.info("Adding new role {}", name); MapOperations resComponent = resources.getComponent(name); - ProviderRole dynamicRole = createDynamicProviderRole(name, resComponent); + ProviderRole dynamicRole = + createDynamicProviderRole(name, resComponent); buildRole(dynamicRole); providerRoles.add(dynamicRole); } @@ -498,24 +510,24 @@ public class AppState { //set the livespan MapOperations globalInternalOpts = - instanceDefinition.getInternalOperations().getGlobalOptions(); + instanceDefinition.getInternalOperations().getGlobalOptions(); startTimeThreshold = globalInternalOpts.getOptionInt( - OptionKeys.INTERNAL_CONTAINER_FAILURE_SHORTLIFE, - OptionKeys.DEFAULT_CONTAINER_FAILURE_SHORTLIFE); - + OptionKeys.INTERNAL_CONTAINER_FAILURE_SHORTLIFE, + OptionKeys.DEFAULT_CONTAINER_FAILURE_SHORTLIFE); + failureThreshold = globalInternalOpts.getOptionInt( - OptionKeys.INTERNAL_CONTAINER_FAILURE_THRESHOLD, - OptionKeys.DEFAULT_CONTAINER_FAILURE_THRESHOLD); + OptionKeys.INTERNAL_CONTAINER_FAILURE_THRESHOLD, + OptionKeys.DEFAULT_CONTAINER_FAILURE_THRESHOLD); initClusterStatus(); // add the roles roleHistory = new RoleHistory(providerRoles); roleHistory.onStart(fs, historyDir); - + //rebuild any live containers rebuildModelFromRestart(liveContainers); - + // any am config options to pick up logServerURL = appmasterConfig.get(YarnConfiguration.YARN_LOG_SERVER_URL, @@ -845,6 +857,27 @@ public class AppState { return nodes; } + + /** + * enum nodes by role ID, from either the active or live node list + * @param roleId role the container must be in + * @param active flag to indicate "use active list" rather than the smaller + * "live" list + * @return a list of nodes, may be empty + */ + public synchronized List<RoleInstance> enumNodesWithRoleId(int roleId, + boolean active) { + List<RoleInstance> nodes = new ArrayList<>(); + Collection<RoleInstance> allRoleInstances; + allRoleInstances = active? activeContainers.values() : liveNodes.values(); + for (RoleInstance node : allRoleInstances) { + if (node.roleId == roleId) { + nodes.add(node); + } + } + return nodes; + } + /** * Build an instance map. @@ -911,19 +944,19 @@ public class AppState { throws SliderInternalStateException { ContainerId id = container.getId(); //look up the container - RoleInstance info = getActiveContainer(id); - if (info == null) { + RoleInstance instance = getActiveContainer(id); + if (instance == null) { throw new SliderInternalStateException( - "No active container with ID " + id.toString()); + "No active container with ID " + id); } //verify that it isn't already released if (containersBeingReleased.containsKey(id)) { throw new SliderInternalStateException( "Container %s already queued for release", id); } - info.released = true; - containersBeingReleased.put(id, info.container); - RoleStatus role = lookupRoleStatus(info.roleId); + instance.released = true; + containersBeingReleased.put(id, instance.container); + RoleStatus role = lookupRoleStatus(instance.roleId); role.incReleasing(); roleHistory.onContainerReleaseSubmitted(container); } @@ -1229,8 +1262,8 @@ public class AppState { if (shortLived) { roleStatus.incStartFailed(); } - - if (failedContainer!= null) { + + if (failedContainer != null) { roleHistory.onFailedContainer(failedContainer, shortLived); } @@ -1485,18 +1518,43 @@ public class AppState { // get the nodes to release int roleId = role.getKey(); - List<NodeInstance> nodesForRelease = - roleHistory.findNodesForRelease(roleId, excess); - - for (NodeInstance node : nodesForRelease) { - RoleInstance possible = findRoleInstanceOnHost(node, roleId); - if (possible == null) { - throw new SliderInternalStateException( - "Failed to find a container to release on node %s", node.hostname); + + // enum all active nodes that aren't being released + List<RoleInstance> containersToRelease = enumNodesWithRoleId(roleId, true); + + // cut all release-in-progress nodes + ListIterator<RoleInstance> li = containersToRelease.listIterator(); + while (li.hasNext()) { + RoleInstance next = li.next(); + if (next.released) { + li.remove(); } - containerReleaseSubmitted(possible.container); - operations.add(new ContainerReleaseOperation(possible.getId())); + } + + // warn if the desired state can't be reaced + if (containersToRelease.size() < excess) { + log.warn("Not enough nodes to release...short of {} nodes", + containersToRelease.size() - excess); + } + + // ask the release selector to sort the targets + containersToRelease = containerReleaseSelector.sortCandidates( + roleId, + containersToRelease, + excess); + + //crop to the excess + List<RoleInstance> finalCandidates = (excess < containersToRelease.size()) + ? containersToRelease.subList(0, excess) + : containersToRelease; + + + // then build up a release operation, logging each container as released + for (RoleInstance possible : finalCandidates) { + log.debug("Targeting for release: {}", possible); + containerReleaseSubmitted(possible.container); + operations.add(new ContainerReleaseOperation(possible.getId())); } } http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerReleaseSelector.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerReleaseSelector.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerReleaseSelector.java new file mode 100644 index 0000000..0cbc134 --- /dev/null +++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/ContainerReleaseSelector.java @@ -0,0 +1,38 @@ +/* + * 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.state; + +import java.util.List; + +/** + * Interface implemented by anything that must choose containers to release + * + */ +public interface ContainerReleaseSelector { + + /** + * Given a list of candidate containers, return a sorted version of the priority + * in which they should be released. + * @param candidates candidate list ... everything considered suitable + * @return + */ + List<RoleInstance> sortCandidates(int roleId, + List<RoleInstance> candidates, + int minimumToSelect); +} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/slider-core/src/main/java/org/apache/slider/server/appmaster/state/MostRecentContainerReleaseSelector.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/MostRecentContainerReleaseSelector.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/MostRecentContainerReleaseSelector.java new file mode 100644 index 0000000..9d936a1 --- /dev/null +++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/MostRecentContainerReleaseSelector.java @@ -0,0 +1,52 @@ +/* + * 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.state; + +import org.apache.slider.common.tools.Comparators; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * Sort the candidate list by the most recent container first. + */ +public class MostRecentContainerReleaseSelector implements ContainerReleaseSelector { + + @Override + public List<RoleInstance> sortCandidates(int roleId, + List<RoleInstance> candidates, + int minimumToSelect) { + Collections.sort(candidates, new newerThan()); + return candidates; + } + + private static class newerThan implements Comparator<RoleInstance>, Serializable { + private final Comparator<Long> innerComparator = + new Comparators.ComparatorReverser<>(new Comparators.LongComparator()); + public int compare(RoleInstance o1, RoleInstance o2) { + return innerComparator.compare(o1.createTime, o2.createTime); + + } + + } + + +} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/slider-core/src/main/java/org/apache/slider/server/appmaster/state/SimpleReleaseSelector.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/state/SimpleReleaseSelector.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/SimpleReleaseSelector.java new file mode 100644 index 0000000..b7f0e05 --- /dev/null +++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/state/SimpleReleaseSelector.java @@ -0,0 +1,34 @@ +/* + * 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.state; + +import java.util.List; + +/** + * Simplest release selector simply returns the list + */ +public class SimpleReleaseSelector implements ContainerReleaseSelector { + + @Override + public List<RoleInstance> sortCandidates(int roleId, + List<RoleInstance> candidates, + int minimumToSelect) { + return candidates; + } +} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateContainerFailure.groovy ---------------------------------------------------------------------- diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateContainerFailure.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateContainerFailure.groovy deleted file mode 100644 index 9c17763..0000000 --- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateContainerFailure.groovy +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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.yarn.api.records.ContainerId -import org.apache.slider.core.exceptions.SliderException -import org.apache.slider.core.exceptions.TriggerClusterTeardownException -import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest -import org.apache.slider.server.appmaster.model.mock.MockRoles -import org.apache.slider.server.appmaster.model.mock.MockYarnEngine -import org.apache.slider.server.appmaster.state.* -import org.junit.Test - -/** - * Test that if you have >1 role, the right roles are chosen for release. - */ -@CompileStatic -@Slf4j -class TestAppStateContainerFailure extends BaseMockAppStateTest - implements MockRoles { - - @Override - String getTestName() { - return "TestAppStateContainerFailure" - } - - /** - * Small cluster with multiple containers per node, - * to guarantee many container allocations on each node - * @return - */ - @Override - MockYarnEngine createYarnEngine() { - return new MockYarnEngine(8000, 4) - } - - @Test - public void testShortLivedFail() throws Throwable { - - role0Status.desired = 1 - List<RoleInstance> instances = createAndStartNodes() - assert instances.size() == 1 - - RoleInstance instance = instances[0] - long created = instance.createTime - long started = instance.startTime - assert created > 0 - assert started >= created - List<ContainerId> ids = extractContainerIds(instances, 0) - - ContainerId cid = ids[0] - assert appState.isShortLived(instance) - AppState.NodeCompletionResult result = appState.onCompletedNode(containerStatus(cid, 1)) - assert result.roleInstance != null - assert result.containerFailed - RoleStatus status = role0Status - assert status.failed == 1 - assert status.startFailed == 1 - - //view the world - appState.getRoleHistory().dump(); - List<NodeInstance> queue = appState.roleHistory.cloneAvailableList(0) - assert queue.size() == 0 - - } - - @Test - public void testLongLivedFail() throws Throwable { - - role0Status.desired = 1 - List<RoleInstance> instances = createAndStartNodes() - assert instances.size() == 1 - - RoleInstance instance = instances[0] - instance.startTime = System.currentTimeMillis() - 60 * 60 * 1000; - assert !appState.isShortLived(instance) - List<ContainerId> ids = extractContainerIds(instances, 0) - - ContainerId cid = ids[0] - AppState.NodeCompletionResult result = appState.onCompletedNode( - containerStatus(cid, 1)) - assert result.roleInstance != null - assert result.containerFailed - RoleStatus status = role0Status - assert status.failed == 1 - assert status.startFailed == 0 - - //view the world - appState.getRoleHistory().dump(); - List<NodeInstance> queue = appState.roleHistory.cloneAvailableList(0) - assert queue.size() == 1 - - } - - @Test - public void testNodeStartFailure() throws Throwable { - - role0Status.desired = 1 - List<RoleInstance> instances = createAndSubmitNodes() - assert instances.size() == 1 - - RoleInstance instance = instances[0] - - List<ContainerId> ids = extractContainerIds(instances, 0) - - ContainerId cid = ids[0] - appState.onNodeManagerContainerStartFailed(cid, new SliderException("oops")) - RoleStatus status = role0Status - assert status.failed == 1 - assert status.startFailed == 1 - - - RoleHistory history = appState.roleHistory - history.dump(); - List<NodeInstance> queue = history.cloneAvailableList(0) - assert queue.size() == 0 - - NodeInstance ni = history.getOrCreateNodeInstance(instance.container) - NodeEntry re = ni.get(0) - assert re.failed == 1 - assert re.startFailed == 1 - } - - @Test - public void testRecurrentStartupFailure() throws Throwable { - - role0Status.desired = 1 - try { - for (int i = 0; i< 100; i++) { - List<RoleInstance> instances = createAndSubmitNodes() - assert instances.size() == 1 - - List<ContainerId> ids = extractContainerIds(instances, 0) - - ContainerId cid = ids[0] - log.info("$i instance $instances[0] $cid") - assert cid - appState.onNodeManagerContainerStartFailed(cid, new SliderException("oops")) - AppState.NodeCompletionResult result = appState.onCompletedNode(containerStatus(cid)) - assert result.containerFailed - } - fail("Cluster did not fail from too many startup failures") - } catch (TriggerClusterTeardownException teardown) { - log.info("Exception $teardown.exitCode : $teardown") - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateDynamicRoles.groovy ---------------------------------------------------------------------- diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateDynamicRoles.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateDynamicRoles.groovy deleted file mode 100644 index 6d70885..0000000 --- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateDynamicRoles.groovy +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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.slider.api.ResourceKeys -import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest -import org.apache.slider.server.appmaster.model.mock.MockRecordFactory -import org.apache.slider.server.appmaster.model.mock.MockRoles -import org.apache.slider.server.appmaster.model.mock.MockYarnEngine -import org.apache.slider.server.appmaster.state.AbstractRMOperation -import org.apache.slider.server.appmaster.state.AppState -import org.apache.slider.server.appmaster.state.RoleInstance -import org.junit.Test - -/** - * Test that if you have >1 role, the right roles are chosen for release. - */ -@CompileStatic -@Slf4j -class TestAppStateDynamicRoles extends BaseMockAppStateTest - implements MockRoles { - - @Override - String getTestName() { - return "TestAppStateDynamicRoles" - } - - /** - * Small cluster with multiple containers per node, - * to guarantee many container allocations on each node - * @return - */ - @Override - MockYarnEngine createYarnEngine() { - return new MockYarnEngine(4, 4) - } - - @Override - void initApp() { - super.initApp() - appState = new AppState(new MockRecordFactory()) - appState.setContainerLimits(RM_MAX_RAM, RM_MAX_CORES) - - def instance = factory.newInstanceDefinition(0,0,0) - - def opts = [ - (ResourceKeys.COMPONENT_INSTANCES): "1", - (ResourceKeys.COMPONENT_PRIORITY): "4", - ] - - instance.resourceOperations.components["dynamic"]= opts - - - appState.buildInstance( - instance, - new Configuration(), - new Configuration(false), - factory.ROLES, - fs, - historyPath, - null, - null) - } - - @Test - public void testAllocateReleaseRealloc() throws Throwable { - - List<RoleInstance> instances = createAndStartNodes() - List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes() - appState.getRoleHistory().dump(); - - } - -} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateRebuildOnAMRestart.groovy ---------------------------------------------------------------------- diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateRebuildOnAMRestart.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateRebuildOnAMRestart.groovy deleted file mode 100644 index 8d7ff4f..0000000 --- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateRebuildOnAMRestart.groovy +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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.Container -import org.apache.slider.api.StatusKeys -import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest -import org.apache.slider.server.appmaster.model.mock.MockRecordFactory -import org.apache.slider.server.appmaster.model.mock.MockRoles -import org.apache.slider.server.appmaster.state.* -import org.junit.Test - -/** - * Test that if you have >1 role, the right roles are chosen for release. - */ -@CompileStatic -@Slf4j -class TestAppStateRebuildOnAMRestart extends BaseMockAppStateTest - implements MockRoles { - - @Override - String getTestName() { - return "TestAppStateRebuildOnAMRestart" - } - - @Test - public void testRebuild() throws Throwable { - - int r0 = 1 - int r1 = 2 - int r2 = 3 - role0Status.desired = r0 - role1Status.desired = r1 - role2Status.desired = r2 - List<RoleInstance> instances = createAndStartNodes() - - int clusterSize = r0 + r1 + r2 - assert instances.size() == clusterSize - - //clone the list - List<RoleInstance> cloned = []; - List<Container> containers = [] - instances.each { RoleInstance elt -> - cloned.add(elt.clone() as RoleInstance) - containers.add(elt.container) - } - NodeMap nodemap = appState.roleHistory.cloneNodemap() - - // now destroy the app state - appState = new AppState(new MockRecordFactory()) - - //and rebuild - appState.buildInstance( - factory.newInstanceDefinition(r0, r1, r2), - new Configuration(), - new Configuration(false), - factory.ROLES, - fs, - historyPath, - containers, - null) - - assert appState.getStartedCountainerCount() == clusterSize - - appState.getRoleHistory().dump(); - - //check that the app state direct structures match - List<RoleInstance> r0live = appState.enumLiveNodesInRole(ROLE0) - List<RoleInstance> r1live = appState.enumLiveNodesInRole(ROLE1) - List<RoleInstance> r2live = appState.enumLiveNodesInRole(ROLE2) - - assert r0 == r0live.size() - assert r1 == r1live.size() - assert r2 == r2live.size() - - //now examine the role history - NodeMap newNodemap = appState.roleHistory.cloneNodemap() - - for (NodeInstance nodeInstance : newNodemap.values()) { - String hostname = nodeInstance.hostname - NodeInstance orig = nodemap[hostname] - assertNotNull("Null entry in original nodemap for " + hostname, orig) - - for (int i = 0; i < ROLE_COUNT; i++) { - - assert (nodeInstance.getActiveRoleInstances(i) == - orig.getActiveRoleInstances(i)) - NodeEntry origRE = orig.getOrCreate(i) - NodeEntry newRE = nodeInstance.getOrCreate(i) - assert origRE.live == newRE.live - assert newRE.starting == 0 - } - } - List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes() - assert ops.size() == 0 - - def status = appState.getClusterStatus() - // verify the AM restart container count was set - String restarted = status.getInfo( - StatusKeys.INFO_CONTAINERS_AM_RESTART) - assert restarted != null; - //and that the count == 1 master + the region servers - assert Integer.parseInt(restarted) == containers.size() - } -} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateRolePlacement.groovy ---------------------------------------------------------------------- diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateRolePlacement.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateRolePlacement.groovy deleted file mode 100644 index fba1ea0..0000000 --- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateRolePlacement.groovy +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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.yarn.api.records.Container -import org.apache.hadoop.yarn.client.api.AMRMClient -import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest -import org.apache.slider.server.appmaster.model.mock.MockRoles -import org.apache.slider.server.appmaster.state.* -import org.junit.Test - -import static org.apache.slider.server.appmaster.state.ContainerPriority.extractRole - -/** - * Test that the app state lets you ask for nodes, get a specific host, - * release it and then get that one back again. - */ -@CompileStatic -@Slf4j -class TestAppStateRolePlacement extends BaseMockAppStateTest - implements MockRoles { - - @Override - String getTestName() { - return "TestAppStateRolePlacement" - } - - - @Test - public void testAllocateReleaseRealloc() throws Throwable { - role0Status.desired = 1 - - List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes() - ContainerRequestOperation operation = (ContainerRequestOperation) ops[0] - AMRMClient.ContainerRequest request = operation.request - Container allocated = engine.allocateContainer(request) - List<ContainerAssignment> assignments = []; - List<AbstractRMOperation> operations = [] - appState.onContainersAllocated([(Container)allocated], assignments, operations) - assert operations.size() == 0 - assert assignments.size() == 1 - ContainerAssignment assigned = assignments[0] - Container container = assigned.container - assert container.id == allocated.id - int roleId = assigned.role.priority - assert roleId == extractRole(request.priority) - assert assigned.role.name == ROLE0 - String containerHostname = RoleHistoryUtils.hostnameOf(container); - RoleInstance ri = roleInstance(assigned) - //tell the app it arrived - appState.containerStartSubmitted(container, ri); - assert appState.onNodeManagerContainerStarted(container.id) - assert role0Status.started == 1 - ops = appState.reviewRequestAndReleaseNodes() - assert ops.size() == 0 - - //now it is surplus - role0Status.desired = 0 - ops = appState.reviewRequestAndReleaseNodes() - ContainerReleaseOperation release = (ContainerReleaseOperation) ops[0] - - assert release.containerId == container.id - engine.execute(ops) - assert appState.onCompletedNode(containerStatus(container)).roleInstance - - //view the world - appState.getRoleHistory().dump(); - - //now ask for a new one - role0Status.desired = 1 - ops = appState.reviewRequestAndReleaseNodes() - assert ops.size() == 1 - operation = (ContainerRequestOperation) ops[0] - AMRMClient.ContainerRequest request2 = operation.request - assert request2 != null - assert request2.nodes[0] == containerHostname - engine.execute(ops) - - } - -} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateRoleRelease.groovy ---------------------------------------------------------------------- diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateRoleRelease.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateRoleRelease.groovy deleted file mode 100644 index f087a30..0000000 --- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestAppStateRoleRelease.groovy +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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.yarn.api.records.ContainerId -import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest -import org.apache.slider.server.appmaster.model.mock.MockRoles -import org.apache.slider.server.appmaster.model.mock.MockYarnEngine -import org.apache.slider.server.appmaster.state.AbstractRMOperation -import org.apache.slider.server.appmaster.state.RoleInstance -import org.junit.Test - -/** - * Test that if you have >1 role, the right roles are chosen for release. - */ -@CompileStatic -@Slf4j -class TestAppStateRoleRelease extends BaseMockAppStateTest - implements MockRoles { - - @Override - String getTestName() { - return "TestAppStateRolePlacement" - } - - /** - * Small cluster with multiple containers per node, - * to guarantee many container allocations on each node - * @return - */ - @Override - MockYarnEngine createYarnEngine() { - return new MockYarnEngine(4, 4) - } - - @Test - public void testAllocateReleaseRealloc() throws Throwable { - /** - * Allocate to all nodes - */ - role0Status.desired = 6 - role1Status.desired = 5 - role2Status.desired = 4 - List<RoleInstance> instances = createAndStartNodes() - assert instances.size() == 15 - - //now it is surplus - role0Status.desired = 0 - List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes() - - List<ContainerId> released = [] - engine.execute(ops, released) - List<ContainerId> ids = extractContainerIds(instances, 0) - released.each { ContainerId cid -> - assert appState.onCompletedNode(containerStatus(cid)).roleInstance - assert ids.contains(cid) - } - - //view the world - appState.getRoleHistory().dump(); - - } - -} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestContainerResourceAllocations.groovy ---------------------------------------------------------------------- diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestContainerResourceAllocations.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestContainerResourceAllocations.groovy deleted file mode 100644 index a0b1100..0000000 --- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestContainerResourceAllocations.groovy +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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.yarn.api.records.Resource -import org.apache.slider.api.ResourceKeys -import org.apache.slider.core.conf.ConfTree -import org.apache.slider.core.conf.ConfTreeOperations -import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest -import org.apache.slider.server.appmaster.model.mock.MockRoles -import org.apache.slider.server.appmaster.state.AbstractRMOperation -import org.apache.slider.server.appmaster.state.ContainerRequestOperation -import org.junit.Test - -/** - * Test the container resource allocation logic - */ -@CompileStatic -@Slf4j -class TestContainerResourceAllocations extends BaseMockAppStateTest { - - @Override - String getTestName() { - "TestContainerResourceAllocations" - } - - @Test - public void testNormalAllocations() throws Throwable { - ConfTree clusterSpec = factory.newConfTree(1, 0, 0) - ConfTreeOperations cto = new ConfTreeOperations(clusterSpec) - - cto.setRoleOpt(MockRoles.ROLE0, ResourceKeys.YARN_MEMORY, 512) - cto.setRoleOpt(MockRoles.ROLE0, ResourceKeys.YARN_CORES, 2) - appState.updateResourceDefinitions(clusterSpec) - List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes() - assert ops.size() == 1 - ContainerRequestOperation operation = (ContainerRequestOperation) ops[0] - Resource requirements = operation.request.capability - assert requirements.memory == 512 - assert requirements.virtualCores == 2 - } - - @Test - public void testMaxMemAllocations() throws Throwable { - ConfTree clusterSpec = factory.newConfTree(1, 0, 0) - ConfTreeOperations cto = new ConfTreeOperations(clusterSpec) - - cto.setComponentOpt(MockRoles.ROLE0, ResourceKeys.YARN_MEMORY, - ResourceKeys.YARN_RESOURCE_MAX) - cto.setRoleOpt(MockRoles.ROLE0, ResourceKeys.YARN_CORES, 2) - appState.updateResourceDefinitions(clusterSpec) - List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes() - assert ops.size() == 1 - ContainerRequestOperation operation = (ContainerRequestOperation) ops[0] - Resource requirements = operation.request.capability - assert requirements.memory == RM_MAX_RAM - assert requirements.virtualCores == 2 - } - - @Test - public void testMaxCoreAllocations() throws Throwable { - ConfTree clusterSpec = factory.newConfTree(1, 0, 0) - ConfTreeOperations cto = new ConfTreeOperations(clusterSpec) - cto.setRoleOpt(MockRoles.ROLE0, ResourceKeys.YARN_MEMORY, - 512) - cto.setComponentOpt(MockRoles.ROLE0, ResourceKeys.YARN_CORES, - ResourceKeys.YARN_RESOURCE_MAX) - appState.updateResourceDefinitions(clusterSpec) - List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes() - assert ops.size() == 1 - ContainerRequestOperation operation = (ContainerRequestOperation) ops[0] - Resource requirements = operation.request.capability - assert requirements.memory == 512 - assert requirements.virtualCores == RM_MAX_CORES - } - - @Test - public void testMaxDefaultAllocations() throws Throwable { - - ConfTree clusterSpec = factory.newConfTree(1, 0, 0) - appState.updateResourceDefinitions(clusterSpec) - List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes() - assert ops.size() == 1 - ContainerRequestOperation operation = (ContainerRequestOperation) ops[0] - Resource requirements = operation.request.capability - assert requirements.memory == ResourceKeys.DEF_YARN_MEMORY - assert requirements.virtualCores == ResourceKeys.DEF_YARN_CORES - } - -} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestFlexDynamicRoles.groovy ---------------------------------------------------------------------- diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestFlexDynamicRoles.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestFlexDynamicRoles.groovy deleted file mode 100644 index 911880a..0000000 --- a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestFlexDynamicRoles.groovy +++ /dev/null @@ -1,189 +0,0 @@ -/* - * 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.fs.Path -import org.apache.slider.api.ResourceKeys -import org.apache.slider.core.conf.ConfTreeOperations -import org.apache.slider.core.exceptions.BadConfigException -import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest -import org.apache.slider.server.appmaster.model.mock.MockRecordFactory -import org.apache.slider.server.appmaster.model.mock.MockRoles -import org.apache.slider.server.appmaster.model.mock.MockYarnEngine -import org.apache.slider.server.appmaster.state.AppState -import org.apache.slider.server.avro.RoleHistoryWriter -import org.junit.Test - -/** - * Test that if you have >1 role, the right roles are chosen for release. - */ -@CompileStatic -@Slf4j -class TestFlexDynamicRoles extends BaseMockAppStateTest - implements MockRoles { - - @Override - String getTestName() { - return "TestAppStateDynamicRoles" - } - - /** - * Small cluster with multiple containers per node, - * to guarantee many container allocations on each node - * @return - */ - @Override - MockYarnEngine createYarnEngine() { - return new MockYarnEngine(4, 4) - } - - @Override - void initApp() { - super.initApp() - appState = new AppState(new MockRecordFactory()) - appState.setContainerLimits(RM_MAX_RAM, RM_MAX_CORES) - - def instance = factory.newInstanceDefinition(0, 0, 0) - - def opts = [ - (ResourceKeys.COMPONENT_INSTANCES): "1", - (ResourceKeys.COMPONENT_PRIORITY): "6", - ] - - instance.resourceOperations.components["dynamic"] = opts - - - appState.buildInstance(instance, - new Configuration(), - new Configuration(false), - factory.ROLES, - fs, - historyPath, - null, null) - } - - - private ConfTreeOperations init() { - createAndStartNodes(); - def resources = appState.instanceDefinition.resources; - return new ConfTreeOperations(resources) - } - - @Test - public void testDynamicFlexAddRole() throws Throwable { - def cd = init() - def opts = [ - (ResourceKeys.COMPONENT_INSTANCES): "1", - (ResourceKeys.COMPONENT_PRIORITY): "7", - ] - - cd.components["role4"] = opts - appState.updateResourceDefinitions(cd.confTree); - createAndStartNodes(); - dumpClusterDescription("updated CD", appState.getClusterStatus()) - appState.lookupRoleStatus(7) - appState.lookupRoleStatus(6) - //gaps are still there - try { - assert null == appState.lookupRoleStatus(5) - } catch (RuntimeException expected) { - } - } - - @Test - public void testDynamicFlexAddRoleConflictingPriority() throws Throwable { - def cd = init() - def opts = [ - (ResourceKeys.COMPONENT_INSTANCES): "1", - (ResourceKeys.COMPONENT_PRIORITY): "6", - ] - - cd.components["role4"] = opts - try { - appState.updateResourceDefinitions(cd.confTree); - dumpClusterDescription("updated CD", appState.getClusterStatus()) - fail("Expected an exception") - } catch (BadConfigException expected) { - } - } - - @Test - public void testDynamicFlexDropRole() throws Throwable { - def cd = init() - cd.components.remove("dynamic"); - appState.updateResourceDefinitions(cd.confTree); - - def getCD = appState.getClusterStatus() - dumpClusterDescription("updated CD", getCD) - //status is retained for future - appState.lookupRoleStatus(6) - } - - - @Test - public void testHistorySaveFlexLoad() throws Throwable { - def cd = init() - def roleHistory = appState.roleHistory - Path history = roleHistory.saveHistory(0x0001) - RoleHistoryWriter historyWriter = new RoleHistoryWriter(); - def opts = [ - (ResourceKeys.COMPONENT_INSTANCES): "1", - (ResourceKeys.COMPONENT_PRIORITY): "7", - ] - - cd.components["role4"] = opts - appState.updateResourceDefinitions(cd.confTree); - createAndStartNodes(); - historyWriter.read(fs, history, appState.roleHistory) - } - - @Test - public void testHistoryFlexSaveLoad() throws Throwable { - def cd = init() - def opts = [ - (ResourceKeys.COMPONENT_INSTANCES): "1", - (ResourceKeys.COMPONENT_PRIORITY): "7", - ] - - cd.components["role4"] = opts - appState.updateResourceDefinitions(cd.confTree); - createAndStartNodes(); - RoleHistoryWriter historyWriter = new RoleHistoryWriter(); - def roleHistory = appState.roleHistory - Path history = roleHistory.saveHistory(0x0002) - //now reset the app state - def historyWorkDir2 = new File("target/history" + testName + "-0002") - def historyPath2 = new Path(historyWorkDir2.toURI()) - appState = new AppState(new MockRecordFactory()) - appState.setContainerLimits(RM_MAX_RAM, RM_MAX_CORES) - appState.buildInstance( - factory.newInstanceDefinition(0, 0, 0), - new Configuration(), - new Configuration(false), - factory.ROLES, - fs, - historyPath2, - null, null) - historyWriter.read(fs, history, appState.roleHistory) - } - -} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateContainerFailure.groovy ---------------------------------------------------------------------- diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateContainerFailure.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateContainerFailure.groovy new file mode 100644 index 0000000..3a287bd --- /dev/null +++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateContainerFailure.groovy @@ -0,0 +1,166 @@ +/* + * 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.yarn.api.records.ContainerId +import org.apache.slider.core.exceptions.SliderException +import org.apache.slider.core.exceptions.TriggerClusterTeardownException +import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest +import org.apache.slider.server.appmaster.model.mock.MockRoles +import org.apache.slider.server.appmaster.model.mock.MockYarnEngine +import org.apache.slider.server.appmaster.state.* +import org.junit.Test + +/** + * Test that if you have >1 role, the right roles are chosen for release. + */ +@CompileStatic +@Slf4j +class TestMockAppStateContainerFailure extends BaseMockAppStateTest + implements MockRoles { + + @Override + String getTestName() { + return "TestAppStateContainerFailure" + } + + /** + * Small cluster with multiple containers per node, + * to guarantee many container allocations on each node + * @return + */ + @Override + MockYarnEngine createYarnEngine() { + return new MockYarnEngine(8000, 4) + } + + @Test + public void testShortLivedFail() throws Throwable { + + role0Status.desired = 1 + List<RoleInstance> instances = createAndStartNodes() + assert instances.size() == 1 + + RoleInstance instance = instances[0] + long created = instance.createTime + long started = instance.startTime + assert created > 0 + assert started >= created + List<ContainerId> ids = extractContainerIds(instances, 0) + + ContainerId cid = ids[0] + assert appState.isShortLived(instance) + AppState.NodeCompletionResult result = appState.onCompletedNode(containerStatus(cid, 1)) + assert result.roleInstance != null + assert result.containerFailed + RoleStatus status = role0Status + assert status.failed == 1 + assert status.startFailed == 1 + + //view the world + appState.getRoleHistory().dump(); + List<NodeInstance> queue = appState.roleHistory.cloneAvailableList(0) + assert queue.size() == 0 + + } + + @Test + public void testLongLivedFail() throws Throwable { + + role0Status.desired = 1 + List<RoleInstance> instances = createAndStartNodes() + assert instances.size() == 1 + + RoleInstance instance = instances[0] + instance.startTime = System.currentTimeMillis() - 60 * 60 * 1000; + assert !appState.isShortLived(instance) + List<ContainerId> ids = extractContainerIds(instances, 0) + + ContainerId cid = ids[0] + AppState.NodeCompletionResult result = appState.onCompletedNode( + containerStatus(cid, 1)) + assert result.roleInstance != null + assert result.containerFailed + RoleStatus status = role0Status + assert status.failed == 1 + assert status.startFailed == 0 + + //view the world + appState.getRoleHistory().dump(); + List<NodeInstance> queue = appState.roleHistory.cloneAvailableList(0) + assert queue.size() == 1 + + } + + @Test + public void testNodeStartFailure() throws Throwable { + + role0Status.desired = 1 + List<RoleInstance> instances = createAndSubmitNodes() + assert instances.size() == 1 + + RoleInstance instance = instances[0] + + List<ContainerId> ids = extractContainerIds(instances, 0) + + ContainerId cid = ids[0] + appState.onNodeManagerContainerStartFailed(cid, new SliderException("oops")) + RoleStatus status = role0Status + assert status.failed == 1 + assert status.startFailed == 1 + + + RoleHistory history = appState.roleHistory + history.dump(); + List<NodeInstance> queue = history.cloneAvailableList(0) + assert queue.size() == 0 + + NodeInstance ni = history.getOrCreateNodeInstance(instance.container) + NodeEntry re = ni.get(0) + assert re.failed == 1 + assert re.startFailed == 1 + } + + @Test + public void testRecurrentStartupFailure() throws Throwable { + + role0Status.desired = 1 + try { + for (int i = 0; i< 100; i++) { + List<RoleInstance> instances = createAndSubmitNodes() + assert instances.size() == 1 + + List<ContainerId> ids = extractContainerIds(instances, 0) + + ContainerId cid = ids[0] + log.info("$i instance $instances[0] $cid") + assert cid + appState.onNodeManagerContainerStartFailed(cid, new SliderException("oops")) + AppState.NodeCompletionResult result = appState.onCompletedNode(containerStatus(cid)) + assert result.containerFailed + } + fail("Cluster did not fail from too many startup failures") + } catch (TriggerClusterTeardownException teardown) { + log.info("Exception $teardown.exitCode : $teardown") + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/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 new file mode 100644 index 0000000..a204bea --- /dev/null +++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateDynamicRoles.groovy @@ -0,0 +1,94 @@ +/* + * 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.slider.api.ResourceKeys +import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest +import org.apache.slider.server.appmaster.model.mock.MockRecordFactory +import org.apache.slider.server.appmaster.model.mock.MockRoles +import org.apache.slider.server.appmaster.model.mock.MockYarnEngine +import org.apache.slider.server.appmaster.state.AbstractRMOperation +import org.apache.slider.server.appmaster.state.AppState +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 TestMockAppStateDynamicRoles extends BaseMockAppStateTest + implements MockRoles { + + @Override + String getTestName() { + return "TestAppStateDynamicRoles" + } + + /** + * Small cluster with multiple containers per node, + * to guarantee many container allocations on each node + * @return + */ + @Override + MockYarnEngine createYarnEngine() { + return new MockYarnEngine(4, 4) + } + + @Override + void initApp() { + super.initApp() + appState = new AppState(new MockRecordFactory()) + appState.setContainerLimits(RM_MAX_RAM, RM_MAX_CORES) + + def instance = factory.newInstanceDefinition(0,0,0) + + def opts = [ + (ResourceKeys.COMPONENT_INSTANCES): "1", + (ResourceKeys.COMPONENT_PRIORITY): "4", + ] + + instance.resourceOperations.components["dynamic"]= opts + + + appState.buildInstance( + instance, + new Configuration(), + new Configuration(false), + factory.ROLES, + fs, + historyPath, + null, + null, new SimpleReleaseSelector()) + } + + @Test + public void testAllocateReleaseRealloc() throws Throwable { + + List<RoleInstance> instances = createAndStartNodes() + List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes() + appState.getRoleHistory().dump(); + + } + +} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateFlexDynamicRoles.groovy ---------------------------------------------------------------------- diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateFlexDynamicRoles.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateFlexDynamicRoles.groovy new file mode 100644 index 0000000..aa330f8 --- /dev/null +++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateFlexDynamicRoles.groovy @@ -0,0 +1,190 @@ +/* + * 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.fs.Path +import org.apache.slider.api.ResourceKeys +import org.apache.slider.core.conf.ConfTreeOperations +import org.apache.slider.core.exceptions.BadConfigException +import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest +import org.apache.slider.server.appmaster.model.mock.MockRecordFactory +import org.apache.slider.server.appmaster.model.mock.MockRoles +import org.apache.slider.server.appmaster.model.mock.MockYarnEngine +import org.apache.slider.server.appmaster.state.AppState +import org.apache.slider.server.appmaster.state.SimpleReleaseSelector +import org.apache.slider.server.avro.RoleHistoryWriter +import org.junit.Test + +/** + * Test that if you have >1 role, the right roles are chosen for release. + */ +@CompileStatic +@Slf4j +class TestMockAppStateFlexDynamicRoles extends BaseMockAppStateTest + implements MockRoles { + + @Override + String getTestName() { + return "TestAppStateDynamicRoles" + } + + /** + * Small cluster with multiple containers per node, + * to guarantee many container allocations on each node + * @return + */ + @Override + MockYarnEngine createYarnEngine() { + return new MockYarnEngine(4, 4) + } + + @Override + void initApp() { + super.initApp() + appState = new AppState(new MockRecordFactory()) + appState.setContainerLimits(RM_MAX_RAM, RM_MAX_CORES) + + def instance = factory.newInstanceDefinition(0, 0, 0) + + def opts = [ + (ResourceKeys.COMPONENT_INSTANCES): "1", + (ResourceKeys.COMPONENT_PRIORITY): "6", + ] + + instance.resourceOperations.components["dynamic"] = opts + + + appState.buildInstance(instance, + new Configuration(), + new Configuration(false), + factory.ROLES, + fs, + historyPath, + null, null, new SimpleReleaseSelector()) + } + + + private ConfTreeOperations init() { + createAndStartNodes(); + def resources = appState.instanceDefinition.resources; + return new ConfTreeOperations(resources) + } + + @Test + public void testDynamicFlexAddRole() throws Throwable { + def cd = init() + def opts = [ + (ResourceKeys.COMPONENT_INSTANCES): "1", + (ResourceKeys.COMPONENT_PRIORITY): "7", + ] + + cd.components["role4"] = opts + appState.updateResourceDefinitions(cd.confTree); + createAndStartNodes(); + dumpClusterDescription("updated CD", appState.getClusterStatus()) + appState.lookupRoleStatus(7) + appState.lookupRoleStatus(6) + //gaps are still there + try { + assert null == appState.lookupRoleStatus(5) + } catch (RuntimeException expected) { + } + } + + @Test + public void testDynamicFlexAddRoleConflictingPriority() throws Throwable { + def cd = init() + def opts = [ + (ResourceKeys.COMPONENT_INSTANCES): "1", + (ResourceKeys.COMPONENT_PRIORITY): "6", + ] + + cd.components["role4"] = opts + try { + appState.updateResourceDefinitions(cd.confTree); + dumpClusterDescription("updated CD", appState.getClusterStatus()) + fail("Expected an exception") + } catch (BadConfigException expected) { + } + } + + @Test + public void testDynamicFlexDropRole() throws Throwable { + def cd = init() + cd.components.remove("dynamic"); + appState.updateResourceDefinitions(cd.confTree); + + def getCD = appState.getClusterStatus() + dumpClusterDescription("updated CD", getCD) + //status is retained for future + appState.lookupRoleStatus(6) + } + + + @Test + public void testHistorySaveFlexLoad() throws Throwable { + def cd = init() + def roleHistory = appState.roleHistory + Path history = roleHistory.saveHistory(0x0001) + RoleHistoryWriter historyWriter = new RoleHistoryWriter(); + def opts = [ + (ResourceKeys.COMPONENT_INSTANCES): "1", + (ResourceKeys.COMPONENT_PRIORITY): "7", + ] + + cd.components["role4"] = opts + appState.updateResourceDefinitions(cd.confTree); + createAndStartNodes(); + historyWriter.read(fs, history, appState.roleHistory) + } + + @Test + public void testHistoryFlexSaveLoad() throws Throwable { + def cd = init() + def opts = [ + (ResourceKeys.COMPONENT_INSTANCES): "1", + (ResourceKeys.COMPONENT_PRIORITY): "7", + ] + + cd.components["role4"] = opts + appState.updateResourceDefinitions(cd.confTree); + createAndStartNodes(); + RoleHistoryWriter historyWriter = new RoleHistoryWriter(); + def roleHistory = appState.roleHistory + Path history = roleHistory.saveHistory(0x0002) + //now reset the app state + def historyWorkDir2 = new File("target/history" + testName + "-0002") + def historyPath2 = new Path(historyWorkDir2.toURI()) + appState = new AppState(new MockRecordFactory()) + appState.setContainerLimits(RM_MAX_RAM, RM_MAX_CORES) + appState.buildInstance( + factory.newInstanceDefinition(0, 0, 0), + new Configuration(), + new Configuration(false), + factory.ROLES, + fs, + historyPath2, + null, null, new SimpleReleaseSelector()) + historyWriter.read(fs, history, appState.roleHistory) + } + +} http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5ce953ca/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateFlexing.groovy ---------------------------------------------------------------------- diff --git a/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateFlexing.groovy b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateFlexing.groovy new file mode 100644 index 0000000..6be158e --- /dev/null +++ b/slider-core/src/test/groovy/org/apache/slider/server/appmaster/model/appstate/TestMockAppStateFlexing.groovy @@ -0,0 +1,126 @@ +/* + * 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.util.logging.Slf4j +import org.apache.hadoop.yarn.api.records.Container +import org.apache.hadoop.yarn.api.records.ContainerId +import org.apache.hadoop.yarn.client.api.AMRMClient +import org.apache.slider.server.appmaster.model.mock.BaseMockAppStateTest +import org.apache.slider.server.appmaster.model.mock.MockFactory +import org.apache.slider.server.appmaster.model.mock.MockRMOperationHandler +import org.apache.slider.server.appmaster.model.mock.MockRoles +import org.apache.slider.server.appmaster.state.AbstractRMOperation +import org.apache.slider.server.appmaster.state.AppState +import org.apache.slider.server.appmaster.state.ContainerAssignment +import org.apache.slider.server.appmaster.state.ContainerReleaseOperation +import org.apache.slider.server.appmaster.state.ContainerRequestOperation +import org.apache.slider.server.appmaster.state.RMOperationHandler +import org.apache.slider.server.appmaster.state.RoleInstance +import org.junit.Test + +import static org.apache.slider.server.appmaster.state.ContainerPriority.buildPriority +import static org.apache.slider.server.appmaster.state.ContainerPriority.extractRole + +@Slf4j +class TestMockAppStateFlexing extends BaseMockAppStateTest implements MockRoles { + + @Override + String getTestName() { + return "TestMockFlexing" + } + + @Test + public void testFlexDuringLaunchPhase() throws Throwable { + role0Status.desired = 1 + + List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes() + List<Container> allocations = engine.execute(ops) + List<ContainerAssignment> assignments = []; + List<AbstractRMOperation> releases = [] + appState.onContainersAllocated(allocations, assignments, releases) + assert assignments.size() == 1 + ContainerAssignment assigned = assignments[0] + Container target = assigned.container + RoleInstance ri = roleInstance(assigned) + + ops = appState.reviewRequestAndReleaseNodes() + assert ops.empty + + //now this is the start point. + appState.containerStartSubmitted(target, ri); + + ops = appState.reviewRequestAndReleaseNodes() + assert ops.empty + + RoleInstance ri2 = appState.innerOnNodeManagerContainerStarted(target.id) + } + + @Test + public void testFlexBeforeAllocationPhase() throws Throwable { + role0Status.desired = 1 + + List<AbstractRMOperation> ops = appState.reviewRequestAndReleaseNodes() + assert !ops.empty + List<AbstractRMOperation> ops2 = appState.reviewRequestAndReleaseNodes() + assert ops2.empty + } + + + @Test + public void testFlexDownTwice() throws Throwable { + int r0 = 6 + int r1 = 0 + int r2 = 0 + role0Status.desired = r0 + role1Status.desired = r1 + role2Status.desired = r2 + List<RoleInstance> instances = createAndStartNodes() + + int clusterSize = r0 + r1 + r2 + assert instances.size() == clusterSize + log.info("shrinking cluster") + r0 = 4 + role0Status.desired = r0 + List<AppState.NodeCompletionResult> completionResults = [] + instances = createStartAndStopNodes(completionResults) + assert instances.size() == 0 + // assert two nodes were released + assert completionResults.size() == 2 + + // no-op review + completionResults = [] + instances = createStartAndStopNodes(completionResults) + assert instances.size() == 0 + // assert two nodes were released + assert completionResults.size() == 0 + + + // now shrink again + role0Status.desired = r0 = 1 + completionResults = [] + instances = createStartAndStopNodes(completionResults) + assert instances.size() == 0 + // assert two nodes were released + assert completionResults.size() == 3 + + } + + +}