View Javadoc

1   /**
2    * Licensed to jclouds, Inc. (jclouds) under one or more
3    * contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  jclouds licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.jclouds.ec2.config;
20  
21  import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS;
22  
23  import java.net.URI;
24  import java.util.Map;
25  import java.util.Set;
26  import java.util.Map.Entry;
27  
28  import javax.annotation.Resource;
29  import javax.inject.Inject;
30  import javax.inject.Singleton;
31  
32  import org.jclouds.aws.config.WithZonesFormSigningRestClientModule;
33  import org.jclouds.ec2.EC2AsyncClient;
34  import org.jclouds.ec2.EC2Client;
35  import org.jclouds.ec2.domain.AvailabilityZoneInfo;
36  import org.jclouds.ec2.services.AMIAsyncClient;
37  import org.jclouds.ec2.services.AMIClient;
38  import org.jclouds.ec2.services.AvailabilityZoneAndRegionAsyncClient;
39  import org.jclouds.ec2.services.AvailabilityZoneAndRegionClient;
40  import org.jclouds.ec2.services.ElasticBlockStoreAsyncClient;
41  import org.jclouds.ec2.services.ElasticBlockStoreClient;
42  import org.jclouds.ec2.services.ElasticIPAddressAsyncClient;
43  import org.jclouds.ec2.services.ElasticIPAddressClient;
44  import org.jclouds.ec2.services.InstanceAsyncClient;
45  import org.jclouds.ec2.services.InstanceClient;
46  import org.jclouds.ec2.services.KeyPairAsyncClient;
47  import org.jclouds.ec2.services.KeyPairClient;
48  import org.jclouds.ec2.services.SecurityGroupAsyncClient;
49  import org.jclouds.ec2.services.SecurityGroupClient;
50  import org.jclouds.ec2.services.WindowsAsyncClient;
51  import org.jclouds.ec2.services.WindowsClient;
52  import org.jclouds.http.HttpResponseException;
53  import org.jclouds.http.RequiresHttp;
54  import org.jclouds.location.Region;
55  import org.jclouds.location.Zone;
56  import org.jclouds.logging.Logger;
57  import org.jclouds.rest.ConfiguresRestClient;
58  
59  import com.google.common.base.Predicates;
60  import com.google.common.base.Splitter;
61  import com.google.common.collect.ImmutableMap;
62  import com.google.common.collect.ImmutableSet;
63  import com.google.common.collect.Maps;
64  import com.google.common.collect.ImmutableMap.Builder;
65  import com.google.inject.ConfigurationException;
66  import com.google.inject.Injector;
67  import com.google.inject.Key;
68  import com.google.inject.name.Names;
69  
70  /**
71   * Configures the EC2 connection.
72   * 
73   * @author Adrian Cole (EDIT: Nick Terry nterry@familysearch.org)
74   */
75  @RequiresHttp
76  @ConfiguresRestClient
77  public class EC2RestClientModule<S extends EC2Client, A extends EC2AsyncClient> extends
78           WithZonesFormSigningRestClientModule<S, A> {
79  
80     public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()//
81              .put(AMIClient.class, AMIAsyncClient.class)//
82              .put(ElasticIPAddressClient.class, ElasticIPAddressAsyncClient.class)//
83              .put(InstanceClient.class, InstanceAsyncClient.class)//
84              .put(KeyPairClient.class, KeyPairAsyncClient.class)//
85              .put(SecurityGroupClient.class, SecurityGroupAsyncClient.class)//
86              .put(WindowsClient.class, WindowsAsyncClient.class)//
87              .put(AvailabilityZoneAndRegionClient.class, AvailabilityZoneAndRegionAsyncClient.class)//
88              .put(ElasticBlockStoreClient.class, ElasticBlockStoreAsyncClient.class)//
89              .build();
90  
91     public static EC2RestClientModule<EC2Client, EC2AsyncClient> create() {
92        return new EC2RestClientModule<EC2Client, EC2AsyncClient>(EC2Client.class, EC2AsyncClient.class, DELEGATE_MAP);
93     }
94  
95     public EC2RestClientModule(Class<S> sync, Class<A> async, Map<Class<?>, Class<?>> delegateMap) {
96        super(sync, async, delegateMap);
97     }
98  
99     @Override
100    protected void bindRegionsToProvider() {
101       bindRegionsToProvider(RegionIdsToURI.class);
102    }
103 
104    @Override
105    protected void bindZonesToProvider() {
106       bindZonesToProvider(RegionIdToZoneId.class);
107    }
108 
109    @Singleton
110    public static class RegionIdsToURI implements javax.inject.Provider<Map<String, URI>> {
111       private final AvailabilityZoneAndRegionClient client;
112       private final Injector injector;
113 
114       @Inject
115       public RegionIdsToURI(EC2Client client, Injector injector) {
116          this.client = client.getAvailabilityZoneAndRegionServices();
117          this.injector = injector;
118       }
119 
120       @Singleton
121       @Region
122       @Override
123       public Map<String, URI> get() {
124          try {
125             String regionString = injector.getInstance(Key.get(String.class, Names.named(PROPERTY_REGIONS)));
126             Set<String> regions = ImmutableSet.copyOf(Splitter.on(',').split(regionString));
127             if (regions.size() > 0)
128                return Maps.filterKeys(client.describeRegions(), Predicates.in(regions));
129          } catch (ConfigurationException e) {
130             // this happens if regions property isn't set
131             // services not run by AWS may not have regions, so this is ok.
132          }
133          return client.describeRegions();
134 
135       }
136    }
137 
138    @Singleton
139    public static class RegionIdToZoneId implements javax.inject.Provider<Map<String, String>> {
140       @Resource
141       protected Logger logger = Logger.NULL;
142       
143       private final AvailabilityZoneAndRegionClient client;
144       private final Map<String, URI> regions;
145 
146       @Inject
147       public RegionIdToZoneId(EC2Client client, @Region Map<String, URI> regions) {
148          this.client = client.getAvailabilityZoneAndRegionServices();
149          this.regions = regions;
150       }
151 
152       @Singleton
153       @Zone
154       @Override
155       public Map<String, String> get() {
156          Builder<String, String> map = ImmutableMap.builder();
157          HttpResponseException exception = null;
158          for (Entry<String, URI> region : regions.entrySet()) {
159             try {
160                for (AvailabilityZoneInfo zoneInfo : client.describeAvailabilityZonesInRegion(region.getKey())) {
161                   map.put(zoneInfo.getZone(), region.getKey());
162                }
163             } catch (HttpResponseException e) {
164                if (e.getMessage().contains("Unable to tunnel through proxy")) {
165                   exception = e;
166                   logger.error(e, "Could not describe availability zones in Region: %s", region.getKey());
167                } else {
168                   throw e;
169                }
170             }
171          }
172          ImmutableMap<String, String> result = map.build();
173          if (result.isEmpty() && exception != null) {
174             throw exception;
175          }
176          return result;
177       }
178 
179    }
180 
181 }