Issue 501: raise illegalstateexception when node dies before customization occurs

This commit is contained in:
Adrian Cole 2011-03-08 09:15:55 -08:00
parent 8ed7dcde82
commit af0cff189c
2 changed files with 154 additions and 6 deletions

View File

@ -128,16 +128,20 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
checkState(!tainted, "this object is not designed to be reused: %s", toString());
tainted = true;
String originalId = node.getId();
NodeMetadata originalNode = node;
try {
if (options.shouldBlockUntilRunning()) {
if (nodeRunning.apply(node)) {
node = getNode.getNode(node.getId());
node = getNode.getNode(originalId);
} else {
NodeMetadata nodeForState = getNode.getNode(node.getId());
NodeMetadata nodeForState = getNode.getNode(originalId);
NodeState state = nodeForState == null ? NodeState.TERMINATED : nodeForState.getState();
throw new IllegalStateException(format(
"node %s didn't achieve the state running within %d seconds, final state: %s", originalId,
timeouts.nodeRunning / 1000, state));
if (state == NodeState.TERMINATED)
throw new IllegalStateException(format("node(%s) terminated before we could customize", originalId));
else
throw new IllegalStateException(format(
"node(%s) didn't achieve the state running within %d seconds, final state: %s", originalId,
timeouts.nodeRunning / 1000, state));
}
if (node == null)
throw new IllegalStateException(format("node %s terminated before applying options", originalId));
@ -156,7 +160,7 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
goodNodes.add(node);
} catch (Exception e) {
logger.error(e, "<< problem applying options to node(%s): ", originalId, getRootCause(e).getMessage());
badNodes.put(node, e);
badNodes.put(node == null ? originalNode : node, e);
}
return null;
}

View File

@ -0,0 +1,144 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.jclouds.compute.strategy;
import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
import static org.testng.Assert.assertEquals;
import java.util.Map;
import java.util.Set;
import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.functions.TemplateOptionsToStatement;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.scriptbuilder.domain.Statement;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
/**
* @author Adrian Cole
*/
@Test(groups = "unit")
public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
@SuppressWarnings("unchecked")
public void testBreakWhenNodeStillPending() {
Predicate<NodeMetadata> nodeRunning = createMock(Predicate.class);
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory = createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class);
GetNodeMetadataStrategy getNode = createMock(GetNodeMetadataStrategy.class);
RetryIfSocketNotYetOpen socketTester = createMock(RetryIfSocketNotYetOpen.class);
Timeouts timeouts = new Timeouts();
Function<TemplateOptions, Statement> templateOptionsToStatement = new TemplateOptionsToStatement();
@SuppressWarnings("unused")
Statement statement = null;
TemplateOptions options = new TemplateOptions();
Set<NodeMetadata> goodNodes = Sets.newLinkedHashSet();
Map<NodeMetadata, Exception> badNodes = Maps.newLinkedHashMap();
Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create();
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.PENDING).build();
// node never reached running state
expect(nodeRunning.apply(node)).andReturn(false);
expect(getNode.getNode(node.getId())).andReturn(node);
// replay mocks
replay(nodeRunning);
replay(initScriptRunnerFactory);
replay(getNode);
replay(socketTester);
// run
new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(nodeRunning, getNode, socketTester, timeouts,
templateOptionsToStatement, initScriptRunnerFactory, options, node, goodNodes, badNodes,
customizationResponses).apply(node);
assertEquals(goodNodes.size(), 0);
assertEquals(badNodes.keySet(), ImmutableSet.of(node));
assertEquals(badNodes.get(node).getMessage(),
"node(id) didn't achieve the state running within 1200 seconds, final state: PENDING");
assertEquals(customizationResponses.size(), 0);
// verify mocks
verify(nodeRunning);
verify(initScriptRunnerFactory);
verify(getNode);
verify(socketTester);
}
@SuppressWarnings("unchecked")
public void testBreakGraceFullyWhenNodeDied() {
Predicate<NodeMetadata> nodeRunning = createMock(Predicate.class);
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory = createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class);
GetNodeMetadataStrategy getNode = createMock(GetNodeMetadataStrategy.class);
RetryIfSocketNotYetOpen socketTester = createMock(RetryIfSocketNotYetOpen.class);
Timeouts timeouts = new Timeouts();
Function<TemplateOptions, Statement> templateOptionsToStatement = new TemplateOptionsToStatement();
@SuppressWarnings("unused")
Statement statement = null;
TemplateOptions options = new TemplateOptions();
Set<NodeMetadata> goodNodes = Sets.newLinkedHashSet();
Map<NodeMetadata, Exception> badNodes = Maps.newLinkedHashMap();
Multimap<NodeMetadata, CustomizationResponse> customizationResponses = LinkedHashMultimap.create();
NodeMetadata node = new NodeMetadataBuilder().ids("id").state(NodeState.PENDING).build();
// node never reached running state
expect(nodeRunning.apply(node)).andReturn(false);
expect(getNode.getNode(node.getId())).andReturn(null);
// replay mocks
replay(nodeRunning);
replay(initScriptRunnerFactory);
replay(getNode);
replay(socketTester);
// run
new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(nodeRunning, getNode, socketTester, timeouts,
templateOptionsToStatement, initScriptRunnerFactory, options, node, goodNodes, badNodes,
customizationResponses).apply(node);
assertEquals(goodNodes.size(), 0);
assertEquals(badNodes.keySet(), ImmutableSet.of(node));
assertEquals(badNodes.get(node).getMessage(), "node(id) terminated before we could customize");
assertEquals(customizationResponses.size(), 0);
// verify mocks
verify(nodeRunning);
verify(initScriptRunnerFactory);
verify(getNode);
verify(socketTester);
}
}