1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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 }