From a4bdd433f4b8ca76c548a7df49b6553762b51e7e Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 23 May 2010 15:39:49 -0700 Subject: [PATCH] Issue 260: fixed i/o threadpool to min=max; refactored session expiry logic. Issue 258 refactored load balancer code --- .../saas/util/AtmosStorageUtils.java | 2 +- .../saas/AtmosStorageClientLiveTest.java | 2 +- .../aws/ec2/compute/EC2ComputeService.java | 57 +------ .../EC2ComputeServiceContextModule.java | 20 +-- .../internal/EC2TemplateBuilderImpl.java | 6 +- .../EC2DestroyLoadBalancerStrategy.java | 65 ++++++++ ....java => EC2LoadBalanceNodesStrategy.java} | 6 +- .../jclouds/aws/s3/blobstore/S3BlobStore.java | 2 +- .../compute/EC2ComputeServiceLiveTest.java | 38 ----- .../ec2/compute/EC2ComputeServiceTest.java | 20 ++- .../EC2LoadBalancerServiceLiveTest.java | 73 +++++++++ .../internal/EC2TemplateBuilderImplTest.java | 32 ++-- .../internal/BaseAsyncBlobStore.java | 2 +- .../blobstore/internal/BaseBlobStore.java | 2 +- .../org/jclouds/compute/ComputeService.java | 31 +--- .../compute/ComputeServiceContext.java | 6 + .../jclouds/compute/LoadBalancerService.java | 71 ++++++++ .../compute/internal/BaseComputeService.java | 12 -- .../internal/BaseLoadBalancerService.java | 142 ++++++++++++++++ .../internal/ComputeServiceContextImpl.java | 15 +- .../compute/internal/TemplateBuilderImpl.java | 44 ++--- .../strategy/DestroyLoadBalancerStrategy.java | 36 ++++ ...egy.java => LoadBalanceNodesStrategy.java} | 2 +- .../BaseLoadBalancerServiceLiveTest.java | 155 ++++++++++++++++++ .../internal/TemplateBuilderImplTest.java | 109 ++++++++---- .../RetryOnTimeOutExceptionSupplier.java | 60 +++++++ .../config/ExecutorServiceModule.java | 2 +- .../concurrent/internal/SyncProxy.java | 6 - .../main/java/org/jclouds/http/HttpUtils.java | 15 ++ .../src/main/java/org/jclouds/util/Utils.java | 14 +- .../RetryOnTimeOutExceptionSupplierTest.java | 127 ++++++++++++++ .../test/java/org/jclouds/util/UtilsTest.java | 20 +++ .../GoGridComputeServiceContextModule.java | 16 +- ...oudServersComputeServiceContextModule.java | 19 +-- .../RackspaceAuthenticationRestModule.java | 29 ++-- ...imuHostingComputeServiceContextModule.java | 19 +-- .../VCloudSessionRefreshLiveTest.java | 61 +++++++ .../VCloudComputeServiceContextModule.java | 24 +-- .../FindLocationForResourceInVDC.java | 8 +- .../functions/VCloudGetNodeMetadata.java | 11 +- .../VCloudGetNodeMetadataStrategy.java | 4 +- .../strategy/VCloudListNodesStrategy.java | 4 +- .../vcloud/config/VCloudRestClientModule.java | 25 +-- .../ParseLoginResponseFromHeaders.java | 4 +- .../strategy/VCloudListNodesStrategyTest.java | 10 +- .../ParseLoginResponseFromHeadersTest.java | 19 +++ ...markVCloudComputeServiceContextModule.java | 9 +- 47 files changed, 1139 insertions(+), 317 deletions(-) create mode 100644 aws/core/src/main/java/org/jclouds/aws/ec2/compute/strategy/EC2DestroyLoadBalancerStrategy.java rename aws/core/src/main/java/org/jclouds/aws/ec2/compute/strategy/{EC2LoadBalancerStrategy.java => EC2LoadBalanceNodesStrategy.java} (94%) create mode 100644 aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2LoadBalancerServiceLiveTest.java create mode 100644 compute/src/main/java/org/jclouds/compute/LoadBalancerService.java create mode 100644 compute/src/main/java/org/jclouds/compute/internal/BaseLoadBalancerService.java create mode 100644 compute/src/main/java/org/jclouds/compute/strategy/DestroyLoadBalancerStrategy.java rename compute/src/main/java/org/jclouds/compute/strategy/{LoadBalancerStrategy.java => LoadBalanceNodesStrategy.java} (96%) create mode 100644 compute/src/test/java/org/jclouds/compute/BaseLoadBalancerServiceLiveTest.java create mode 100644 core/src/main/java/org/jclouds/concurrent/RetryOnTimeOutExceptionSupplier.java create mode 100644 core/src/test/java/org/jclouds/concurrent/RetryOnTimeOutExceptionSupplierTest.java create mode 100644 vcloud/bluelock/src/test/java/org/jclouds/vcloud/bluelock/VCloudSessionRefreshLiveTest.java diff --git a/atmos/src/main/java/org/jclouds/atmosonline/saas/util/AtmosStorageUtils.java b/atmos/src/main/java/org/jclouds/atmosonline/saas/util/AtmosStorageUtils.java index 5058ed3910..543eda9b55 100644 --- a/atmos/src/main/java/org/jclouds/atmosonline/saas/util/AtmosStorageUtils.java +++ b/atmos/src/main/java/org/jclouds/atmosonline/saas/util/AtmosStorageUtils.java @@ -80,7 +80,7 @@ public class AtmosStorageUtils { public static void deleteAndEnsureGone(final AtmosStorageClient sync, final String path) { try { - if (!Utils.enventuallyTrue(new Supplier() { + if (!Utils.eventuallyTrue(new Supplier() { public Boolean get() { sync.deletePath(path); return !sync.pathExists(path); diff --git a/atmos/src/test/java/org/jclouds/atmosonline/saas/AtmosStorageClientLiveTest.java b/atmos/src/test/java/org/jclouds/atmosonline/saas/AtmosStorageClientLiveTest.java index fcf71ae9ec..400434cf53 100644 --- a/atmos/src/test/java/org/jclouds/atmosonline/saas/AtmosStorageClientLiveTest.java +++ b/atmos/src/test/java/org/jclouds/atmosonline/saas/AtmosStorageClientLiveTest.java @@ -363,7 +363,7 @@ public class AtmosStorageClientLiveTest { connection.deletePath(path); } catch (KeyNotFoundException ex) { } - assert Utils.enventuallyTrue(new Supplier() { + assert Utils.eventuallyTrue(new Supplier() { public Boolean get() { return !connection.pathExists(path); } diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/EC2ComputeService.java b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/EC2ComputeService.java index f990653638..07efc6778e 100644 --- a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/EC2ComputeService.java +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/EC2ComputeService.java @@ -18,13 +18,9 @@ */ package org.jclouds.aws.ec2.compute; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; import static org.jclouds.aws.ec2.util.EC2Utils.parseHandle; import static org.jclouds.util.Utils.checkNotEmpty; -import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.Map.Entry; @@ -41,7 +37,6 @@ import org.jclouds.aws.ec2.compute.domain.RegionAndName; import org.jclouds.aws.ec2.compute.domain.RegionNameAndIngressRules; import org.jclouds.aws.ec2.compute.options.EC2TemplateOptions; import org.jclouds.aws.ec2.domain.KeyPair; -import org.jclouds.aws.ec2.util.EC2Utils; import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.NodeMetadata; @@ -49,19 +44,15 @@ import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.internal.BaseComputeService; import org.jclouds.compute.options.TemplateOptions; -import org.jclouds.compute.predicates.NodePredicates; import org.jclouds.compute.strategy.DestroyNodeStrategy; import org.jclouds.compute.strategy.GetNodeMetadataStrategy; import org.jclouds.compute.strategy.ListNodesStrategy; -import org.jclouds.compute.strategy.LoadBalancerStrategy; import org.jclouds.compute.strategy.RebootNodeStrategy; import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy; import org.jclouds.compute.util.ComputeUtils; import org.jclouds.domain.Location; import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.collect.Iterables; import com.google.common.collect.Maps; /** @@ -72,7 +63,6 @@ public class EC2ComputeService extends BaseComputeService { private final EC2Client ec2Client; private final Map credentialsMap; private final Map securityGroupMap; - private final LoadBalancerStrategy loadBalancerStrategy; @Inject protected EC2ComputeService(ComputeServiceContext context, @@ -83,13 +73,11 @@ public class EC2ComputeService extends BaseComputeService { RebootNodeStrategy rebootNodeStrategy, DestroyNodeStrategy destroyNodeStrategy, Provider templateBuilderProvider, Provider templateOptionsProvider, ComputeUtils utils, - @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, - LoadBalancerStrategy loadBalancerStrategy, EC2Client ec2Client, + @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client ec2Client, Map credentialsMap, Map securityGroupMap) { super(context, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, templateBuilderProvider, templateOptionsProvider, utils, executor); - this.loadBalancerStrategy = checkNotNull(loadBalancerStrategy, "loadBalancerStrategy"); this.ec2Client = ec2Client; this.credentialsMap = credentialsMap; this.securityGroupMap = securityGroupMap; @@ -146,47 +134,4 @@ public class EC2ComputeService extends BaseComputeService { return EC2TemplateOptions.class.cast(super.templateOptions()); } - - @Override - public Set loadBalanceNodesMatching(Predicate filter, String loadBalancerName, - String protocol, int loadBalancerPort, int instancePort) { - checkNotNull(loadBalancerName, "loadBalancerName"); - checkNotNull(protocol, "protocol"); - checkArgument(protocol.toUpperCase().equals("HTTP") || protocol.toUpperCase().equals("TCP"), - "Acceptable values for protocol are HTTP or TCP"); - - Map> locationMap = new HashMap>(); - for (NodeMetadata node : Iterables.filter(super - .listNodesDetailsMatching(NodePredicates.all()), Predicates.and(filter, Predicates - .not(NodePredicates.TERMINATED)))) { - - Set ids = locationMap.get(node.getLocation()); - if(ids == null) - ids = new HashSet(); - ids.add(node.getProviderId()); - locationMap.put(node.getLocation(), ids); - } - Set dnsNames = new HashSet(0); - for(Location location: locationMap.keySet()) - { - logger.debug(">> creating load balancer (%s)", loadBalancerName); - String dnsName = loadBalancerStrategy.execute(location, loadBalancerName, protocol, - loadBalancerPort, instancePort, locationMap.get(location)); - dnsNames.add(dnsName); - logger.debug("<< created load balancer (%s) DNS (%s)", loadBalancerName, dnsName); - } - return dnsNames; - } - - @Override - public void deleteLoadBalancer(String dnsName) { - - Map tuple = EC2Utils.getLoadBalancerNameAndRegionFromDnsName(dnsName); - //Only one load balancer per DNS name is expected - for(String key: tuple.keySet()) - { - ec2Client.getElasticLoadBalancerServices().deleteLoadBalancerInRegion(key, - tuple.get(key)); - } - } } \ No newline at end of file diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/config/EC2ComputeServiceContextModule.java b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/config/EC2ComputeServiceContextModule.java index 478972254e..3b8d4f3206 100755 --- a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/config/EC2ComputeServiceContextModule.java +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/config/EC2ComputeServiceContextModule.java @@ -55,8 +55,9 @@ import org.jclouds.aws.ec2.compute.functions.RegionAndIdToImage; import org.jclouds.aws.ec2.compute.functions.RunningInstanceToNodeMetadata; import org.jclouds.aws.ec2.compute.internal.EC2TemplateBuilderImpl; import org.jclouds.aws.ec2.compute.options.EC2TemplateOptions; +import org.jclouds.aws.ec2.compute.strategy.EC2DestroyLoadBalancerStrategy; import org.jclouds.aws.ec2.compute.strategy.EC2DestroyNodeStrategy; -import org.jclouds.aws.ec2.compute.strategy.EC2LoadBalancerStrategy; +import org.jclouds.aws.ec2.compute.strategy.EC2LoadBalanceNodesStrategy; import org.jclouds.aws.ec2.compute.strategy.EC2RunNodesAndAddToSetStrategy; import org.jclouds.aws.ec2.config.EC2ContextModule; import org.jclouds.aws.ec2.domain.KeyPair; @@ -78,10 +79,11 @@ import org.jclouds.compute.predicates.NodePredicates; import org.jclouds.compute.predicates.ScriptStatusReturnsZero; import org.jclouds.compute.predicates.ScriptStatusReturnsZero.CommandUsingClient; import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.compute.strategy.DestroyLoadBalancerStrategy; import org.jclouds.compute.strategy.DestroyNodeStrategy; import org.jclouds.compute.strategy.GetNodeMetadataStrategy; import org.jclouds.compute.strategy.ListNodesStrategy; -import org.jclouds.compute.strategy.LoadBalancerStrategy; +import org.jclouds.compute.strategy.LoadBalanceNodesStrategy; import org.jclouds.compute.strategy.RebootNodeStrategy; import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy; import org.jclouds.concurrent.ConcurrentUtils; @@ -90,7 +92,6 @@ import org.jclouds.domain.LocationScope; import org.jclouds.domain.internal.LocationImpl; import org.jclouds.logging.Logger; import org.jclouds.predicates.RetryablePredicate; -import org.jclouds.rest.RestContext; import org.jclouds.util.Jsr330; import com.google.common.base.Function; @@ -127,7 +128,11 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule { bind(TemplateBuilder.class).to(EC2TemplateBuilderImpl.class); bind(TemplateOptions.class).to(EC2TemplateOptions.class); bind(ComputeService.class).to(EC2ComputeService.class); - bind(LoadBalancerStrategy.class).to(EC2LoadBalancerStrategy.class); + bind(new TypeLiteral() { + }).to(new TypeLiteral>() { + }).in(Scopes.SINGLETON); + bind(LoadBalanceNodesStrategy.class).to(EC2LoadBalanceNodesStrategy.class); + bind(DestroyLoadBalancerStrategy.class).to(EC2DestroyLoadBalancerStrategy.class); bind(RunNodesAndAddToSetStrategy.class).to(EC2RunNodesAndAddToSetStrategy.class); bind(ListNodesStrategy.class).to(EC2ListNodesStrategy.class); bind(GetNodeMetadataStrategy.class).to(EC2GetNodeMetadataStrategy.class); @@ -284,13 +289,6 @@ public class EC2ComputeServiceContextModule extends EC2ContextModule { return Maps.newLinkedHashMap(); } - @Provides - @Singleton - ComputeServiceContext provideContext(ComputeService computeService, - RestContext context) { - return new ComputeServiceContextImpl(computeService, context); - } - @Provides @Singleton Function indexer() { diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/internal/EC2TemplateBuilderImpl.java b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/internal/EC2TemplateBuilderImpl.java index 60985800ee..b902b011f0 100644 --- a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/internal/EC2TemplateBuilderImpl.java +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/internal/EC2TemplateBuilderImpl.java @@ -28,9 +28,9 @@ public class EC2TemplateBuilderImpl extends TemplateBuilderImpl { private final ConcurrentMap imageMap; @Inject - protected EC2TemplateBuilderImpl(Set locations, Set images, - Set sizes, Location defaultLocation, - Provider optionsProvider, + protected EC2TemplateBuilderImpl(Provider> locations, + Provider> images, Provider> sizes, + Location defaultLocation, Provider optionsProvider, @Named("DEFAULT") Provider defaultTemplateProvider, ConcurrentMap imageMap) { super(locations, images, sizes, defaultLocation, optionsProvider, defaultTemplateProvider); diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/strategy/EC2DestroyLoadBalancerStrategy.java b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/strategy/EC2DestroyLoadBalancerStrategy.java new file mode 100644 index 0000000000..e1f05efaa3 --- /dev/null +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/strategy/EC2DestroyLoadBalancerStrategy.java @@ -0,0 +1,65 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.jclouds.aws.ec2.compute.strategy; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.InetAddress; +import java.util.Map; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.aws.ec2.services.ElasticLoadBalancerClient; +import org.jclouds.aws.ec2.util.EC2Utils; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.compute.strategy.DestroyLoadBalancerStrategy; +import org.jclouds.logging.Logger; + +/** + * + * @author Adrian Cole + */ +@Singleton +public class EC2DestroyLoadBalancerStrategy implements DestroyLoadBalancerStrategy { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + private final ElasticLoadBalancerClient elbClient; + + @Inject + protected EC2DestroyLoadBalancerStrategy(ElasticLoadBalancerClient elbClient) { + this.elbClient = checkNotNull(elbClient, "elbClient"); + } + + @Override + public boolean execute(InetAddress loadBalancer) { + Map tuple = EC2Utils.getLoadBalancerNameAndRegionFromDnsName(loadBalancer + .getCanonicalHostName()); + // Only one load balancer per DNS name is expected + for (String key : tuple.keySet()) { + elbClient.deleteLoadBalancerInRegion(key, tuple.get(key)); + } + return true; + } +} \ No newline at end of file diff --git a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/strategy/EC2LoadBalancerStrategy.java b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/strategy/EC2LoadBalanceNodesStrategy.java similarity index 94% rename from aws/core/src/main/java/org/jclouds/aws/ec2/compute/strategy/EC2LoadBalancerStrategy.java rename to aws/core/src/main/java/org/jclouds/aws/ec2/compute/strategy/EC2LoadBalanceNodesStrategy.java index e9141b5173..3c412e5fa1 100644 --- a/aws/core/src/main/java/org/jclouds/aws/ec2/compute/strategy/EC2LoadBalancerStrategy.java +++ b/aws/core/src/main/java/org/jclouds/aws/ec2/compute/strategy/EC2LoadBalanceNodesStrategy.java @@ -33,7 +33,7 @@ import org.jclouds.aws.ec2.domain.AvailabilityZone; import org.jclouds.aws.ec2.services.ElasticLoadBalancerClient; import org.jclouds.aws.ec2.util.EC2Utils.GetRegionFromLocation; import org.jclouds.compute.reference.ComputeServiceConstants; -import org.jclouds.compute.strategy.LoadBalancerStrategy; +import org.jclouds.compute.strategy.LoadBalanceNodesStrategy; import org.jclouds.domain.Location; import org.jclouds.logging.Logger; @@ -42,7 +42,7 @@ import org.jclouds.logging.Logger; * @author Adrian Cole */ @Singleton -public class EC2LoadBalancerStrategy implements LoadBalancerStrategy { +public class EC2LoadBalanceNodesStrategy implements LoadBalanceNodesStrategy { @Resource @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; @@ -50,7 +50,7 @@ public class EC2LoadBalancerStrategy implements LoadBalancerStrategy { protected final GetRegionFromLocation getRegionFromLocation; @Inject - protected EC2LoadBalancerStrategy(EC2Client ec2Client, + protected EC2LoadBalanceNodesStrategy(EC2Client ec2Client, GetRegionFromLocation getRegionFromLocation) { this.ec2Client = ec2Client; this.getRegionFromLocation = getRegionFromLocation; diff --git a/aws/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStore.java b/aws/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStore.java index 5aed722ba6..6d3a89746c 100644 --- a/aws/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStore.java +++ b/aws/core/src/main/java/org/jclouds/aws/s3/blobstore/S3BlobStore.java @@ -167,7 +167,7 @@ public class S3BlobStore extends BaseBlobStore { */ public void clearAndDeleteContainer(final String container) { try { - if (!Utils.enventuallyTrue(new Supplier() { + if (!Utils.eventuallyTrue(new Supplier() { public Boolean get() { clearContainer(container); return sync.deleteBucketIfEmpty(container); diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2ComputeServiceLiveTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2ComputeServiceLiveTest.java index decd2c3a43..20784d97d9 100644 --- a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2ComputeServiceLiveTest.java +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2ComputeServiceLiveTest.java @@ -19,26 +19,20 @@ package org.jclouds.aws.ec2.compute; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import java.util.HashSet; import java.util.Set; -import org.jclouds.aws.domain.Region; import org.jclouds.aws.ec2.EC2Client; import org.jclouds.aws.ec2.compute.options.EC2TemplateOptions; -import org.jclouds.aws.ec2.domain.ElasticLoadBalancer; import org.jclouds.aws.ec2.domain.IpProtocol; import org.jclouds.aws.ec2.domain.KeyPair; import org.jclouds.aws.ec2.domain.RunningInstance; import org.jclouds.aws.ec2.domain.SecurityGroup; -import org.jclouds.aws.ec2.services.ElasticLoadBalancerClient; import org.jclouds.aws.ec2.services.InstanceClient; import org.jclouds.aws.ec2.services.KeyPairClient; import org.jclouds.aws.ec2.services.SecurityGroupClient; import org.jclouds.compute.BaseComputeServiceLiveTest; import org.jclouds.compute.domain.NodeMetadata; -import org.jclouds.compute.domain.Template; import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.predicates.NodePredicates; import org.jclouds.domain.Credentials; @@ -179,38 +173,6 @@ public class EC2ComputeServiceLiveTest extends BaseComputeServiceLiveTest { } } - @Test(enabled = true, dependsOnMethods = "testCorrectAuthException") - public void testLoadBalanceNodesMatching() throws Exception { - - ElasticLoadBalancerClient elbClient = EC2Client.class.cast( - context.getProviderSpecificContext().getApi()).getElasticLoadBalancerServices(); - - String tag = "jcloudsElbTest"; - Template template = client.templateBuilder().build(); - try { - Set nodes = client.runNodesWithTag(tag, 2, template); - Set instanceIds = new HashSet(); - for (NodeMetadata node : nodes) { - instanceIds.add(node.getProviderId()); - } - - // create load balancers - - Set dnsNames = client.loadBalanceNodesMatching(NodePredicates.withTag(tag), tag, "HTTP", - 80, 80); - assertNotNull(dnsNames); - Set elbs = elbClient.describeLoadBalancersInRegion(Region.US_EAST_1, - tag); - assertNotNull(elbs); - ElasticLoadBalancer elb = elbs.iterator().next(); - assertEquals(elb.getInstanceIds(), instanceIds); - } finally { - elbClient.deleteLoadBalancerInRegion(Region.US_EAST_1, tag); - // finaly destroy nodes - client.destroyNodesMatching(NodePredicates.withTag(tag)); - } - } - private RunningInstance getInstance(InstanceClient instanceClient, String id) { RunningInstance instance = Iterables.getOnlyElement(Iterables.getOnlyElement(instanceClient .describeInstancesInRegion(null, id))); diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2ComputeServiceTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2ComputeServiceTest.java index c80ae9eec8..5af0ed017c 100644 --- a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2ComputeServiceTest.java +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2ComputeServiceTest.java @@ -29,12 +29,15 @@ import static org.easymock.EasyMock.expect; import static org.easymock.classextension.EasyMock.createMock; import static org.easymock.classextension.EasyMock.replay; +import java.util.Set; + import javax.inject.Provider; import org.jclouds.aws.ec2.compute.domain.EC2Size; import org.jclouds.compute.domain.Architecture; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.Size; import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.internal.ImageImpl; @@ -49,6 +52,7 @@ import org.testng.annotations.Test; import com.google.common.base.Function; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; +import com.google.inject.util.Providers; /** * Tests compute service specifically to EC2. @@ -130,10 +134,18 @@ public class EC2ComputeServiceTest { Architecture.X86_64, new Credentials("root", null)); replay(optionsProvider); replay(templateBuilderProvider); - return new TemplateBuilderImpl(ImmutableSet.of(location), ImmutableSet.of(image), - ImmutableSet.of(EC2Size.C1_MEDIUM, EC2Size.C1_XLARGE, EC2Size.M1_LARGE, - EC2Size.M1_SMALL, EC2Size.M1_XLARGE, EC2Size.M2_XLARGE, EC2Size.M2_2XLARGE, - EC2Size.M2_4XLARGE), location, optionsProvider, templateBuilderProvider) { + Provider> locations = Providers + .> of(ImmutableSet. of(location)); + Provider> images = Providers.> of(ImmutableSet + . of(image)); + Provider> sizes = Providers.> of(ImmutableSet + . of(EC2Size.C1_MEDIUM, EC2Size.C1_XLARGE, EC2Size.M1_LARGE, EC2Size.M1_SMALL, + EC2Size.M1_XLARGE, EC2Size.M2_XLARGE, EC2Size.M2_2XLARGE, + EC2Size.M2_4XLARGE)); + + return new TemplateBuilderImpl(locations, images, sizes, location, optionsProvider, + templateBuilderProvider) { + }; } diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2LoadBalancerServiceLiveTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2LoadBalancerServiceLiveTest.java new file mode 100644 index 0000000000..441e86c246 --- /dev/null +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/EC2LoadBalancerServiceLiveTest.java @@ -0,0 +1,73 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ +package org.jclouds.aws.ec2.compute; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.util.HashSet; +import java.util.Set; + +import org.jclouds.aws.domain.Region; +import org.jclouds.aws.ec2.EC2Client; +import org.jclouds.aws.ec2.domain.ElasticLoadBalancer; +import org.jclouds.aws.ec2.services.ElasticLoadBalancerClient; +import org.jclouds.compute.BaseLoadBalancerServiceLiveTest; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.ssh.jsch.config.JschSshClientModule; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * + * @author Lili Nadar + */ +@Test(groups = "live", sequential = true, testName = "ec2.EC2LoadBalancerServiceLiveTest") +public class EC2LoadBalancerServiceLiveTest extends BaseLoadBalancerServiceLiveTest { + + @BeforeClass + @Override + public void setServiceDefaults() { + service = "ec2"; + } + + @Override + protected JschSshClientModule getSshModule() { + return new JschSshClientModule(); + } + + @Override + protected void validateNodesInLoadBalancer() { + // TODO create a LoadBalancer object and an appropriate list method so that this + // does not have to be EC2 specific code + ElasticLoadBalancerClient elbClient = EC2Client.class.cast( + context.getProviderSpecificContext().getApi()).getElasticLoadBalancerServices(); + + Set instanceIds = new HashSet(); + for (NodeMetadata node : nodes) { + instanceIds.add(node.getProviderId()); + } + Set elbs = elbClient + .describeLoadBalancersInRegion(Region.US_EAST_1, tag); + assertNotNull(elbs); + ElasticLoadBalancer elb = elbs.iterator().next(); + assertEquals(elb.getInstanceIds(), instanceIds); + } + +} diff --git a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/internal/EC2TemplateBuilderImplTest.java b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/internal/EC2TemplateBuilderImplTest.java index 5e0fa55e50..19411fed60 100644 --- a/aws/core/src/test/java/org/jclouds/aws/ec2/compute/internal/EC2TemplateBuilderImplTest.java +++ b/aws/core/src/test/java/org/jclouds/aws/ec2/compute/internal/EC2TemplateBuilderImplTest.java @@ -51,6 +51,7 @@ import com.google.common.base.Function; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.MapMaker; +import com.google.inject.util.Providers; /** * @@ -77,8 +78,9 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest { } @Override - protected EC2TemplateBuilderImpl createTemplateBuilder(Set locations, - Set images, Set sizes, Location defaultLocation, + protected EC2TemplateBuilderImpl createTemplateBuilder( + Provider> locations, Provider> images, + Provider> sizes, Location defaultLocation, Provider optionsProvider, Provider templateBuilderProvider) { return new EC2TemplateBuilderImpl(locations, images, sizes, defaultLocation, optionsProvider, @@ -89,10 +91,15 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest { @Test public void testParseOnDemand() { Location location = new LocationImpl(LocationScope.REGION, "region", "region", null); - Set locations = ImmutableSet. of(location); - Set images = ImmutableSet. of(); - Set sizes = ImmutableSet. of(new SizeImpl("1", "1", "region/1", location, null, - ImmutableMap. of(), 1, 1, 1, ImagePredicates.any())); + + Provider> locations = Providers + .> of(ImmutableSet. of(location)); + Provider> images = Providers.> of(ImmutableSet + . of()); + Provider> sizes = Providers.> of(ImmutableSet + . of(new SizeImpl("1", "1", "region/1", location, null, ImmutableMap + . of(), 1, 1, 1, ImagePredicates.any()))); + Location defaultLocation = createMock(Location.class); Provider optionsProvider = createMock(Provider.class); Provider templateBuilderProvider = createMock(Provider.class); @@ -125,10 +132,15 @@ public class EC2TemplateBuilderImplTest extends TemplateBuilderImplTest { @Test(expectedExceptions = NoSuchElementException.class) public void testParseOnDemandNotFound() { Location location = new LocationImpl(LocationScope.REGION, "region", "region", null); - Set locations = ImmutableSet. of(location); - Set images = ImmutableSet. of(); - Set sizes = ImmutableSet. of(new SizeImpl("1", "1", "region/1", location, null, - ImmutableMap. of(), 1, 1, 1, ImagePredicates.any())); + + Provider> locations = Providers + .> of(ImmutableSet. of(location)); + Provider> images = Providers.> of(ImmutableSet + . of()); + Provider> sizes = Providers.> of(ImmutableSet + . of(new SizeImpl("1", "1", "region/1", location, null, ImmutableMap + . of(), 1, 1, 1, ImagePredicates.any()))); + Location defaultLocation = createMock(Location.class); Provider optionsProvider = createMock(Provider.class); Provider templateBuilderProvider = createMock(Provider.class); diff --git a/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseAsyncBlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseAsyncBlobStore.java index bc6c37714a..cb33be687e 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseAsyncBlobStore.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseAsyncBlobStore.java @@ -252,7 +252,7 @@ public abstract class BaseAsyncBlobStore implements AsyncBlobStore { protected void deleteAndEnsurePathGone(final String container) { try { - if (!Utils.enventuallyTrue(new Supplier() { + if (!Utils.eventuallyTrue(new Supplier() { public Boolean get() { try { clearContainer(container, recursive()); diff --git a/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java b/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java index 2bbfa1ad04..ff1d2c0528 100644 --- a/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java +++ b/blobstore/src/main/java/org/jclouds/blobstore/internal/BaseBlobStore.java @@ -194,7 +194,7 @@ public abstract class BaseBlobStore implements BlobStore { protected void clearAndDeleteContainer(final String container) { try { - if (!Utils.enventuallyTrue(new Supplier() { + if (!Utils.eventuallyTrue(new Supplier() { public Boolean get() { try { clearContainer(container, recursive()); diff --git a/compute/src/main/java/org/jclouds/compute/ComputeService.java b/compute/src/main/java/org/jclouds/compute/ComputeService.java index 66b871cb54..d0724a6134 100755 --- a/compute/src/main/java/org/jclouds/compute/ComputeService.java +++ b/compute/src/main/java/org/jclouds/compute/ComputeService.java @@ -33,7 +33,6 @@ import org.jclouds.compute.options.TemplateOptions; import org.jclouds.domain.Location; import org.jclouds.ssh.ExecResponse; -import com.google.common.annotations.Beta; import com.google.common.base.Predicate; import com.google.inject.ImplementedBy; @@ -146,8 +145,8 @@ public interface ComputeService { Set runNodesWithTag(String tag, int count) throws RunNodesException; /** - * destroy the node, given its id. If it is the only node in a tag set, the dependent - * resources will also be destroyed. + * destroy the node, given its id. If it is the only node in a tag set, the dependent resources + * will also be destroyed. */ void destroyNode(String id); @@ -215,30 +214,4 @@ public interface ComputeService { Predicate filter, byte[] runScript, RunScriptOptions options) throws RunScriptOnNodesException; - /** - * @param filter - * Predicate-based filter to define which nodes to loadbalance - * @param loadBalancerName - * Load balancer name - * @param protocol - * LoadBalancer transport protocol to use for routing - TCP or HTTP. This property - * cannot be modified for the life of the LoadBalancer. - * @param loadBalancerPort - * The external TCP port of the LoadBalancer. Valid LoadBalancer ports are - 80, 443 - * and 1024 through 65535. This property cannot be modified for the life of the - * LoadBalancer. - * @param instancePort - * The InstancePort data type is simple type of type: integer. It is the TCP port on - * which the server on the instance is listening. Valid instance ports are one (1) - * through 65535. This property cannot be modified for the life of the LoadBalancer. - * - * @return DNS Name of the load balancer - */ - @Beta - Set loadBalanceNodesMatching(Predicate filter, String loadBalancerName, - String protocol, int loadBalancerPort, int instancePort); - - @Beta - void deleteLoadBalancer(String handle); - } diff --git a/compute/src/main/java/org/jclouds/compute/ComputeServiceContext.java b/compute/src/main/java/org/jclouds/compute/ComputeServiceContext.java index 1667cb8753..ebfd60fc7a 100644 --- a/compute/src/main/java/org/jclouds/compute/ComputeServiceContext.java +++ b/compute/src/main/java/org/jclouds/compute/ComputeServiceContext.java @@ -35,6 +35,12 @@ public interface ComputeServiceContext { ComputeService getComputeService(); + /** + * + * @return null, if the cloud does not support load balancer services + */ + LoadBalancerService getLoadBalancerService(); + RestContext getProviderSpecificContext(); void close(); diff --git a/compute/src/main/java/org/jclouds/compute/LoadBalancerService.java b/compute/src/main/java/org/jclouds/compute/LoadBalancerService.java new file mode 100644 index 0000000000..ce62840b46 --- /dev/null +++ b/compute/src/main/java/org/jclouds/compute/LoadBalancerService.java @@ -0,0 +1,71 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ +package org.jclouds.compute; + +import java.net.InetAddress; +import java.util.Set; + +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.internal.BaseLoadBalancerService; + +import com.google.common.annotations.Beta; +import com.google.common.base.Predicate; +import com.google.inject.ImplementedBy; + +/** + * Provides portable access to load balancer services. + * + * @author Lili Nadar + */ +@Beta +@ImplementedBy(BaseLoadBalancerService.class) +public interface LoadBalancerService { + + /** + * @return a reference to the context that created this LoadBalancerService. + */ + ComputeServiceContext getContext(); + + /** + * @param filter + * Predicate-based filter to define which nodes to loadbalance + * @param loadBalancerName + * Load balancer name + * @param protocol + * LoadBalancer transport protocol to use for routing - TCP or HTTP. This property + * cannot be modified for the life of the LoadBalancer. + * @param loadBalancerPort + * The external TCP port of the LoadBalancer. Valid LoadBalancer ports are - 80, 443 + * and 1024 through 65535. This property cannot be modified for the life of the + * LoadBalancer. + * @param instancePort + * The InstancePort data type is simple type of type: integer. It is the TCP port on + * which the server on the instance is listening. Valid instance ports are one (1) + * through 65535. This property cannot be modified for the life of the LoadBalancer. + * + * @return DNS Name of the load balancer + */ + @Beta + Set loadBalanceNodesMatching(Predicate filter, + String loadBalancerName, String protocol, int loadBalancerPort, int instancePort); + + @Beta + void destroyLoadBalancer(InetAddress handle); + +} diff --git a/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java b/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java index 66171c9da4..489034faa3 100755 --- a/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java +++ b/compute/src/main/java/org/jclouds/compute/internal/BaseComputeService.java @@ -422,16 +422,4 @@ public class BaseComputeService implements ComputeService { public TemplateOptions templateOptions() { return templateOptionsProvider.get(); } - - @Override - public void deleteLoadBalancer(String handle) { - throw new UnsupportedOperationException("deleteLoadBalancer not supported in this cloud"); - } - - @Override - public Set loadBalanceNodesMatching(Predicate filter, String loadBalancerName, - String protocol, int loadBalancerPort, int instancePort) { - throw new UnsupportedOperationException( - "loadBalanceNodesMatching not supported in this cloud"); - } } \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/internal/BaseLoadBalancerService.java b/compute/src/main/java/org/jclouds/compute/internal/BaseLoadBalancerService.java new file mode 100644 index 0000000000..fc0ed8a5be --- /dev/null +++ b/compute/src/main/java/org/jclouds/compute/internal/BaseLoadBalancerService.java @@ -0,0 +1,142 @@ +/** + * + * Copyright (C) 2009 Global Cloud Specialists, Inc. + * + * ==================================================================== + * 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.compute.internal; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Map; +import java.util.Set; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.compute.LoadBalancerService; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.predicates.NodePredicates; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.compute.strategy.DestroyLoadBalancerStrategy; +import org.jclouds.compute.strategy.LoadBalanceNodesStrategy; +import org.jclouds.domain.Location; +import org.jclouds.logging.Logger; + +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.base.Throwables; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +/** + * + * @author Lili Nadar + * @author Adrian Cole + */ +@Singleton +public class BaseLoadBalancerService implements LoadBalancerService { + + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + protected final ComputeServiceContext context; + protected final LoadBalanceNodesStrategy loadBalancerStrategy; + protected final DestroyLoadBalancerStrategy destroyLoadBalancerStrategy; + + @Inject + protected BaseLoadBalancerService(ComputeServiceContext context, + LoadBalanceNodesStrategy loadBalancerStrategy, + DestroyLoadBalancerStrategy destroyLoadBalancerStrategy) { + this.context = checkNotNull(context, "context"); + this.loadBalancerStrategy = checkNotNull(loadBalancerStrategy, "loadBalancerStrategy"); + this.destroyLoadBalancerStrategy = checkNotNull(destroyLoadBalancerStrategy, + "destroyLoadBalancerStrategy"); + + } + + /** + * {@inheritDoc} + */ + @Override + public ComputeServiceContext getContext() { + return context; + } + + @Override + public Set loadBalanceNodesMatching(Predicate filter, + String loadBalancerName, String protocol, int loadBalancerPort, int instancePort) { + checkNotNull(loadBalancerName, "loadBalancerName"); + checkNotNull(protocol, "protocol"); + checkArgument(protocol.toUpperCase().equals("HTTP") || protocol.toUpperCase().equals("TCP"), + "Acceptable values for protocol are HTTP or TCP"); + + Map> locationMap = Maps.newHashMap(); + for (NodeMetadata node : Iterables.filter(context.getComputeService() + .listNodesDetailsMatching(NodePredicates.all()), Predicates.and(filter, Predicates + .not(NodePredicates.TERMINATED)))) { + Set ids = locationMap.get(node.getLocation()); + if (ids == null) + ids = Sets.newHashSet(); + ids.add(node.getProviderId()); + locationMap.put(node.getLocation(), ids); + } + Set dnsNames = Sets.newHashSet(); + for (Location location : locationMap.keySet()) { + logger.debug(">> creating load balancer (%s)", loadBalancerName); + String dnsName = loadBalancerStrategy.execute(location, loadBalancerName, protocol, + loadBalancerPort, instancePort, locationMap.get(location)); + for (int i = 0; i < 3; i++) { + try { + dnsNames.add(InetAddress.getByName(dnsName)); + } catch (UnknownHostException e) { + try { + Thread.sleep(1000); + } catch (InterruptedException e1) { + Throwables.propagate(e1); + } + continue; + } + } + logger.debug("<< created load balancer (%s) DNS (%s)", loadBalancerName, dnsName); + } + return dnsNames; + } + + /** + * {@inheritDoc} + */ + @Override + public void destroyLoadBalancer(InetAddress loadBalancer) { + checkNotNull(loadBalancer, "loadBalancer"); + logger.debug(">> destroying load balancer(%s)", loadBalancer); + boolean successful = destroyLoadBalancerStrategy.execute(loadBalancer); + logger.debug("<< destroyed load balancer(%s) success(%s)", loadBalancer, successful); + } + +} \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/internal/ComputeServiceContextImpl.java b/compute/src/main/java/org/jclouds/compute/internal/ComputeServiceContextImpl.java index 2d25c01cd8..7d7d313d95 100644 --- a/compute/src/main/java/org/jclouds/compute/internal/ComputeServiceContextImpl.java +++ b/compute/src/main/java/org/jclouds/compute/internal/ComputeServiceContextImpl.java @@ -21,24 +21,32 @@ package org.jclouds.compute.internal; import static com.google.common.base.Preconditions.checkNotNull; +import javax.annotation.Nullable; import javax.inject.Inject; +import javax.inject.Singleton; import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.compute.LoadBalancerService; import org.jclouds.rest.RestContext; /** * @author Adrian Cole */ +@Singleton public class ComputeServiceContextImpl implements ComputeServiceContext { private final ComputeService computeService; + private final LoadBalancerService loadBalancerService; private final RestContext providerSpecificContext; @Inject public ComputeServiceContextImpl(ComputeService computeService, + @Nullable LoadBalancerService loadBalancerService, RestContext providerSpecificContext) { this.computeService = checkNotNull(computeService, "computeService"); - this.providerSpecificContext = checkNotNull(providerSpecificContext, "providerSpecificContext");; + this.loadBalancerService = loadBalancerService; + this.providerSpecificContext = checkNotNull(providerSpecificContext, + "providerSpecificContext"); } public ComputeService getComputeService() { @@ -55,4 +63,9 @@ public class ComputeServiceContextImpl implements ComputeServiceContext { public void close() { providerSpecificContext.close(); } + + @Override + public LoadBalancerService getLoadBalancerService() { + return loadBalancerService; + } } diff --git a/compute/src/main/java/org/jclouds/compute/internal/TemplateBuilderImpl.java b/compute/src/main/java/org/jclouds/compute/internal/TemplateBuilderImpl.java index 32a7116cf0..af5e8254d0 100644 --- a/compute/src/main/java/org/jclouds/compute/internal/TemplateBuilderImpl.java +++ b/compute/src/main/java/org/jclouds/compute/internal/TemplateBuilderImpl.java @@ -64,9 +64,9 @@ public class TemplateBuilderImpl implements TemplateBuilder { @Named(ComputeServiceConstants.COMPUTE_LOGGER) protected Logger logger = Logger.NULL; - private final Set images; - private final Set sizes; - private final Set locations; + private final Provider> images; + private final Provider> sizes; + private final Provider> locations; private final Provider optionsProvider; private final Provider defaultTemplateProvider; private final Location defaultLocation; @@ -101,9 +101,9 @@ public class TemplateBuilderImpl implements TemplateBuilder { protected TemplateOptions options; @Inject - protected TemplateBuilderImpl(Set locations, Set images, - Set sizes, Location defaultLocation, - Provider optionsProvider, + protected TemplateBuilderImpl(Provider> locations, + Provider> images, Provider> sizes, + Location defaultLocation, Provider optionsProvider, @Named("DEFAULT") Provider defaultTemplateProvider) { this.locations = locations; this.images = images; @@ -413,7 +413,7 @@ public class TemplateBuilderImpl implements TemplateBuilder { } protected Location resolveLocation() { - Location location = Iterables.find(locations, new Predicate() { + Location location = Iterables.find(locations.get(), new Predicate() { @Override public boolean apply(Location input) { @@ -428,23 +428,23 @@ public class TemplateBuilderImpl implements TemplateBuilder { protected Size resolveSize(Ordering sizeOrdering, final List images) { Size size; try { - Iterable sizesThatAreCompatibleWithOurImages = Iterables.filter(sizes, - new Predicate() { + Iterable sizesThatAreCompatibleWithOurImages = Iterables.filter(sizes + .get(), new Predicate() { + @Override + public boolean apply(final Size size) { + boolean returnVal = false; + if (size != null) + returnVal = Iterables.any(images, new Predicate() { + @Override - public boolean apply(final Size size) { - boolean returnVal = false; - if (size != null) - returnVal = Iterables.any(images, new Predicate() { - - @Override - public boolean apply(Image input) { - return size.supportsImage(input); - } - - }); - return returnVal; + public boolean apply(Image input) { + return size.supportsImage(input); } + }); + return returnVal; + } + }); size = sizeOrdering.max(Iterables.filter(sizesThatAreCompatibleWithOurImages, sizePredicate)); } catch (NoSuchElementException exception) { @@ -471,7 +471,7 @@ public class TemplateBuilderImpl implements TemplateBuilder { protected List resolveImages() { Predicate imagePredicate = buildImagePredicate(); try { - Iterable matchingImages = Iterables.filter(images, imagePredicate); + Iterable matchingImages = Iterables.filter(images.get(), imagePredicate); if (logger.isTraceEnabled()) logger.trace("<< matched images(%s)", matchingImages); List maxImages = Utils.multiMax(DEFAULT_IMAGE_ORDERING, matchingImages); diff --git a/compute/src/main/java/org/jclouds/compute/strategy/DestroyLoadBalancerStrategy.java b/compute/src/main/java/org/jclouds/compute/strategy/DestroyLoadBalancerStrategy.java new file mode 100644 index 0000000000..a951269189 --- /dev/null +++ b/compute/src/main/java/org/jclouds/compute/strategy/DestroyLoadBalancerStrategy.java @@ -0,0 +1,36 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.jclouds.compute.strategy; + +import java.net.InetAddress; + +import com.google.common.annotations.Beta; + +/** + * + * + * @author Adrian Cole + */ +@Beta +public interface DestroyLoadBalancerStrategy { + + boolean execute(InetAddress loadBalancer); + +} \ No newline at end of file diff --git a/compute/src/main/java/org/jclouds/compute/strategy/LoadBalancerStrategy.java b/compute/src/main/java/org/jclouds/compute/strategy/LoadBalanceNodesStrategy.java similarity index 96% rename from compute/src/main/java/org/jclouds/compute/strategy/LoadBalancerStrategy.java rename to compute/src/main/java/org/jclouds/compute/strategy/LoadBalanceNodesStrategy.java index 0a62fd84be..a4ab10c406 100644 --- a/compute/src/main/java/org/jclouds/compute/strategy/LoadBalancerStrategy.java +++ b/compute/src/main/java/org/jclouds/compute/strategy/LoadBalanceNodesStrategy.java @@ -28,7 +28,7 @@ import org.jclouds.domain.Location; * * @author Lili Nader */ -public interface LoadBalancerStrategy { +public interface LoadBalanceNodesStrategy { String execute(Location loaction, String name, String protocol, int loadBalancerPort, int instancePort, Set instanceIds); diff --git a/compute/src/test/java/org/jclouds/compute/BaseLoadBalancerServiceLiveTest.java b/compute/src/test/java/org/jclouds/compute/BaseLoadBalancerServiceLiveTest.java new file mode 100644 index 0000000000..d3c7aa7665 --- /dev/null +++ b/compute/src/test/java/org/jclouds/compute/BaseLoadBalancerServiceLiveTest.java @@ -0,0 +1,155 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ +package org.jclouds.compute; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.testng.Assert.assertNotNull; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.NodeState; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.domain.TemplateBuilder; +import org.jclouds.compute.predicates.NodePredicates; +import org.jclouds.logging.log4j.config.Log4JLoggingModule; +import org.jclouds.predicates.RetryablePredicate; +import org.jclouds.predicates.SocketOpen; +import org.jclouds.ssh.SshClient; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeGroups; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Module; + +/** + * + * @author Adrian Cole + */ +@Test(groups = "live", sequential = true, testName = "compute.BaseLoadBalancerServiceTest") +public abstract class BaseLoadBalancerServiceLiveTest { + @BeforeClass + abstract public void setServiceDefaults(); + + protected String service; + protected SshClient.Factory sshFactory; + protected String tag; + + protected RetryablePredicate socketTester; + protected SortedSet nodes; + protected ComputeServiceContext context; + protected ComputeService client; + protected LoadBalancerService lbClient; + protected String user; + protected String password; + protected Template template; + protected Map keyPair; + protected Set loadbalancers; + + @BeforeGroups(groups = { "live" }) + public void setupClient() throws InterruptedException, ExecutionException, TimeoutException, + IOException, RunNodesException { + if (tag == null) + tag = checkNotNull(service, "service") + "lb"; + user = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user"); + password = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key"); + + initializeContextAndClient(); + + Injector injector = Guice.createInjector(getSshModule()); + sshFactory = injector.getInstance(SshClient.Factory.class); + SocketOpen socketOpen = injector.getInstance(SocketOpen.class); + socketTester = new RetryablePredicate(socketOpen, 60, 1, TimeUnit.SECONDS); + injector.injectMembers(socketOpen); // add logger + + Template template = client.templateBuilder().build(); + + nodes = Sets.newTreeSet(client.runNodesWithTag(tag, 2, template)); + } + + private void initializeContextAndClient() throws IOException { + if (context != null) + context.close(); + context = new ComputeServiceContextFactory().createContext(service, user, password, + ImmutableSet.of(new Log4JLoggingModule(), getSshModule())); + client = context.getComputeService(); + lbClient = context.getLoadBalancerService(); + } + + abstract protected Module getSshModule(); + + protected Template buildTemplate(TemplateBuilder templateBuilder) { + return templateBuilder.build(); + } + + @Test(enabled = true) + public void testLoadBalanceNodesMatching() throws Exception { + + // create load balancers + loadbalancers = lbClient.loadBalanceNodesMatching(NodePredicates.withTag(tag), tag, "HTTP", + 80, 80); + assertNotNull(loadbalancers); + validateNodesInLoadBalancer(); + + } + + // TODO create a LoadBalancerService method for this. + protected abstract void validateNodesInLoadBalancer(); + + @Test(enabled = true, dependsOnMethods = "testLoadBalanceNodesMatching") + public void testDestroyLoadBalancers() throws Exception { + for (InetAddress lb : loadbalancers) { + lbClient.destroyLoadBalancer(lb); + } + } + + @AfterTest + protected void cleanup() throws InterruptedException, ExecutionException, TimeoutException { + if (nodes != null) { + client.destroyNodesMatching(NodePredicates.withTag(tag)); + for (NodeMetadata node : Iterables.filter(client.listNodesDetailsMatching(NodePredicates + .all()), NodePredicates.withTag(tag))) { + assert node.getState() == NodeState.TERMINATED : node; + } + } + if (loadbalancers != null) { + client.destroyNodesMatching(NodePredicates.withTag(tag)); + for (NodeMetadata node : Iterables.filter(client.listNodesDetailsMatching(NodePredicates + .all()), NodePredicates.withTag(tag))) { + assert node.getState() == NodeState.TERMINATED : node; + } + } + context.close(); + } + +} diff --git a/compute/src/test/java/org/jclouds/compute/internal/TemplateBuilderImplTest.java b/compute/src/test/java/org/jclouds/compute/internal/TemplateBuilderImplTest.java index 924ce6063e..5d87816469 100644 --- a/compute/src/test/java/org/jclouds/compute/internal/TemplateBuilderImplTest.java +++ b/compute/src/test/java/org/jclouds/compute/internal/TemplateBuilderImplTest.java @@ -42,6 +42,7 @@ import org.testng.annotations.Test; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.inject.util.Providers; /** * @@ -60,9 +61,12 @@ public class TemplateBuilderImplTest { Size size = new SizeImpl("sizeId", null, "sizeId", defaultLocation, null, ImmutableMap . of(), 1.0, 0, 0, ImagePredicates.any()); - Set locations = ImmutableSet. of(defaultLocation); - Set images = ImmutableSet. of(image, image2); - Set sizes = ImmutableSet. of(size); + Provider> locations = Providers + .> of(ImmutableSet. of(defaultLocation)); + Provider> images = Providers.> of(ImmutableSet + . of(image, image2)); + Provider> sizes = Providers.> of(ImmutableSet + . of(size)); Provider optionsProvider = createMock(Provider.class); Provider templateBuilderProvider = createMock(Provider.class); TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class); @@ -86,7 +90,7 @@ public class TemplateBuilderImplTest { TemplateBuilderImpl template = createTemplateBuilder(locations, images, sizes, defaultLocation, optionsProvider, templateBuilderProvider); - assertEquals(template.resolveImages(), images); + assertEquals(template.resolveImages(), images.get()); verify(image); verify(image2); @@ -106,9 +110,12 @@ public class TemplateBuilderImplTest { Size size = new SizeImpl("sizeId", null, "sizeId", defaultLocation, null, ImmutableMap . of(), 1.0, 0, 0, ImagePredicates.any()); - Set locations = ImmutableSet. of(defaultLocation); - Set images = ImmutableSet. of(image, image2); - Set sizes = ImmutableSet. of(size); + Provider> locations = Providers + .> of(ImmutableSet. of(defaultLocation)); + Provider> images = Providers.> of(ImmutableSet + . of(image, image2)); + Provider> sizes = Providers.> of(ImmutableSet + . of(size)); Provider optionsProvider = createMock(Provider.class); Provider templateBuilderProvider = createMock(Provider.class); TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class); @@ -150,9 +157,12 @@ public class TemplateBuilderImplTest { Size size = new SizeImpl("sizeId", null, "sizeId", defaultLocation, null, ImmutableMap . of(), 0, 0, 0, ImagePredicates.idEquals("imageId")); - Set locations = ImmutableSet. of(defaultLocation); - Set images = ImmutableSet. of(image); - Set sizes = ImmutableSet. of(size); + Provider> locations = Providers + .> of(ImmutableSet. of(defaultLocation)); + Provider> images = Providers.> of(ImmutableSet + . of(image)); + Provider> sizes = Providers.> of(ImmutableSet + . of(size)); Provider optionsProvider = createMock(Provider.class); Provider templateBuilderProvider = createMock(Provider.class); TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class); @@ -194,9 +204,12 @@ public class TemplateBuilderImplTest { Size size = new SizeImpl("sizeId", null, "sizeId", defaultLocation, null, ImmutableMap . of(), 0, 0, 0, ImagePredicates.idEquals("imageId")); - Set locations = ImmutableSet. of(defaultLocation); - Set images = ImmutableSet. of(image); - Set sizes = ImmutableSet. of(size); + Provider> locations = Providers + .> of(ImmutableSet. of(defaultLocation)); + Provider> images = Providers.> of(ImmutableSet + . of(image)); + Provider> sizes = Providers.> of(ImmutableSet + . of(size)); Provider optionsProvider = createMock(Provider.class); Provider templateBuilderProvider = createMock(Provider.class); TemplateBuilder defaultTemplate = createMock(TemplateBuilder.class); @@ -237,9 +250,12 @@ public class TemplateBuilderImplTest { public void testOptionsUsesDefaultTemplateBuilder() { TemplateOptions options = new TemplateOptions(); - Set locations = ImmutableSet. of(); - Set images = ImmutableSet. of(); - Set sizes = ImmutableSet. of(); + Provider> locations = Providers + .> of(ImmutableSet. of()); + Provider> images = Providers.> of(ImmutableSet + . of()); + Provider> sizes = Providers.> of(ImmutableSet + . of()); Location defaultLocation = createMock(Location.class); Provider optionsProvider = createMock(Provider.class); Provider templateBuilderProvider = createMock(Provider.class); @@ -268,9 +284,14 @@ public class TemplateBuilderImplTest { @SuppressWarnings("unchecked") @Test public void testNothingUsesDefaultTemplateBuilder() { - Set locations = ImmutableSet. of(); - Set images = ImmutableSet. of(); - Set sizes = ImmutableSet. of(); + + Provider> locations = Providers + .> of(ImmutableSet. of()); + Provider> images = Providers.> of(ImmutableSet + . of()); + Provider> sizes = Providers.> of(ImmutableSet + . of()); + Location defaultLocation = createMock(Location.class); Provider optionsProvider = createMock(Provider.class); Provider templateBuilderProvider = createMock(Provider.class); @@ -295,8 +316,9 @@ public class TemplateBuilderImplTest { verify(templateBuilderProvider); } - protected TemplateBuilderImpl createTemplateBuilder(Set locations, Set images, - Set sizes, Location defaultLocation, Provider optionsProvider, + protected TemplateBuilderImpl createTemplateBuilder(Provider> locations, + Provider> images, Provider> sizes, + Location defaultLocation, Provider optionsProvider, Provider templateBuilderProvider) { TemplateBuilderImpl template = new TemplateBuilderImpl(locations, images, sizes, defaultLocation, optionsProvider, templateBuilderProvider); @@ -306,9 +328,12 @@ public class TemplateBuilderImplTest { @SuppressWarnings("unchecked") @Test public void testSuppliedLocationWithNoOptions() { - Set locations = ImmutableSet. of(); - Set images = ImmutableSet. of(); - Set sizes = ImmutableSet. of(); + Provider> locations = Providers + .> of(ImmutableSet. of()); + Provider> images = Providers.> of(ImmutableSet + . of()); + Provider> sizes = Providers.> of(ImmutableSet + . of()); Location defaultLocation = createMock(Location.class); Provider optionsProvider = createMock(Provider.class); Provider templateBuilderProvider = createMock(Provider.class); @@ -340,9 +365,12 @@ public class TemplateBuilderImplTest { @SuppressWarnings("unchecked") @Test public void testSuppliedLocationAndOptions() { - Set locations = ImmutableSet. of(); - Set images = ImmutableSet. of(); - Set sizes = ImmutableSet. of(); + Provider> locations = Providers + .> of(ImmutableSet. of()); + Provider> images = Providers.> of(ImmutableSet + . of()); + Provider> sizes = Providers.> of(ImmutableSet + . of()); Location defaultLocation = createMock(Location.class); Provider optionsProvider = createMock(Provider.class); Provider templateBuilderProvider = createMock(Provider.class); @@ -369,9 +397,12 @@ public class TemplateBuilderImplTest { @SuppressWarnings("unchecked") @Test public void testDefaultLocationWithNoOptionsNoSuchElement() { - Set locations = ImmutableSet. of(); - Set images = ImmutableSet. of(); - Set sizes = ImmutableSet. of(); + Provider> locations = Providers + .> of(ImmutableSet. of()); + Provider> images = Providers.> of(ImmutableSet + . of()); + Provider> sizes = Providers.> of(ImmutableSet + . of()); Location defaultLocation = createMock(Location.class); Provider optionsProvider = createMock(Provider.class); Provider templateBuilderProvider = createMock(Provider.class); @@ -404,9 +435,12 @@ public class TemplateBuilderImplTest { @SuppressWarnings("unchecked") @Test public void testDefaultLocationWithOptions() { - Set locations = ImmutableSet. of(); - Set images = ImmutableSet. of(); - Set sizes = ImmutableSet. of(); + Provider> locations = Providers + .> of(ImmutableSet. of()); + Provider> images = Providers.> of(ImmutableSet + . of()); + Provider> sizes = Providers.> of(ImmutableSet + . of()); Location defaultLocation = createMock(Location.class); Provider optionsProvider = createMock(Provider.class); Provider templateBuilderProvider = createMock(Provider.class); @@ -435,9 +469,12 @@ public class TemplateBuilderImplTest { @SuppressWarnings("unchecked") @Test public void testImageIdNullsEverythingElse() { - Set locations = ImmutableSet. of(); - Set images = ImmutableSet. of(); - Set sizes = ImmutableSet. of(); + Provider> locations = Providers + .> of(ImmutableSet. of()); + Provider> images = Providers.> of(ImmutableSet + . of()); + Provider> sizes = Providers.> of(ImmutableSet + . of()); Location defaultLocation = createMock(Location.class); Provider optionsProvider = createMock(Provider.class); Provider templateBuilderProvider = createMock(Provider.class); diff --git a/core/src/main/java/org/jclouds/concurrent/RetryOnTimeOutExceptionSupplier.java b/core/src/main/java/org/jclouds/concurrent/RetryOnTimeOutExceptionSupplier.java new file mode 100644 index 0000000000..f4c6a4e1b4 --- /dev/null +++ b/core/src/main/java/org/jclouds/concurrent/RetryOnTimeOutExceptionSupplier.java @@ -0,0 +1,60 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ +package org.jclouds.concurrent; + +import java.util.concurrent.TimeoutException; + +import org.jclouds.util.Utils; + +import com.google.common.base.Supplier; +import com.google.common.base.Throwables; + +/** + * + * @author Adrian Cole + */ +public class RetryOnTimeOutExceptionSupplier implements Supplier { + private final Supplier delegate; + + public RetryOnTimeOutExceptionSupplier(Supplier delegate) { + this.delegate = delegate; + } + + @Override + public T get() { + TimeoutException ex = null; + for (int i = 0; i < 3; i++) { + try { + ex = null; + return delegate.get(); + } catch (Exception e) { + if ((ex = Utils.getFirstThrowableOfType(e, TimeoutException.class)) != null) + continue; + Throwables.propagate(e); + assert false; + return null; + } + } + if (ex != null) + Throwables.propagate(ex); + assert false; + return null; + } + +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/concurrent/config/ExecutorServiceModule.java b/core/src/main/java/org/jclouds/concurrent/config/ExecutorServiceModule.java index 0413205d41..78d6971ac2 100644 --- a/core/src/main/java/org/jclouds/concurrent/config/ExecutorServiceModule.java +++ b/core/src/main/java/org/jclouds/concurrent/config/ExecutorServiceModule.java @@ -126,7 +126,7 @@ public class ExecutorServiceModule extends AbstractModule { @VisibleForTesting static ExecutorService newFixedThreadPoolNamed(String name, int maxCount) { - return new ThreadPoolExecutor(0, maxCount, 60L, TimeUnit.SECONDS, + return new ThreadPoolExecutor(maxCount, maxCount, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue(), new NamingThreadFactory(name)); } diff --git a/core/src/main/java/org/jclouds/concurrent/internal/SyncProxy.java b/core/src/main/java/org/jclouds/concurrent/internal/SyncProxy.java index c7a043859f..f16a309e1b 100644 --- a/core/src/main/java/org/jclouds/concurrent/internal/SyncProxy.java +++ b/core/src/main/java/org/jclouds/concurrent/internal/SyncProxy.java @@ -27,12 +27,9 @@ import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import javax.annotation.Resource; import javax.inject.Inject; -import javax.inject.Singleton; import org.jclouds.concurrent.Timeout; -import org.jclouds.logging.Logger; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableSet; @@ -45,7 +42,6 @@ import com.google.common.util.concurrent.ListenableFuture; * @author Adrian Cole */ @SuppressWarnings("deprecation") -@Singleton public class SyncProxy implements InvocationHandler { @SuppressWarnings("unchecked") @@ -55,8 +51,6 @@ public class SyncProxy implements InvocationHandler { new SyncProxy(clazz, delegate)); } - @Resource - protected Logger logger = Logger.NULL; private final Object delegate; private final Class declaring; private final Map methodMap; diff --git a/core/src/main/java/org/jclouds/http/HttpUtils.java b/core/src/main/java/org/jclouds/http/HttpUtils.java index ed54d71062..a66520a34e 100644 --- a/core/src/main/java/org/jclouds/http/HttpUtils.java +++ b/core/src/main/java/org/jclouds/http/HttpUtils.java @@ -195,6 +195,21 @@ public class HttpUtils { } } + /** + * Content stream may need to be read. However, we should always close the http stream. + */ + public static void consumeContent(HttpResponse response) { + if (response.getContent() != null) { + try { + ByteStreams.toByteArray(response.getContent()); + } catch (IOException e) { + Throwables.propagate(e); + } finally { + Closeables.closeQuietly(response.getContent()); + } + } + } + /** * Content stream may need to be read. However, we should always close the http stream. */ diff --git a/core/src/main/java/org/jclouds/util/Utils.java b/core/src/main/java/org/jclouds/util/Utils.java index e136ee40d2..38e878d59c 100644 --- a/core/src/main/java/org/jclouds/util/Utils.java +++ b/core/src/main/java/org/jclouds/util/Utils.java @@ -32,6 +32,7 @@ import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Set; import java.util.Map.Entry; import java.util.regex.Matcher; @@ -42,9 +43,11 @@ import javax.annotation.Resource; import org.jclouds.logging.Logger; import com.google.common.base.Charsets; +import com.google.common.base.Predicates; import com.google.common.base.Supplier; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.io.ByteStreams; import com.google.common.io.Closeables; @@ -95,6 +98,15 @@ public class Utils { return null; } + @SuppressWarnings("unchecked") + public static T getFirstThrowableOfType(Throwable from, Class clazz) { + try { + return (T) Iterables.find(Throwables.getCausalChain(from), Predicates.instanceOf(clazz)); + } catch (NoSuchElementException e) { + return null; + } + } + public static Throwable firstRootCauseOrOriginalException(ProvisionException e) { for (Message message : e.getErrorMessages()) { Throwable cause = Throwables.getRootCause(message.getCause()); @@ -145,7 +157,7 @@ public class Utils { }; } - public static boolean enventuallyTrue(Supplier assertion, long inconsistencyMillis) + public static boolean eventuallyTrue(Supplier assertion, long inconsistencyMillis) throws InterruptedException { for (int i = 0; i < 30; i++) { diff --git a/core/src/test/java/org/jclouds/concurrent/RetryOnTimeOutExceptionSupplierTest.java b/core/src/test/java/org/jclouds/concurrent/RetryOnTimeOutExceptionSupplierTest.java new file mode 100644 index 0000000000..31bbf95614 --- /dev/null +++ b/core/src/test/java/org/jclouds/concurrent/RetryOnTimeOutExceptionSupplierTest.java @@ -0,0 +1,127 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ +package org.jclouds.concurrent; + +import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor; +import static org.easymock.EasyMock.expect; +import static org.easymock.classextension.EasyMock.createMock; +import static org.easymock.classextension.EasyMock.replay; +import static org.easymock.classextension.EasyMock.verify; +import static org.testng.Assert.assertEquals; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeoutException; + +import org.jclouds.rest.AuthorizationException; +import org.testng.annotations.Test; + +import com.google.common.base.Supplier; + +/** + * Tests behavior of RetryOnTimeOutExceptionSupplier + * + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "concurrent.RetryOnTimeOutExceptionSupplierTest") +public class RetryOnTimeOutExceptionSupplierTest { + ExecutorService executorService = sameThreadExecutor(); + + @SuppressWarnings("unchecked") + @Test + public void testGetThrowsOriginalExceptionButRetriesOnTimeoutException() throws InterruptedException, ExecutionException { + Supplier delegate = createMock(Supplier.class); + TimeoutException timeout = createMock(TimeoutException.class); + RuntimeException throwable = new RuntimeException(timeout); + + expect(delegate.get()).andThrow(throwable); + expect(timeout.getCause()).andReturn(null).anyTimes(); + expect(delegate.get()).andThrow(throwable); + expect(delegate.get()).andThrow(throwable); + + replay(delegate); + replay(timeout); + + RetryOnTimeOutExceptionSupplier supplier = new RetryOnTimeOutExceptionSupplier( + delegate); + try { + supplier.get(); + assert false; + } catch (RuntimeException e) { + assertEquals(e.getCause(), timeout); + } + + verify(delegate); + verify(timeout); + + } + + @SuppressWarnings("unchecked") + @Test + public void testGetAllowsTwoFailuresOnTimeoutException() throws InterruptedException, ExecutionException { + Supplier delegate = createMock(Supplier.class); + TimeoutException timeout = createMock(TimeoutException.class); + RuntimeException throwable = new RuntimeException(timeout); + + expect(delegate.get()).andThrow(throwable); + expect(timeout.getCause()).andReturn(null).anyTimes(); + expect(delegate.get()).andThrow(throwable); + expect(delegate.get()).andReturn("foo"); + + replay(delegate); + replay(timeout); + + RetryOnTimeOutExceptionSupplier supplier = new RetryOnTimeOutExceptionSupplier( + delegate); + assertEquals(supplier.get(), "foo"); + + verify(delegate); + verify(timeout); + } + + @SuppressWarnings("unchecked") + @Test + public void testGetAllowsNoFailuresOnOtherExceptions() throws InterruptedException, ExecutionException { + Supplier delegate = createMock(Supplier.class); + AuthorizationException auth = createMock(AuthorizationException.class); + RuntimeException throwable = new RuntimeException(auth); + + expect(delegate.get()).andThrow(throwable); + expect(auth.getCause()).andReturn(null).anyTimes(); + + + replay(delegate); + replay(auth); + + RetryOnTimeOutExceptionSupplier supplier = new RetryOnTimeOutExceptionSupplier( + delegate); + + try { + supplier.get(); + assert false; + } catch (RuntimeException e) { + assertEquals(e.getCause(), auth); + } + + verify(delegate); + verify(auth); + + } + +} diff --git a/core/src/test/java/org/jclouds/util/UtilsTest.java b/core/src/test/java/org/jclouds/util/UtilsTest.java index 1ca7808a7b..a72061d5f6 100644 --- a/core/src/test/java/org/jclouds/util/UtilsTest.java +++ b/core/src/test/java/org/jclouds/util/UtilsTest.java @@ -22,6 +22,7 @@ import static org.easymock.classextension.EasyMock.createMock; import static org.testng.Assert.assertEquals; import java.io.UnsupportedEncodingException; +import java.util.concurrent.TimeoutException; import org.jclouds.rest.AuthorizationException; import org.testng.annotations.Test; @@ -46,6 +47,25 @@ public class UtilsTest { assertEquals(Utils.firstRootCauseOrOriginalException(pex), aex); } + public void testGetFirstThrowableOfTypeOuter() { + AuthorizationException aex = createMock(AuthorizationException.class); + assertEquals(Utils.getFirstThrowableOfType(aex, AuthorizationException.class), aex); + } + + public void testGetFirstThrowableOfTypeInner() { + AuthorizationException aex = createMock(AuthorizationException.class); + Message message = new Message(ImmutableList.of(), "test", aex); + ProvisionException pex = new ProvisionException(ImmutableSet.of(message)); + assertEquals(Utils.getFirstThrowableOfType(pex, AuthorizationException.class), aex); + } + + public void testGetFirstThrowableOfTypeFail() { + TimeoutException aex = createMock(TimeoutException.class); + Message message = new Message(ImmutableList.of(), "test", aex); + ProvisionException pex = new ProvisionException(ImmutableSet.of(message)); + assertEquals(Utils.getFirstThrowableOfType(pex, AuthorizationException.class), null); + } + public void testReplaceTokens() throws UnsupportedEncodingException { assertEquals(Utils.replaceTokens("hello {where}", ImmutableMap.of("where", "world")), "hello world"); diff --git a/gogrid/src/main/java/org/jclouds/gogrid/compute/config/GoGridComputeServiceContextModule.java b/gogrid/src/main/java/org/jclouds/gogrid/compute/config/GoGridComputeServiceContextModule.java index 59fecaa247..60b42c22e0 100755 --- a/gogrid/src/main/java/org/jclouds/gogrid/compute/config/GoGridComputeServiceContextModule.java +++ b/gogrid/src/main/java/org/jclouds/gogrid/compute/config/GoGridComputeServiceContextModule.java @@ -37,8 +37,8 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; -import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.compute.LoadBalancerService; import org.jclouds.compute.domain.Architecture; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.Image; @@ -76,7 +76,6 @@ import org.jclouds.gogrid.predicates.ServerLatestJobCompleted; import org.jclouds.gogrid.util.GoGridUtils; import org.jclouds.logging.Logger; import org.jclouds.predicates.RetryablePredicate; -import org.jclouds.rest.RestContext; import com.google.common.base.Function; import com.google.common.base.Predicate; @@ -86,7 +85,9 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; import com.google.inject.Provides; +import com.google.inject.Scopes; import com.google.inject.TypeLiteral; +import com.google.inject.util.Providers; /** * @author Oleksiy Yarmula @@ -103,6 +104,10 @@ public class GoGridComputeServiceContextModule extends GoGridContextModule { super.configure(); bind(new TypeLiteral>() { }).to(ServerToNodeMetadata.class); + bind(LoadBalancerService.class).toProvider(Providers. of(null)); + bind(new TypeLiteral() { + }).to(new TypeLiteral>() { + }).in(Scopes.SINGLETON); bind(AddNodeWithTagStrategy.class).to(GoGridAddNodeWithTagStrategy.class); bind(ListNodesStrategy.class).to(GoGridListNodesStrategy.class); bind(GetNodeMetadataStrategy.class).to(GoGridGetNodeMetadataStrategy.class); @@ -269,13 +274,6 @@ public class GoGridComputeServiceContextModule extends GoGridContextModule { }; } - @Provides - @Singleton - ComputeServiceContext provideContext(ComputeService computeService, - RestContext context) { - return new ComputeServiceContextImpl(computeService, context); - } - @Provides @Singleton @Named("NOT_RUNNING") diff --git a/rackspace/src/main/java/org/jclouds/rackspace/cloudservers/compute/config/CloudServersComputeServiceContextModule.java b/rackspace/src/main/java/org/jclouds/rackspace/cloudservers/compute/config/CloudServersComputeServiceContextModule.java index 36ed59ee71..aa5d81e716 100755 --- a/rackspace/src/main/java/org/jclouds/rackspace/cloudservers/compute/config/CloudServersComputeServiceContextModule.java +++ b/rackspace/src/main/java/org/jclouds/rackspace/cloudservers/compute/config/CloudServersComputeServiceContextModule.java @@ -36,8 +36,8 @@ import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.Constants; -import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.compute.LoadBalancerService; import org.jclouds.compute.domain.Architecture; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.Image; @@ -79,7 +79,6 @@ import org.jclouds.rackspace.cloudservers.domain.ServerStatus; import org.jclouds.rackspace.cloudservers.options.ListOptions; import org.jclouds.rackspace.config.RackspaceLocationsModule; import org.jclouds.rackspace.reference.RackspaceConstants; -import org.jclouds.rest.RestContext; import com.google.common.base.Function; import com.google.common.base.Predicate; @@ -88,7 +87,9 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; import com.google.inject.Provides; +import com.google.inject.Scopes; import com.google.inject.TypeLiteral; +import com.google.inject.util.Providers; /** * Configures the {@link CloudServersComputeServiceContext}; requires {@link BaseComputeService} @@ -109,6 +110,12 @@ public class CloudServersComputeServiceContextModule extends CloudServersContext install(new RackspaceLocationsModule(providerName)); bind(new TypeLiteral>() { }).to(ServerToNodeMetadata.class); + bind(LoadBalancerService.class).toProvider(Providers. of(null)); + bind(new TypeLiteral() { + }) + .to( + new TypeLiteral>() { + }).in(Scopes.SINGLETON); bind(AddNodeWithTagStrategy.class).to(CloudServersAddNodeWithTagStrategy.class); bind(ListNodesStrategy.class).to(CloudServersListNodesStrategy.class); bind(GetNodeMetadataStrategy.class).to(CloudServersGetNodeMetadataStrategy.class); @@ -279,14 +286,6 @@ public class CloudServersComputeServiceContextModule extends CloudServersContext .put(ServerStatus.UNKNOWN, NodeState.UNKNOWN).build(); } - @Provides - @Singleton - ComputeServiceContext provideContext(ComputeService computeService, - RestContext context) { - return new ComputeServiceContextImpl( - computeService, context); - } - @Provides @Singleton @Named("NOT_RUNNING") diff --git a/rackspace/src/main/java/org/jclouds/rackspace/config/RackspaceAuthenticationRestModule.java b/rackspace/src/main/java/org/jclouds/rackspace/config/RackspaceAuthenticationRestModule.java index 694c8d7b7f..753404b96c 100755 --- a/rackspace/src/main/java/org/jclouds/rackspace/config/RackspaceAuthenticationRestModule.java +++ b/rackspace/src/main/java/org/jclouds/rackspace/config/RackspaceAuthenticationRestModule.java @@ -32,6 +32,7 @@ import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.concurrent.ExpirableSupplier; +import org.jclouds.concurrent.RetryOnTimeOutExceptionSupplier; import org.jclouds.date.TimeStamp; import org.jclouds.http.RequiresHttp; import org.jclouds.rackspace.Authentication; @@ -80,18 +81,22 @@ public class RackspaceAuthenticationRestModule extends AbstractModule { Supplier provideAuthenticationResponseCache( final RestClientFactory factory, @Named(PROPERTY_RACKSPACE_USER) final String user, @Named(PROPERTY_RACKSPACE_KEY) final String key) { - return new ExpirableSupplier(new Supplier() { - public AuthenticationResponse get() { - try { - ListenableFuture response = factory.create( - RackspaceAuthentication.class).authenticate(user, key); - return response.get(30, TimeUnit.SECONDS); - } catch (Exception e) { - Throwables.propagateIfPossible(e); - throw new RuntimeException("Error logging in", e); - } - } - }, 23, TimeUnit.HOURS); + return new ExpirableSupplier( + new RetryOnTimeOutExceptionSupplier( + new Supplier() { + public AuthenticationResponse get() { + try { + ListenableFuture response = factory + .create(RackspaceAuthentication.class).authenticate(user, + key); + return response.get(30, TimeUnit.SECONDS); + } catch (Exception e) { + Throwables.propagate(e); + assert false : e; + return null; + } + } + }), 23, TimeUnit.HOURS); } @Provides diff --git a/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/compute/config/RimuHostingComputeServiceContextModule.java b/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/compute/config/RimuHostingComputeServiceContextModule.java index ec918a38b1..54e74d6caa 100755 --- a/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/compute/config/RimuHostingComputeServiceContextModule.java +++ b/rimuhosting/src/main/java/org/jclouds/rimuhosting/miro/compute/config/RimuHostingComputeServiceContextModule.java @@ -40,8 +40,8 @@ import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.Constants; -import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.compute.LoadBalancerService; import org.jclouds.compute.domain.Architecture; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.Image; @@ -71,7 +71,6 @@ import org.jclouds.domain.LocationScope; import org.jclouds.domain.internal.LocationImpl; import org.jclouds.logging.Logger; import org.jclouds.predicates.RetryablePredicate; -import org.jclouds.rest.RestContext; import org.jclouds.rimuhosting.miro.RimuHostingAsyncClient; import org.jclouds.rimuhosting.miro.RimuHostingClient; import org.jclouds.rimuhosting.miro.config.RimuHostingContextModule; @@ -89,7 +88,9 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; import com.google.inject.Provides; +import com.google.inject.Scopes; import com.google.inject.TypeLiteral; +import com.google.inject.util.Providers; /** * Configures the {@link RimuHostingComputeServiceContext}; requires @@ -109,6 +110,12 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo super.configure(); bind(new TypeLiteral>() { }).to(ServerToNodeMetadata.class); + bind(LoadBalancerService.class).toProvider(Providers. of(null)); + bind(new TypeLiteral() { + }) + .to( + new TypeLiteral>() { + }).in(Scopes.SINGLETON); bind(new TypeLiteral>>() { }).to(ServerToPublicAddresses.class); bind(AddNodeWithTagStrategy.class).to(RimuHostingAddNodeWithTagStrategy.class); @@ -352,14 +359,6 @@ public class RimuHostingComputeServiceContextModule extends RimuHostingContextMo } } - @Provides - @Singleton - ComputeServiceContext provideContext(ComputeService computeService, - RestContext context) { - return new ComputeServiceContextImpl( - computeService, context); - } - @Provides @Singleton @Named("NOT_RUNNING") diff --git a/vcloud/bluelock/src/test/java/org/jclouds/vcloud/bluelock/VCloudSessionRefreshLiveTest.java b/vcloud/bluelock/src/test/java/org/jclouds/vcloud/bluelock/VCloudSessionRefreshLiveTest.java new file mode 100644 index 0000000000..33a0c236fa --- /dev/null +++ b/vcloud/bluelock/src/test/java/org/jclouds/vcloud/bluelock/VCloudSessionRefreshLiveTest.java @@ -0,0 +1,61 @@ +package org.jclouds.vcloud.bluelock; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_SESSIONINTERVAL; + +import java.io.IOException; +import java.util.Properties; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.compute.ComputeServiceContextFactory; +import org.jclouds.logging.log4j.config.Log4JLoggingModule; +import org.jclouds.vcloud.VCloudClient; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeGroups; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Module; + +/** + * Tests session refresh works + * + * @author Adrian Cole + */ +@Test(groups = "live", sequential = true, testName = "vcloud.VCloudSessionRefreshLiveTest") +public class VCloudSessionRefreshLiveTest { + + private final static int timeOut = 40; + protected VCloudClient connection; + protected String account; + protected ComputeServiceContext context; + + @Test + public void testSessionRefresh() throws Exception { + connection.getDefaultOrganization(); + Thread.sleep(timeOut * 1000); + connection.getDefaultOrganization(); + } + + @BeforeGroups(groups = { "live" }) + public void setupClient() throws IOException { + account = checkNotNull(System.getProperty("jclouds.test.user"), "jclouds.test.user"); + String key = checkNotNull(System.getProperty("jclouds.test.key"), "jclouds.test.key"); + + Properties props = new Properties(); + props.setProperty(PROPERTY_VCLOUD_SESSIONINTERVAL, 40 + ""); + + context = new ComputeServiceContextFactory().createContext("bluelock", account, key, + ImmutableSet. of(new Log4JLoggingModule()), props); + + connection = VCloudClient.class.cast(context.getProviderSpecificContext().getApi()); + } + + @AfterTest + protected void cleanup() throws InterruptedException, ExecutionException, TimeoutException { + context.close(); + } + +} diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceContextModule.java b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceContextModule.java index 2e18112daa..033db86b1a 100755 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceContextModule.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/config/VCloudComputeServiceContextModule.java @@ -27,8 +27,8 @@ import java.util.concurrent.TimeUnit; import javax.inject.Named; import javax.inject.Singleton; -import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.compute.LoadBalancerService; import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.NodeState; @@ -45,7 +45,6 @@ import org.jclouds.compute.strategy.RebootNodeStrategy; import org.jclouds.compute.strategy.RunNodesAndAddToSetStrategy; import org.jclouds.domain.Location; import org.jclouds.predicates.RetryablePredicate; -import org.jclouds.rest.RestContext; import org.jclouds.vcloud.VCloudAsyncClient; import org.jclouds.vcloud.VCloudClient; import org.jclouds.vcloud.compute.BaseVCloudComputeClient; @@ -70,6 +69,7 @@ import com.google.common.collect.Iterables; import com.google.inject.Provides; import com.google.inject.Scopes; import com.google.inject.TypeLiteral; +import com.google.inject.util.Providers; /** * Configures the {@link VCloudComputeServiceContext}; requires {@link BaseVCloudComputeClient} @@ -85,14 +85,13 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule { this.providerName = providerName; } - @Singleton @Provides Map provideVAppStatusToNodeState() { - return ImmutableMap. builder().put(VAppStatus.OFF, - NodeState.SUSPENDED).put(VAppStatus.ON, NodeState.RUNNING).put(VAppStatus.RESOLVED, - NodeState.PENDING).put(VAppStatus.SUSPENDED, NodeState.SUSPENDED).put( - VAppStatus.UNRESOLVED, NodeState.PENDING).build(); + return ImmutableMap. builder() + .put(VAppStatus.OFF, NodeState.SUSPENDED).put(VAppStatus.ON, NodeState.RUNNING).put( + VAppStatus.RESOLVED, NodeState.PENDING).put(VAppStatus.SUSPENDED, + NodeState.SUSPENDED).put(VAppStatus.UNRESOLVED, NodeState.PENDING).build(); } @Provides @@ -106,12 +105,16 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule { super.configure(); bind(String.class).annotatedWith(VCloud.class).toInstance(providerName); bind(AddNodeWithTagStrategy.class).to(VCloudAddNodeWithTagStrategy.class); + bind(new TypeLiteral() { + }).to(new TypeLiteral>() { + }).in(Scopes.SINGLETON); bind(RunNodesAndAddToSetStrategy.class).to( EncodeTemplateIdIntoNameRunNodesAndAddToSetStrategy.class); bind(ListNodesStrategy.class).to(VCloudListNodesStrategy.class); bind(GetNodeMetadataStrategy.class).to(VCloudGetNodeMetadataStrategy.class); bind(RebootNodeStrategy.class).to(VCloudRebootNodeStrategy.class); bind(DestroyNodeStrategy.class).to(VCloudDestroyNodeStrategy.class); + bindLoadBalancer(); bindSizes(); bindImages(); bindLocations(); @@ -132,11 +135,8 @@ public class VCloudComputeServiceContextModule extends VCloudContextModule { TimeUnit.SECONDS); } - @Provides - @Singleton - protected ComputeServiceContext provideContext(ComputeService computeService, - RestContext context) { - return new ComputeServiceContextImpl(computeService, context); + protected void bindLoadBalancer() { + bind(LoadBalancerService.class).toProvider(Providers. of(null)); } protected void bindImages() { diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/functions/FindLocationForResourceInVDC.java b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/functions/FindLocationForResourceInVDC.java index 1f68b42bfb..649681d94f 100644 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/functions/FindLocationForResourceInVDC.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/functions/FindLocationForResourceInVDC.java @@ -23,6 +23,7 @@ import java.util.Set; import javax.annotation.Resource; import javax.inject.Inject; +import javax.inject.Provider; import javax.inject.Singleton; import org.jclouds.domain.Location; @@ -43,11 +44,12 @@ public class FindLocationForResourceInVDC { @Resource protected Logger logger = Logger.NULL; - final Set locations; + final Provider> locations; final Location defaultLocation; @Inject - public FindLocationForResourceInVDC(Set locations, Location defaultLocation) { + public FindLocationForResourceInVDC(Provider> locations, + Location defaultLocation) { this.locations = locations; this.defaultLocation = defaultLocation; } @@ -55,7 +57,7 @@ public class FindLocationForResourceInVDC { public Location apply(NamedResource resource, final String vdcId) { Location location = null; try { - location = Iterables.find(locations, new Predicate() { + location = Iterables.find(locations.get(), new Predicate() { @Override public boolean apply(Location input) { diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/functions/VCloudGetNodeMetadata.java b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/functions/VCloudGetNodeMetadata.java index d3b4cac923..988b8b56d9 100644 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/functions/VCloudGetNodeMetadata.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/functions/VCloudGetNodeMetadata.java @@ -29,6 +29,7 @@ import java.util.regex.Pattern; import javax.annotation.Resource; import javax.inject.Inject; import javax.inject.Named; +import javax.inject.Provider; import javax.inject.Singleton; import org.jclouds.compute.domain.Image; @@ -62,7 +63,7 @@ public class VCloudGetNodeMetadata { public Logger logger = Logger.NULL; protected final VCloudClient client; protected final VCloudComputeClient computeClient; - protected final Set images; + protected final Provider> images; protected final FindLocationForResourceInVDC findLocationForResourceInVDC; protected final GetExtra getExtra; protected final Map vAppStatusToNodeState; @@ -76,7 +77,8 @@ public class VCloudGetNodeMetadata { @Inject protected VCloudGetNodeMetadata(VCloudClient client, VCloudComputeClient computeClient, Map vAppStatusToNodeState, GetExtra getExtra, - FindLocationForResourceInVDC findLocationForResourceInVDC, Set images) { + FindLocationForResourceInVDC findLocationForResourceInVDC, + Provider> images) { this.client = checkNotNull(client, "client"); this.images = checkNotNull(images, "images"); this.getExtra = checkNotNull(getExtra, "getExtra"); @@ -99,11 +101,12 @@ public class VCloudGetNodeMetadata { String templateIdInHexWithoutLeadingZeros = matcher.group(2).replaceAll("^[0]+", ""); final String templateId = Integer.parseInt(templateIdInHexWithoutLeadingZeros, 16) + ""; try { - image = Iterables.find(images, new Predicate() { + image = Iterables.find(images.get(), new Predicate() { @Override public boolean apply(Image input) { - return input.getProviderId().equals(templateId) && input.getLocation().equals(location); + return input.getProviderId().equals(templateId) + && input.getLocation().equals(location); } }); diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudGetNodeMetadataStrategy.java b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudGetNodeMetadataStrategy.java index d6df8ee6fc..6210d46d89 100644 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudGetNodeMetadataStrategy.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudGetNodeMetadataStrategy.java @@ -24,6 +24,7 @@ import java.util.Map; import java.util.Set; import javax.inject.Inject; +import javax.inject.Provider; import javax.inject.Singleton; import org.jclouds.compute.domain.Image; @@ -47,7 +48,8 @@ public class VCloudGetNodeMetadataStrategy extends VCloudGetNodeMetadata impleme @Inject protected VCloudGetNodeMetadataStrategy(VCloudClient client, VCloudComputeClient computeClient, Map vAppStatusToNodeState, GetExtra getExtra, - FindLocationForResourceInVDC findLocationForResourceInVDC, Set images) { + FindLocationForResourceInVDC findLocationForResourceInVDC, + Provider> images) { super(client, computeClient, vAppStatusToNodeState, getExtra, findLocationForResourceInVDC, images); } diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudListNodesStrategy.java b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudListNodesStrategy.java index 723a466350..53dd7d7571 100644 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudListNodesStrategy.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/compute/strategy/VCloudListNodesStrategy.java @@ -24,6 +24,7 @@ import java.util.Set; import javax.annotation.Resource; import javax.inject.Inject; import javax.inject.Named; +import javax.inject.Provider; import javax.inject.Singleton; import org.jclouds.compute.domain.ComputeMetadata; @@ -62,7 +63,8 @@ public class VCloudListNodesStrategy extends VCloudGetNodeMetadata implements Li @Inject protected VCloudListNodesStrategy(VCloudClient client, VCloudComputeClient computeClient, Map vAppStatusToNodeState, GetExtra getExtra, - FindLocationForResourceInVDC findLocationForResourceInVDC, Set images) { + FindLocationForResourceInVDC findLocationForResourceInVDC, + Provider> images) { super(client, computeClient, vAppStatusToNodeState, getExtra, findLocationForResourceInVDC, images); } 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 7f71d1e6ca..1c1dccb1df 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 @@ -42,6 +42,7 @@ import javax.inject.Named; import javax.inject.Singleton; import org.jclouds.concurrent.ExpirableSupplier; +import org.jclouds.concurrent.RetryOnTimeOutExceptionSupplier; import org.jclouds.concurrent.internal.SyncProxy; import org.jclouds.encryption.EncryptionService; import org.jclouds.http.HttpErrorHandler; @@ -158,17 +159,19 @@ public class VCloudRestClientModule extends AbstractModule { @Singleton Supplier provideVCloudTokenCache( @Named(PROPERTY_VCLOUD_SESSIONINTERVAL) long seconds, final VCloudLoginAsyncClient login) { - return new ExpirableSupplier(new Supplier() { - public VCloudSession get() { - try { - return login.login().get(180, TimeUnit.SECONDS); - } catch (Exception e) { - Throwables.propagate(e); - assert false; - return null; - } - } - }, seconds, TimeUnit.SECONDS); + return new ExpirableSupplier( + new RetryOnTimeOutExceptionSupplier(new Supplier() { + public VCloudSession get() { + try { + return login.login().get(10, TimeUnit.SECONDS); + } catch (Exception e) { + Throwables.propagate(e); + assert false : e; + return null; + } + } + + }), seconds, TimeUnit.SECONDS); } @Provides diff --git a/vcloud/core/src/main/java/org/jclouds/vcloud/functions/ParseLoginResponseFromHeaders.java b/vcloud/core/src/main/java/org/jclouds/vcloud/functions/ParseLoginResponseFromHeaders.java index bd60e09c8f..ee0fb7279d 100755 --- a/vcloud/core/src/main/java/org/jclouds/vcloud/functions/ParseLoginResponseFromHeaders.java +++ b/vcloud/core/src/main/java/org/jclouds/vcloud/functions/ParseLoginResponseFromHeaders.java @@ -31,6 +31,7 @@ import javax.ws.rs.core.HttpHeaders; import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponseException; +import org.jclouds.http.HttpUtils; import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax.Factory; import org.jclouds.vcloud.VCloudToken; @@ -48,7 +49,7 @@ import com.google.common.base.Function; */ @Singleton public class ParseLoginResponseFromHeaders implements Function { - static final Pattern pattern = Pattern.compile("vcloud-token=(.*); [Pp]ath=.*"); + static final Pattern pattern = Pattern.compile("vcloud-token=([^;]+);.*"); private final ParseSax.Factory factory; private final Provider orgHandlerProvider; @@ -87,6 +88,7 @@ public class ParseLoginResponseFromHeaders implements Function locations = ImmutableSet.of(vdcL); - - Set images = ImmutableSet.of(); + Provider> locations = Providers + .> of(ImmutableSet.of(vdcL)); + Provider> images = Providers.> of(ImmutableSet + . of()); FindLocationForResourceInVDC findLocationForResourceInVDC = new FindLocationForResourceInVDC( locations, null); VCloudListNodesStrategy strategy = new VCloudListNodesStrategy(client, computeClient, diff --git a/vcloud/core/src/test/java/org/jclouds/vcloud/functions/ParseLoginResponseFromHeadersTest.java b/vcloud/core/src/test/java/org/jclouds/vcloud/functions/ParseLoginResponseFromHeadersTest.java index efcdd6bdd7..bc2d274bda 100644 --- a/vcloud/core/src/test/java/org/jclouds/vcloud/functions/ParseLoginResponseFromHeadersTest.java +++ b/vcloud/core/src/test/java/org/jclouds/vcloud/functions/ParseLoginResponseFromHeadersTest.java @@ -65,4 +65,23 @@ public class ParseLoginResponseFromHeadersTest extends BaseHandlerTest { } + @Test + public void testApplyBlueLock() { + HttpResponse response = new HttpResponse(); + response.setMessage("OK"); + response.setStatusCode(200); + response.setContent(getClass().getResourceAsStream("/orglist.xml")); + response.getHeaders().put(HttpHeaders.SET_COOKIE, + "vcloud-token=c9f232506df9b65d7b7d97b7499eddd7; Domain=.bluelock.com; Path=/"); + response.getHeaders().put(HttpHeaders.CONTENT_LENGTH, "307"); + response.getHeaders().put(HttpHeaders.CONTENT_TYPE, + "Content-Type: application/xml; charset=utf-8"); + VCloudSession reply = parser.apply(response); + assertEquals(reply.getVCloudToken(), "c9f232506df9b65d7b7d97b7499eddd7"); + assertEquals(reply.getOrgs(), ImmutableMap.of("adrian@jclouds.org", new NamedResourceImpl("48", + "adrian@jclouds.org", VCloudMediaType.ORG_XML, URI + .create("https://services.vcloudexpress.terremark.com/api/v0.8/org/48")))); + + } + } diff --git a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/config/TerremarkVCloudComputeServiceContextModule.java b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/config/TerremarkVCloudComputeServiceContextModule.java index d0d9e9b304..95a50a6acd 100755 --- a/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/config/TerremarkVCloudComputeServiceContextModule.java +++ b/vcloud/terremark/src/main/java/org/jclouds/vcloud/terremark/compute/config/TerremarkVCloudComputeServiceContextModule.java @@ -57,9 +57,16 @@ public class TerremarkVCloudComputeServiceContextModule extends VCloudComputeSer bind(VCloudComputeClient.class).to(TerremarkVCloudComputeClient.class); bind(PopulateDefaultLoginCredentialsForImageStrategy.class).to( ParseVAppTemplateDescriptionToGetDefaultLoginCredentials.class); - } + // TODO + // @Override + // protected void bindLoadBalancer() { + // bind(LoadBalanceNodesStrategy.class).to(TerremarkLoadBalanceNodesStrategy.class); + // bind(DestroyLoadBalancerStrategy.class).to(TerremarkDestroyLoadBalancerStrategy.class); + // } + // + @Named("PASSWORD") @Provides String providePassword() {