EMMA Coverage Report (generated Fri Apr 27 15:03:37 EDT 2012)
[all classes][org.jclouds.ec2.compute.strategy]

COVERAGE SUMMARY FOR SOURCE FILE [EC2CreateNodesInGroupThenAddToSet.java]

nameclass, %method, %block, %line, %
EC2CreateNodesInGroupThenAddToSet.java100% (2/2)100% (10/10)90%  (439/489)97%  (75.5/78)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class EC2CreateNodesInGroupThenAddToSet100% (1/1)100% (8/8)90%  (428/478)97%  (74.5/77)
createNodesInRegionAndZone (String, String, String, int, Template, RunInstanc... 100% (1/1)49%  (47/96)82%  (9/11)
populateCredentials (Iterable): void 100% (1/1)98%  (54/55)94%  (8.5/9)
<static initializer> 100% (1/1)100% (5/5)100% (1/1)
EC2CreateNodesInGroupThenAddToSet (EC2Client, LoadingCache, Predicate, Provid... 100% (1/1)100% (69/69)100% (14/14)
allocateElasticIpsInRegion (int, Template): Iterable 100% (1/1)100% (45/45)100% (8/8)
assignElasticIpsToInstances (Iterable, Iterable): void 100% (1/1)100% (108/108)100% (18/18)
createKeyPairAndSecurityGroupsAsNeededThenRunInstances (String, int, Template... 100% (1/1)100% (24/24)100% (4/4)
execute (String, int, Template, Set, Map, Multimap): Map 100% (1/1)100% (76/76)100% (12/12)
     
class EC2CreateNodesInGroupThenAddToSet$1100% (1/1)100% (2/2)100% (11/11)100% (2/2)
EC2CreateNodesInGroupThenAddToSet$1 (): void 100% (1/1)100% (3/3)100% (1/1)
apply (RunningInstance): RegionAndName 100% (1/1)100% (8/8)100% (1/1)

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 */
19package org.jclouds.ec2.compute.strategy;
20 
21import static com.google.common.base.Preconditions.checkNotNull;
22import static com.google.common.collect.Iterables.all;
23import static com.google.common.collect.Iterables.transform;
24import static org.jclouds.ec2.compute.util.EC2ComputeUtils.getZoneFromLocationOrNull;
25 
26import java.util.Map;
27import java.util.Set;
28import java.util.concurrent.Future;
29import java.util.concurrent.atomic.AtomicReference;
30 
31import javax.annotation.Resource;
32import javax.inject.Inject;
33import javax.inject.Named;
34import javax.inject.Provider;
35import javax.inject.Singleton;
36 
37import org.jclouds.aws.util.AWSUtils;
38import org.jclouds.compute.config.CustomizationResponse;
39import org.jclouds.compute.domain.NodeMetadata;
40import org.jclouds.compute.domain.Template;
41import org.jclouds.compute.domain.TemplateBuilder;
42import org.jclouds.compute.reference.ComputeServiceConstants;
43import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet;
44import org.jclouds.compute.util.ComputeUtils;
45import org.jclouds.domain.Credentials;
46import org.jclouds.ec2.EC2Client;
47import org.jclouds.ec2.compute.domain.RegionAndName;
48import org.jclouds.ec2.compute.predicates.InstancePresent;
49import org.jclouds.ec2.domain.RunningInstance;
50import org.jclouds.ec2.options.RunInstancesOptions;
51import org.jclouds.ec2.reference.EC2Constants;
52import org.jclouds.logging.Logger;
53 
54import com.google.common.annotations.VisibleForTesting;
55import com.google.common.base.Function;
56import com.google.common.base.Joiner;
57import com.google.common.base.Predicate;
58import com.google.common.cache.LoadingCache;
59import com.google.common.collect.ImmutableSet;
60import com.google.common.collect.ImmutableSet.Builder;
61import com.google.common.collect.Iterables;
62import com.google.common.collect.Multimap;
63 
64/**
65 * creates futures that correlate to
66 * 
67 * @author Adrian Cole
68 */
69@Singleton
70public class EC2CreateNodesInGroupThenAddToSet implements CreateNodesInGroupThenAddToSet {
71 
72   @Resource
73   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
74   protected Logger logger = Logger.NULL;
75 
76   @Inject
77   @Named(EC2Constants.PROPERTY_EC2_AUTO_ALLOCATE_ELASTIC_IPS)
78   @VisibleForTesting
79   boolean autoAllocateElasticIps = false;
80 
81   @VisibleForTesting
82   final EC2Client client;
83   @VisibleForTesting
84   final Predicate<AtomicReference<NodeMetadata>> nodeRunning;
85   @VisibleForTesting
86   final LoadingCache<RegionAndName, String> elasticIpCache;
87   @VisibleForTesting
88   final CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize;
89   @VisibleForTesting
90   final Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata;
91   @VisibleForTesting
92   final ComputeUtils utils;
93   final InstancePresent instancePresent;
94   final LoadingCache<RunningInstance, Credentials> instanceToCredentials;
95   final Map<String, Credentials> credentialStore;
96   final Provider<TemplateBuilder> templateBuilderProvider;
97 
98 
99 
100   @Inject
101   protected EC2CreateNodesInGroupThenAddToSet(
102            EC2Client client,
103            @Named("ELASTICIP")
104            LoadingCache<RegionAndName, String> elasticIpCache, 
105            @Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
106            Provider<TemplateBuilder> templateBuilderProvider,
107            CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
108            InstancePresent instancePresent, Function<RunningInstance, NodeMetadata> runningInstanceToNodeMetadata,
109            LoadingCache<RunningInstance, Credentials> instanceToCredentials, Map<String, Credentials> credentialStore,
110            ComputeUtils utils) {
111      this.client = checkNotNull(client, "client");
112      this.elasticIpCache = checkNotNull(elasticIpCache, "elasticIpCache");
113      this.nodeRunning = checkNotNull(nodeRunning, "nodeRunning");
114      this.templateBuilderProvider = checkNotNull(templateBuilderProvider, "templateBuilderProvider");
115      this.instancePresent = checkNotNull(instancePresent, "instancePresent");
116      this.createKeyPairAndSecurityGroupsAsNeededAndReturncustomize = checkNotNull(
117               createKeyPairAndSecurityGroupsAsNeededAndReturncustomize,
118               "createKeyPairAndSecurityGroupsAsNeededAndReturncustomize");
119      this.runningInstanceToNodeMetadata = checkNotNull(runningInstanceToNodeMetadata, "runningInstanceToNodeMetadata");
120      this.instanceToCredentials = checkNotNull(instanceToCredentials, "instanceToCredentials");
121      this.credentialStore = checkNotNull(credentialStore, "credentialStore");
122      this.utils = checkNotNull(utils, "utils");
123   }
124 
125   public static Function<RunningInstance, RegionAndName> instanceToRegionAndName = new Function<RunningInstance, RegionAndName>() {
126      @Override
127      public RegionAndName apply(RunningInstance from) {
128         return new RegionAndName(from.getRegion(), from.getId());
129      }
130   };
131 
132   @Override
133   public Map<?, Future<Void>> execute(String group, int count, Template template, Set<NodeMetadata> goodNodes,
134            Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
135      // ensure we don't mutate the input template
136      template = templateBuilderProvider.get().fromTemplate(template).build();
137 
138      Iterable<String> ips = allocateElasticIpsInRegion(count, template);
139 
140      Iterable<? extends RunningInstance> started = createKeyPairAndSecurityGroupsAsNeededThenRunInstances(group,
141               count, template);
142 
143      Iterable<RegionAndName> ids = transform(started, instanceToRegionAndName);
144 
145      String idsString = Joiner.on(',').join(ids);
146      if (Iterables.size(ids) > 0) {
147         logger.debug("<< started instances(%s)", idsString);
148         all(ids, instancePresent);
149         logger.debug("<< present instances(%s)", idsString);
150         populateCredentials(started);
151      }
152      
153      assignElasticIpsToInstances(ips, started);
154      
155      return utils.customizeNodesAndAddToGoodMapOrPutExceptionIntoBadMap(template.getOptions(), transform(started,
156               runningInstanceToNodeMetadata), goodNodes, badNodes, customizationResponses);
157   }
158 
159   protected void populateCredentials(Iterable<? extends RunningInstance> started) {
160      Credentials credentials = null;
161      for (RunningInstance instance : started) {
162         credentials = instanceToCredentials.apply(instance);
163         if (credentials != null)
164            break;
165      }
166      if (credentials != null)
167         for (RunningInstance instance : started)
168            credentialStore.put("node#" + instance.getRegion() + "/" + instance.getId(), credentials);
169   }
170 
171   protected Iterable<String> allocateElasticIpsInRegion(int count, Template template) {
172      
173      Builder<String> ips = ImmutableSet.builder();
174      if (!autoAllocateElasticIps)
175         return ips.build();
176 
177      String region = AWSUtils.getRegionFromLocationOrNull(template.getLocation());
178      logger.debug("<< allocating %d elastic IPs for nodes in region (%s)", count, region);
179 
180      for (int i = 0; i < count; ++i) {
181         ips.add(client.getElasticIPAddressServices().allocateAddressInRegion(region));
182      }
183      return ips.build();
184   }
185 
186   protected void assignElasticIpsToInstances(Iterable<String> ips, Iterable<? extends RunningInstance> startedInstances) {
187 
188      if (!autoAllocateElasticIps)
189         return;
190 
191      // TODO parallel
192      int i = 0;
193      for (RunningInstance startedInstance : startedInstances) {
194         String ip = Iterables.get(ips, i);
195         String region = startedInstance.getRegion();
196         String id = startedInstance.getId();
197         RegionAndName coordinates = new RegionAndName(region, id);
198 
199         // block until instance is running
200         logger.debug(">> awaiting status running instance(%s)", coordinates);
201         AtomicReference<NodeMetadata> node = new AtomicReference<NodeMetadata>(runningInstanceToNodeMetadata.apply(startedInstance));
202         nodeRunning.apply(node);
203         logger.trace("<< running instance(%s)", coordinates);
204         logger.debug(">> associating elastic IP %s to instance %s", ip, coordinates);
205         client.getElasticIPAddressServices().associateAddressInRegion(region, ip, id);
206         logger.trace("<< associated elastic IP %s to instance %s", ip, coordinates);
207         // add mapping of instance to ip into the cache
208         elasticIpCache.put(coordinates, ip);
209      }
210   }
211 
212   protected Iterable<? extends RunningInstance> createKeyPairAndSecurityGroupsAsNeededThenRunInstances(String group,
213            int count, Template template) {
214      String region = AWSUtils.getRegionFromLocationOrNull(template.getLocation());
215      String zone = getZoneFromLocationOrNull(template.getLocation());
216      RunInstancesOptions instanceOptions = createKeyPairAndSecurityGroupsAsNeededAndReturncustomize.execute(region,
217               group, template);
218      return createNodesInRegionAndZone(region, zone, group, count, template, instanceOptions);
219   }
220 
221   protected Iterable<? extends RunningInstance> createNodesInRegionAndZone(String region, String zone, String group,
222            int count, Template template, RunInstancesOptions instanceOptions) {
223      int countStarted = 0;
224      int tries = 0;
225      Iterable<? extends RunningInstance> started = ImmutableSet.<RunningInstance> of();
226 
227      while (countStarted < count && tries++ < count) {
228         if (logger.isDebugEnabled())
229            logger.debug(">> running %d instance region(%s) zone(%s) ami(%s) params(%s)", count - countStarted, region,
230                     zone, template.getImage().getProviderId(), instanceOptions.buildFormParameters());
231 
232         started = Iterables.concat(started, client.getInstanceServices().runInstancesInRegion(region, zone,
233                  template.getImage().getProviderId(), 1, count - countStarted, instanceOptions));
234 
235         countStarted = Iterables.size(started);
236         if (countStarted < count)
237            logger.debug(">> not enough instances (%d/%d) started, attempting again", countStarted, count);
238      }
239      return started;
240   }
241 
242}

[all classes][org.jclouds.ec2.compute.strategy]
EMMA 2.0.5312 (C) Vladimir Roubtsov