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.aws.ec2.compute.suppliers;
20  
21  import static com.google.common.collect.Iterables.concat;
22  import static com.google.common.collect.Iterables.transform;
23  import static com.google.common.collect.Maps.uniqueIndex;
24  import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_AMI_QUERY;
25  import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_CC_AMI_QUERY;
26  import static org.jclouds.aws.ec2.reference.AWSEC2Constants.PROPERTY_EC2_CC_REGIONS;
27  
28  import java.util.Set;
29  import java.util.concurrent.ExecutorService;
30  import java.util.concurrent.Future;
31  
32  import javax.annotation.Resource;
33  import javax.inject.Inject;
34  import javax.inject.Named;
35  import javax.inject.Singleton;
36  
37  import org.jclouds.Constants;
38  import org.jclouds.aws.ec2.compute.config.ClusterCompute;
39  import org.jclouds.compute.domain.Image;
40  import org.jclouds.compute.reference.ComputeServiceConstants;
41  import org.jclouds.ec2.compute.domain.RegionAndName;
42  import org.jclouds.location.Region;
43  import org.jclouds.logging.Logger;
44  
45  import com.google.common.base.Function;
46  import com.google.common.base.Splitter;
47  import com.google.common.base.Supplier;
48  import com.google.common.base.Throwables;
49  import com.google.common.cache.Cache;
50  import com.google.common.cache.CacheBuilder;
51  import com.google.common.cache.CacheLoader;
52  import com.google.common.collect.ImmutableMultimap;
53  import com.google.common.collect.ImmutableSet;
54  import com.google.common.collect.Iterables;
55  import com.google.common.collect.Multimap;
56  import com.google.common.util.concurrent.Futures;
57  
58  /**
59   * 
60   * @author Adrian Cole
61   */
62  @Singleton
63  public class AWSRegionAndNameToImageSupplier implements Supplier<Cache<RegionAndName, ? extends Image>> {
64     @Resource
65     @Named(ComputeServiceConstants.COMPUTE_LOGGER)
66     protected Logger logger = Logger.NULL;
67  
68     private final CacheLoader<RegionAndName, Image> regionAndIdToImage;
69     private final Set<String> clusterComputeIds;
70     private final CallForImages.Factory factory;
71     private final ExecutorService executor;
72  
73     private final Iterable<String> regions;
74     private final String amiQuery;
75     private final Iterable<String> clusterRegions;
76     private final String ccAmiQuery;
77  
78     @Inject
79     protected AWSRegionAndNameToImageSupplier(@Region Set<String> regions,
80              @Named(PROPERTY_EC2_AMI_QUERY) String amiQuery, @Named(PROPERTY_EC2_CC_REGIONS) String clusterRegions,
81              @Named(PROPERTY_EC2_CC_AMI_QUERY) String ccAmiQuery, CacheLoader<RegionAndName, Image> regionAndIdToImage,
82              CallForImages.Factory factory, @ClusterCompute Set<String> clusterComputeIds,
83              @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
84        this.factory = factory;
85        this.regions = regions;
86        this.amiQuery = amiQuery;
87        this.clusterRegions = Splitter.on(',').split(clusterRegions);
88        this.ccAmiQuery = ccAmiQuery;
89        this.regionAndIdToImage = regionAndIdToImage;
90        this.clusterComputeIds = clusterComputeIds;
91        this.executor = executor;
92     }
93  
94     @Override
95     public Cache<RegionAndName, ? extends Image> get() {
96        Future<Iterable<Image>> normalImages = images(regions, amiQuery, PROPERTY_EC2_AMI_QUERY);
97        ImmutableSet<Image> clusterImages;
98        try {
99           clusterImages = ImmutableSet.copyOf(images(clusterRegions, ccAmiQuery, PROPERTY_EC2_CC_AMI_QUERY).get());
100       } catch (Exception e) {
101          logger.warn(e, "Error parsing images in query %s", ccAmiQuery);
102          Throwables.propagate(e);
103          return null;
104       }
105       Iterables.addAll(clusterComputeIds, transform(clusterImages, new Function<Image, String>() {
106 
107          @Override
108          public String apply(Image arg0) {
109             return arg0.getId();
110          }
111       }));
112       Iterable<? extends Image> parsedImages;
113       try {
114          parsedImages = ImmutableSet.copyOf(concat(clusterImages, normalImages.get()));
115       } catch (Exception e) {
116          logger.warn(e, "Error parsing images in query %s", amiQuery);
117          Throwables.propagate(e);
118          return null;
119       }
120       Cache<RegionAndName, Image> cache = CacheBuilder.newBuilder().build(regionAndIdToImage);
121 
122       cache.asMap().putAll(uniqueIndex(parsedImages, new Function<Image, RegionAndName>() {
123 
124          @Override
125          public RegionAndName apply(Image from) {
126             return new RegionAndName(from.getLocation().getId(), from.getProviderId());
127          }
128 
129       }));
130       logger.debug("<< images(%d)", cache.asMap().size());
131       return cache;
132    }
133 
134    private Future<Iterable<Image>> images(Iterable<String> regions, String query, String tag) {
135       if (query.equals("")) {
136          logger.debug(">> no %s specified, skipping image parsing", tag);
137          return Futures.<Iterable<Image>> immediateFuture(ImmutableSet.<Image> of());
138       } else {
139          return executor.submit(factory.parseImagesFromRegionsUsingFilter(regions, QueryStringToMultimap.INSTANCE
140                   .apply(query)));
141       }
142    }
143 
144    public static enum QueryStringToMultimap implements Function<String, Multimap<String, String>> {
145       INSTANCE;
146       @Override
147       public Multimap<String, String> apply(String arg0) {
148          ImmutableMultimap.Builder<String, String> builder = ImmutableMultimap.<String, String> builder();
149          for (String pair : Splitter.on(';').split(arg0)) {
150             String[] keyValue = pair.split("=");
151             if (keyValue.length == 1)
152                builder.putAll(keyValue[0], ImmutableSet.<String> of());
153             else
154                builder.putAll(keyValue[0], Splitter.on(',').split(keyValue[1]));
155          }
156          return builder.build();
157       }
158    }
159 }