Fixed ec2 issue where whole thing aborts if one regoin is unavailable. Should be easy to implement with other providers.

This commit is contained in:
nterry 2011-09-01 10:36:00 -06:00
parent 073eba9699
commit 428b2bd2ea
2 changed files with 119 additions and 16 deletions

View File

@ -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<S extends EC2Client, A extends EC2AsyncClient>
}
@Singleton
public static class RegionIdToZoneId implements javax.inject.Provider<Map<String, String>> {
private final AvailabilityZoneAndRegionClient client;
private final Map<String, URI> regions;
@Inject
public RegionIdToZoneId(EC2Client client, @Region Map<String, URI> regions) {
this.client = client.getAvailabilityZoneAndRegionServices();
this.regions = regions;
}
@Singleton
@Zone
@Override
public Map<String, String> get() {
Builder<String, String> map = ImmutableMap.<String, String> builder();
Builder<String, String> map = ImmutableMap.builder();
HttpResponseException exception = null;
for (Entry<String, URI> 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<String, String> result = map.build();
if (result.isEmpty() && exception != null) {
throw exception;
}
return result;
}
}

View File

@ -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<String, URI> regions = new LinkedHashMap<String, URI>();
regions.put("accessibleRegion1", null);
regions.put("inaccessibleRegion", null);
regions.put("accessibleRegion2", null);
control.replay();
Map<String,String> expectedResult = new HashMap<String,String>();
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<String, URI> regions = new LinkedHashMap<String, URI>();
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.<AvailabilityZoneInfo>emptySet());
Map<String, URI> regions = new LinkedHashMap<String, URI>();
regions.put("emptyRegion", null);
control.replay();
EC2RestClientModule.RegionIdToZoneId regionIdToZoneId = new EC2RestClientModule.RegionIdToZoneId(client, regions);
assertEquals(regionIdToZoneId.get(), Collections.<String, String>emptyMap());
control.verify();
}
}