From 1eda57537bb46748295d1ea524f3d5ca9b8ae461 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 31 Oct 2010 18:41:26 -0700 Subject: [PATCH] Issue 383: started to resolve eCloud compatibility problems --- .../compute/BaseComputeServiceLiveTest.java | 73 ++++++------ .../StubComputeServiceIntegrationTest.java | 15 +++ .../ImageForVCloudExpressVAppTemplate.java | 11 +- .../config/CommonVCloudRestClientModule.java | 27 ++--- .../jclouds/vcloud/VCloudAsyncClientTest.java | 14 +-- .../vcloud/VCloudExpressAsyncClientTest.java | 2 +- .../TerremarkECloudContextBuilder.java | 5 +- .../compute/TerremarkVCloudComputeClient.java | 104 ++++++++++-------- .../functions/CreateUniqueKeyPair.java | 6 +- .../compute/strategy/DeleteKeyPair.java | 7 +- ...scriptionToGetDefaultLoginCredentials.java | 20 +++- .../TerremarkECloudRestClientModule.java | 41 ++++++- ...eTerremarkVCloudErrorFromHttpResponse.java | 14 ++- .../TerremarkECloudAsyncClientTest.java | 4 +- ...TerremarkVCloudExpressAsyncClientTest.java | 2 +- ...kECloudComputeServiceLiveTestDisabled.java | 19 +++- ...rkVCloudExpressComputeServiceLiveTest.java | 8 +- ...ltLoginCredentialsForVAppTemplateTest.java | 16 ++- ...remarkVCloudErrorFromHttpResponseTest.java | 7 ++ .../resources/terremark/ec_description.txt | 6 + 20 files changed, 268 insertions(+), 133 deletions(-) create mode 100644 vcloud/terremark/src/test/resources/terremark/ec_description.txt diff --git a/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java b/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java index d316a5feb4..9b056ed3e2 100755 --- a/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java +++ b/compute/src/test/java/org/jclouds/compute/BaseComputeServiceLiveTest.java @@ -408,6 +408,45 @@ public abstract class BaseComputeServiceLiveTest { testGet(); } + @Test(enabled = true, dependsOnMethods = "testSuspendResume") + public void testListNodes() throws Exception { + for (ComputeMetadata node : client.listNodes()) { + assert node.getProviderId() != null; + assert node.getLocation() != null; + assertEquals(node.getType(), ComputeType.NODE); + } + } + + @Test(enabled = true, dependsOnMethods = "testSuspendResume") + public void testGetNodesWithDetails() throws Exception { + for (NodeMetadata node : client.listNodesDetailsMatching(all())) { + assert node.getProviderId() != null : node; + assert node.getLocation() != null : node; + assertEquals(node.getType(), ComputeType.NODE); + assert node instanceof NodeMetadata; + NodeMetadata nodeMetadata = (NodeMetadata) node; + assert nodeMetadata.getProviderId() != null : nodeMetadata; + // nullable + // assert nodeMetadata.getImage() != null : node; + // user specified name is not always supported + // assert nodeMetadata.getName() != null : nodeMetadata; + if (nodeMetadata.getState() == NodeState.RUNNING) { + assert nodeMetadata.getPublicAddresses() != null : nodeMetadata; + assert nodeMetadata.getPublicAddresses().size() > 0 || nodeMetadata.getPrivateAddresses().size() > 0 : nodeMetadata; + assertNotNull(nodeMetadata.getPrivateAddresses()); + } + } + } + + @Test(enabled = true, dependsOnMethods = { "testListNodes", "testGetNodesWithDetails" }) + public void testDestroyNodes() { + client.destroyNodesMatching(withTag(tag)); + for (NodeMetadata node : filter(client.listNodesDetailsMatching(all()), withTag(tag))) { + assert node.getState() == NodeState.TERMINATED : node; + assertEquals(context.getCredentialStore().get("node#" + node.getId()), null); + } + } + private Set refreshNodes() { return filter(client.listNodesDetailsMatching(all()), and(withTag(tag), not(TERMINATED))); } @@ -445,34 +484,6 @@ public abstract class BaseComputeServiceLiveTest { assert t.getOptions().isIncludeMetadata() : "The metadata option should be 'true' " + "for the created template"; } - public void testListNodes() throws Exception { - for (ComputeMetadata node : client.listNodes()) { - assert node.getProviderId() != null; - assert node.getLocation() != null; - assertEquals(node.getType(), ComputeType.NODE); - } - } - - public void testGetNodesWithDetails() throws Exception { - for (NodeMetadata node : client.listNodesDetailsMatching(all())) { - assert node.getProviderId() != null : node; - assert node.getLocation() != null : node; - assertEquals(node.getType(), ComputeType.NODE); - assert node instanceof NodeMetadata; - NodeMetadata nodeMetadata = (NodeMetadata) node; - assert nodeMetadata.getProviderId() != null : nodeMetadata; - // nullable - // assert nodeMetadata.getImage() != null : node; - // user specified name is not always supported - // assert nodeMetadata.getName() != null : nodeMetadata; - if (nodeMetadata.getState() == NodeState.RUNNING) { - assert nodeMetadata.getPublicAddresses() != null : nodeMetadata; - assert nodeMetadata.getPublicAddresses().size() > 0 || nodeMetadata.getPrivateAddresses().size() > 0 : nodeMetadata; - assertNotNull(nodeMetadata.getPrivateAddresses()); - } - } - } - public void testListImages() throws Exception { for (Image image : client.listImages()) { assert image.getProviderId() != null : image; @@ -606,11 +617,7 @@ public abstract class BaseComputeServiceLiveTest { @AfterTest protected void cleanup() throws InterruptedException, ExecutionException, TimeoutException { if (nodes != null) { - client.destroyNodesMatching(withTag(tag)); - for (NodeMetadata node : filter(client.listNodesDetailsMatching(all()), withTag(tag))) { - assert node.getState() == NodeState.TERMINATED : node; - assertEquals(context.getCredentialStore().get("node#" + node.getId()), null); - } + testDestroyNodes(); } context.close(); } diff --git a/compute/src/test/java/org/jclouds/compute/StubComputeServiceIntegrationTest.java b/compute/src/test/java/org/jclouds/compute/StubComputeServiceIntegrationTest.java index 1880b4277a..3c270d1ca9 100644 --- a/compute/src/test/java/org/jclouds/compute/StubComputeServiceIntegrationTest.java +++ b/compute/src/test/java/org/jclouds/compute/StubComputeServiceIntegrationTest.java @@ -371,6 +371,21 @@ public class StubComputeServiceIntegrationTest extends BaseComputeServiceLiveTes super.testTemplateMatch(); } + @Override + public void testGetNodesWithDetails() throws Exception { + super.testGetNodesWithDetails(); + } + + @Override + public void testListNodes() throws Exception { + super.testListNodes(); + } + + @Override + public void testDestroyNodes() { + super.testDestroyNodes(); + } + @Override protected void cleanup() throws InterruptedException, ExecutionException, TimeoutException { super.cleanup(); diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVCloudExpressVAppTemplate.java b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVCloudExpressVAppTemplate.java index 3cb068aeb6..b6e6dd8ad7 100644 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVCloudExpressVAppTemplate.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/functions/ImageForVCloudExpressVAppTemplate.java @@ -22,6 +22,9 @@ package org.jclouds.vcloud.compute.functions; import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.compute.util.ComputeServiceUtils.parseOsFamilyOrNull; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import javax.inject.Inject; import org.jclouds.compute.domain.Image; @@ -44,7 +47,7 @@ public class ImageForVCloudExpressVAppTemplate implements Function> vDCtoOrgSupplier) { + protected String provideDefaultVDCName( + @org.jclouds.vcloud.endpoints.VDC Supplier> vDCtoOrgSupplier) { Map vDCtoOrg = vDCtoOrgSupplier.get(); checkState(vDCtoOrg.keySet().size() > 0, "No vdcs present!"); return get(vDCtoOrg.keySet(), 0); @@ -408,12 +409,11 @@ public class CommonVCloudRestClientModule networks = vDC.getAvailableNetworks(); checkState(networks.size() > 0, "No networks present in vDC: " + vDC.getName()); if (networks.size() == 1) @@ -425,18 +425,7 @@ public class CommonVCloudRestClientModule networks, + Injector injector) { + logger.warn("default network for vdc %s not set", vDC.getName()); + return Iterables.getLast(networks.values()).getHref(); + } + @Provides @Singleton protected Org provideOrg(CommonVCloudClient discovery) { diff --git a/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudAsyncClientTest.java b/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudAsyncClientTest.java index 74aa2cd63e..15b8d7deeb 100644 --- a/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudAsyncClientTest.java +++ b/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudAsyncClientTest.java @@ -216,7 +216,6 @@ public class VCloudAsyncClientTest extends RestClientTest { checkFilters(request); } - public void testCaptureVAppInVDC() throws SecurityException, NoSuchMethodException, IOException { Method method = VCloudAsyncClient.class.getMethod("captureVAppInVDC", URI.class, URI.class, String.class, CaptureVAppOptions[].class); @@ -242,8 +241,8 @@ public class VCloudAsyncClientTest extends RestClientTest { CaptureVAppOptions[].class); HttpRequest request = processor.createRequest(method, URI .create("https://vcenterprise.bluelock.com/api/v1.0/vdc/1"), URI - .create("https://vcenterprise.bluelock.com/api/v1.0/vapp/201"), "my-template", - new CaptureVAppOptions().withDescription("The description of the new vApp Template")); + .create("https://vcenterprise.bluelock.com/api/v1.0/vapp/201"), "my-template", new CaptureVAppOptions() + .withDescription("The description of the new vApp Template")); assertRequestLineEquals(request, "POST https://vcenterprise.bluelock.com/api/v1.0/vdc/1/action/captureVApp HTTP/1.1"); @@ -258,8 +257,6 @@ public class VCloudAsyncClientTest extends RestClientTest { checkFilters(request); } - - public void testlistOrgs() throws SecurityException, NoSuchMethodException, IOException { Method method = VCloudAsyncClient.class.getMethod("listOrgs"); HttpRequest request = processor.createRequest(method); @@ -857,12 +854,13 @@ public class VCloudAsyncClientTest extends RestClientTest { } @Override - protected String provideDefaultVDCName(@org.jclouds.vcloud.endpoints.VDC Supplier> vDCtoOrgSupplier) { + protected String provideDefaultVDCName( + @org.jclouds.vcloud.endpoints.VDC Supplier> vDCtoOrgSupplier) { return "vdc"; } - + @Override - protected URI provideDefaultNetwork(URI vdc, CommonVCloudClient client, Injector injector) { + protected URI provideDefaultNetwork(URI vdc, Injector injector) { return URI.create("https://vcenterprise.bluelock.com/api/v1.0/network/1990"); } diff --git a/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudExpressAsyncClientTest.java b/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudExpressAsyncClientTest.java index f8c648fc17..1fe2e00ca6 100644 --- a/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudExpressAsyncClientTest.java +++ b/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudExpressAsyncClientTest.java @@ -694,7 +694,7 @@ public class VCloudExpressAsyncClientTest extends RestClientTest modules) { - // TODO make ecloud version which retrieves passwords from the vapptemplate description - modules.add(new VCloudExpressComputeServiceContextModule()); + modules.add(new TerremarkVCloudComputeServiceContextModule()); } @Override diff --git a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudComputeClient.java b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudComputeClient.java index 86e2b3f16a..27f4e7c007 100644 --- a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudComputeClient.java +++ b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudComputeClient.java @@ -37,6 +37,7 @@ import javax.inject.Singleton; import org.jclouds.compute.domain.NodeState; import org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy; import org.jclouds.domain.Credentials; +import org.jclouds.http.HttpResponseException; import org.jclouds.vcloud.compute.internal.VCloudExpressComputeClientImpl; import org.jclouds.vcloud.domain.Status; import org.jclouds.vcloud.domain.Task; @@ -46,6 +47,7 @@ import org.jclouds.vcloud.domain.VCloudExpressVApp; import org.jclouds.vcloud.domain.VCloudExpressVAppTemplate; import org.jclouds.vcloud.options.InstantiateVAppTemplateOptions; import org.jclouds.vcloud.terremark.TerremarkECloudClient; +import org.jclouds.vcloud.terremark.TerremarkVCloudClient; import org.jclouds.vcloud.terremark.TerremarkVCloudExpressClient; import org.jclouds.vcloud.terremark.domain.InternetService; import org.jclouds.vcloud.terremark.domain.Node; @@ -63,16 +65,16 @@ import com.google.common.collect.Sets; @Singleton public class TerremarkVCloudComputeClient extends VCloudExpressComputeClientImpl { - protected final TerremarkVCloudExpressClient client; + protected final TerremarkVCloudClient client; protected final PopulateDefaultLoginCredentialsForImageStrategy credentialsProvider; protected final Provider passwordGenerator; protected final Map credentialStore; @Inject - protected TerremarkVCloudComputeClient(TerremarkVCloudExpressClient client, - PopulateDefaultLoginCredentialsForImageStrategy credentialsProvider, - @Named("PASSWORD") Provider passwordGenerator, Predicate successTester, - Map vAppStatusToNodeState, Map credentialStore) { + protected TerremarkVCloudComputeClient(TerremarkVCloudClient client, + PopulateDefaultLoginCredentialsForImageStrategy credentialsProvider, + @Named("PASSWORD") Provider passwordGenerator, Predicate successTester, + Map vAppStatusToNodeState, Map credentialStore) { super(client, successTester, vAppStatusToNodeState); this.client = client; this.credentialsProvider = credentialsProvider; @@ -82,7 +84,7 @@ public class TerremarkVCloudComputeClient extends VCloudExpressComputeClientImpl @Override public VCloudExpressVApp start(@Nullable URI VDC, URI templateId, String name, - InstantiateVAppTemplateOptions options, int... portsToOpen) { + InstantiateVAppTemplateOptions options, int... portsToOpen) { if (options.getDiskSizeKilobytes() != null) { logger.warn("trmk does not support resizing the primary disk; unsetting disk size"); } @@ -92,7 +94,7 @@ public class TerremarkVCloudComputeClient extends VCloudExpressComputeClientImpl String password = null; VCloudExpressVAppTemplate template = client.getVAppTemplate(templateId); if (template.getDescription().indexOf("Windows") != -1 - && options instanceof TerremarkInstantiateVAppTemplateOptions) { + && options instanceof TerremarkInstantiateVAppTemplateOptions) { password = passwordGenerator.get(); TerremarkInstantiateVAppTemplateOptions.class.cast(options).getProperties().put("password", password); } @@ -100,8 +102,8 @@ public class TerremarkVCloudComputeClient extends VCloudExpressComputeClientImpl VCloudExpressVApp vAppResponse = super.start(VDC, templateId, name, options, portsToOpen); if (password != null) { - credentialStore.put("node#" + vAppResponse.getHref().toASCIIString(), new Credentials(defaultCredentials.identity, - password)); + credentialStore.put("node#" + vAppResponse.getHref().toASCIIString(), new Credentials( + defaultCredentials.identity, password)); } if (portsToOpen.length > 0) createPublicAddressMappedToPorts(vAppResponse.getHref(), portsToOpen); @@ -116,51 +118,67 @@ public class TerremarkVCloudComputeClient extends VCloudExpressComputeClientImpl InternetService is = null; Protocol protocol; switch (port) { - case 22: - protocol = Protocol.TCP; - break; - case 80: - case 8080: - protocol = Protocol.HTTP; - break; - case 443: - protocol = Protocol.HTTPS; - break; - default: - protocol = Protocol.HTTP; - break; + case 22: + protocol = Protocol.TCP; + break; + case 80: + case 8080: + protocol = Protocol.HTTP; + break; + case 443: + protocol = Protocol.HTTPS; + break; + default: + protocol = Protocol.HTTP; + break; } if (ip == null) { if (client instanceof TerremarkVCloudExpressClient) { is = TerremarkVCloudExpressClient.class.cast(client).addInternetServiceToVDC( - vApp.getVDC().getHref(), - vApp.getName() + "-" + port, - protocol, - port, - withDescription(String.format("port %d access to serverId: %s name: %s", port, vApp.getName(), - vApp.getName()))); + vApp.getVDC().getHref(), + vApp.getName() + "-" + port, + protocol, + port, + withDescription(String.format("port %d access to serverId: %s name: %s", port, vApp.getName(), + vApp.getName()))); ip = is.getPublicIpAddress(); } else { logger.debug(">> creating InternetService in vDC %s:%s:%d", vApp.getVDC().getName(), protocol, port); - ip = TerremarkECloudClient.class.cast(client).activatePublicIpInVDC(vApp.getVDC().getHref()); + // http://support.theenterprisecloud.com/kb/default.asp?id=706&Lang=1&SID= + // response with a 500 error code means we should look for an existing public ip to + // use + try { + ip = TerremarkECloudClient.class.cast(client).activatePublicIpInVDC(vApp.getVDC().getHref()); + } catch (HttpResponseException e) { + if (e.getResponse().getStatusCode() == 500) { + logger.warn(">> no more ip addresses available, looking for one to re-use"); + for (PublicIpAddress existingIp : client.getPublicIpsAssociatedWithVDC(vApp.getVDC().getHref())) { + Set services = client.getInternetServicesOnPublicIp(existingIp.getId()); + if (services.size() == 0) { + ip = existingIp; + break; + } + } + if (ip == null) + throw e; + } else { + throw e; + } + } is = client.addInternetServiceToExistingIp(ip.getId(), vApp.getName() + "-" + port, protocol, port, - withDescription(String.format("port %d access to serverId: %s name: %s", port, vApp.getName(), - vApp.getName()))); + withDescription(String.format("port %d access to serverId: %s name: %s", port, vApp.getName(), + vApp.getName()))); } } else { logger.debug(">> adding InternetService %s:%s:%d", ip.getAddress(), protocol, port); - is = client.addInternetServiceToExistingIp( - ip.getId(), - vApp.getName() + "-" + port, - protocol, - port, - withDescription(String.format("port %d access to serverId: %s name: %s", port, vApp.getName(), - vApp.getName()))); + is = client.addInternetServiceToExistingIp(ip.getId(), vApp.getName() + "-" + port, protocol, port, + withDescription(String.format("port %d access to serverId: %s name: %s", port, vApp.getName(), + vApp.getName()))); } - logger.debug("<< created InternetService(%s) %s:%s:%d", is.getName(), is.getPublicIpAddress().getAddress(), - is.getProtocol(), is.getPort()); + logger.debug("<< created InternetService(%s) %s:%s:%d", is.getName(), is.getPublicIpAddress().getAddress(), is + .getProtocol(), is.getPort()); logger.debug(">> adding Node %s:%d -> %s:%d", is.getPublicIpAddress().getAddress(), is.getPort(), - privateAddress, port); + privateAddress, port); Node node = client.addNode(is.getId(), privateAddress, vApp.getName() + "-" + port, port); logger.debug("<< added Node(%s)", node.getName()); } @@ -174,13 +192,13 @@ public class TerremarkVCloudComputeClient extends VCloudExpressComputeClientImpl if (vApp.getNetworkToAddresses().containsValue(node.getIpAddress())) { ipAddresses.add(service.getPublicIpAddress()); logger.debug(">> deleting Node(%s) %s:%d -> %s:%d", node.getName(), service.getPublicIpAddress() - .getAddress(), service.getPort(), node.getIpAddress(), node.getPort()); + .getAddress(), service.getPort(), node.getIpAddress(), node.getPort()); client.deleteNode(node.getId()); logger.debug("<< deleted Node(%s)", node.getName()); Set nodes = client.getNodes(service.getId()); if (nodes.size() == 0) { logger.debug(">> deleting InternetService(%s) %s:%d", service.getName(), service.getPublicIpAddress() - .getAddress(), service.getPort()); + .getAddress(), service.getPort()); client.deleteInternetService(service.getId()); logger.debug("<< deleted InternetService(%s)", service.getName()); continue SERVICE; diff --git a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/functions/CreateUniqueKeyPair.java b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/functions/CreateUniqueKeyPair.java index 291f5350e8..7c183fd7a7 100644 --- a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/functions/CreateUniqueKeyPair.java +++ b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/functions/CreateUniqueKeyPair.java @@ -32,7 +32,7 @@ import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.http.HttpResponseException; import org.jclouds.logging.Logger; import org.jclouds.util.Utils; -import org.jclouds.vcloud.terremark.TerremarkVCloudExpressClient; +import org.jclouds.vcloud.terremark.TerremarkVCloudClient; import org.jclouds.vcloud.terremark.compute.domain.OrgAndName; import org.jclouds.vcloud.terremark.domain.KeyPair; @@ -48,11 +48,11 @@ public class CreateUniqueKeyPair implements Function { @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; - protected final TerremarkVCloudExpressClient trmkClient; + protected final TerremarkVCloudClient trmkClient; protected Supplier randomSuffix; @Inject - CreateUniqueKeyPair(TerremarkVCloudExpressClient trmkClient, Supplier randomSuffix) { + CreateUniqueKeyPair(TerremarkVCloudClient trmkClient, Supplier randomSuffix) { this.trmkClient = trmkClient; this.randomSuffix = randomSuffix; } diff --git a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/strategy/DeleteKeyPair.java b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/strategy/DeleteKeyPair.java index 34b28f2c84..91e8f70c22 100644 --- a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/strategy/DeleteKeyPair.java +++ b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/strategy/DeleteKeyPair.java @@ -28,7 +28,7 @@ import javax.inject.Singleton; import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.logging.Logger; -import org.jclouds.vcloud.terremark.TerremarkVCloudExpressClient; +import org.jclouds.vcloud.terremark.TerremarkVCloudClient; import org.jclouds.vcloud.terremark.compute.domain.KeyPairCredentials; import org.jclouds.vcloud.terremark.compute.domain.OrgAndName; import org.jclouds.vcloud.terremark.domain.KeyPair; @@ -44,12 +44,11 @@ public class DeleteKeyPair { @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; - final TerremarkVCloudExpressClient terremarkClient; + final TerremarkVCloudClient terremarkClient; final ConcurrentMap credentialsMap; @Inject - DeleteKeyPair(TerremarkVCloudExpressClient terremarkClient, - ConcurrentMap credentialsMap) { + DeleteKeyPair(TerremarkVCloudClient terremarkClient, ConcurrentMap credentialsMap) { this.terremarkClient = terremarkClient; this.credentialsMap = credentialsMap; } diff --git a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/strategy/ParseVAppTemplateDescriptionToGetDefaultLoginCredentials.java b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/strategy/ParseVAppTemplateDescriptionToGetDefaultLoginCredentials.java index 48a4cbd71a..dcbd28fb09 100644 --- a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/strategy/ParseVAppTemplateDescriptionToGetDefaultLoginCredentials.java +++ b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/strategy/ParseVAppTemplateDescriptionToGetDefaultLoginCredentials.java @@ -25,10 +25,14 @@ import static com.google.common.base.Preconditions.checkNotNull; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.annotation.Resource; +import javax.inject.Named; import javax.inject.Singleton; +import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy; import org.jclouds.domain.Credentials; +import org.jclouds.logging.Logger; import org.jclouds.vcloud.domain.VCloudExpressVAppTemplate; /** @@ -36,15 +40,20 @@ import org.jclouds.vcloud.domain.VCloudExpressVAppTemplate; */ @Singleton public class ParseVAppTemplateDescriptionToGetDefaultLoginCredentials implements - PopulateDefaultLoginCredentialsForImageStrategy { + PopulateDefaultLoginCredentialsForImageStrategy { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + public static final Pattern USER_PASSWORD_PATTERN = Pattern - .compile(".*[Uu]sername: ([a-z]+) ?.*\n[Pp]assword: ([^ \n\r]+) ?\r?\n.*"); + .compile(".*[Uu]sername: ([a-z]+) ?.*\n[Pp]assword: ([^ \n\r]+) ?\r?\n.*"); @Override public Credentials execute(Object resourceToAuthenticate) { checkNotNull(resourceToAuthenticate); - checkArgument(resourceToAuthenticate instanceof VCloudExpressVAppTemplate, "Resource must be an VAppTemplate (for Terremark)"); + checkArgument(resourceToAuthenticate instanceof VCloudExpressVAppTemplate, + "Resource must be an VAppTemplate (for Terremark)"); VCloudExpressVAppTemplate template = (VCloudExpressVAppTemplate) resourceToAuthenticate; String search = template.getDescription() != null ? template.getDescription() : template.getName(); if (search.indexOf("Windows") >= 0) { @@ -54,8 +63,9 @@ public class ParseVAppTemplateDescriptionToGetDefaultLoginCredentials implements if (matcher.find()) { return new Credentials(matcher.group(1), matcher.group(2)); } else { - throw new RuntimeException("could not parse username/password for image: " + template.getHref() + "\n" - + search); + logger.warn("could not parse username/password for image: " + template.getHref() + "\n" + + search); + return null; } } } diff --git a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/config/TerremarkECloudRestClientModule.java b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/config/TerremarkECloudRestClientModule.java index fbb096657e..c13caa7e8c 100644 --- a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/config/TerremarkECloudRestClientModule.java +++ b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/config/TerremarkECloudRestClientModule.java @@ -19,17 +19,27 @@ package org.jclouds.vcloud.terremark.config; +import java.net.URI; +import java.util.Map; +import java.util.NoSuchElementException; + import javax.inject.Singleton; import org.jclouds.http.RequiresHttp; import org.jclouds.rest.ConfiguresRestClient; +import org.jclouds.rest.ResourceNotFoundException; import org.jclouds.vcloud.VCloudExpressAsyncClient; import org.jclouds.vcloud.VCloudExpressClient; -import org.jclouds.vcloud.terremark.TerremarkVCloudAsyncClient; -import org.jclouds.vcloud.terremark.TerremarkVCloudClient; +import org.jclouds.vcloud.domain.ReferenceType; +import org.jclouds.vcloud.domain.network.OrgNetwork; import org.jclouds.vcloud.terremark.TerremarkECloudAsyncClient; import org.jclouds.vcloud.terremark.TerremarkECloudClient; +import org.jclouds.vcloud.terremark.TerremarkVCloudAsyncClient; +import org.jclouds.vcloud.terremark.TerremarkVCloudClient; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import com.google.inject.Injector; import com.google.inject.Provides; /** @@ -70,4 +80,31 @@ public class TerremarkECloudRestClientModule extends return in; } + @Override + protected URI findDefaultNetworkForVDC(org.jclouds.vcloud.domain.VDC vDC, Map networks, + final Injector injector) { + // TODO FIXME XXX: In Terremark Enterprise environment with multiple VDC's this does not + // work well. + // Each VDC will have differnt network subnets. So we cannot assume the default VDC's + // networks will + // work with non-default VDC's. So make PROPERTY_VCLOUD_DEFAULT_NETWORK optional. If + // this property + // is not set, they are expected to add NetworkConfig to the options when launching a + // server. + logger.warn("default network for vdc %s not set", vDC.getName()); + try { + return Iterables.find(networks.values(), new Predicate() { + + @Override + public boolean apply(ReferenceType input) { + OrgNetwork network = injector.getInstance(TerremarkECloudClient.class).getNetwork(input.getHref()); + // TODO: get extension data on this network and check NetworkType == DMZ + return network.getDescription() != null &&network.getDescription().toLowerCase().contains("dmz"); + } + + }).getHref(); + } catch (NoSuchElementException e) { + throw new ResourceNotFoundException("no dmz networks in vdc " + vDC.getName() + ": " + networks); + } + } } diff --git a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/handlers/ParseTerremarkVCloudErrorFromHttpResponse.java b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/handlers/ParseTerremarkVCloudErrorFromHttpResponse.java index 110ddf4a97..5a2b6e54e6 100644 --- a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/handlers/ParseTerremarkVCloudErrorFromHttpResponse.java +++ b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/handlers/ParseTerremarkVCloudErrorFromHttpResponse.java @@ -54,10 +54,11 @@ public class ParseTerremarkVCloudErrorFromHttpResponse implements HttpErrorHandl try { String content = parseErrorFromContentOrNull(command, response); - if (response.getMessage() != null && ((response.getMessage().indexOf("because there is a pending task running") != -1) - || (response.getMessage().indexOf("because it is already powered off") != -1) - || (response.getMessage().indexOf("already exists") != -1) - || (response.getMessage().indexOf("same name exists") != -1))) + if (response.getMessage() != null + && ((response.getMessage().indexOf("because there is a pending task running") != -1) + || (response.getMessage().indexOf("because it is already powered off") != -1) + || (response.getMessage().indexOf("already exists") != -1) || (response.getMessage() + .indexOf("same name exists") != -1))) exception = new IllegalStateException(response.getMessage(), exception); else switch (response.getStatusCode()) { @@ -80,8 +81,9 @@ public class ParseTerremarkVCloudErrorFromHttpResponse implements HttpErrorHandl } exception = new ResourceNotFoundException(message, exception); break; - default: - exception = new HttpResponseException(command, response, content); + case 501: + if (response.getMessage() != null && (response.getMessage().indexOf("NotImplemented") != -1)) + exception = new UnsupportedOperationException(response.getMessage(), exception); } } finally { releasePayload(response); diff --git a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/TerremarkECloudAsyncClientTest.java b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/TerremarkECloudAsyncClientTest.java index 19fc861bde..ae1f723d9d 100644 --- a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/TerremarkECloudAsyncClientTest.java +++ b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/TerremarkECloudAsyncClientTest.java @@ -51,8 +51,8 @@ import org.jclouds.util.Utils; import org.jclouds.vcloud.CommonVCloudClient; import org.jclouds.vcloud.VCloudExpressAsyncClientTest.VCloudRestClientModuleExtension.TestOrgCatalogItemSupplier; import org.jclouds.vcloud.VCloudExpressAsyncClientTest.VCloudRestClientModuleExtension.TestOrgCatalogSupplier; -import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.Org; +import org.jclouds.vcloud.domain.ReferenceType; import org.jclouds.vcloud.domain.VCloudSession; import org.jclouds.vcloud.domain.internal.ReferenceTypeImpl; import org.jclouds.vcloud.domain.network.NetworkConfig; @@ -604,7 +604,7 @@ public class TerremarkECloudAsyncClientTest extends RestClientTest tmContext = new ComputeServiceContextFactory() + .createContext(provider, identity, credential).getProviderSpecificContext(); + VCloudExpressVApp vApp = tmContext.getApi().findVAppInOrgVDCNamed(null, null, allData.getName()); + assertEquals(vApp.getName(), allData.getName()); } } + @Override + public void testDestroyNodes() { + super.testDestroyNodes(); + } + @Override protected JschSshClientModule getSshModule() { return new JschSshClientModule(); diff --git a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudExpressComputeServiceLiveTest.java b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudExpressComputeServiceLiveTest.java index 1bbdcc0777..f8d52c5c10 100644 --- a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudExpressComputeServiceLiveTest.java +++ b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/TerremarkVCloudExpressComputeServiceLiveTest.java @@ -34,6 +34,7 @@ import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.rest.RestContext; import org.jclouds.ssh.jsch.config.JschSshClientModule; import org.jclouds.vcloud.domain.VCloudExpressVApp; +import org.jclouds.vcloud.terremark.TerremarkVCloudClient; import org.jclouds.vcloud.terremark.TerremarkVCloudExpressAsyncClient; import org.jclouds.vcloud.terremark.TerremarkVCloudExpressClient; import org.testng.annotations.Test; @@ -105,13 +106,18 @@ public class TerremarkVCloudExpressComputeServiceLiveTest extends BaseComputeSer assertEquals(node.getType(), ComputeType.NODE); NodeMetadata allData = client.getNodeMetadata(node.getId()); System.out.println(allData.getHardware()); - RestContext tmContext = new ComputeServiceContextFactory() + RestContext tmContext = new ComputeServiceContextFactory() .createContext(provider, identity, credential).getProviderSpecificContext(); VCloudExpressVApp vApp = tmContext.getApi().findVAppInOrgVDCNamed(null, null, allData.getName()); assertEquals(vApp.getName(), allData.getName()); } } + @Override + public void testDestroyNodes() { + super.testDestroyNodes(); + } + @Override protected JschSshClientModule getSshModule() { return new JschSshClientModule(); diff --git a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/strategy/PopulateDefaultLoginCredentialsForVAppTemplateTest.java b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/strategy/PopulateDefaultLoginCredentialsForVAppTemplateTest.java index eab1f7a580..8298ce5789 100644 --- a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/strategy/PopulateDefaultLoginCredentialsForVAppTemplateTest.java +++ b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/compute/strategy/PopulateDefaultLoginCredentialsForVAppTemplateTest.java @@ -81,7 +81,21 @@ public class PopulateDefaultLoginCredentialsForVAppTemplateTest { assertEquals(creds.credential, "vpncubed"); verify(template); } - + + @Test + public void testEC() throws IOException { + InputStream is = getClass().getResourceAsStream("/terremark/ec_description.txt"); + String description = new String(ByteStreams.toByteArray(is)); + VCloudExpressVAppTemplate template = createMock(VCloudExpressVAppTemplate.class); + expect(template.getDescription()).andReturn(description).atLeastOnce(); + replay(template); + ParseVAppTemplateDescriptionToGetDefaultLoginCredentials converter = new ParseVAppTemplateDescriptionToGetDefaultLoginCredentials(); + Credentials creds = converter.execute(template); + assertEquals(creds.identity, "ecloud"); + assertEquals(creds.credential, "TmrkCl0ud1s#1!"); + verify(template); + } + @Test public void testWindows() throws IOException { InputStream is = getClass().getResourceAsStream("/terremark/windows_description.txt"); diff --git a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/handlers/ParseTerremarkVCloudErrorFromHttpResponseTest.java b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/handlers/ParseTerremarkVCloudErrorFromHttpResponseTest.java index f01856cec5..19062050d9 100644 --- a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/handlers/ParseTerremarkVCloudErrorFromHttpResponseTest.java +++ b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/handlers/ParseTerremarkVCloudErrorFromHttpResponseTest.java @@ -71,6 +71,13 @@ public class ParseTerremarkVCloudErrorFromHttpResponseTest extends BaseHttpError "", "", AuthorizationException.class); } + @Test + public void test501SetsNotImplementedMakesUnsupportedOperationException() { + assertCodeMakes("POST", URI + .create("https://services.enterprisecloud.terremark.com/api/v0.8b-ext2.5/vapp/49373/action/undeploy"), + 501, "HTTP/1.1 501 NotImplemented", "", UnsupportedOperationException.class); + } + @Test public void testbecause_there_is_a_pending_task_runningSetsIllegalStateException() { assertCodeMakes("GET", URI.create("https://services.vcloudexpress.terremark.com/api/v0.8a-ext1.6/vdc/32"), 500, diff --git a/vcloud/terremark/src/test/resources/terremark/ec_description.txt b/vcloud/terremark/src/test/resources/terremark/ec_description.txt new file mode 100644 index 0000000000..0f5cd160dd --- /dev/null +++ b/vcloud/terremark/src/test/resources/terremark/ec_description.txt @@ -0,0 +1,6 @@ +username: ecloud +password: TmrkCl0ud1s#1! + +This template consists of a base Ubuntu Server 10.04 installation. Additional software is available via apt. Updates are available via Software Updater. + +The hostname and base IP will be set as part of the server creation process based on user input.