From 428b2bd2ea2d73354e15ffad52516105b15576cd Mon Sep 17 00:00:00 2001 From: nterry Date: Thu, 1 Sep 2011 10:36:00 -0600 Subject: [PATCH] Fixed ec2 issue where whole thing aborts if one regoin is unavailable. Should be easy to implement with other providers. --- .../ec2/config/EC2RestClientModule.java | 35 +++--- .../ec2/config/EC2RestClientModuleTest.java | 100 ++++++++++++++++++ 2 files changed, 119 insertions(+), 16 deletions(-) create mode 100644 apis/ec2/src/test/java/org/jclouds/ec2/config/EC2RestClientModuleTest.java diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/config/EC2RestClientModule.java b/apis/ec2/src/main/java/org/jclouds/ec2/config/EC2RestClientModule.java index c612905821..90464c7937 100644 --- a/apis/ec2/src/main/java/org/jclouds/ec2/config/EC2RestClientModule.java +++ b/apis/ec2/src/main/java/org/jclouds/ec2/config/EC2RestClientModule.java @@ -67,7 +67,7 @@ import com.google.inject.name.Names; /** * Configures the EC2 connection. * - * @author Adrian Cole + * @author Adrian Cole (EDIT: Nick Terry nterry@familysearch.org) */ @RequiresHttp @ConfiguresRestClient @@ -133,27 +133,30 @@ public class EC2RestClientModule } @Singleton - public static class RegionIdToZoneId implements javax.inject.Provider> { - private final AvailabilityZoneAndRegionClient client; - private final Map regions; - - @Inject - public RegionIdToZoneId(EC2Client client, @Region Map regions) { - this.client = client.getAvailabilityZoneAndRegionServices(); - this.regions = regions; - } - - @Singleton @Zone @Override public Map get() { - Builder map = ImmutableMap. builder(); + Builder map = ImmutableMap.builder(); + HttpResponseException exception = null; for (Entry region : regions.entrySet()) { - for (AvailabilityZoneInfo zoneInfo : client.describeAvailabilityZonesInRegion(region.getKey())) { - map.put(zoneInfo.getZone(), region.getKey()); + try { + for (AvailabilityZoneInfo zoneInfo : client.describeAvailabilityZonesInRegion(region.getKey())) { + map.put(zoneInfo.getZone(), region.getKey()); + } + } catch (HttpResponseException e) { + if (e.getMessage().contains("Unable to tunnel through proxy")) { + exception = e; + logger.error(e, "Could not describe availability zones in Region: %s", region.getKey()); + } else { + throw e; + } } } - return map.build(); + ImmutableMap result = map.build(); + if (result.isEmpty() && exception != null) { + throw exception; + } + return result; } } diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/config/EC2RestClientModuleTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/config/EC2RestClientModuleTest.java new file mode 100644 index 0000000000..d3e34de392 --- /dev/null +++ b/apis/ec2/src/test/java/org/jclouds/ec2/config/EC2RestClientModuleTest.java @@ -0,0 +1,100 @@ +package org.jclouds.ec2.config; + +import static org.easymock.classextension.EasyMock.*; + +import org.easymock.classextension.IMocksControl; +import org.jclouds.ec2.EC2Client; +import org.jclouds.ec2.domain.AvailabilityZoneInfo; +import org.jclouds.ec2.services.AvailabilityZoneAndRegionClient; +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpResponseException; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +import java.net.URI; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * A test for {@link EC2RestClientModule}. + * + * @author Eric Pabst (pabstec@familysearch.org) + */ +public class EC2RestClientModuleTest { + @Test + public void testDescribeAvailabilityZonesInRegion_BestEffort() { + IMocksControl control = createControl(); + EC2Client client = control.createMock(EC2Client.class); + AvailabilityZoneAndRegionClient regionClient = control.createMock(AvailabilityZoneAndRegionClient.class); + AvailabilityZoneInfo info1 = control.createMock(AvailabilityZoneInfo.class); + AvailabilityZoneInfo info2 = control.createMock(AvailabilityZoneInfo.class); + HttpCommand command = control.createMock(HttpCommand.class); + HttpResponseException exception = new HttpResponseException("Error: Unable to tunnel through proxy: ...", command, null); + + expect(client.getAvailabilityZoneAndRegionServices()).andStubReturn(regionClient); + expect(regionClient.describeAvailabilityZonesInRegion("accessibleRegion1")).andReturn(Collections.singleton(info1)); + expect(regionClient.describeAvailabilityZonesInRegion("inaccessibleRegion")).andThrow(exception); + expect(regionClient.describeAvailabilityZonesInRegion("accessibleRegion2")).andReturn(Collections.singleton(info2)); + expect(info1.getZone()).andStubReturn("zone1"); + expect(info2.getZone()).andStubReturn("zone2"); + + Map regions = new LinkedHashMap(); + regions.put("accessibleRegion1", null); + regions.put("inaccessibleRegion", null); + regions.put("accessibleRegion2", null); + control.replay(); + + Map expectedResult = new HashMap(); + expectedResult.put("zone1", "accessibleRegion1"); + expectedResult.put("zone2", "accessibleRegion2"); + + EC2RestClientModule.RegionIdToZoneId regionIdToZoneId = new EC2RestClientModule.RegionIdToZoneId(client, regions); + assertEquals(regionIdToZoneId.get(), expectedResult); + control.verify(); + } + + @Test + public void testDescribeAvailabilityZonesInRegion_RethrowIfNoneFound() { + IMocksControl control = createControl(); + EC2Client client = control.createMock(EC2Client.class); + AvailabilityZoneAndRegionClient regionClient = control.createMock(AvailabilityZoneAndRegionClient.class); + HttpCommand command = control.createMock(HttpCommand.class); + HttpResponseException exception = new HttpResponseException("Error: Unable to tunnel through proxy: ...", command, null); + + expect(client.getAvailabilityZoneAndRegionServices()).andStubReturn(regionClient); + expect(regionClient.describeAvailabilityZonesInRegion("inaccessibleRegion")).andThrow(exception); + + Map regions = new LinkedHashMap(); + regions.put("inaccessibleRegion", null); + control.replay(); + + EC2RestClientModule.RegionIdToZoneId regionIdToZoneId = new EC2RestClientModule.RegionIdToZoneId(client, regions); + try { + regionIdToZoneId.get(); + fail("expected exception"); + } catch (HttpResponseException e) { + assertEquals(e, exception); + } + control.verify(); + } + + @Test + public void testDescribeAvailabilityZonesInRegion_NoZones() { + IMocksControl control = createControl(); + EC2Client client = control.createMock(EC2Client.class); + AvailabilityZoneAndRegionClient regionClient = control.createMock(AvailabilityZoneAndRegionClient.class); + + expect(client.getAvailabilityZoneAndRegionServices()).andStubReturn(regionClient); + expect(regionClient.describeAvailabilityZonesInRegion("emptyRegion")).andReturn(Collections.emptySet()); + + Map regions = new LinkedHashMap(); + regions.put("emptyRegion", null); + control.replay(); + + EC2RestClientModule.RegionIdToZoneId regionIdToZoneId = new EC2RestClientModule.RegionIdToZoneId(client, regions); + assertEquals(regionIdToZoneId.get(), Collections.emptyMap()); + control.verify(); + } +}