From 9a1abce72fc0af9dc09a92d7e18fe15c777d141a Mon Sep 17 00:00:00 2001 From: "adrian.f.cole" Date: Sun, 15 Nov 2009 01:48:27 +0000 Subject: [PATCH] Issue 112: added better testing for cloud compatibility git-svn-id: http://jclouds.googlecode.com/svn/trunk@2290 3d8758e0-26b5-11de-8745-db77d3ebf521 --- .../predicates/RetryablePredicate.java | 75 ++++++++++++++ .../org/jclouds/predicates/SocketOpen.java | 79 +++++++++++++++ .../predicates/RetryablePredicateTest.java | 68 +++++++++++++ .../java/org/jclouds/vcloud/VCloudClient.java | 6 ++ .../org/jclouds/vcloud/VCloudDiscovery.java | 4 +- .../java/org/jclouds/vcloud/VCloudLogin.java | 3 +- .../VCloudDiscoveryRestClientModule.java | 8 +- .../vcloud/config/VCloudRestClientModule.java | 19 ++-- .../vcloud/functions/CatalogIdToUri.java | 5 +- .../jclouds/vcloud/functions/VAppIdToUri.java | 5 +- .../jclouds/vcloud/VCloudClientLiveTest.java | 7 ++ .../vcloud/VCloudDiscoveryLiveTest.java | 3 +- .../jclouds/vcloud/VCloudLoginLiveTest.java | 3 +- .../VCloudDiscoveryRestClientModuleTest.java | 47 +++++++-- .../vcloud/predicates/TaskSuccess.java | 63 ++++++++++++ vcloud/core/src/test/resources/log4j.xml | 15 ++- ...tantiateVAppTemplateParamsToXmlEntity.java | 7 ++ .../InstantiateVAppTemplateOptions.java | 50 ++++++++++ .../terremark/ConfigureInternetService.xml | 4 + .../InstantiateVAppTemplateParams.xml | 6 +- .../TerremarkVCloudClientLiveTest.java | 97 +++++++++++-------- ...iateVAppTemplateParamsToXmlEntityTest.java | 5 +- .../InstantiateVAppTemplateOptionsTest.java | 60 ++++++++++++ .../InstantiateVAppTemplateParams-test.xml | 6 +- 24 files changed, 566 insertions(+), 79 deletions(-) create mode 100644 core/src/main/java/org/jclouds/predicates/RetryablePredicate.java create mode 100644 core/src/main/java/org/jclouds/predicates/SocketOpen.java create mode 100644 core/src/test/java/org/jclouds/predicates/RetryablePredicateTest.java create mode 100644 vcloud/core/src/test/java/org/jclouds/vcloud/predicates/TaskSuccess.java create mode 100644 vcloud/terremark/src/main/resources/terremark/ConfigureInternetService.xml diff --git a/core/src/main/java/org/jclouds/predicates/RetryablePredicate.java b/core/src/main/java/org/jclouds/predicates/RetryablePredicate.java new file mode 100644 index 0000000000..38ac92d808 --- /dev/null +++ b/core/src/main/java/org/jclouds/predicates/RetryablePredicate.java @@ -0,0 +1,75 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.jclouds.predicates; + +import java.util.concurrent.TimeUnit; + +import javax.annotation.Resource; + +import org.jclouds.logging.Logger; +import org.joda.time.DateTime; + +import com.google.common.base.Predicate; + +/** + * + * Retries a condition until it is met or a timeout occurs. + * + * @author Adrian Cole + */ +public class RetryablePredicate implements Predicate { + private final int maxWait; + private final int checkInterval; + private final Predicate predicate; + + @Resource + protected Logger logger = Logger.NULL; + + public RetryablePredicate(Predicate predicate, long maxWait, long checkInterval, TimeUnit unit) { + this.predicate = predicate; + this.maxWait = (int) unit.toMillis(maxWait); + this.checkInterval = (int) unit.toMillis(checkInterval); + } + + @Override + public boolean apply(T input) { + try { + for (DateTime end = new DateTime().plusMillis(maxWait); before(end); Thread + .sleep(checkInterval)) { + if (predicate.apply(input)) { + return true; + } else if (!before(end)){ + return false; + } + } + } catch (InterruptedException e) { + logger.warn(e, "predicate %s on %s interrupted, returning false", input, predicate); + } + return false; + } + + boolean before(DateTime end){ + return new DateTime().compareTo(end) < 1; + } +} diff --git a/core/src/main/java/org/jclouds/predicates/SocketOpen.java b/core/src/main/java/org/jclouds/predicates/SocketOpen.java new file mode 100644 index 0000000000..cff9945916 --- /dev/null +++ b/core/src/main/java/org/jclouds/predicates/SocketOpen.java @@ -0,0 +1,79 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * 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.jclouds.predicates; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.logging.Logger; + +import com.google.common.base.Predicate; + +/** + * + * Tests to see if a socket is open. + * + * @author Adrian Cole + */ +@Singleton +public class SocketOpen implements Predicate { + + @Resource + protected Logger logger = Logger.NULL; + + @Inject(optional = true) + @Named("org.jclouds.socket_timeout") + private int timeout = 2000; + + @Override + public boolean apply(InetSocketAddress socketAddress) { + Socket socket = null; + try { + logger.trace("testing socket %s", socketAddress); + socket = new Socket(); + socket.setReuseAddress(false); + socket.setSoLinger(false, 1); + socket.setSoTimeout(timeout); + socket.connect(socketAddress, timeout); + } catch (IOException e) { + return false; + } finally { + if (socket != null) { + try { + socket.close(); + } catch (IOException ioe) { + // no work to do + } + } + } + return true; + } + +} diff --git a/core/src/test/java/org/jclouds/predicates/RetryablePredicateTest.java b/core/src/test/java/org/jclouds/predicates/RetryablePredicateTest.java new file mode 100644 index 0000000000..3150040358 --- /dev/null +++ b/core/src/test/java/org/jclouds/predicates/RetryablePredicateTest.java @@ -0,0 +1,68 @@ +package org.jclouds.predicates; + +import java.util.concurrent.TimeUnit; + +import org.joda.time.DateTime; +import org.testng.annotations.Test; + +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; + +/** + * + * @author Adrian Cole + * + */ +@Test(groups = "unit", sequential = true, testName = "jclouds.RetryablePredicateTest") +public class RetryablePredicateTest { + + @Test + void testAlwaysTrue() { + RetryablePredicate predicate = new RetryablePredicate(Predicates + . alwaysTrue(), 3, 1, TimeUnit.SECONDS); + DateTime start = new DateTime(); + predicate.apply(""); + DateTime now = new DateTime(); + assert now.compareTo(start.plusSeconds(1)) < 0 : String.format("%s should be less than %s", + now, start.plusSeconds(1)); } + + @Test + void testAlwaysFalseMillis() { + RetryablePredicate predicate = new RetryablePredicate(Predicates + . alwaysFalse(), 3, 1, TimeUnit.SECONDS); + DateTime start = new DateTime(); + predicate.apply(""); + DateTime now = new DateTime(); + assert now.compareTo(start.plusSeconds(3)) > 0 : String.format("%s should be less than %s", + start.plusSeconds(3), now); + assert now.compareTo(start.plusSeconds(6)) <= 0 : String.format( + "%s should be greater than %s", start.plusSeconds(6), now); + + } + + private static class SecondTimeTrue implements Predicate { + + private int count = 0; + + @Override + public boolean apply(String input) { + return count++ == 1; + } + + } + + @Test + void testSecondTimeTrue() { + RetryablePredicate predicate = new RetryablePredicate(new SecondTimeTrue(), + 3, 1, TimeUnit.SECONDS); + + DateTime start = new DateTime(); + predicate.apply(""); + DateTime now = new DateTime(); + assert now.compareTo(start.plusSeconds(1)) > 0 : String.format("%s should be greater than %s", + now,start.plusSeconds(1)); + assert now.compareTo(start.plusSeconds(2)) <= 0 : String.format( + "%s should be greater than %s", start.plusSeconds(2), now); + } + +} \ No newline at end of file diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/VCloudClient.java b/vcloud/core/src/main/java/org/jclouds/vcloud/VCloudClient.java index 8aecffc3e1..a7929cdca5 100644 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/VCloudClient.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/VCloudClient.java @@ -26,6 +26,7 @@ package org.jclouds.vcloud; import static org.jclouds.vcloud.VCloudMediaType.CATALOG_XML; import static org.jclouds.vcloud.VCloudMediaType.TASKSLIST_XML; import static org.jclouds.vcloud.VCloudMediaType.TASK_XML; +import static org.jclouds.vcloud.VCloudMediaType.VAPP_XML; import static org.jclouds.vcloud.VCloudMediaType.VDC_XML; import java.net.URI; @@ -157,4 +158,9 @@ public interface VCloudClient { @Path("/action/cancel") Future cancelTask(@Endpoint URI task); + @GET + @Consumes(VAPP_XML) + @Endpoint(org.jclouds.vcloud.endpoints.VCloud.class) + @Path("/vapp/{vAppId}") + String getVApp(@PathParam("vAppId") String appId); } diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/VCloudDiscovery.java b/vcloud/core/src/main/java/org/jclouds/vcloud/VCloudDiscovery.java index c12d76588f..f61247943e 100644 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/VCloudDiscovery.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/VCloudDiscovery.java @@ -23,6 +23,8 @@ */ package org.jclouds.vcloud; +import java.util.concurrent.Future; + import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -52,5 +54,5 @@ public interface VCloudDiscovery { @Endpoint(Org.class) @Consumes(VCloudMediaType.ORG_XML) @XMLResponseParser(OrgHandler.class) - Organization getOrganization(); + Future getOrganization(); } diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/VCloudLogin.java b/vcloud/core/src/main/java/org/jclouds/vcloud/VCloudLogin.java index e9ee5fa23a..f25dae9c84 100755 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/VCloudLogin.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/VCloudLogin.java @@ -24,6 +24,7 @@ package org.jclouds.vcloud; import java.util.Map; +import java.util.concurrent.Future; import javax.ws.rs.Consumes; import javax.ws.rs.POST; @@ -66,5 +67,5 @@ public interface VCloudLogin { @ResponseParser(ParseLoginResponseFromHeaders.class) @Path("/login") @Consumes(MediaType.APPLICATION_XML) - VCloudSession login(); + Future login(); } diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/config/VCloudDiscoveryRestClientModule.java b/vcloud/core/src/main/java/org/jclouds/vcloud/config/VCloudDiscoveryRestClientModule.java index 48004e56fa..db173e7bec 100755 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/config/VCloudDiscoveryRestClientModule.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/config/VCloudDiscoveryRestClientModule.java @@ -39,6 +39,7 @@ import org.jclouds.concurrent.ExpirableSupplier; import org.jclouds.http.RequiresHttp; import org.jclouds.http.filters.BasicAuthentication; import org.jclouds.rest.RestClientFactory; +import org.jclouds.util.Utils; import org.jclouds.vcloud.VCloudDiscovery; import org.jclouds.vcloud.VCloudLogin; import org.jclouds.vcloud.VCloudToken; @@ -85,7 +86,12 @@ public class VCloudDiscoveryRestClientModule extends AbstractModule { @Named(PROPERTY_VCLOUD_SESSIONINTERVAL) long seconds, final VCloudLogin login) { return new ExpirableSupplier(new Supplier() { public VCloudSession get() { - return login.login(); + try { + return login.login().get(45, TimeUnit.SECONDS); + } catch (Exception e) { + Utils. rethrowIfRuntimeOrSameType(e); + throw new RuntimeException("Error logging in", e); + } } }, seconds, TimeUnit.SECONDS); } diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java b/vcloud/core/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java index ec44c97a01..17e6e633b6 100644 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/config/VCloudRestClientModule.java @@ -68,29 +68,30 @@ public class VCloudRestClientModule extends AbstractModule { @Provides @Catalog @Singleton - protected URI provideCatalog(VCloudDiscovery discovery) { - return discovery.getOrganization().getCatalog().getLocation(); + protected URI provideCatalog(VCloudDiscovery discovery) throws InterruptedException, ExecutionException, TimeoutException { + return discovery.getOrganization().get(45, TimeUnit.SECONDS).getCatalog().getLocation(); } @Provides @CatalogItemRoot @Singleton String provideCatalogItemRoot(@VCloud URI vcloudUri) { - return vcloudUri.toASCIIString()+"/catalogItem"; + return vcloudUri.toASCIIString() + "/catalogItem"; } @Provides @VAppRoot @Singleton String provideVAppRoot(@VCloud URI vcloudUri) { - return vcloudUri.toASCIIString()+"/vapp"; + return vcloudUri.toASCIIString() + "/vapp"; } - + @Provides @VDC @Singleton - protected URI provideDefaultVDC(VCloudDiscovery discovery) { - return discovery.getOrganization().getVDCs().values().iterator().next().getLocation(); + protected URI provideDefaultVDC(VCloudDiscovery discovery) throws InterruptedException, ExecutionException, TimeoutException { + return discovery.getOrganization().get(45, TimeUnit.SECONDS).getVDCs().values().iterator() + .next().getLocation(); } @Provides @@ -105,7 +106,7 @@ public class VCloudRestClientModule extends AbstractModule { @Provides @TasksList @Singleton - protected URI provideDefaultTasksList(VCloudDiscovery discovery) { - return discovery.getOrganization().getTasksLists().values().iterator().next().getLocation(); + protected URI provideDefaultTasksList(VCloudDiscovery discovery) throws InterruptedException, ExecutionException, TimeoutException { + return discovery.getOrganization().get(45, TimeUnit.SECONDS).getTasksLists().values().iterator().next().getLocation(); } } diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/functions/CatalogIdToUri.java b/vcloud/core/src/main/java/org/jclouds/vcloud/functions/CatalogIdToUri.java index 56dc2e5c19..9236a81aed 100644 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/functions/CatalogIdToUri.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/functions/CatalogIdToUri.java @@ -18,12 +18,11 @@ public class CatalogIdToUri implements Function { @Inject @CatalogItemRoot private String catalogItemRoot; - - @Override + public String apply(Object from) { checkArgument(checkNotNull(from, "from") instanceof Integer, "this binder is only valid for Integers!"); - return String.format("%s/%d",catalogItemRoot,from); + return String.format("%s/%d", catalogItemRoot, from); } } \ No newline at end of file diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/functions/VAppIdToUri.java b/vcloud/core/src/main/java/org/jclouds/vcloud/functions/VAppIdToUri.java index a272de0595..45fd170f8f 100644 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/functions/VAppIdToUri.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/functions/VAppIdToUri.java @@ -18,12 +18,11 @@ public class VAppIdToUri implements Function { @Inject @VAppRoot private String vAppRoot; - - @Override + public String apply(Object from) { checkArgument(checkNotNull(from, "from") instanceof Integer, "this binder is only valid for Integers!"); - return String.format("%s/%d",vAppRoot,from); + return String.format("%s/%d", vAppRoot, from); } } \ No newline at end of file diff --git a/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudClientLiveTest.java b/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudClientLiveTest.java index 751bb107cf..f1baab8c79 100644 --- a/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudClientLiveTest.java +++ b/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudClientLiveTest.java @@ -89,6 +89,13 @@ public class VCloudClientLiveTest { } } + @Test(enabled = false) + public void testGetVApp() throws Exception { + String response = connection.getVApp("188849-2"); + assertNotNull(response); + System.out.println(response); + } + @BeforeGroups(groups = { "live" }) public void setupClient() { String endpoint = checkNotNull(System.getProperty("jclouds.test.endpoint"), diff --git a/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudDiscoveryLiveTest.java b/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudDiscoveryLiveTest.java index f6d64aa1d4..d1cdb6cb03 100644 --- a/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudDiscoveryLiveTest.java +++ b/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudDiscoveryLiveTest.java @@ -33,6 +33,7 @@ import static org.testng.Assert.assertNotNull; import java.net.URI; import java.util.List; import java.util.Properties; +import java.util.concurrent.TimeUnit; import javax.inject.Named; import javax.inject.Singleton; @@ -89,7 +90,7 @@ public class VCloudDiscoveryLiveTest { @Test public void testOrganization() throws Exception { - Organization response = context.getApi().getOrganization(); + Organization response = context.getApi().getOrganization().get(45, TimeUnit.SECONDS); assertNotNull(response); assertNotNull(account); assertNotNull(response.getCatalog()); diff --git a/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudLoginLiveTest.java b/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudLoginLiveTest.java index 20bb048b48..67bf2b2d9a 100755 --- a/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudLoginLiveTest.java +++ b/vcloud/core/src/test/java/org/jclouds/vcloud/VCloudLoginLiveTest.java @@ -32,6 +32,7 @@ import static org.testng.Assert.assertNotNull; import java.net.URI; import java.util.List; import java.util.Properties; +import java.util.concurrent.TimeUnit; import javax.inject.Named; import javax.inject.Singleton; @@ -91,7 +92,7 @@ public class VCloudLoginLiveTest { public void testLogin() throws Exception { VCloudLogin authentication = context.getApi(); for (int i = 0; i < 5; i++) { - VCloudSession response = authentication.login(); + VCloudSession response = authentication.login().get(45, TimeUnit.SECONDS); assertNotNull(response); assertNotNull(response.getVCloudToken()); assertNotNull(response.getOrgs()); diff --git a/vcloud/core/src/test/java/org/jclouds/vcloud/config/VCloudDiscoveryRestClientModuleTest.java b/vcloud/core/src/test/java/org/jclouds/vcloud/config/VCloudDiscoveryRestClientModuleTest.java index 1a3ec66329..da19e68d64 100644 --- a/vcloud/core/src/test/java/org/jclouds/vcloud/config/VCloudDiscoveryRestClientModuleTest.java +++ b/vcloud/core/src/test/java/org/jclouds/vcloud/config/VCloudDiscoveryRestClientModuleTest.java @@ -30,6 +30,10 @@ import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_USER; import static org.testng.Assert.assertEquals; import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import org.jclouds.http.HttpRetryHandler; @@ -70,6 +74,25 @@ public class VCloudDiscoveryRestClientModuleTest { }); } + public static abstract class FutureBase implements Future { + public boolean cancel(boolean b) { + return false; + } + + public boolean isCancelled() { + return false; + } + + public boolean isDone() { + return true; + } + + public V get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException, + TimeoutException { + return get(); + } + } + @Test void testUpdatesOnlyOncePerSecond() throws NoSuchMethodException, InterruptedException { VCloudDiscoveryRestClientModule module = new VCloudDiscoveryRestClientModule(); @@ -77,18 +100,24 @@ public class VCloudDiscoveryRestClientModuleTest { private final AtomicInteger token = new AtomicInteger(); - public VCloudSession login() { - return new VCloudSession() { + public Future login() { + return new FutureBase() { + @Override + public VCloudSession get() throws InterruptedException, ExecutionException { + return new VCloudSession() { - public Map getOrgs() { - return null; + public Map getOrgs() { + return null; + } + + public String getVCloudToken() { + return token.incrementAndGet() + ""; + } + + }; } - - public String getVCloudToken() { - return token.incrementAndGet() + ""; - } - }; + } }; diff --git a/vcloud/core/src/test/java/org/jclouds/vcloud/predicates/TaskSuccess.java b/vcloud/core/src/test/java/org/jclouds/vcloud/predicates/TaskSuccess.java new file mode 100644 index 0000000000..0afbb9f28c --- /dev/null +++ b/vcloud/core/src/test/java/org/jclouds/vcloud/predicates/TaskSuccess.java @@ -0,0 +1,63 @@ +package org.jclouds.vcloud.predicates; + +import java.net.URI; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.logging.Logger; +import org.jclouds.vcloud.VCloudClient; +import org.jclouds.vcloud.domain.Task; +import org.jclouds.vcloud.domain.TaskStatus; + +import com.google.common.base.Predicate; + +/** + * + * Tests to see if a task succeeds. + * + * @author Adrian Cole + */ +@Singleton +public class TaskSuccess implements Predicate { + + private final VCloudClient client; + + @Inject(optional = true) + @Named("org.jclouds.vcloud.timeout") + private long taskTimeout = 30000; + + @Resource + protected Logger logger = Logger.NULL; + + @Inject + public TaskSuccess(VCloudClient client) { + this.client = client; + } + + public boolean apply(URI taskUri) { + logger.trace("looking for status on task %s", taskUri); + + Task task; + try { + task = client.getTask(taskUri).get(taskTimeout, TimeUnit.MILLISECONDS); + logger.trace("%s: looking for status %s: currently: %s", task, TaskStatus.SUCCESS, task + .getStatus()); + return task.getStatus() == TaskStatus.SUCCESS; + } catch (InterruptedException e) { + logger.warn(e, "%s interrupted, returning false", taskUri); + } catch (ExecutionException e) { + logger.warn(e, "%s exception, returning false", taskUri); + } catch (TimeoutException e) { + logger.warn(e, "%s timeout, returning false", taskUri); + } + + return false; + } + +} diff --git a/vcloud/core/src/test/resources/log4j.xml b/vcloud/core/src/test/resources/log4j.xml index d712a5bd47..05c47af5d2 100755 --- a/vcloud/core/src/test/resources/log4j.xml +++ b/vcloud/core/src/test/resources/log4j.xml @@ -98,12 +98,25 @@ + + + + + + + + + + + + + + --> diff --git a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/binders/BindInstantiateVAppTemplateParamsToXmlEntity.java b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/binders/BindInstantiateVAppTemplateParamsToXmlEntity.java index 168613e47f..1bd8152b21 100644 --- a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/binders/BindInstantiateVAppTemplateParamsToXmlEntity.java +++ b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/binders/BindInstantiateVAppTemplateParamsToXmlEntity.java @@ -29,6 +29,10 @@ public class BindInstantiateVAppTemplateParamsToXmlEntity implements MapBinder { public void bindToRequest(HttpRequest request, Map postParams) { String name = checkNotNull(postParams.get("name"), "name parameter not present"); + String password = checkNotNull(postParams.get("password"), "password parameter not present"); + String row = checkNotNull(postParams.get("row"), "row parameter not present"); + String group = checkNotNull(postParams.get("group"), "group parameter not present"); + String template = checkNotNull(postParams.get("template"), "template parameter not present"); String count = checkNotNull(postParams.get("count"), "count parameter not present"); String megabytes = checkNotNull(postParams.get("megabytes"), @@ -36,6 +40,9 @@ public class BindInstantiateVAppTemplateParamsToXmlEntity implements MapBinder { String network = checkNotNull(postParams.get("network"), "network parameter not present"); String entity = xmlTemplate.replaceAll("\\{name\\}", name); + entity = entity.replaceAll("\\{password\\}", password); + entity = entity.replaceAll("\\{row\\}", row); + entity = entity.replaceAll("\\{group\\}", group); entity = entity.replaceAll("\\{template\\}", template); entity = entity.replaceAll("\\{count\\}", count); entity = entity.replaceAll("\\{megabytes\\}", megabytes); diff --git a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/options/InstantiateVAppTemplateOptions.java b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/options/InstantiateVAppTemplateOptions.java index 1e090496af..2863cdd7f2 100644 --- a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/options/InstantiateVAppTemplateOptions.java +++ b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/options/InstantiateVAppTemplateOptions.java @@ -24,6 +24,13 @@ public class InstantiateVAppTemplateOptions extends BindInstantiateVAppTemplateP @Network private URI defaultNetwork; + @VisibleForTesting + String password = "password"; + @VisibleForTesting + String group = "default"; + @VisibleForTesting + String row = "default"; + @VisibleForTesting String cpuCount = "1"; @VisibleForTesting @@ -35,6 +42,9 @@ public class InstantiateVAppTemplateOptions extends BindInstantiateVAppTemplateP Map copy = Maps.newHashMap(); copy.putAll(postParams); copy.put("count", cpuCount); + copy.put("password", password); + copy.put("group", group); + copy.put("row", row); copy.put("megabytes", megabytes); copy.put("network", network != null ? network : defaultNetwork.toASCIIString()); super.bindToRequest(request, copy); @@ -57,6 +67,21 @@ public class InstantiateVAppTemplateOptions extends BindInstantiateVAppTemplateP return this; } + public InstantiateVAppTemplateOptions withPassword(String password) { + this.password = password; + return this; + } + + public InstantiateVAppTemplateOptions inGroup(String group) { + this.group = group; + return this; + } + + public InstantiateVAppTemplateOptions inRow(String row) { + this.row = row; + return this; + } + public static class Builder { /** @@ -82,5 +107,30 @@ public class InstantiateVAppTemplateOptions extends BindInstantiateVAppTemplateP InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); return options.inNetwork(networkLocation); } + + /** + * @see InstantiateVAppTemplateOptions#withPassword(String) + */ + public static InstantiateVAppTemplateOptions withPassword(String password) { + InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); + return options.withPassword(password); + } + + /** + * @see InstantiateVAppTemplateOptions#inGroup(String) + */ + public static InstantiateVAppTemplateOptions inGroup(String group) { + InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); + return options.inGroup(group); + } + + /** + * @see InstantiateVAppTemplateOptions#inRow(String) + */ + public static InstantiateVAppTemplateOptions inRow(String row) { + InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); + return options.inRow(row); + } + } } diff --git a/vcloud/terremark/src/main/resources/terremark/ConfigureInternetService.xml b/vcloud/terremark/src/main/resources/terremark/ConfigureInternetService.xml new file mode 100644 index 0000000000..02b2baa81b --- /dev/null +++ b/vcloud/terremark/src/main/resources/terremark/ConfigureInternetService.xml @@ -0,0 +1,4 @@ + + {id}{options} + \ No newline at end of file diff --git a/vcloud/terremark/src/main/resources/terremark/InstantiateVAppTemplateParams.xml b/vcloud/terremark/src/main/resources/terremark/InstantiateVAppTemplateParams.xml index fa37f37522..cbd57e8c19 100644 --- a/vcloud/terremark/src/main/resources/terremark/InstantiateVAppTemplateParams.xml +++ b/vcloud/terremark/src/main/resources/terremark/InstantiateVAppTemplateParams.xml @@ -5,11 +5,11 @@ + ovf:key="password" ovf:value="{password}" /> + ovf:key="row" ovf:value="{row}" /> + ovf:key="group" ovf:value="{group}" /> diff --git a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/TerremarkVCloudClientLiveTest.java b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/TerremarkVCloudClientLiveTest.java index ac7c19a931..204accb3f7 100644 --- a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/TerremarkVCloudClientLiveTest.java +++ b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/TerremarkVCloudClientLiveTest.java @@ -36,10 +36,10 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import org.jclouds.concurrent.WithinThreadExecutorService; -import org.jclouds.concurrent.config.ExecutorServiceModule; import org.jclouds.http.HttpResponseException; import org.jclouds.logging.log4j.config.Log4JLoggingModule; +import org.jclouds.predicates.RetryablePredicate; +import org.jclouds.predicates.SocketOpen; import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient.Factory; import org.jclouds.ssh.jsch.config.JschSshClientModule; @@ -48,6 +48,7 @@ import org.jclouds.vcloud.VCloudClientLiveTest; import org.jclouds.vcloud.domain.Task; import org.jclouds.vcloud.domain.TaskStatus; import org.jclouds.vcloud.domain.VAppStatus; +import org.jclouds.vcloud.predicates.TaskSuccess; import org.jclouds.vcloud.terremark.domain.InternetService; import org.jclouds.vcloud.terremark.domain.Node; import org.jclouds.vcloud.terremark.domain.ResourceType; @@ -58,7 +59,6 @@ import org.testng.annotations.BeforeGroups; import org.testng.annotations.Test; import com.google.common.collect.Iterables; -import com.google.inject.Guice; import com.google.inject.Injector; /** @@ -77,6 +77,10 @@ public class TerremarkVCloudClientLiveTest extends VCloudClientLiveTest { private Node node; private VApp vApp; + private RetryablePredicate socketTester; + + private RetryablePredicate successTester; + public static final String PREFIX = System.getProperty("user.name") + "-terremark"; @Test @@ -95,12 +99,16 @@ public class TerremarkVCloudClientLiveTest extends VCloudClientLiveTest { String serverName = "adriantest"; int processorCount = 1; int memory = 512; - long hardDisk = 4194304; - String catalogOs = "Ubuntu JeOS 9.04 (32-bit)"; - String expectedOs = "Ubuntu Linux (32-bit)"; + // long hardDisk = 4194304; + // String catalogOs = "Ubuntu JeOS 9.04 (32-bit)"; + // String expectedOs = "Ubuntu Linux (32-bit)"; + long hardDisk = 4194304 / 4 * 10; + String catalogOs = "CentOS 5.3 (32-bit)"; + String expectedOs = "Red Hat Enterprise Linux 5 (32-bit)"; int templateId = tmClient.getCatalog().get(45, TimeUnit.SECONDS).get(catalogOs).getId(); + System.out.printf("%d: instantiating vApp%n", System.currentTimeMillis()); vApp = tmClient.instantiateVAppTemplate(serverName, templateId).get(45, TimeUnit.SECONDS); assertEquals(vApp.getStatus(), VAppStatus.CREATING); @@ -127,13 +135,17 @@ public class TerremarkVCloudClientLiveTest extends VCloudClientLiveTest { assertEquals(((HttpResponseException) e.getCause()).getResponse().getStatusCode(), 501); } - deployTask = blockUntilSuccess(deployTask); + assert successTester.apply(deployTask.getLocation()); + System.out.printf("%d: done deploying vApp%n", System.currentTimeMillis()); vApp = tmClient.getVApp(vApp.getId()).get(45, TimeUnit.SECONDS); verifyConfigurationOfVApp(vApp, serverName, expectedOs, processorCount, memory, hardDisk); assertEquals(vApp.getStatus(), VAppStatus.OFF); - deployTask = blockUntilSuccess(tmClient.powerOnVApp(vApp.getId()).get(45, TimeUnit.SECONDS)); + assert successTester.apply(tmClient.powerOnVApp(vApp.getId()).get(45, TimeUnit.SECONDS) + .getLocation()); + System.out.printf("%d: done powering on vApp%n", System.currentTimeMillis()); + vApp = tmClient.getVApp(vApp.getId()).get(45, TimeUnit.SECONDS); assertEquals(vApp.getStatus(), VAppStatus.ON); @@ -151,13 +163,7 @@ public class TerremarkVCloudClientLiveTest extends VCloudClientLiveTest { node = tmClient.addNode(is.getId(), vApp.getNetworkToAddresses().values().iterator().next(), vApp.getName() + "-SSH", 22).get(45, TimeUnit.SECONDS); publicIp = is.getPublicIpAddress().getAddress(); - try { - doCheckPass(publicIp); - } catch (Exception e) { - // TODO - harden this up, when we stop hanging - System.err.printf("%s:22 -> %s:22%n%s%n", vApp.getNetworkToAddresses().values().iterator() - .next(), publicIp, e.getMessage()); - } + doCheckPass(publicIp); } @Test(dependsOnMethods = "testPublicIp") @@ -178,15 +184,20 @@ public class TerremarkVCloudClientLiveTest extends VCloudClientLiveTest { assertEquals(((HttpResponseException) e.getCause()).getResponse().getStatusCode(), 501); } - blockUntilSuccess(tmClient.resetVApp(vApp.getId()).get(45, TimeUnit.SECONDS)); + assert successTester.apply(tmClient.resetVApp(vApp.getId()).get(45, TimeUnit.SECONDS) + .getLocation()); + vApp = tmClient.getVApp(vApp.getId()).get(45, TimeUnit.SECONDS); assertEquals(vApp.getStatus(), VAppStatus.ON); - tmClient.shutdownVApp(vApp.getId()).get(45, TimeUnit.SECONDS); - vApp = tmClient.getVApp(vApp.getId()).get(45, TimeUnit.SECONDS); - assertEquals(vApp.getStatus(), VAppStatus.ON); + // TODO we need to determine whether shutdown is supported before invoking it. + // tmClient.shutdownVApp(vApp.getId()).get(45, TimeUnit.SECONDS); + // vApp = tmClient.getVApp(vApp.getId()).get(45, TimeUnit.SECONDS); + // assertEquals(vApp.getStatus(), VAppStatus.ON); + + assert successTester.apply(tmClient.powerOffVApp(vApp.getId()).get(45, TimeUnit.SECONDS) + .getLocation()); - blockUntilSuccess(tmClient.powerOffVApp(vApp.getId()).get(45, TimeUnit.SECONDS)); vApp = tmClient.getVApp(vApp.getId()).get(45, TimeUnit.SECONDS); assertEquals(vApp.getStatus(), VAppStatus.OFF); } @@ -208,18 +219,6 @@ public class TerremarkVCloudClientLiveTest extends VCloudClientLiveTest { .get(ResourceType.VIRTUAL_DISK).getVirtualQuantity()); } - private Task blockUntilSuccess(Task task) throws InterruptedException, ExecutionException, - TimeoutException { - for (task = tmClient.getTask(task.getLocation()).get(30, TimeUnit.SECONDS); task.getStatus() != TaskStatus.SUCCESS; task = tmClient - .getTask(task.getLocation()).get(30, TimeUnit.SECONDS)) { - System.out.printf("%s blocking on status active: currently: %s%n", task.getOwner() - .getName(), task.getStatus()); - Thread.sleep(5 * 1000); - } - System.out.printf("%s complete%n", task.getResult().getName()); - return task; - } - private Task getLastTaskFor(URI owner) throws InterruptedException, ExecutionException, TimeoutException { return Iterables.getLast(tmClient.getDefaultTasksList().get(45, TimeUnit.SECONDS) @@ -227,11 +226,17 @@ public class TerremarkVCloudClientLiveTest extends VCloudClientLiveTest { } private void doCheckPass(InetAddress address) throws IOException { - System.out.printf("%s:%s%n", address, 22); - SshClient connection = sshFactory.create(new InetSocketAddress(address, 22), "vcloud", - "p4ssw0rd"); + InetSocketAddress socket = new InetSocketAddress(address, 22); + + System.out.printf("%d: %s awaiting ssh service to start%n", System.currentTimeMillis(), + socket); + assert socketTester.apply(socket); + System.out.printf("%d: %s ssh service started%n", System.currentTimeMillis(), socket); + + SshClient connection = sshFactory.create(socket, "vcloud", "p4ssw0rd"); try { connection.connect(); + System.out.printf("%d: %s ssh connection made%n", System.currentTimeMillis(), socket); InputStream etcPasswd = connection.get("/etc/passwd"); Utils.toStringAndClose(etcPasswd); } finally { @@ -248,8 +253,10 @@ public class TerremarkVCloudClientLiveTest extends VCloudClientLiveTest { tmClient.deleteInternetService(is.getId()).get(30, TimeUnit.SECONDS); if (vApp != null) { try { - blockUntilSuccess(tmClient.powerOffVApp(vApp.getId()).get(45, TimeUnit.SECONDS)); + successTester.apply(tmClient.powerOffVApp(vApp.getId()).get(45, TimeUnit.SECONDS) + .getLocation()); } catch (Exception e) { + } tmClient.deleteVApp(vApp.getId()).get(45, TimeUnit.SECONDS); } @@ -260,13 +267,19 @@ public class TerremarkVCloudClientLiveTest extends VCloudClientLiveTest { public void setupClient() { account = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user"); String key = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key"); - connection = tmClient = new TerremarkVCloudContextBuilder( - new TerremarkVCloudPropertiesBuilder(account, key).build()).withModules( - new Log4JLoggingModule()).buildContext().getApi(); - Injector injector = Guice.createInjector(new Log4JLoggingModule(), new JschSshClientModule(), - new ExecutorServiceModule(new WithinThreadExecutorService())); - sshFactory = injector.getInstance(SshClient.Factory.class); + Injector injector = new TerremarkVCloudContextBuilder(new TerremarkVCloudPropertiesBuilder( + account, key).build()).withModules(new Log4JLoggingModule(), + new JschSshClientModule()).buildInjector(); + connection = tmClient = injector.getInstance(TerremarkVCloudClient.class); + + sshFactory = injector.getInstance(SshClient.Factory.class); + socketTester = new RetryablePredicate(injector + .getInstance(SocketOpen.class), 130, 10, TimeUnit.SECONDS);// make it longer then + // default internet + // service timeout + successTester = new RetryablePredicate(injector.getInstance(TaskSuccess.class), 300, 10, + TimeUnit.SECONDS); } } diff --git a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/binders/BindInstantiateVAppTemplateParamsToXmlEntityTest.java b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/binders/BindInstantiateVAppTemplateParamsToXmlEntityTest.java index 609b072542..ef9b1a8ca8 100644 --- a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/binders/BindInstantiateVAppTemplateParamsToXmlEntityTest.java +++ b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/binders/BindInstantiateVAppTemplateParamsToXmlEntityTest.java @@ -78,13 +78,16 @@ public class BindInstantiateVAppTemplateParamsToXmlEntityTest { Map map = Maps.newHashMap(); map.put("name", "name"); + map.put("password", "password"); + map.put("row", "row"); + map.put("group", "group"); map.put("template", "http://catalogItem/3"); map.put("count", "1"); map.put("megabytes", "512"); map.put("network", "http://network"); binder.bindToRequest(request, map); assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_TYPE), "application/unknown"); - assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH), "2247"); + assertEquals(request.getFirstHeaderOrNull(HttpHeaders.CONTENT_LENGTH), "2239"); assertEquals(request.getEntity(), expected); } diff --git a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/options/InstantiateVAppTemplateOptionsTest.java b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/options/InstantiateVAppTemplateOptionsTest.java index 4472037016..d90dfd0bcd 100644 --- a/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/options/InstantiateVAppTemplateOptionsTest.java +++ b/vcloud/terremark/src/test/java/org/jclouds/vcloud/terremark/options/InstantiateVAppTemplateOptionsTest.java @@ -1,8 +1,11 @@ package org.jclouds.vcloud.terremark.options; import static org.jclouds.vcloud.terremark.options.InstantiateVAppTemplateOptions.Builder.cpuCount; +import static org.jclouds.vcloud.terremark.options.InstantiateVAppTemplateOptions.Builder.inGroup; import static org.jclouds.vcloud.terremark.options.InstantiateVAppTemplateOptions.Builder.inNetwork; +import static org.jclouds.vcloud.terremark.options.InstantiateVAppTemplateOptions.Builder.inRow; import static org.jclouds.vcloud.terremark.options.InstantiateVAppTemplateOptions.Builder.megabytes; +import static org.jclouds.vcloud.terremark.options.InstantiateVAppTemplateOptions.Builder.withPassword; import static org.testng.Assert.assertEquals; import java.net.URI; @@ -23,6 +26,63 @@ public class InstantiateVAppTemplateOptionsTest { Injector injector = Guice.createInjector(new ParserModule()); + @Test + public void testInGroupDefault() { + InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); + assertEquals(options.group, "default"); + } + + @Test + public void testInGroup() { + InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); + options.inGroup("group1"); + assertEquals(options.group, "group1"); + } + + @Test + public void testInGroupStatic() { + InstantiateVAppTemplateOptions options = inGroup("group1"); + assertEquals(options.group, "group1"); + } + + @Test + public void testInRowDefault() { + InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); + assertEquals(options.row, "default"); + } + + @Test + public void testInRow() { + InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); + options.inRow("row1"); + assertEquals(options.row, "row1"); + } + + @Test + public void testInRowStatic() { + InstantiateVAppTemplateOptions options = inRow("row1"); + assertEquals(options.row, "row1"); + } + + @Test + public void testWithPasswordDefault() { + InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); + assertEquals(options.password, "password"); + } + + @Test + public void testWithPassword() { + InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); + options.withPassword("password1"); + assertEquals(options.password, "password1"); + } + + @Test + public void testWithPasswordStatic() { + InstantiateVAppTemplateOptions options = withPassword("password1"); + assertEquals(options.password, "password1"); + } + @Test public void testInNetwork() { InstantiateVAppTemplateOptions options = new InstantiateVAppTemplateOptions(); diff --git a/vcloud/terremark/src/test/resources/terremark/InstantiateVAppTemplateParams-test.xml b/vcloud/terremark/src/test/resources/terremark/InstantiateVAppTemplateParams-test.xml index 25ed6202f8..bd9766f27b 100644 --- a/vcloud/terremark/src/test/resources/terremark/InstantiateVAppTemplateParams-test.xml +++ b/vcloud/terremark/src/test/resources/terremark/InstantiateVAppTemplateParams-test.xml @@ -5,11 +5,11 @@ + ovf:key="password" ovf:value="password" /> + ovf:key="row" ovf:value="row" /> + ovf:key="group" ovf:value="group" />