FGCP: catch exceptions when node is not in expected state when rebooting, deleting, etc. and ensure it reaches the final state the user wants
Project: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/commit/d3a180ef Tree: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/tree/d3a180ef Diff: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/diff/d3a180ef Branch: refs/heads/master Commit: d3a180eff84db4ac65a32d9b4d318322e4aa77f5 Parents: 2f11286 Author: Dies Koper <[email protected]> Authored: Wed May 22 15:22:58 2013 +1000 Committer: Andrew Gaul <[email protected]> Committed: Thu May 23 16:21:51 2013 -0700 ---------------------------------------------------------------------- .../strategy/FGCPComputeServiceAdapter.java | 105 +++++++++------ .../fgcp/handlers/FGCPServerErrorRetryHandler.java | 5 +- .../fgcp/handlers/ResponseNotSuccessHandler.java | 2 +- .../fgcp/services/ErrorResponseExpectTest.java | 37 +++++- .../IllegalState_ALREADY_STOPPED-response.xml | 5 + .../responses/IllegalState_RUNNING-response.xml | 5 + 6 files changed, 111 insertions(+), 48 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/d3a180ef/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/strategy/FGCPComputeServiceAdapter.java ---------------------------------------------------------------------- diff --git a/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/strategy/FGCPComputeServiceAdapter.java b/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/strategy/FGCPComputeServiceAdapter.java index 72b8975..e1cbfce 100644 --- a/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/strategy/FGCPComputeServiceAdapter.java +++ b/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/strategy/FGCPComputeServiceAdapter.java @@ -41,16 +41,17 @@ import org.jclouds.fujitsu.fgcp.compute.functions.ResourceIdToFirewallId; import org.jclouds.fujitsu.fgcp.compute.functions.ResourceIdToSystemId; import org.jclouds.fujitsu.fgcp.compute.predicates.ServerStarted; import org.jclouds.fujitsu.fgcp.compute.predicates.ServerStopped; -import org.jclouds.fujitsu.fgcp.compute.predicates.SystemStatusNormal; import org.jclouds.fujitsu.fgcp.compute.strategy.VServerMetadata.Builder; import org.jclouds.fujitsu.fgcp.domain.DiskImage; import org.jclouds.fujitsu.fgcp.domain.ServerType; +import org.jclouds.fujitsu.fgcp.domain.VServer; import org.jclouds.fujitsu.fgcp.domain.VServerStatus; import org.jclouds.fujitsu.fgcp.domain.VServerWithDetails; import org.jclouds.fujitsu.fgcp.domain.VServerWithVNICs; import org.jclouds.fujitsu.fgcp.domain.VSystem; import org.jclouds.fujitsu.fgcp.domain.VSystemWithDetails; import org.jclouds.logging.Logger; +import org.jclouds.rest.ResourceNotFoundException; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableSet; @@ -73,20 +74,18 @@ public class FGCPComputeServiceAdapter implements protected Predicate<String> serverStopped = null; protected Predicate<String> serverStarted = null; protected Predicate<String> serverCreated = null; - protected Predicate<String> systemNormal = null; protected ResourceIdToFirewallId toFirewallId = null; protected ResourceIdToSystemId toSystemId = null; @Inject public FGCPComputeServiceAdapter(FGCPApi api, ServerStopped serverStopped, - ServerStarted serverStarted, SystemStatusNormal systemNormal, - Timeouts timeouts, ResourceIdToFirewallId toFirewallId, + ServerStarted serverStarted, Timeouts timeouts, + ResourceIdToFirewallId toFirewallId, ResourceIdToSystemId toSystemId) { this.api = checkNotNull(api, "api"); this.serverStopped = retry(checkNotNull(serverStopped), timeouts.nodeSuspended); this.serverStarted = retry(checkNotNull(serverStarted), timeouts.nodeRunning); this.serverCreated = retry(checkNotNull(serverStopped), timeouts.nodeRunning); - this.systemNormal = retry(checkNotNull(systemNormal), timeouts.nodeTerminated); this.toFirewallId = checkNotNull(toFirewallId, "ResourceIdToFirewallId"); this.toSystemId = checkNotNull(toSystemId, "ResourceIdToSystemId"); } @@ -104,8 +103,7 @@ public class FGCPComputeServiceAdapter implements // wait until fully created (i.e. transitions to stopped status) checkState(serverCreated.apply(id), "node %s not reaching STOPPED state after creation", id); resumeNode(id); - // wait until fully started - checkState(serverStarted.apply(id), "could not start %s after creation", id); + // don't wait until fully started, template "optionToNotBlock" takes care of that VServerMetadata server = getNode(id); // do we need this? @@ -158,31 +156,34 @@ public class FGCPComputeServiceAdapter implements Builder builder = VServerMetadata.builder(); builder.id(id); - // mapped public ips? -// String fwId = toFirewallId.apply(id); - // futures.add(asyncApi.getBuiltinServerApi().getConfiguration(fwId, - // BuiltinServerConfiguration.SLB_RULE)); - - VServerWithDetails server = api.getVirtualServerApi().getDetails(id); - VServerStatus status = api.getVirtualServerApi().getStatus(id); - logger.info("%s [%s] - %s", id, status, server); - if (server == null) { - server = api.getVirtualServerApi().getDetails(id); - logger.warn("!!!!!!!!!! server returned null. 2nd try: %s", server); + try { + VServerWithDetails server = api.getVirtualServerApi().getDetails(id); + // skip FWs and SLBs + if (isFWorSLB(server)) { + return null; + } + VServerStatus status = api.getVirtualServerApi().getStatus(id); + logger.trace("Node %s [%s] - %s", id, status, server); + builder.serverWithDetails(server); + builder.status(status); + builder.initialPassword(api.getVirtualServerApi().getInitialPassword(id)); + + // mapped public ips? +// String fwId = toFirewallId.apply(id); + // futures.add(asyncApi.getBuiltinServerApi().getConfiguration(fwId, + // BuiltinServerConfiguration.FW_RULE)); + } catch (ResourceNotFoundException e) { + return null; } - builder.serverWithDetails(server); - builder.status(status == null ? VServerStatus.UNRECOGNIZED : status); - // System.out.println("status in adapter#getNode: " - // + (VServerStatus) results.get(1) - // +" for " - // + server.getId()); - builder.initialPassword(api.getVirtualServerApi().getInitialPassword(id)); - // SLB slb = ((BuiltinServer) results.get(4)).; - // slb. return builder.build(); } + private boolean isFWorSLB(VServer server) { + String serverType = server.getType(); + return "firewall".equals(serverType) || "slb".equals(serverType); + } + /** * {@inheritDoc} */ @@ -197,15 +198,9 @@ public class FGCPComputeServiceAdapter implements for (VServerWithVNICs server : systemDetails.getServers()) { - // skip FW (S-0001) and SLBs (>0 for SLB) - // TODO: rewrite to use serverType instead - if (!server.getId().endsWith("-S-0001") && server.getVnics().iterator().next().getNicNo() == 0) { - + // skip FWs and SLBs + if (!isFWorSLB(server)) { servers.add(getNode(server.getId())); - // Builder builder = VServerMetadata.builder(); - // builder.server(server); - // builder.status(VServerStatus.UNRECOGNIZED); - // servers.add(builder.build()); } } } @@ -233,9 +228,6 @@ public class FGCPComputeServiceAdapter implements suspendNode(id); checkState(serverStopped.apply(id), "could not stop %s before destroying it", id); api.getVirtualServerApi().destroy(id); - // wait until vsys completes reconfiguration - String systemId = toSystemId.apply(id); - checkState(systemNormal.apply(systemId), "system %s not returning to NORMAL", systemId); } /** @@ -253,7 +245,13 @@ public class FGCPComputeServiceAdapter implements */ @Override public void resumeNode(String id) { - api.getVirtualServerApi().start(id); + try { + api.getVirtualServerApi().start(id); + } catch (IllegalStateException ise) { + if (!(ise.getMessage().contains("ALREADY_STARTED") || ise.getMessage().contains("STARTING"))) { + throw ise; + } + } } /** @@ -261,6 +259,33 @@ public class FGCPComputeServiceAdapter implements */ @Override public void suspendNode(String id) { - api.getVirtualServerApi().stop(id); + try { + api.getVirtualServerApi().stop(id); + } catch (IllegalStateException ise) { + if (ise.getMessage().contains("ALREADY_STOPPED") || ise.getMessage().contains("STOPPING")) { + logger.trace("suspendNode({0}) - {1}", id, ise.getMessage()); + // ignore as it has/will reach the desired destination state + } else if (ise.getMessage().contains("STARTING")) { + // wait till running, then try to stop again + logger.trace("suspendNode({0}) - {1} - waiting to reach RUNNING state", id, ise.getMessage()); + checkState(serverStarted.apply(id), "starting %s didn't reach RUNNING state", id); + logger.trace("suspendNode({0}) - now RUNNING, trying to stop again", id); + try { + api.getVirtualServerApi().stop(id); + } catch (IllegalStateException e) { + if (e.getMessage().contains("ALREADY_STOPPED") || e.getMessage().contains("STOPPING")) { + logger.trace("suspendNode({0}) - {1}", id, e.getMessage()); + // ignore as it has/will reach the desired destination state + } else { + throw e; + } + } + } else { + throw ise; + } + } catch (RuntimeException e) { + logger.error(e, "suspendNode({0}) - exception occurred!", id); + throw e; + } } } http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/d3a180ef/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/handlers/FGCPServerErrorRetryHandler.java ---------------------------------------------------------------------- diff --git a/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/handlers/FGCPServerErrorRetryHandler.java b/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/handlers/FGCPServerErrorRetryHandler.java index 8c4da29..47936ca 100644 --- a/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/handlers/FGCPServerErrorRetryHandler.java +++ b/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/handlers/FGCPServerErrorRetryHandler.java @@ -25,7 +25,6 @@ import org.jclouds.http.HttpCommand; import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpRetryHandler; import org.jclouds.http.HttpUtils; -import org.jclouds.http.handlers.BackoffLimitedRetryHandler; import org.jclouds.logging.Logger; import com.google.inject.Singleton; @@ -37,7 +36,7 @@ import com.google.inject.Singleton; */ @Singleton public class FGCPServerErrorRetryHandler implements HttpRetryHandler { - private final BackoffLimitedRetryHandler backoffHandler; + private final HttpRetryHandler backoffHandler; @Inject @Named(Constants.PROPERTY_MAX_RETRIES) @@ -46,7 +45,7 @@ public class FGCPServerErrorRetryHandler implements HttpRetryHandler { protected Logger logger = Logger.NULL; @Inject - public FGCPServerErrorRetryHandler(BackoffLimitedRetryHandler backoffHandler) { + public FGCPServerErrorRetryHandler(FGCPBackoffLimitedRetryHandler backoffHandler) { this.backoffHandler = backoffHandler; } http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/d3a180ef/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/handlers/ResponseNotSuccessHandler.java ---------------------------------------------------------------------- diff --git a/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/handlers/ResponseNotSuccessHandler.java b/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/handlers/ResponseNotSuccessHandler.java index 9d4ea62..ec461dd 100644 --- a/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/handlers/ResponseNotSuccessHandler.java +++ b/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/handlers/ResponseNotSuccessHandler.java @@ -48,7 +48,7 @@ public class ResponseNotSuccessHandler implements HttpErrorHandler { private static final Pattern RESOURCE_NOT_FOUND_PATTERN = Pattern.compile(".*RESOURCE_NOT_FOUND.*"); private static final Pattern NOT_IMPLEMENTED_PATTERN = Pattern.compile(".*NOTFOUND: API to the Version.*"); private static final Pattern ILLEGAL_STATE_PATTERN = Pattern - .compile(".*(NEVER_BOOTED|ALREADY_STARTED|ILLEGAL_STATE).*"); + .compile(".*(NEVER_BOOTED|ALREADY_STARTED|ALREADY_STOPPED|ILLEGAL_STATE).*"); private static final Pattern ILLEGAL_ARGUMENT_PATTERN = Pattern .compile(".*(SERVER_NAME_ALREADY_EXISTS|VALIDATION_ERROR).*"); http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/d3a180ef/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/ErrorResponseExpectTest.java ---------------------------------------------------------------------- diff --git a/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/ErrorResponseExpectTest.java b/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/ErrorResponseExpectTest.java index 1c8f8b9..c651fc4 100644 --- a/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/ErrorResponseExpectTest.java +++ b/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/ErrorResponseExpectTest.java @@ -22,7 +22,6 @@ import static org.testng.Assert.fail; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; -import org.jclouds.http.HttpResponseException; import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.ResourceNotFoundException; import org.testng.annotations.Test; @@ -45,11 +44,11 @@ public class ErrorResponseExpectTest extends BaseFGCPRestApiExpectTest { api.createServer("vm1", "economy", "IMG_A1B2C3_1234567890ABCD", "ABCDEFGH-A123B456CE-N-DMZ"); fail("should have thrown an exception"); } catch (IllegalStateException e) { - assertTrue(e.getMessage().contains("RECONFIG_ING")); + assertTrue(e.getMessage().contains("RECONFIG_ING"), e.getMessage()); } } - public void testAuthenticationErrorDueToCertFromDifferentRegion() { + public void testAuthorizationErrorDueToCertFromDifferentRegion() { HttpRequest request = buildGETWithQuery("Action=CreateVServer" + "&vserverName=vm1" + "&vserverType=economy" + "&diskImageId=IMG_A1B2C3_1234567890ABCD" + "&networkId=ABCDEFGH-A123B456CE-N-DMZ" + "&vsysId=ABCDEFGH-A123B456CE"); @@ -65,6 +64,36 @@ public class ErrorResponseExpectTest extends BaseFGCPRestApiExpectTest { } } + public void testIllegalStateDueToStartingRunningServer() { + HttpRequest request = buildGETWithQuery("Action=StartVServer" + "&vserverId=ABCDEFGH-A123B456CE-S-0004" + + "&vsysId=ABCDEFGH-A123B456CE"); + HttpResponse response = HttpResponse.builder().statusCode(500) + .payload(payloadFromResource("/IllegalState_RUNNING-response.xml")).build(); + VirtualServerApi api = requestSendsResponse(request, response).getVirtualServerApi(); + + try { + api.start("ABCDEFGH-A123B456CE-S-0004"); + fail("should have thrown an exception"); + } catch (IllegalStateException e) { + assertTrue(e.getMessage().contains("RUNNING"), e.getMessage()); + } + } + + public void testIllegalStateDueToStoppingStoppedServer() { + HttpRequest request = buildGETWithQuery("Action=StopVServer" + "&vserverId=ABCDEFGH-A123B456CE-S-0004" + + "&vsysId=ABCDEFGH-A123B456CE"); + HttpResponse response = HttpResponse.builder().statusCode(500) + .payload(payloadFromResource("/IllegalState_ALREADY_STOPPED-response.xml")).build(); + VirtualServerApi api = requestSendsResponse(request, response).getVirtualServerApi(); + + try { + api.stop("ABCDEFGH-A123B456CE-S-0004"); + fail("should have thrown an exception"); + } catch (IllegalStateException e) { + assertTrue(e.getMessage().contains("ALREADY_STOPPED"), e.getMessage()); + } + } + public void testErrorDueToWrongResourceId() { HttpRequest request = buildGETWithQuery("Action=CreateVServer" + "&vserverName=vm1" + "&vserverType=economy" + "&diskImageId=IMG_DOES_NOT_EXIST" + "&networkId=ABCDEFGH-A123B456CE-N-DMZ" @@ -77,7 +106,7 @@ public class ErrorResponseExpectTest extends BaseFGCPRestApiExpectTest { api.createServer("vm1", "economy", "IMG_DOES_NOT_EXIST", "ABCDEFGH-A123B456CE-N-DMZ"); fail("should have thrown an exception"); } catch (ResourceNotFoundException e) { - assertTrue(e.getMessage().contains("RESOURCE_NOT_FOUND")); + assertTrue(e.getMessage().contains("RESOURCE_NOT_FOUND"), e.getMessage()); } } http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/d3a180ef/fgcp/src/test/resources/responses/IllegalState_ALREADY_STOPPED-response.xml ---------------------------------------------------------------------- diff --git a/fgcp/src/test/resources/responses/IllegalState_ALREADY_STOPPED-response.xml b/fgcp/src/test/resources/responses/IllegalState_ALREADY_STOPPED-response.xml new file mode 100644 index 0000000..37370a4 --- /dev/null +++ b/fgcp/src/test/resources/responses/IllegalState_ALREADY_STOPPED-response.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CreateVServerResponse xmlns="http://apioviss.jp.fujitsu.com"> + <responseMessage>The status of Instance[ABCDEFGH-A123B456CE-S-0004] is [STOPPED].</responseMessage> + <responseStatus>ALREADY_STOPPED</responseStatus> +</CreateVServerResponse> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/d3a180ef/fgcp/src/test/resources/responses/IllegalState_RUNNING-response.xml ---------------------------------------------------------------------- diff --git a/fgcp/src/test/resources/responses/IllegalState_RUNNING-response.xml b/fgcp/src/test/resources/responses/IllegalState_RUNNING-response.xml new file mode 100644 index 0000000..b263e18 --- /dev/null +++ b/fgcp/src/test/resources/responses/IllegalState_RUNNING-response.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CreateVServerResponse xmlns="http://apioviss.jp.fujitsu.com"> + <responseMessage>The status of Instance[ABCDEFGH-A123B456CE-S-0004] is [RUNNING].</responseMessage> + <responseStatus>ALREADY_STARTED</responseStatus> +</CreateVServerResponse> \ No newline at end of file
